Files
contracts-app/site/llm_client.py
T
naeel c580c935ac fix(llm): модель gpt-oss-120b, max_tokens 8000
Доступные модели на api.aillm.ru: whisper, qwen3.6-27b, gpt-oss-120b.
gpt-oss-120b — та самая 120B модель.
max_tokens поднят до 8000 (reasoning съедает часть токенов).
2026-06-14 07:22:10 +04:00

81 lines
2.7 KiB
Python

"""
llm_client.py — Тонкий HTTP-клиент к LLM API.
Только отправить промпт → получить ответ. Никакой бизнес-логики.
Бизнес-логика (промпты, парсинг ответа) → extractor.py.
Использует:
LLM_API_URL — URL API (по умолчанию https://api.aillm.ru/v1/chat/completions)
LLM_API_KEY — ключ авторизации
"""
import os
import requests
# ── Конфигурация ────────────────────────────────────────────────
DEFAULT_URL = "https://api.aillm.ru/v1/chat/completions"
DEFAULT_MODEL = "gpt-oss-120b" # 120B модель через LiteLLM-прокси
def ask(prompt: str, model: str = None, max_tokens: int = 8000) -> dict:
"""
Отправить промпт к LLM API.
Args:
prompt: текст промпта
model: модель (None = DEFAULT_MODEL)
max_tokens: максимум токенов в ответе
Returns:
{"text": "ответ модели", "model": "...", "usage": {...}}
или
{"error": "описание ошибки"}
"""
api_url = os.getenv("LLM_API_URL", DEFAULT_URL)
api_key = os.getenv("LLM_API_KEY", "")
if not api_key:
return {"error": "LLM_API_KEY not set"}
model = model or DEFAULT_MODEL
payload = {
"model": model,
"messages": [
{"role": "user", "content": prompt},
],
"max_tokens": max_tokens,
"temperature": 0.1, # низкая температура = стабильный формат ответа
}
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
}
try:
resp = requests.post(api_url, json=payload, headers=headers, timeout=120)
resp.raise_for_status()
data = resp.json()
# OpenAI-совместимый формат ответа
choice = data.get("choices", [{}])[0]
message = choice.get("message", {})
text = message.get("content", "")
return {
"text": text,
"model": data.get("model", model),
"usage": data.get("usage", {}),
}
except requests.exceptions.Timeout:
return {"error": "LLM timeout (120s)"}
except requests.exceptions.HTTPError as e:
return {"error": f"LLM HTTP {e.response.status_code}: {e.response.text[:500]}"}
except requests.exceptions.RequestException as e:
return {"error": f"LLM request failed: {e}"}
except Exception as e:
return {"error": f"LLM unexpected: {e}"}