diff --git a/HISTORY/2026-10-07_docs_ai_assistant.md b/HISTORY/2026-10-07_docs_ai_assistant.md new file mode 100644 index 0000000..d4e8df7 --- /dev/null +++ b/HISTORY/2026-10-07_docs_ai_assistant.md @@ -0,0 +1,73 @@ +# tf_docs: AI-ассистент документации (эндпоинт + виджет) + +Дата: 2026-10-07 + +## Что сделано + +Реализован AI-ассистент по документации Nubes: пользователь задаёт вопрос на сайте, +получает ответ по строгому шаблону со ссылками-источниками. + +Схема: + +``` +Браузер (виджет assistant.js) + │ POST //_api/assist {question} + ▼ +tf_docs (NodeJS, кластер nodejsk8s) + │-- validateInput / rate-limit / семафор / дедлайн / кэш / дедуп + │-- Этап 1: LLM → resource_type (по списку реальных nubes_* из индекса) + │-- Поиск: search_index.json (с VM) → объединение (П.8) → top-K + │-- Этап 2: LLM → ответ по шаблону Роль/Задача/Контекст/Требования/Ограничения + ▼ +Ответ {answer, sources[], meta} +``` + +Индекс тянется с `VM_DOCS_BASE_URL//search/search_index.json` (ВМ 213 отдаёт +статику; в `tf_docs` — т.к. сервис теперь не только 302-роутер). + +## Новые файлы (tf_docs) + +| Файл | Назначение | +|---|---| +| `assist.js` | каркас: validateInput (413/415/400), rate-limit, семафор, llmChat, jsonError | +| `search.js` | лексический поиск: HTML-clean, буст страницам ресурсов, транслит кириллица→латиница, подресурс→родитель | +| `stage1.js` | этап 1: `resource_type` через LLM (`response_format: json_object`) | +| `stage2.js` | объединение поиска (П.8) + этап 2 (строгий шаблон, 502 при нарушении) | +| `orchestrator.js` | оркестратор: дедлайн 40с, rate-limit, семафор=4, дедуп одинаковых запросов, отмена по `req.close` | +| `llm_project/` | бриф, план по шагам, пробник api.aillm.ru, эталонные вопросы, оценки | + +## Изменения существующих + +- `server.js` — ветка `POST //_api/assist` ДО проверки 405; загрузка `orchestrator.js` в try/catch (не роняет статику). +- `Dockerfile` — добавлены `assist.js search.js stage1.js stage2.js orchestrator.js`. +- `README.md` — эндпоинт и переменные окружения. +- `tf_provider`: `docs/30_registry/javascripts/assistant.js` (виджет), `extra.css` (стили), `mkdocs.yml` (`extra_javascript`). + +## Переменные окружения (jsonEnv в ЛК) + +```json +{ + "VM_DOCS_BASE_URL": "http://5.172.178.213", + "LLM_BASE_URL": "https://api.aillm.ru", + "LLM_API_KEY": "<секрет>", + "LLM_MODEL": "gpt-oss-120b" +} +``` + +## Проверено живыми вызовами + +- api.aillm.ru: `response_format json_object` ✅; `reasoning_effort` ❌ (400 UnsupportedParamsError) — не используется; `reasoning_content` есть → игнорируется; пустой `content` при малом `max_tokens` → повтор ×2. +- Этап 1: выдуманный `nubes_instance` → отбрасывается (`null`). +- Сквозной запрос на прод: `POST /nubes-test/_api/assist` → 200, ответ по шаблону, `sources` валидны, ~12 с. +- Виджет на `https://tf-docs.nodejsk8s.dev.nubes.ru/nubes-test/`: FAB + панель, полный цикл «вопрос → ответ → источники» работает. +- Оценка на 28 эталонных вопросах: этап 1 ≈ 79 %, поиск 71 % → **93 %** после улучшений. + +## Деплой + +1. `tf_docs`: push в `terraform/tf_docs` → redeploy/modyfy в ЛК (образ собирается из git). +2. `tf_provider`: push → сборка+публикация сайта (`TOOLS/scripts/04_build_and_publish_docs.sh --profile TOOLS/config/test`) → S3 → `mc mirror` на ВМ 213 (`/var/www/tf-docs/nubes-test/`). + +## Открытые пункты + +- Ротация ключа `LLM_API_KEY` (ключ засветился в логе) — отдельный сервисный ключ. +- Точность этапа 1 (79 %) можно поднять (промпт/примеры).