class LLMClient:
"""Клиент для отправки текста на OpenAI-совместимый LLM-сервер (vLLM и т.п.)."""
def __init__(self, base_url: str, model_name: str, api_key: str = "none"):
self.base_url = base_url.rstrip("/")
self.server_url = self.base_url + "/v1/chat/completions"
self.models_url = self.base_url + "/v1/models"
self.model_name = model_name
self.headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}",
}
def get_models(self) -> list:
"""Получает список доступных моделей с сервера."""
try:
response = requests.get(self.models_url, headers=self.headers, timeout=30)
response.raise_for_status()
data = response.json()
if "data" in data:
return [model["id"] for model in data["data"]]
return []
except requests.exceptions.RequestException as e:
logger.error("Ошибка при получении списка моделей: %s", e)
return []
except (KeyError, TypeError, ValueError) as e:
logger.error("Ошибка парсинга списка моделей: %s", e)
return []
def send_prompt(
self,
system_role: str,
user_text: str,
temperature: float = 0.2,
response_format: Optional[dict] = None,
) -> str:
payload = {
"model": self.model_name,
"messages": [
{"role": "system", "content": system_role},
{"role": "user", "content": user_text},
],
"temperature": temperature,
}
if response_format is not None:
payload["response_format"] = response_format
last_error = "Неизвестная ошибка"
for attempt in range(1, MAX_RETRIES + 1):
try:
response = requests.post(
self.server_url,
headers=self.headers,
json=payload,
timeout=REQUEST_TIMEOUT_SEC,
)
response.raise_for_status()
return response.json()["choices"][0]["message"]["content"]
except requests.exceptions.RequestException as e:
last_error = f"Ошибка соединения с LLM-сервером: {e}"
except (KeyError, IndexError):
last_error = f"Ошибка парсинга ответа. Сервер вернул: {response.text}"
logger.warning("Попытка %s/%s не удалась: %s", attempt, MAX_RETRIES, last_error)
if attempt < MAX_RETRIES:
time.sleep(RETRY_DELAY_SEC * attempt)
return f"__LLM_ERROR__ {last_error}"
client = LLMClient(base_url=BASE_URL, model_name=MODEL_NAME, api_key=API_KEY)