41 KiB
SESSION HANDOFF — AI-ассистент документации Nubes (чат 2026-10-07 … 2026-10-08)
Для кого этот файл. Это полный отчёт-передача для нового чата (новая сессия / другой агент). Читать целиком перед первой правкой. Составлен 2026-10-12 по транскрипту сессии, git-истории и живым проверкам. Источник фактов указывается в виде
файл:строкаилиgit:<hash>.
0. ПРАВИЛА РАБОТЫ С ЭТИМ ПОЛЬЗОВАТЕЛЕМ (читать первым, нарушать нельзя)
Приказы получены дословно в этой сессии (и подкреплены раздражением при нарушениях):
- ⛔ НИЧЕГО не менять без прямой команды: не править код, не коммитить, не деплоить, не откатывать, не менять конфиги, не лезть в соседние репозитории. Роль агента — советник, не исполнитель.
- ⛔
terraform apply/terraform destroy— НИКОГДА сам. Разрешено:init,plan,validate,show,state show. (Нарушение 2026-10-04: после падения apply полез в API PROD и пытался удалить инстанс — инстансыnot createdудаляет ТОЛЬКО владелец в ЛК.) - Коммит после КАЖДОЙ правки, дробить по смыслу, не копить untracked. Push — только по отдельной команде.
- Ответ — кратко (1–5 строк или короткий список). Развёрнуто — только если прямо просят.
- Вопрос = только ответ. Никаких «а ещё могу», «давай я». После работы — «готово» и ждать.
- ⛔ Не спрашивать то, что можно выяснить самому (репо, HAR, git-история,
generated/*.yaml, API, логи VS Code). Спрашивать только про то, чего в данных нет в принципе (выбор человека: аккаунт, ключ, домен, цифры). - Не расширять область (scope creep). «Сделай актуальным везде» НЕ даёт права на дополнительные шаги.
- Команда понятна не на 100% → НИЧЕГО не делать, задать один короткий уточняющий вопрос, ждать.
- Анти-зацикливание: не более 2 однотипных вызовов инструмента подряд; после двух безрезультатных — остановиться и доложить.
- Документировать ВСЁ, включая собственные ошибки.
- Не рекомендовать и не менять без замера. Рекомендация без замера — догадка. Сначала «до/после» тем же инструментом, потом вывод.
- О текущем поведении — только КОД (
файл:строка). ДокументыHISTORY/,docs/*_history*описывают прошлое и могут противоречить коду. - Любое утверждение должно быть проверяемым. Не смог доказать — писать «не знаю / не проверено».
1. Что это за проект (кратко)
AI-ассистент документации Terraform-провайдера Nubes — виджет на сайте документации: пользователь пишет задачу своими словами, получает ответ строго по шаблону со ссылками на страницы документации.
Это не свободный чат, а RAG-пайплайн: сначала лексический поиск находит фрагменты документации, затем LLM пересказывает их в фиксированном формате.
- Модель:
gpt-oss-120bчерезhttps://api.aillm.ru(OpenAI-совместимый). - Backend: Node.js 18, без внешних npm-зависимостей (только встроенные
http/https/fetch/AbortController). - Поиск v1: лексический (BM25-подобный) по
search_index.jsonMkDocs. - Статус на 2026-10-12: работает на всех трёх стендах, v1 заморожен, ждём реальных откликов DevOps-тестировщиков.
Подробная архитектура: tf_docs/llm_project/docs/ASSISTANT_ARCHITECTURE.md (327 строк).
Дорожная карта: tf_docs/llm_project/docs/ROADMAP_AND_LIMITS.md (127 строк).
2. Что было запрошено (все 99 запросов сессии — сжатая выжимка)
Полный список запросов восстановлен из транскрипта
(…/GitHub.copilot-chat/transcripts/f3e064fa-….jsonl, 2707 строк, 99 сообщений
пользователя).
Блок А. Старт и бриф (10:34–10:51). Прочитать бриф по AI-ассистенту, собрать
факты (только чтение), затем написать код. Требование: всегда привлекать
DeepSeek Flash как субагента, когда это целесообразно и не рискованно (он
значительно дешевле). Затем — написать модули: каркас assist.js, search.js,
stage1.js, виджет для MkDocs, эталонный набор вопросов.
Блок Б. Деплой и первые тесты (10:58–14:45). «Как ты тестил? Давай тесты на
деплое». Выяснение, что и куда редеплоить (экземпляр NodeJS tf-docs в Nubes),
добавление переменных окружения, «САМ делай redeploy. тесты. правки. и так — по
циклу, пока всё не оптимизируешь».
Блок В. Оптимизация и оценка (14:00–15:50). «Показывай прогресс», код-ревью «насколько умён этот режим», «наверняка надо ещё улучшать», «твоё ОБЪЕКТИВНОЕ мнение — хорошо получилось?».
Блок Г. UI и TODO (14:37). «?» неинформативно → надпись LLM на кнопке; в конце ответа — время обработки и число токенов (несрочно, в TODO).
Блок Д. Эмбеддинги и таймер (16:03–16:07). Вопросы: есть ли индикация прогресса (таймер), что такое эмбеддинги, где хранится результат, что будет если не делать. Приказ: «всё документируй ПОДРОБНО, в т.ч. по эмбеддингу, и делай таймер-индикацию».
Блок Е. Curated-примеры (16:52–17:06). Раздражение: ассистент обязан
опираться на проверенные примеры (/home/naeel/TF/tf_provider/TEST_STAND/CRUD,
опубликованные как curated/*) — «именно ЭТО МЫ тестировали НА РЕАЛЬНЫХ
деплоях». Затем: сделать для prod стенда.
Блок Ж. Документирование и синк (17:32–18:04). «Всё документируй, коммить и
пушь», синк ~/TF на ВМ 213, если нет — сделать ПОДРОБНУЮ инструкцию; определить
самое сложное в интеграции; «чтобы это легко находилось».
Блок З. Планы развития (04:49–05:15). Что и как совершенствовать; куда складывать сбор данных (варианты: stdout/Grafana, S3, файл на ВМ, PG); «может, вообще сейчас ничего не делать?» → решение заморозить v1 и ждать откликов (тестировать будут DevOps-инженеры, не случайные юзеры). Так как данных нет — сделать тест-набор на 300 вопросов («НЕ СПЕША, внимательно сочини»), затем прогнать тесты.
Блок И. Приёмка (05:19–06:15). Прогон 300 вопросов, показ прогресса, вопрос «что надо будет править? результаты ВСЕ сохранил?» (приказ: пока НИЧЕГО не править).
3. Хронология работ (что реально сделано)
Все времена — из транскрипта; коммиты — git log репозиториев tf_docs и
tf_provider.
3.1. Каркас и модули (10:40–13:57, tf_docs)
| Время | Сделано | Коммит |
|---|---|---|
| 13:41 | Каркас assist.js: validateInput (415/413/400), rate-limit, семафор, llmChat, jsonError, чтение env |
e419b38 |
| 13:43 | Live-проверка api.aillm.ru скриптом-пробником (probe/probe_aillm.js, probe/RESULTS.md) |
e5817ff |
| 13:46 | Лексический поиск search.js + эталонный набор 28 вопросов |
827870d |
| 13:48 | Этап 1 — извлечение resource_type через LLM по списку реальных nubes_* |
4e8d115 |
| 13:49 | Этап 2 — объединение результатов поиска (П.8) + генерация по строгому шаблону | c2e2f9c |
| 13:50 | Маршрут POST /<stand>/_api/assist в server.js + оркестратор пайплайна |
e8b6d9b |
| 13:51 | Dockerfile (копирование новых модулей) + README (эндпоинт, переменные) |
490d8b6 |
| 13:57 | Перф поиска: буст страницам ресурсов, транслит кириллица→латиница, подресурс→родитель (точность на эталоне 71% → 93%) | 2136536 |
| 14:11 | Форматирование модулей + план по шагам | c59f024 |
3.2. Виджет на сайте (13:53–19:09, tf_provider)
| Время | Сделано | Коммит |
|---|---|---|
| 13:53 | Виджет ассистента: плавающая кнопка + панель, стили, подключение в mkdocs.yml |
f6827fc |
| 14:37 | Форматирование extra.css |
13d294f |
| 15:17 | Пояснение в виджете: что это, что может и чего не может | 0a17cae |
| 16:07 | Описание — раскрывающийся блок <details>/<summary> |
bfc57ca |
| 18:55 | FAB «LLM», в ответе — время и число токенов | 166196a |
| 19:08 | Таймер-индикация «⏳ N с» при загрузке | 79d57ac |
3.3. Тесты и надёжность (14:11–18:53)
| Событие | Детали | Коммит |
|---|---|---|
| Прогон №1 (62 вопроса, прод) | 56/62, 6 отказов 502 bad_llm_output |
— |
| Найдена причина 502 | ответ обрезался max_tokens: 1024 до секции «Ограничения» (finish_reason: length); плюс собственный баг: regex \b не работает с кириллицей → заголовки «не находились» |
b99344e |
| Фикс | max_tokens 1024 → 2048 + повтор ×2 с удвоением (до 4096), устойчивая проверка заголовков |
b99344e |
| Прогон №2 | 60/62; добавлен повтор при транзиентных ошибках LLM | 0065026, 298299a |
| Прогон №3 | 61/62; фикс: отвечать по шаблону и на вопросы вне документации (инъекции → 200 вместо 502) | dafcb6b, 568b73d |
| Автоматизация redeploy через Nubes API | Bearer + CFS-параметры; opUid берётся из заголовка Location, не из тела |
a4b2ddc |
| Прогон №4 | 62/62, ноль отказов | 9728fe4 |
| Перф-оптимизации | кэш индекса (TTL 10 мин) + предрасчёт списков + дедлайн 40 с + логирование этапов | 99e034d |
| Предтокенизация документов | поиск ~1.2 с → ~6 мс | 5848fcc |
| Прогон №5 | 61/62 (1 — клиентский сбой сети TypeError: fetch failed) |
5018acf |
| Токены в ответе | сбор usage и отдача в meta |
f42017f |
3.4. Документация, продуктизация, prod (19:09–21:05)
| Событие | Коммит |
|---|---|
| Полная документация ассистента (архитектура, API, поиск, безопасность, деплой, тесты, эмбеддинги v2) | fe93645 |
Поднят вес curated/*-страниц выше ресурсных (готовые примеры, проверенные на реальных деплоях) |
382b7b0 |
Три стенда (nubes-test, nubes-dev, nubes prod), приоритет curated, разбор инцидента генератора nav |
f1a774d |
Фикс генератора: кавычить заголовки сервисов в _nav_fragment.yml ([DEPRECATED] ломал YAML) — TOOLS/docs-generator/internal/writers/writers.go, yamlScalar() |
322235c |
HowTo: публикация сайта, redeploy через API, синк на ВМ 213 (+ sync-tf-to-vm213.sh) |
~/HowTo/* (вне git) |
| Ссылки на документацию ассистента и HowTo в README репозиториев | d52ae10, ad42957 |
Индекс проекта ассистента llm_project/README.md |
ad42957 |
3.5. 2026-10-08: дорожная карта, 300 вопросов, прогон
| Время | Событие | Коммит |
|---|---|---|
| 08:03 | Дорожная карта, границы применимости, план тестирования DevOps, варианты сбора данных | f5683fa |
| 08:19 | Тест-набор из 300 вопросов (llm_project/golden/golden_questions_300.json) |
cd74ff2 |
| 08:21 | Раннер: поддержка внешнего набора (--file/--out) + метрика попадания в expected_pages |
fc5245b |
| 08:21→09:13 (~52 мин) | Полный прогон 300 вопросов на nubes-test |
— |
| 09:14 | Результаты (RESULTS_300.json, RESULTS_300.md) |
5ab9274 |
4. Файлы (что где лежит)
4.1. Backend — репозиторий tf_docs (/home/naeel/TF/tf_docs)
Remote: https://gitea.services.ngcloud.ru/terraform/tf_docs.git
| Файл | Назначение |
|---|---|
server.js |
HTTP-сервер: прокси GET/HEAD статики на ВМ 213 + ветка POST /<stand>/_api/assist до проверки 405. orchestrator.js грузится в try/catch, чтобы не ронять статику. |
assist.js |
Каркас: validateInput, createRateLimiter, createSemaphore, llmChat, jsonError, normalizeQuery, ENV, maskKey. |
search.js |
Лексический поиск: токенизация, HTML-очистка, стоп-слова, TRANSLIT (кириллица→латиница), буст по типу страницы, resourceBaseSegment() (подресурс→родитель), предтокенизация, listResourceTypes() (56 типов), resourcePages() (35 страниц). |
stage1.js |
Этап 1: LLM извлекает resource_type (response_format: json_object), сверка со списком реальных ресурсов, empty_content → повтор ×2. |
stage2.js |
mergeSearchResults (объединение по location, max score, страница ресурса первой) + stage2Generate (строгий шаблон, повтор ×2 с удвоением бюджета, hasHeader с учётом кириллицы), collectSources, sanitizeSourceUrl. |
orchestrator.js |
Пайплайн целиком: handleAssist, createSharedState, fetchIndex (кэш TTL 10 мин + stale-fallback), runPipeline (дедлайн 40 с, тайминги этапов, сбор токенов), logAssist (однострочный JSON в stdout). |
Dockerfile |
node:18-alpine, копирует все 6 модулей. |
README.md |
Эндпоинт, контракт, переменные окружения. |
llm_project/ |
Всё про ассистента: планы, документация, тесты, диагностика. |
4.2. tf_docs/llm_project/
| Файл | Что |
|---|---|
README.md |
Карта файлов проекта ассистента |
docs/ASSISTANT_ARCHITECTURE.md |
Полная документация (архитектура, API, поиск, безопасность, деплой, тесты, эмбеддинги v2, инциденты) |
docs/ROADMAP_AND_LIMITS.md |
Дорожная карта, границы применимости, план тестирования DevOps, варианты сбора данных |
PLAN_docs_ai_assistant_STEPS.md |
Исходный план по шагам (11 этапов) |
probe/probe_aillm.js, probe/RESULTS.md |
Live-проверка API api.aillm.ru и её результаты |
golden/golden_questions.json |
28 эталонных вопросов с ожидаемыми страницами |
golden/EVAL_1.md |
Оценка поиска на эталоне (шаг 9) |
golden/golden_questions_300.json |
300 вопросов (поля q, expected_pages, resource_type, cat) |
tests/run_e2e_live.js |
Прогон по живому эндпоинту (учёт 429, --file, --out, метрика hit) |
tests/redeploy.js |
Redeploy tf-docs через Nubes API |
tests/debug_bad_llm_output.js |
Захват сырого ответа LLM (диагностика) |
tests/RESULTS_LIVE.{json,md} |
Результаты прогонов 62 вопроса (5 итераций) |
tests/RESULTS_300.{json,md} |
Результаты прогона 300 вопросов (.log — в .gitignore) |
tests/ANALYSIS_bad_llm_output.md |
Разбор отказов 502, причины и фиксы |
4.3. Виджет и сайт — репозиторий tf_provider (/home/naeel/TF/tf_provider)
Remote: https://gitea.services.ngcloud.ru/terraform/tf_provider.git
| Файл | Назначение |
|---|---|
docs/30_registry/javascripts/assistant.js |
Виджет: FAB «LLM», панель, раскрывающееся описание, таймер «⏳ N с», ответ + источники, время и токены. ES5, IIFE, без зависимостей, вывод только через textContent. |
docs/30_registry/assets/extra.css |
Стили виджета |
mkdocs.yml |
Подключение assistant.js в extra_javascript |
TOOLS/docs-generator/internal/writers/writers.go |
yamlScalar() — кавычит заголовки со спецсимволами в _nav_fragment.yml |
4.4. HowTo (вне git)
Фактическое расположение: ~/HowTo/ (/home/naeel/HowTo/).
~/HowTo/README.md — индекс инструкций
~/HowTo/howto-publish-docs-site.md — публикация сайта (tf_provider → S3 → ВМ 213)
~/HowTo/howto-tf-docs-redeploy-api.md — redeploy tf-docs через Nubes API
~/HowTo/howto-sync-to-vm213.md — синк каталогов на ВМ 213
~/HowTo/sync-tf-to-vm213.sh — скрипт синка ~/TF → ВМ 213
~/HowTo/howto-ssh-access.md — доступы к 213 / Vultr / 3060
~/HowTo/vm-access-and-services.md — что есть на ВМ 213
5. Архитектура и контракт (для быстрого старта)
5.1. Поток
Браузер (виджет assistant.js)
│ POST /<stand>/_api/assist {"question": "..."}
▼
tf_docs (Node.js 18, кластер nodejsk8s)
├─ validateInput (415/413/400) [assist.js]
├─ rate-limit по IP (429 + Retry-After) [assist.js]
├─ кэш ответов + дедуп одинаковых запросов
├─ семафор ASSIST_MAX_CONCURRENT=4 (иначе 503)
├─ дедлайн 40 с (AbortController)
├─ Этап 1: LLM → resource_type [stage1.js]
├─ Поиск: search_index.json → top-K [search.js]
├─ Объединение результатов (П.8) [stage2.js]
└─ Этап 2: LLM → ответ по шаблону [stage2.js]
▼
{ answer, sources[], meta }
Индекс берётся с VM_DOCS_BASE_URL/<stand>/search/search_index.json (ВМ 213,
823 документа на момент прогона).
5.2. Контракт API
Запрос: POST /<stand>/_api/assist, Content-Type: application/json,
тело {"question": "..."} ≤ 2 КБ.
Ответ 200:
{
"answer": "Роль/Задача/Контекст/Требования/Ограничения",
"sources": [{"title": "...", "url": "/<stand>/..."}],
"meta": {
"model": "gpt-oss-120b", "resource_type": "nubes_...|null",
"stage1_ok": true, "elapsed_ms": 12000,
"index_ms": 86, "stage1_ms": 1200, "search_ms": 6, "stage2_ms": 8300,
"tokens": 2868, "prompt_tokens": 2105, "completion_tokens": 763
}
}
Ошибки ({"error": code, "message": ...}):
| HTTP | code | Смысл |
|---|---|---|
| 400 | — | невалидный JSON / пустой вопрос |
| 413 | — | тело > 2 КБ |
| 415 | — | Content-Type не application/json |
| 429 | rate_limited |
превышен лимит (заголовок Retry-After) |
| 503 | busy |
семафор исчерпан (Retry-After: 5) |
| 502 | bad_llm_output |
LLM не выдал обязательные заголовки |
| 503 | index_unavailable |
не удалось загрузить индекс |
5.3. Переменные окружения (задаются в ЛК как jsonEnv)
VM_DOCS_BASE_URL (обязательна, http://5.172.178.213) · LLM_BASE_URL
(https://api.aillm.ru) · LLM_API_KEY (Secret) · LLM_MODEL (gpt-oss-120b) ·
ASSIST_MAX_CONCURRENT (4) · ASSIST_TOTAL_DEADLINE_MS (40000) ·
ASSIST_LLM_TIMEOUT_MS (25000) · ASSIST_RATE_PER_WINDOW (6) ·
ASSIST_RATE_WINDOW_MS (60000) · ASSIST_REPLICAS (1) · ASSIST_MAX_BODY (2048) ·
ASSIST_INDEX_TTL_MS (600000) · ASSIST_TRUSTED_PROXY_CIDR.
5.4. Факты по LLM API (проверено live, probe/RESULTS.md)
| Параметр | Результат |
|---|---|
response_format: {type:"json_object"} |
✅ поддерживается (этап 1) |
reasoning_effort |
❌ 400 UnsupportedParamsError — не передавать |
reasoning_content |
✅ есть в ответе — игнорировать, брать только content |
stream: true |
✅ SSE; в v1 не используется |
Пустой content |
⚠️ при малом max_tokens → content: null; обрабатывать как ошибку + повтор |
| Доступные модели | gpt-oss-120b, qwen3.8-27b-fp8(-rtx6000), user-bge-m3, bge-reranker-v2-m3, whisper |
| Задержка этапа 1 | ~1.0–1.3 с |
6. Инфраструктура
6.1. Стенды
Проверено 2026-10-12: POST /<stand>/_api/assist с Content-Type: text/plain
отвечает 415 на всех трёх стендах (ветка ассистента жива), статика
/<stand>/search/search_index.json — 200.
| Стенд | URL | Профиль сборки | Namespace (S3/URL) |
|---|---|---|---|
| test | https://tf-docs.nodejsk8s.dev.nubes.ru/nubes-test/ |
TOOLS/config/test |
nubes-test |
| dev | https://tf-docs.nodejsk8s.dev.nubes.ru/nubes-dev/ |
TOOLS/config/dev |
nubes-dev |
| prod | https://tf-docs.nodejsk8s.dev.nubes.ru/nubes/ |
TOOLS/config/prod |
nubes |
6.2. Цепочка публикации документации
stack/<стенд>/<svc>/rendered.md ─┐
generated/<стенд>/docs/ ─┴─► MkDocs build ► site/ ► S3 ► mc mirror ► ВМ 213 nginx
# 1) сборка + публикация в S3
cd ~/TF/tf_provider
DOCS_SKIP_LINT=1 bash TOOLS/scripts/04_build_and_publish_docs.sh --profile TOOLS/config/test
# 2) зеркало S3 → ВМ 213 (БЕЗ ЭТОГО ШАГА ИЗМЕНЕНИЙ НА САЙТЕ НЕ БУДЕТ)
ssh -i ~/.ssh/naeel_vm_id_ed25519 naeel@5.172.178.213 \
"mc mirror --overwrite --remove nubes/terraform-registry/docs/nubes-test/nubes/ /var/www/tf-docs/nubes-test/"
6.3. Redeploy backend'а
node ~/TF/tf_docs/llm_project/tests/redeploy.js
Либо вручную через API: instanceUid (test) 7a48a863-9b40-4cef-a352-033ee9dde8de,
endpoint https://lk-api-gateway-test.ngcloud.ru/api/v1/svc, токены
~/TF/tf_provider/secrets/{test,dev,prod}.token, обязателен
User-Agent: Mozilla/5.0 (иначе DDoS-Guard блокирует).
opUid операции — в заголовке Location, не в теле.
6.4. Доступы
| Что | Значение |
|---|---|
| ВМ 213 | naeel@5.172.178.213, ключ ~/.ssh/naeel_vm_id_ed25519 |
| Статика на ВМ | /var/www/tf-docs/<ns>/ |
| Ключ LLM | ~/nubes/llm.key (и ~/TF/tf_provider/secrets/llm.key) — не логировать |
| Токены платформы | ~/TF/tf_provider/secrets/{test,dev,prod}.token |
Синк ~/TF → ВМ 213 |
~/HowTo/sync-tf-to-vm213.sh [--dry-run] |
6.5. Окружение разработки
npmНЕ установлен → тесты запускать какnode --test, синтаксис проверятьnode -c файл.js.du— не GNU (ключ-shломается);rsyncесть.
7. Тестирование: результаты
7.1. Прогон 62 вопроса (5 итераций, RESULTS_LIVE.*)
| Прогон | 200 OK | Отказов | Причина и фикс |
|---|---|---|---|
| 1 | 56/62 | 6 | обрезка max_tokens: 1024 → 2048 + повтор; баг \b с кириллицей |
| 2 | 60/62 | 2 | + повтор при транзиентных ошибках |
| 3 | 61/62 | 1 | + шаблон для вопросов вне документации |
| 4 | 62/62 | 0 | — |
| 5 | 61/62 | 1 | клиентский сбой сети (не бэкенд) |
Задержки (5-й прогон): p50 7.7 с, p95 23 с, max 40.8 с — доминирует LLM; собственный код ≈ 6 мс поиск + кэш.
7.2. Прогон 300 вопросов (RESULTS_300.*, 2026-10-08, nubes-test)
Команда:
cd ~/TF/tf_docs
node llm_project/tests/run_e2e_live.js --stand nubes-test \
--file golden/golden_questions_300.json --out RESULTS_300
Итог:
| Метрика | Значение |
|---|---|
| Ответов 200 | 300/300 |
| Ошибок (4xx/5xx/сеть) | 0 |
| Шаблон соблюдён | 300/300 |
resource_type определён |
247/300 |
| Латентность | min 157 мс, p50 5.35 с, p95 10.57 с, max 15.66 с |
Негатив/инъекции без resource_type |
16/17 |
Попадание в expected_pages |
261/268 (97.4 %) |
| Пауз на 429 | 42 (rate-limit 6/мин) |
| Длительность прогона | ~52 мин (08:21 → 09:13) |
По категориям:
| Кат. | Всего | 200 | hit |
|---|---|---|---|
| db | 69 | 69 | 69/69 |
| vmware | 42 | 42 | 41/42 |
| app | 38 | 38 | 38/38 |
| queue | 28 | 28 | 27/28 |
| k8s | 26 | 26 | 25/26 |
| net | 16 | 16 | 16/16 |
| neg | 17 | 17 | — |
| curated | 16 | 16 | 16/16 |
| s3 | 12 | 12 | 12/12 |
| meta | 12 | 12 | 0/1 |
| typo | 10 | 10 | 6/8 |
| llm | 9 | 9 | 8/9 |
| lang | 5 | 5 | 3/3 |
7 промахов hit=NO (ожидаемая страница не попала в sources):
| # | Вопрос | Ожидалось | Получено | Характер |
|---|---|---|---|---|
| 67 | как дать права только на чтение kafka юзеру | kafka |
akhq, lucee, nextcloud, postgres |
реальный промах поиска |
| 105 | как привязать vdc к группе | vc_vdc_group |
curated/pipeline/..., vc_nsxt |
реальный промах |
| 147 | какие модели можно развернуть | llm_ai |
curated/crud/..., akhq, clickhouse |
реальный промах (+ rt=null) |
| 184 | какие версии провайдера доступны | template |
— | ошибка разметки: страницы про версии в индексе нет вообще |
| 213 | как сделать чтобы сервис был доступен из интернета | vcexternalip |
nextcloud, vapp, vc_nsxt |
реальный промах |
| 214 | что нужно чтобы завести боевой стенд с базой очередями и приложением | postgres,kafka,nodejs |
curated/crud/three_apps |
спорный: ответ ассистента, вероятно, лучше |
| 234 | как удалить ноду из кластера | k8s_sthutrval_cluster |
mariadb, mongodb ops |
реальный промах |
Проверено: все ожидаемые страницы, кроме «версий провайдера», есть в индексе (823 документа) — значит промахи 67/105/147/213/234/214 вызваны ранжированием, а не отсутствием страницы.
8. Что надо будет править (приоритеты; НИЧЕГО ещё не правилось)
- Морфология русских запросов — главная причина промахов. «ноду» ≠ «нода»,
«группе» ≠ «группа», «модели» ≠ «модель». Промахи №234, №105, №213, №147.
Лечится стеммингом/усечением русских окончаний в
search.js(или эмбеддингами). - Буст совпадения по заголовку страницы — №67: запрос про kafka, а в топ-5
попали
akhq,lucee,nextcloud,postgres, сама страницаkafkaне попала вообще. - Этап 1 не определил
resource_typeв 23 вопросах, где тип ожидается (db 2, vmware 3, net 1, llm 1, k8s 1, s3 1, typo 7, curated 7). Лечится few-shot примерами в промпте (нода→ кластер,модели→llm_ai,firewall на edge→vc_nsxt,DNS-запись→dnsrecord,файлы в s3→s3bucket). - Ошибки в разметке тест-набора (не баг ассистента): №184 —
expected_pages: ["template"]при отсутствии страницы о версиях; №213 отнесён к категорииtypo, хотя опечатки нет (на метрики не влияет). - Спорный №214 — ожидание
postgres,kafka,nodejs, ответcurated/crud/three_apps: вероятно, ответ ассистента правильнее. - Расхождения в документах:
llm_project/README.mdиROADMAP_AND_LIMITS.mdссылаются на~/nubes/HowTo/…, фактически файлы лежат в~/HowTo/. ТакжеASSISTANT_ARCHITECTURE.md:§11описывает только прогон 62 вопроса — результаты 300 вопросов там не отражены. - Не баг, но ограничение: rate-limit 6/мин даёт 42 паузы на 300 вопросов; полный прогон ≈ 52 мин.
Реальных промахов поиска — 5–6 из 300. Ошибок ответа (шаблон, 5xx, уход от темы) — 0.
9. Что НЕ реализовано (обсуждено и отложено осознанно)
| Тема | Решение | Детали |
|---|---|---|
| Эмбеддинги + реранкер (v2) | НЕ делать сейчас | user-bge-m3 (1024 dims) + bge-reranker-v2-m3. 823 документа ≈ 3.4 МБ float32 → хранить в памяти Map: location → Float32Array, рядом с кэшем индекса. Отдельной БД/файла не нужно. ~50–100 строк vectorSearch.js, ~полдня. См. ASSISTANT_ARCHITECTURE.md:§12. |
| Сбор реальных вопросов/фидбэка | НЕ реализовано | Варианты: stdout→Grafana, S3 (JSONL), файл/PG на ВМ 213 (⛔ нельзя в /var/www/tf-docs/ — перезапишет mc mirror), managed nubes_postgres рядом с tf_docs. Рекомендация при старте: stdout; при необходимости — managed PG. См. ROADMAP_AND_LIMITS.md:§3. |
| Стриминг (SSE) | отложено | Ответ отдаётся целиком; задержку 5–10 с маскирует таймер. |
| Кэш ответов TTL/LRU | отложено | Сейчас in-memory Map без TTL, чистится только перезапуском. |
| Несколько реплик | отложено | ASSIST_REPLICAS=1, кэш/лимиты не шарятся. |
Позиция пользователя: заморозить v1, дождаться реальных отзывов от
DevOps-инженеров (не случайных юзеров), собирать отзывы вручную по шаблону
ROADMAP_AND_LIMITS.md:§5.4, и только потом внедрять улучшения.
10. Ключевые уроки и «грабли» (не наступать снова)
- Regex
\bне работает с кириллицей в JS безu-флага — из-за этого все заголовки ответа считались отсутствующими. Проверять заголовки в начале строки. max_tokensмал → ответ обрезается до последней секции шаблона → ложный 502. Бюджет 2048 + повтор ×2.reasoning_effortне поддерживается моделью — 400.reasoning_contentприсутствует в ответе — игнорировать, братьcontent.- opUid операции redeploy — в заголовке
Location, не в теле ответа. - Redeploy требует CFS-параметр
startupConfiguration(брать из живого состояния), иначе 422. - Обязателен
User-Agent: Mozilla/5.0при работе с Nubes API (DDoS-Guard). mc mirrorобязателен после публикации в S3, иначе сайт не изменится.- Индекс кэшируется 10 мин — после публикации доков свежие страницы появляются в ассистенте с задержкой.
- YAML-nav: заголовок сервиса со спецсимволами (
[DEPRECATED]) без кавычек ломает сборку — исправлено в генераторе (yamlScalar()), но помнить. npmв окружении нет — толькоnode.
11. ИНСТРУКЦИИ ДЛЯ НОВОГО ЧАТА
11.1. Порядок действий в начале
- Прочитать этот файл целиком.
- Прочитать
tf_docs/llm_project/docs/ASSISTANT_ARCHITECTURE.mdи…/ROADMAP_AND_LIMITS.md. - Проверить
git statusвtf_docsиtf_provider— не остались ли незакоммиченные правки. - Ничего не менять, пока пользователь не дал прямую команду.
11.2. Чего делать НЕЛЬЗЯ (повтор, критично)
- править код / коммитить / пушить / деплоить / откатывать без прямой команды;
terraform apply/destroy— никогда;- удалять инстансы в ЛК (даже
not created) — только владелец; - логировать или печатать
LLM_API_KEYи токены; - спрашивать то, что можно узнать из файлов/git/API;
- расширять область задачи («раз уж правлю, сделаю ещё X»).
11.3. Типовые команды
# --- backend: проверка синтаксиса и правки ---
node -c /home/naeel/TF/tf_docs/search.js
# --- прогон тестов (любой набор, любой стенд) ---
cd /home/naeel/TF/tf_docs
node llm_project/tests/run_e2e_live.js --stand nubes-test \
--file golden/golden_questions_300.json --out RESULTS_300
node llm_project/tests/run_e2e_live.js --stand nubes-test # встроенные 62
# --- redeploy сервиса ---
node ~/TF/tf_docs/llm_project/tests/redeploy.js
# --- публикация документации + зеркало на ВМ 213 ---
cd ~/TF/tf_provider
DOCS_SKIP_LINT=1 bash TOOLS/scripts/04_build_and_publish_docs.sh --profile TOOLS/config/test
ssh -i ~/.ssh/naeel_vm_id_ed25519 naeel@5.172.178.213 \
"mc mirror --overwrite --remove nubes/terraform-registry/docs/nubes-test/nubes/ /var/www/tf-docs/nubes-test/"
# --- синк ~/TF на ВМ 213 ---
~/HowTo/sync-tf-to-vm213.sh --dry-run
11.4. Живая проверка эндпоинта без расхода токенов LLM
# 415 => ветка ассистента жива; 200 у search_index.json => статика/индекс на месте
curl -s -o /dev/null -w "%{http_code}\n" -X POST \
https://tf-docs.nodejsk8s.dev.nubes.ru/nubes-test/_api/assist \
-H 'Content-Type: text/plain' --data 'x' -H 'User-Agent: Mozilla/5.0'
Внимание: реальный POST с application/json вызывает два вызова LLM и
тратит деньги. Тестовые прогоны согласовывать с пользователем.
11.5. Что, вероятно, попросят дальше (по итогам сессии)
- Править поиск (морфология / буст заголовка) и этап 1 (few-shot) — список в §8.
- Поправить разметку 300-вопросного набора (№184, №213).
- Привести в порядок ссылки на
~/HowTo/в документации. - После получения реальных отзывов DevOps — решение об эмбеддингах и сборе данных.
12. Состояние на момент передачи
| Что | Состояние |
|---|---|
Репозиторий tf_docs |
Всё закоммичено, HEAD 5ab9274; незакоммиченного нет |
Репозиторий tf_provider |
Последний коммит этой сессии d52ae10 (10-07 21:05); позже (10-09, 10-10) были другие работы — см. git log |
| Стенды | test/dev/prod — ассистент отвечает (проверено GET/POST 415, 2026-10-12) |
| v1 | Заморожен, ждём реальных откликов |
| 300-вопросный прогон | Завершён, результаты закоммичены, правки не начаты (приказ: «пока НИЧЕГО не правь») |
| Открытые вопросы к пользователю | нет |