feat(llm): провайдер за протоколом — OpenAI-совместимый API и mock, фабрика по конфигу
- LLMProvider: complete(messages, schema) -> LLMResult (текст, разобранный JSON, токены) - openai_compat: /chat/completions, structured output через response_format json_schema, JSON из ```-обёртки тоже разбирается; ретраи на 429/5xx и сетевые ошибки, 4xx — сразу ошибка - mock: детерминированные правила для тестов и демо без сети - LLMSettings (LLM_PROVIDER/BASE_URL/MODEL/API_KEY…), CLI python -m app.llm.cli Refs #17 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
"""LLM provider contract (ADR-008): the rest of the bot depends on this, never on a vendor SDK."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Literal, Protocol
|
||||
|
||||
Role = Literal["system", "user", "assistant"]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ChatMessage:
|
||||
role: Role
|
||||
content: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class JsonSchema:
|
||||
"""Ask the model for a JSON object of this shape (structured output)."""
|
||||
|
||||
name: str
|
||||
schema: dict[str, Any]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class LLMResult:
|
||||
text: str
|
||||
# Parsed object when a JSON schema was requested and the reply was valid JSON; None otherwise.
|
||||
# The caller still validates it — a model can return well-formed JSON of the wrong shape.
|
||||
data: dict[str, Any] | None = None
|
||||
prompt_tokens: int = 0
|
||||
completion_tokens: int = 0
|
||||
raw: dict[str, Any] = field(default_factory=dict, repr=False)
|
||||
|
||||
@property
|
||||
def tokens(self) -> int:
|
||||
return self.prompt_tokens + self.completion_tokens
|
||||
|
||||
|
||||
class LLMError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class LLMProvider(Protocol):
|
||||
async def complete(self, messages: list[ChatMessage], schema: JsonSchema | None = None) -> LLMResult: ...
|
||||
|
||||
async def aclose(self) -> None: ...
|
||||
Reference in New Issue
Block a user