92 lines
3.0 KiB
Go
92 lines
3.0 KiB
Go
// Package llm — провайдер LLM за интерфейсом (дискриминатор type).
|
|
//
|
|
// Реализация выбирается полем [llm].type (см. docs/specs/recognition.md).
|
|
// Первый и пока единственный тип — "openai-compat": OpenAI-совместимый Chat
|
|
// Completions API (локальные серверы LM Studio/llama.cpp/Ollama и облачные
|
|
// совместимые провайдеры — DeepSeek, Qwen и др.).
|
|
//
|
|
// Пакет отвечает за один вызов модели и транспортную устойчивость (ретраи
|
|
// на сетевые сбои, 429 и 5xx). Бюджет переразбора ответа со схемой-в-промпте
|
|
// (llm.max_retries) принадлежит вызывающему recognize, а не провайдеру.
|
|
package llm
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"time"
|
|
)
|
|
|
|
// Role — роль сообщения в диалоге.
|
|
type Role string
|
|
|
|
const (
|
|
RoleSystem Role = "system"
|
|
RoleUser Role = "user"
|
|
RoleAssistant Role = "assistant"
|
|
)
|
|
|
|
// Message — одно сообщение запроса.
|
|
type Message struct {
|
|
Role Role
|
|
Content string
|
|
}
|
|
|
|
// Request — запрос к модели.
|
|
type Request struct {
|
|
Messages []Message
|
|
JSONMode bool // response_format: json_object (структурированный вывод)
|
|
Temperature *float64 // nil — не передаём, у модели остаётся её дефолт
|
|
MaxTokens int // 0 — не передаём
|
|
}
|
|
|
|
// Usage — расход токенов и стоимость (если провайдер их сообщает).
|
|
type Usage struct {
|
|
PromptTokens int
|
|
CompletionTokens int
|
|
TotalTokens int
|
|
Cost float64
|
|
}
|
|
|
|
// Response — ответ модели.
|
|
type Response struct {
|
|
Content string
|
|
Model string
|
|
Usage Usage
|
|
}
|
|
|
|
// Provider — абстракция доступа к LLM. recognize работает только с ним и не
|
|
// знает про конкретный транспорт.
|
|
type Provider interface {
|
|
Complete(ctx context.Context, req Request) (Response, error)
|
|
}
|
|
|
|
// Config — параметры провайдера (подмножество [llm] из конфига).
|
|
type Config struct {
|
|
Type string
|
|
BaseURL string
|
|
APIKey string
|
|
Model string
|
|
Proxy string
|
|
Timeout time.Duration
|
|
}
|
|
|
|
// ErrUnknownType — запрошенный [llm].type не поддерживается.
|
|
var ErrUnknownType = errors.New("llm: unknown provider type")
|
|
|
|
// New собирает провайдер по дискриминатору cfg.Type. logger nil → slog.Default().
|
|
func New(cfg Config, logger *slog.Logger) (Provider, error) {
|
|
if logger == nil {
|
|
logger = slog.Default()
|
|
}
|
|
switch cfg.Type {
|
|
case "openai-compat":
|
|
return newOpenAICompat(cfg, logger)
|
|
case "":
|
|
return nil, fmt.Errorf("%w: %q (set [llm].type)", ErrUnknownType, cfg.Type)
|
|
default:
|
|
return nil, fmt.Errorf("%w: %q", ErrUnknownType, cfg.Type)
|
|
}
|
|
}
|