- Бэкенд: FastAPI + SQLAlchemy async + PostgreSQL, JWT-аутентификация, Qdrant multi-tenant векторное хранилище, Celery воркер - Фронтенд: React + Vite + TypeScript SPA (логин, регистрация, дашборд, поиск по коллекциям, настройки) - Инфраструктура: docker-compose, Helm-чарт, GitHub Actions CI, Prometheus/Grafana мониторинг - Embedding через OpenRouter (nvidia/llama-nemotron-embed-vl-1b-v2:free) - LLM: google/gemma-4-31b-it:free через OpenRouter
33 lines
1.6 KiB
Python
33 lines
1.6 KiB
Python
from openai import OpenAI
|
||
|
||
from app.config import settings
|
||
|
||
client = OpenAI(
|
||
base_url="https://openrouter.ai/api/v1",
|
||
api_key=settings.openrouter_api_key,
|
||
)
|
||
|
||
SYSTEM_PROMPT = """Ты — специалист техподдержки. Отвечай клиенту, используя ТОЛЬКО информацию из переданных тикетов (контекст).
|
||
|
||
Правила:
|
||
- Если контекст содержит подходящее решение — напиши ответ своими словами, адаптируя под вопрос
|
||
- Если контекст не относится к вопросу — напиши: «Недостаточно информации в истории обращений»
|
||
- НЕ придумывай ответы, НЕ используй общие знания
|
||
- НЕ говори «обратитесь в службу поддержки» — ты сам и есть поддержка
|
||
- Укажи в конце: «Основано на тикете №...»"""
|
||
|
||
|
||
async def generate_answer(query: str, context: str) -> str:
|
||
response = await client.chat.completions.create(
|
||
model=settings.openrouter_llm_model,
|
||
messages=[
|
||
{"role": "system", "content": SYSTEM_PROMPT},
|
||
{
|
||
"role": "user",
|
||
"content": f"Контекст (история обращений):\n{context}\n\nВопрос клиента:\n{query}",
|
||
},
|
||
],
|
||
temperature=0.1,
|
||
max_tokens=2000,
|
||
)
|
||
return response.choices[0].message.content
|