# 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 %) можно поднять (промпт/примеры).