Initial import NDC_1C
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
# 260323_ACCOUNTING_AGENT_GUI_INTEGRATION_GUIDELINES
|
||||
|
||||
Дата: 23.03.2026 (MSK)
|
||||
Контур: NodeDC (`dc_node`) / бухгалтерский агент (черновой GUI + временный монолитный backend)
|
||||
Статус: интеграционные рекомендации для внешнего разработчика
|
||||
|
||||
---
|
||||
|
||||
## 1. Цель документа
|
||||
|
||||
Зафиксировать единые требования к GUI и backend бухгалтерского агента, который разрабатывается изолированно, чтобы:
|
||||
|
||||
1. интеграция в текущий `Node.js`-проект прошла без болезненных переделок;
|
||||
2. архитектура оставалась совместимой с текущей моделью NodeDC (`UI -> runtime -> OPS`);
|
||||
3. переход с временного монолита на будущую runtime-оркестрацию был обратимым и предсказуемым.
|
||||
|
||||
---
|
||||
|
||||
## 2. Базовые принципы (обязательные)
|
||||
|
||||
1. Сначала совместимость, потом скорость: любое быстрое решение допускается только если не ломает будущую интеграцию.
|
||||
2. GUI и backend делаются как изолируемый модуль, а не как форк всей платформы.
|
||||
3. Контракты API/событий/статусов должны быть стабильными с первой версии.
|
||||
4. Нельзя смешивать UI-логику, runtime-логику исполнения и слой хранения в один неразделимый блок.
|
||||
5. Пользовательская терминология в интерфейсе: использовать `NDC` (не `N8N`) в текстах UI.
|
||||
6. Технические идентификаторы не переименовывать: routes, env vars, payload keys, event names, internal symbols остаются техническими.
|
||||
|
||||
---
|
||||
|
||||
## 3. Технологический профиль (что нужно соблюдать)
|
||||
|
||||
### 3.1 Frontend
|
||||
|
||||
1. Совместимый стек: `React 18` + `TypeScript` + подход, совместимый с `Vite`.
|
||||
2. Архитектурно: компонентный UI с разделением на контейнеры данных и презентационные блоки.
|
||||
3. Все сетевые вызовы через единый API-клиент-слой (не `fetch` хаотично по компонентам).
|
||||
4. Состояние:
|
||||
- локальное UI-состояние отдельно;
|
||||
- серверное состояние отдельно (runs, statuses, results, trace).
|
||||
|
||||
### 3.2 Backend
|
||||
|
||||
1. Совместимый стек: `Node.js` + `Express` + JSON API.
|
||||
2. Формат тела запроса: поддержка `application/json` и `application/*+json`.
|
||||
3. Для хранения/аналитики ориентироваться на модель, совместимую с Postgres-онтологией (`session/run/result/event`).
|
||||
4. Временный runtime монолитный, но за абстракцией (см. раздел 8).
|
||||
|
||||
### 3.3 Форматы
|
||||
|
||||
1. Время только в `ISO 8601`.
|
||||
2. Денежные поля и суммы: явная валюта + числовой формат без двусмысленностей.
|
||||
3. Ошибки API: структурированный ответ с `code`, `message`, `details`.
|
||||
4. Любой статус должен быть машинно-читаемым и человеко-понятным.
|
||||
|
||||
---
|
||||
|
||||
## 4. Архитектурные границы ответственности
|
||||
|
||||
1. GUI отвечает за:
|
||||
- запуск/остановку;
|
||||
- отображение состояния;
|
||||
- фильтры/настройки;
|
||||
- операторские действия.
|
||||
2. Backend отвечает за:
|
||||
- исполнение сценария;
|
||||
- очередь и жизненный цикл задач;
|
||||
- запись результатов и ошибок;
|
||||
- выдачу данных для монитора.
|
||||
3. Слой данных отвечает за:
|
||||
- историчность;
|
||||
- идемпотентность результатов;
|
||||
- диагностируемость событий.
|
||||
4. GUI не должен содержать тяжелую бизнес-обработку бухгалтерских документов/очередей.
|
||||
|
||||
---
|
||||
|
||||
## 5. Минимальный API-контракт (для безболезненной интеграции)
|
||||
|
||||
Рекомендуется выделить отдельный namespace, например `/api/accounting-agent/*`, и зафиксировать минимум:
|
||||
|
||||
1. `POST /runs/start`
|
||||
- старт сессии/прогона;
|
||||
- возвращает `sessionId`, `runId`, `status`.
|
||||
2. `POST /runs/finish`
|
||||
- нормализованное завершение `DONE/FAILED/CANCELLED`;
|
||||
- причина/метаданные ошибки при неуспехе.
|
||||
3. `GET /runs`
|
||||
- список прогонов с фильтрами.
|
||||
4. `GET /runs/:runId`
|
||||
- карточка прогона + агрегированный статус.
|
||||
5. `POST /tasks/enqueue`
|
||||
- постановка бухгалтерской задачи в очередь.
|
||||
6. `POST /tasks/claim` (или эквивалент)
|
||||
- получение следующей задачи worker-частью.
|
||||
7. `POST /tasks/:taskId/complete`
|
||||
- успешное завершение с результатом.
|
||||
8. `POST /tasks/:taskId/error`
|
||||
- завершение с нормализованной ошибкой.
|
||||
9. `GET /results`
|
||||
- витрина результатов для GUI/монитора.
|
||||
10. `GET /trace/run/:runId`
|
||||
- лента событий для диагностики.
|
||||
11. `GET /health`
|
||||
- техническое здоровье сервиса.
|
||||
|
||||
Важно:
|
||||
|
||||
1. Контракты payload фиксируются версией (`v1`) и не ломаются без явной миграции.
|
||||
2. Поля `sessionId/runId/taskId` обязательны в событиях и логах.
|
||||
|
||||
---
|
||||
|
||||
## 6. Канон статусов и жизненного цикла
|
||||
|
||||
Единый словарь статусов для GUI и backend:
|
||||
|
||||
1. `NONE`
|
||||
2. `QUEUED`
|
||||
3. `RUNNING`
|
||||
4. `DONE`
|
||||
5. `ERROR`
|
||||
6. `STALE`
|
||||
7. `CANCELLED`
|
||||
|
||||
Правила:
|
||||
|
||||
1. Терминальные статусы (`DONE/ERROR/CANCELLED`) имеют приоритет и не откатываются в `RUNNING`.
|
||||
2. Повторный запуск не перетирает историю, а создаёт новую сущность запуска/задачи.
|
||||
3. Для каждого перехода статуса обязателен `updatedAt` и источник изменения (`source`).
|
||||
|
||||
---
|
||||
|
||||
## 7. Требования к GUI бухгалтерского агента
|
||||
|
||||
### 7.1 Что обязательно в первой версии
|
||||
|
||||
1. Панель запуска и остановки.
|
||||
2. Панель прогонов (`runs`) со статусом, временем, инициатором.
|
||||
3. Панель результатов (`results`) с фильтрами и быстрым поиском.
|
||||
4. Панель ошибок/исключений.
|
||||
5. Панель трассировки (`trace`) по выбранному `runId`.
|
||||
6. Явная индикация: что обновляется в реальном времени, а что по ручному refresh.
|
||||
|
||||
### 7.2 UX-правила
|
||||
|
||||
1. Никаких скрытых магических фильтров, влияющих на выдачу без отображения в UI.
|
||||
2. Любое действие пользователя должно иметь видимый эффект: `queued/running/done/error`.
|
||||
3. Длинные операции не блокируют интерфейс целиком.
|
||||
4. Ошибки показываются в 2 слоя:
|
||||
- коротко для оператора;
|
||||
- подробно для диагностики (код, traceId/runId).
|
||||
|
||||
### 7.3 Терминология UI
|
||||
|
||||
1. Во всех пользовательских текстах использовать `NDC`.
|
||||
2. Не использовать `N8N` в текстах интерфейса.
|
||||
3. В техническом коде/маршрутах внутренние названия не переписывать автоматически.
|
||||
|
||||
---
|
||||
|
||||
## 8. Требования к временному монолитному backend (с прицелом на замену runtime)
|
||||
|
||||
Чтобы потом перейти к отдельному runtime/оркестрации без переписывания GUI:
|
||||
|
||||
1. Ввести слой-адаптер исполнения (runtime adapter) как отдельный модуль.
|
||||
2. GUI/backend общаются с этим адаптером через стабильный внутренний контракт.
|
||||
3. В монолитной версии адаптер реализован локально.
|
||||
4. В будущей версии адаптер можно заменить на внешний runtime (без смены GUI API).
|
||||
5. Очередь/ретраи/лимиты должны быть инкапсулированы в backend, а не в GUI.
|
||||
|
||||
Минимальные способности адаптера исполнения:
|
||||
|
||||
1. `startRun`;
|
||||
2. `stopRun`;
|
||||
3. `enqueueTask`;
|
||||
4. `claimTask`;
|
||||
5. `completeTask`;
|
||||
6. `failTask`;
|
||||
7. `getRunState`;
|
||||
8. `getRunTrace`.
|
||||
|
||||
---
|
||||
|
||||
## 9. Наблюдаемость, логирование, диагностика
|
||||
|
||||
1. Логи в структурированном формате JSON.
|
||||
2. Обязательные поля логов: `timestamp`, `level`, `service`, `sessionId`, `runId`, `taskId`, `eventType`.
|
||||
3. Для ошибок обязательны: `errorCode`, `errorMessage`, `stack` (где применимо).
|
||||
4. Должна быть возможность получить trace по `runId` без ручного доступа к серверу.
|
||||
5. Учитывать рабочую таймзону проекта: `Europe/Moscow` в операционных отчётах.
|
||||
|
||||
---
|
||||
|
||||
## 10. Безопасность и эксплуатационные правила
|
||||
|
||||
1. В секретах/ключах не хранить чувствительные данные в открытых логах.
|
||||
2. Любые внешние интеграции — через конфигурацию окружения, без хардкода.
|
||||
3. Все потенциально тяжелые операции ограничить по timeout/retry.
|
||||
4. Обязательны idempotency-защиты для endpoint-ов старта/завершения/записи результатов.
|
||||
|
||||
---
|
||||
|
||||
## 11. Definition of Done для подрядчика
|
||||
|
||||
Задача считается готовой, если выполнено всё:
|
||||
|
||||
1. GUI поднимается и работает локально в связке с backend.
|
||||
2. Есть запуск/остановка/мониторинг прогонов.
|
||||
3. Статусы и жизненный цикл реализованы по канону раздела 6.
|
||||
4. API покрывает минимальный контракт раздела 5.
|
||||
5. Есть trace-диагностика по `runId`.
|
||||
6. Ошибки и логирование структурированы.
|
||||
7. Терминология UI приведена к `NDC`.
|
||||
8. Подтверждена обратимая миграция с монолита на внешний runtime-адаптер без смены UI-контрактов.
|
||||
|
||||
---
|
||||
|
||||
## 12. Интеграционный чеклист перед вливанием в `dc_node`
|
||||
|
||||
1. Совпадает ли словарь статусов с существующим монитором.
|
||||
2. Присутствуют ли `sessionId/runId` во всех критичных сущностях и событиях.
|
||||
3. Нет ли скрытых зависимостей GUI от конкретной монолитной реализации runtime.
|
||||
4. Не дублирует ли модуль существующие механизмы хранения/трассировки.
|
||||
5. Не конфликтуют ли route-префиксы и форматы ответов с текущим API-паттерном.
|
||||
6. Можно ли подключить модуль в NodeDC поэтапно (feature flag / scoped rollout).
|
||||
|
||||
---
|
||||
|
||||
## 13. Короткий итог для разработчика GUI
|
||||
|
||||
1. Делай интерфейс и backend как автономный модуль, но по контрактам, совместимым с NodeDC.
|
||||
2. Сейчас runtime может быть монолитным, но обязан быть спрятан за адаптером.
|
||||
3. UI должен опираться на стабильные статусы, `run/session`-идентификаторы и наблюдаемую trace-модель.
|
||||
4. Всё, что пользователь видит, называем через `NDC`.
|
||||
@@ -0,0 +1,840 @@
|
||||
AI СЛОЙ ДЛЯ НАРМАЛИЗАЦИИ ЗАПРОСОВ ОТ ЮЗЕРА - ГУЙ ДОЛЖЕН БЫТЬ ПОЛНОСТЬЮ РУИФИЦИРОВАН !!!
|
||||
|
||||
|
||||
|
||||
Ниже — **конкретное ТЗ для Codex** на первый этап интеграции LLM в контур бухгалтерского ассистента.
|
||||
|
||||
Основа решения: использовать **Responses API**, а не legacy-путь Assistants, и заставить модель возвращать **строго структурированный JSON** через structured outputs / JSON schema. API-ключ нельзя светить в client-side коде, поэтому даже для localhost-стенда запросы должны идти через локальный backend-proxy. ([OpenAI Платформа][1])
|
||||
|
||||
---
|
||||
|
||||
# ТЗ: LLM Normalizer Playground + Pre-Router Normalization Layer
|
||||
|
||||
## 1. Цель этапа
|
||||
|
||||
Реализовать локальный тестовый стенд и базовый backend-слой для интеграции LLM в качестве **нормализатора человеческих бухгалтерских запросов**.
|
||||
|
||||
LLM на этом этапе **не отвечает за финальный бухгалтерский ответ** и **не ходит напрямую в данные**.
|
||||
LLM отвечает только за:
|
||||
|
||||
* разбор человеческого запроса;
|
||||
* выделение сущностей, периода, типа задачи и причинно-следственной формы;
|
||||
* возврат строго структурированного JSON;
|
||||
* подготовку нормализованного input для существующего router/orchestration слоя.
|
||||
|
||||
---
|
||||
|
||||
## 2. Бизнес-смысл этапа
|
||||
|
||||
Текущий deterministic router хорошо работает на каноничных и полуструктурированных вопросах, но заметно хуже справляется с длинными человеческими формулировками, особенно в cross-entity и causal explain сценариях.
|
||||
|
||||
Цель этого этапа — не заменить router, а поставить перед ним **semantic front-end**, который переводит живой язык пользователя в нормализованный внутренний контракт.
|
||||
|
||||
Новая целевая цепочка:
|
||||
|
||||
**Пользователь → LLM Normalizer → Normalized Query JSON → Existing Router → Existing Retrieval/Stores/Batch → Final Answer Layer**
|
||||
|
||||
---
|
||||
|
||||
## 3. Что должно получиться на выходе
|
||||
|
||||
После реализации должен существовать рабочий localhost-стенд, в котором можно:
|
||||
|
||||
* вставить API key;
|
||||
* выбрать модель;
|
||||
* редактировать системный / developer prompt;
|
||||
* редактировать domain prompt;
|
||||
* ввести человеческий бухгалтерский вопрос;
|
||||
* отправить запрос в OpenAI через локальный backend;
|
||||
* получить:
|
||||
|
||||
* raw model output,
|
||||
* normalized JSON output,
|
||||
* parsed route hint,
|
||||
* confidence,
|
||||
* token usage,
|
||||
* latency,
|
||||
* trace/log записи;
|
||||
* сохранить результат как тест-кейс для дальнейшей оценки.
|
||||
|
||||
---
|
||||
|
||||
## 4. Технологическое решение
|
||||
|
||||
### 4.1 API-путь
|
||||
|
||||
Использовать **Responses API** как основной способ интеграции. Это соответствует текущему рекомендуемому стеку OpenAI для новых интеграций. ([OpenAI Платформа][1])
|
||||
|
||||
### 4.2 Формат ответа модели
|
||||
|
||||
Использовать **structured outputs / JSON schema response format**, чтобы модель возвращала не свободный текст, а строго валидируемый JSON-объект. ([OpenAI Платформа][1])
|
||||
|
||||
### 4.3 Безопасность ключа
|
||||
|
||||
API key не должен использоваться напрямую из фронта.
|
||||
Ключ должен передаваться в локальный backend-proxy и использоваться только серверной частью. В документации OpenAI прямо сказано, что API key — секрет и его нельзя светить в браузере или клиентском коде. ([OpenAI Платформа][2])
|
||||
|
||||
### 4.4 Целевая модель первого этапа
|
||||
|
||||
Для первого этапа предусмотреть параметризуемую модель, по умолчанию — `gpt-4o-mini` как fast/cheap normalizer-кандидат. Конкретный model id должен быть настраиваемым из UI, без хардкода в коде.
|
||||
|
||||
---
|
||||
|
||||
## 5. Scope этапа
|
||||
|
||||
### В scope входит
|
||||
|
||||
* localhost GUI playground;
|
||||
* локальный backend-proxy для OpenAI API;
|
||||
* normalizer prompt system;
|
||||
* structured JSON schema;
|
||||
* вызов Responses API;
|
||||
* валидация JSON-ответа;
|
||||
* логирование запросов/ответов;
|
||||
* нормализация route hints;
|
||||
* сохранение trace;
|
||||
* базовый eval-mode на заранее заданном наборе вопросов.
|
||||
|
||||
### В scope не входит
|
||||
|
||||
* полноценный production chat;
|
||||
* tool use;
|
||||
* live access к 1С данным;
|
||||
* финальный answer synthesis;
|
||||
* agentic orchestration;
|
||||
* самостоятельный выбор model toolchain;
|
||||
* дообучение модели;
|
||||
* интеграция в production UI Node/DC.
|
||||
|
||||
---
|
||||
|
||||
## 6. Архитектура решения
|
||||
|
||||
## 6.1 Общая схема
|
||||
|
||||
### Компоненты
|
||||
|
||||
1. **Frontend Playground**
|
||||
2. **Local Backend Proxy**
|
||||
3. **Prompt Manager**
|
||||
4. **Normalizer Service**
|
||||
5. **Schema Validator**
|
||||
6. **Trace Logger**
|
||||
7. **Optional Eval Runner**
|
||||
8. **Route Hint Adapter** для передачи результата в существующий router
|
||||
|
||||
### Поток
|
||||
|
||||
1. Пользователь вводит сырой вопрос.
|
||||
2. Frontend отправляет payload на local backend.
|
||||
3. Backend собирает prompt + schema + user input.
|
||||
4. Backend вызывает Responses API.
|
||||
5. Backend получает structured JSON.
|
||||
6. Backend валидирует JSON по schema.
|
||||
7. Backend вычисляет route hint summary.
|
||||
8. Backend возвращает UI:
|
||||
|
||||
* raw response,
|
||||
* normalized JSON,
|
||||
* parse status,
|
||||
* validation status,
|
||||
* usage,
|
||||
* latency,
|
||||
* trace id.
|
||||
|
||||
---
|
||||
|
||||
## 7. Требования к GUI
|
||||
|
||||
Нужен простой localhost GUI. Подойдёт React/Vite/Next localhost-only интерфейс или любой быстрый web UI.
|
||||
|
||||
## 7.1 Обязательные блоки интерфейса
|
||||
|
||||
### A. Connection Panel
|
||||
|
||||
Поля:
|
||||
|
||||
* `OpenAI API Key`
|
||||
* `Model ID`
|
||||
* `Base URL` (опционально, по умолчанию OpenAI)
|
||||
* `Temperature`
|
||||
* `Max output tokens`
|
||||
|
||||
Кнопки:
|
||||
|
||||
* `Save local session config`
|
||||
* `Test connection`
|
||||
|
||||
### B. Prompt Panel
|
||||
|
||||
Отдельные текстовые области:
|
||||
|
||||
* `System Prompt`
|
||||
* `Developer / Instruction Prompt`
|
||||
* `Domain Prompt`
|
||||
* `Schema Notes` (опционально)
|
||||
* `Few-shot examples` (опционально)
|
||||
|
||||
Кнопки:
|
||||
|
||||
* `Load preset`
|
||||
* `Save preset`
|
||||
* `Diff with previous`
|
||||
* `Reset to default`
|
||||
|
||||
### C. User Query Panel
|
||||
|
||||
Поля:
|
||||
|
||||
* `Raw user question`
|
||||
* `Optional period context`
|
||||
* `Optional business context`
|
||||
* `Optional expected route` (для eval mode)
|
||||
|
||||
Кнопки:
|
||||
|
||||
* `Normalize`
|
||||
* `Normalize + Save as test case`
|
||||
|
||||
### D. Output Panel
|
||||
|
||||
Вкладки:
|
||||
|
||||
* `Normalized JSON`
|
||||
* `Raw model output`
|
||||
* `Route hint summary`
|
||||
* `Validation`
|
||||
* `Logs`
|
||||
|
||||
### E. Runtime Metrics Panel
|
||||
|
||||
Показывать:
|
||||
|
||||
* `trace_id`
|
||||
* `request_started_at`
|
||||
* `request_finished_at`
|
||||
* `latency_ms`
|
||||
* `input_tokens`
|
||||
* `output_tokens`
|
||||
* `total_tokens`
|
||||
* `validation_status`
|
||||
* `confidence`
|
||||
* `schema_version`
|
||||
* `prompt_version`
|
||||
|
||||
### F. History Panel
|
||||
|
||||
Список прошлых запросов:
|
||||
|
||||
* timestamp
|
||||
* shortened question
|
||||
* model
|
||||
* confidence
|
||||
* validation pass/fail
|
||||
* route hint
|
||||
* save status
|
||||
|
||||
---
|
||||
|
||||
## 8. Требования к backend
|
||||
|
||||
Backend должен быть локальным HTTP-сервисом.
|
||||
|
||||
Подойдут:
|
||||
|
||||
* Node.js + Express / Fastify
|
||||
или
|
||||
* Python + FastAPI
|
||||
|
||||
Рекомендуемый вариант для скорости: **Node.js + Fastify**.
|
||||
|
||||
## 8.1 Обязательные endpoint’ы
|
||||
|
||||
### `POST /api/openai/test-connection`
|
||||
|
||||
Проверка, что ключ рабочий и Responses API доступен.
|
||||
|
||||
### `POST /api/normalize`
|
||||
|
||||
Основной endpoint для нормализации вопроса.
|
||||
|
||||
Вход:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiKey": "string",
|
||||
"model": "gpt-4o-mini",
|
||||
"temperature": 0,
|
||||
"systemPrompt": "string",
|
||||
"developerPrompt": "string",
|
||||
"domainPrompt": "string",
|
||||
"schemaVersion": "v1",
|
||||
"userQuestion": "string",
|
||||
"context": {
|
||||
"period_hint": "2020-06",
|
||||
"business_context": "optional"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Выход:
|
||||
|
||||
```json
|
||||
{
|
||||
"trace_id": "string",
|
||||
"ok": true,
|
||||
"normalized": { ... },
|
||||
"route_hint_summary": { ... },
|
||||
"raw_model_output": "string or object",
|
||||
"validation": {
|
||||
"passed": true,
|
||||
"errors": []
|
||||
},
|
||||
"usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"total_tokens": 0
|
||||
},
|
||||
"latency_ms": 0,
|
||||
"prompt_version": "normalizer_v1",
|
||||
"schema_version": "v1"
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /api/eval/run`
|
||||
|
||||
Запуск серии нормализаций на тестовом наборе.
|
||||
|
||||
### `GET /api/history`
|
||||
|
||||
История запросов.
|
||||
|
||||
### `GET /api/history/:trace_id`
|
||||
|
||||
Получение полного trace.
|
||||
|
||||
### `POST /api/presets/save`
|
||||
|
||||
Сохранение набора prompt’ов / конфигурации.
|
||||
|
||||
### `GET /api/presets`
|
||||
|
||||
Получение доступных prompt presets.
|
||||
|
||||
---
|
||||
|
||||
## 9. Центральная сущность: Normalized Query JSON
|
||||
|
||||
Это ключевой контракт между LLM и вашим deterministic router.
|
||||
|
||||
## 9.1 Schema version
|
||||
|
||||
Первая версия:
|
||||
|
||||
* `schema_version = "normalized_query_v1"`
|
||||
|
||||
## 9.2 Обязательные поля
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": "normalized_query_v1",
|
||||
"user_question_raw": "string",
|
||||
"normalized_question": "string",
|
||||
"intent_class": "heavy_analytical | cross_entity | drilldown_explain | rule_based_account_control | anomaly_probe | period_close_risk | ambiguous_human_query | simple_factual",
|
||||
"business_problem_type": "string",
|
||||
"domain_entities": ["string"],
|
||||
"accounts_mentioned": ["string"],
|
||||
"documents_mentioned": ["string"],
|
||||
"registers_mentioned": ["string"],
|
||||
"period_scope": {
|
||||
"type": "explicit | inferred | missing",
|
||||
"value": "string | null",
|
||||
"confidence": "high | medium | low"
|
||||
},
|
||||
"requires": {
|
||||
"needs_cross_entity_join": true,
|
||||
"needs_causal_chain": true,
|
||||
"needs_exact_object_trace": false,
|
||||
"needs_ranking": false,
|
||||
"needs_anomaly_summary": false,
|
||||
"needs_runtime_truth": false,
|
||||
"needs_period_cut": true,
|
||||
"needs_evidence": true
|
||||
},
|
||||
"expected_output_shape": "ranked_list | evidence_chain | anomaly_summary | point_answer | reconciliation_report | prioritized_review_list",
|
||||
"route_hint": "store_canonical | store_feature_risk | hybrid_store_plus_live | live_mcp_drilldown | batch_refresh_then_store",
|
||||
"ambiguities": [
|
||||
{
|
||||
"field": "period_scope",
|
||||
"reason": "month not specified",
|
||||
"severity": "medium"
|
||||
}
|
||||
],
|
||||
"confidence": {
|
||||
"overall": "high | medium | low",
|
||||
"intent_class": "high | medium | low",
|
||||
"route_hint": "high | medium | low"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Семанические требования к normalizer
|
||||
|
||||
LLM normalizer обязан:
|
||||
|
||||
### 10.1 Не отвечать на бухгалтерский вопрос по сути
|
||||
|
||||
Она не должна возвращать:
|
||||
|
||||
* “вероятно, проблема в 62 счёте”
|
||||
* “скорее всего, не хватает оплаты”
|
||||
|
||||
Она должна возвращать **нормализованную интерпретацию**, а не бизнес-ответ.
|
||||
|
||||
### 10.2 Выделять причинно-следственную форму
|
||||
|
||||
Если вопрос содержит конструкции типа:
|
||||
|
||||
* “не бьётся”
|
||||
* “не собралось в цепочку”
|
||||
* “разложи по документам, оплатам, закрывающим”
|
||||
* “чем подтверждается”
|
||||
* “почему висит хвост”
|
||||
* “не видно прихода под реализацию”
|
||||
|
||||
LLM должна поднимать:
|
||||
|
||||
* `needs_cross_entity_join = true`
|
||||
* `needs_causal_chain = true`
|
||||
* часто `needs_evidence = true`
|
||||
|
||||
### 10.3 Отдельно распознавать exact object trace
|
||||
|
||||
Если вопрос про:
|
||||
|
||||
* конкретный документ,
|
||||
* конкретную проводку,
|
||||
* конкретную строку,
|
||||
* конкретный объект,
|
||||
* конкретный номер / ref / line / posting
|
||||
|
||||
Тогда поднимать:
|
||||
|
||||
* `needs_exact_object_trace = true`
|
||||
|
||||
### 10.4 Различать множественный explain и точечный drilldown
|
||||
|
||||
Если вопрос:
|
||||
|
||||
* “по нескольким материалам покажи, почему зависли”
|
||||
* “по каким кейсам это происходит”
|
||||
* “по каким поставщикам не бьётся”
|
||||
|
||||
Это **не** exact drilldown.
|
||||
Это множественный causal explain → чаще `hybrid_store_plus_live`.
|
||||
|
||||
### 10.5 Не путать risk-лексику с risk-route
|
||||
|
||||
Если в вопросе есть слова:
|
||||
|
||||
* “риск”
|
||||
* “проблема”
|
||||
* “аномалия”
|
||||
* “опасный”
|
||||
но одновременно есть document/payment/posting chain semantics,
|
||||
то normalizer не должен автоматически относить это к `store_feature_risk`.
|
||||
Он должен сохранять causal cross-entity приоритет.
|
||||
|
||||
---
|
||||
|
||||
## 11. Prompt system
|
||||
|
||||
Нужна управляемая prompt-архитектура.
|
||||
|
||||
## 11.1 Структура prompt’ов
|
||||
|
||||
Разделить prompt минимум на 3 уровня:
|
||||
|
||||
### `system_prompt`
|
||||
|
||||
Общие жесткие правила:
|
||||
|
||||
* ты не отвечаешь на бухгалтерский вопрос;
|
||||
* ты возвращаешь только JSON;
|
||||
* ты обязан следовать schema;
|
||||
* ты не выдумываешь период, если его нельзя разумно вывести;
|
||||
* ты явно помечаешь ambiguity.
|
||||
|
||||
### `developer_prompt`
|
||||
|
||||
Правила нормализации:
|
||||
|
||||
* классификация типов вопросов;
|
||||
* различение heavy/cross-entity/drilldown;
|
||||
* правила выбора route_hint;
|
||||
* правила confidence;
|
||||
* правила causal semantics.
|
||||
|
||||
### `domain_prompt`
|
||||
|
||||
Предметная специфика:
|
||||
|
||||
* словарь бухгалтерских формулировок;
|
||||
* названия счетов;
|
||||
* доменные сущности;
|
||||
* типовые паттерны “хвост”, “не бьётся”, “акт сверки”, “закрывающие”, “реализация без оплаты”, “продажа раньше прихода”, “ошибка даты”, “97 счёт”, “ОС”, “банковская выписка” и т.д.
|
||||
|
||||
## 11.2 Few-shot examples
|
||||
|
||||
Добавить отдельный блок примеров:
|
||||
|
||||
* raw question
|
||||
* expected normalized JSON fragment
|
||||
|
||||
Минимум 10–15 примеров на старт.
|
||||
|
||||
---
|
||||
|
||||
## 12. Route Hint Adapter
|
||||
|
||||
Нужен слой, который переводит normalized JSON в input существующего router.
|
||||
|
||||
## 12.1 Требования
|
||||
|
||||
На основе `normalized_query_v1` строить объект:
|
||||
|
||||
```json
|
||||
{
|
||||
"intent_class": "cross_entity",
|
||||
"decision_flags": {
|
||||
"needs_cross_entity_join": true,
|
||||
"needs_causal_chain": true,
|
||||
"needs_exact_object_trace": false,
|
||||
"needs_ranking": false,
|
||||
"needs_anomaly_summary": false,
|
||||
"needs_runtime_truth": false
|
||||
},
|
||||
"route_hint": "hybrid_store_plus_live",
|
||||
"confidence": "medium",
|
||||
"entities": { ... },
|
||||
"period_scope": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
## 12.2 Поведение
|
||||
|
||||
Этот adapter пока только готовит payload и показывает его в UI.
|
||||
Интеграция в боевой router может быть следующей фазой.
|
||||
|
||||
---
|
||||
|
||||
## 13. Логирование и traceability
|
||||
|
||||
Каждая нормализация должна логироваться.
|
||||
|
||||
## 13.1 Что сохранять
|
||||
|
||||
* `trace_id`
|
||||
* timestamp
|
||||
* model
|
||||
* prompt_version
|
||||
* schema_version
|
||||
* raw user question
|
||||
* context
|
||||
* raw request payload
|
||||
* raw model response
|
||||
* parsed normalized JSON
|
||||
* validation result
|
||||
* route_hint
|
||||
* confidence
|
||||
* token usage
|
||||
* latency
|
||||
* optional expected route
|
||||
* optional eval label
|
||||
|
||||
## 13.2 Формат хранения
|
||||
|
||||
Хранить локально в JSONL или SQLite.
|
||||
|
||||
Рекомендуемый вариант:
|
||||
|
||||
* `data/normalizer_traces/*.json`
|
||||
или
|
||||
* `data/normalizer.sqlite`
|
||||
|
||||
---
|
||||
|
||||
## 14. Eval mode
|
||||
|
||||
Нужен режим оценки качества normalizer.
|
||||
|
||||
## 14.1 Источник eval-набора
|
||||
|
||||
Собрать eval corpus из:
|
||||
|
||||
* каноничных benchmark-вопросов;
|
||||
* creative stress вопросов;
|
||||
* реальных человеческих фраз из диалогов.
|
||||
|
||||
## 14.2 Формат тест-кейса
|
||||
|
||||
```json
|
||||
{
|
||||
"case_id": "NQ-001",
|
||||
"raw_question": "Где у нас не бьются взаиморасчёты по поставщикам...",
|
||||
"expected": {
|
||||
"intent_class": "cross_entity",
|
||||
"route_hint": "hybrid_store_plus_live",
|
||||
"requires": {
|
||||
"needs_cross_entity_join": true,
|
||||
"needs_causal_chain": true
|
||||
},
|
||||
"accounts_mentioned": ["60"],
|
||||
"expected_output_shape": "reconciliation_report"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 14.3 Метрики eval
|
||||
|
||||
Считать:
|
||||
|
||||
* `intent_class_accuracy`
|
||||
* `route_hint_accuracy`
|
||||
* `causal_flag_accuracy`
|
||||
* `period_scope_accuracy`
|
||||
* `entity_extraction_accuracy`
|
||||
* `schema_validation_pass_rate`
|
||||
* `high_confidence_error_rate`
|
||||
|
||||
---
|
||||
|
||||
## 15. Валидация structured output
|
||||
|
||||
## 15.1 Обязательное правило
|
||||
|
||||
Если модель вернула невалидный JSON:
|
||||
|
||||
* backend не должен silently repair;
|
||||
* backend должен помечать `validation.passed = false`;
|
||||
* UI должен показывать ошибку;
|
||||
* запись должна логироваться.
|
||||
|
||||
## 15.2 Допустимый soft-recovery
|
||||
|
||||
Разрешён только один controlled retry:
|
||||
|
||||
* при invalid JSON
|
||||
* с дополнительной server-side инструкцией “return valid JSON strictly matching schema”
|
||||
|
||||
Но не больше 1 повтора на запрос.
|
||||
|
||||
---
|
||||
|
||||
## 16. Security requirements
|
||||
|
||||
### 16.1 Обязательные требования
|
||||
|
||||
* ключ не хранить в localStorage в открытом виде;
|
||||
* ключ не отправлять в сторонние домены;
|
||||
* ключ не логировать в trace;
|
||||
* ключ не возвращать во frontend response;
|
||||
* backend должен редактировать чувствительные поля из логов.
|
||||
|
||||
### 16.2 Допустимый режим для localhost
|
||||
|
||||
Разрешается:
|
||||
|
||||
* временно держать ключ в памяти backend-процесса;
|
||||
* или вводить ключ вручную на сессию без персистентного хранения.
|
||||
|
||||
---
|
||||
|
||||
## 17. Нефункциональные требования
|
||||
|
||||
* UI должен быть пригоден для localhost-тестов без production hardening.
|
||||
* Нормализация одного запроса должна быть достаточно быстрой для интерактивной работы.
|
||||
* Код должен быть модульным, чтобы потом normalizer можно было вынести из playground в основной backend.
|
||||
* Все schema и prompts должны быть версионируемыми.
|
||||
* Архитектура должна позволять заменить модель без переписывания всего пайплайна.
|
||||
|
||||
---
|
||||
|
||||
## 18. Предлагаемая структура проекта
|
||||
|
||||
```text
|
||||
llm_normalizer/
|
||||
frontend/
|
||||
src/
|
||||
components/
|
||||
pages/
|
||||
api/
|
||||
state/
|
||||
package.json
|
||||
|
||||
backend/
|
||||
src/
|
||||
server.ts
|
||||
routes/
|
||||
normalize.ts
|
||||
presets.ts
|
||||
history.ts
|
||||
eval.ts
|
||||
testConnection.ts
|
||||
services/
|
||||
openaiResponsesClient.ts
|
||||
normalizerService.ts
|
||||
promptBuilder.ts
|
||||
schemaValidator.ts
|
||||
routeHintAdapter.ts
|
||||
traceLogger.ts
|
||||
schemas/
|
||||
normalized_query_v1.json
|
||||
prompts/
|
||||
system/
|
||||
developer/
|
||||
domain/
|
||||
fewshot/
|
||||
storage/
|
||||
types/
|
||||
package.json
|
||||
|
||||
data/
|
||||
presets/
|
||||
traces/
|
||||
eval_cases/
|
||||
|
||||
docs/
|
||||
README.md
|
||||
API.md
|
||||
SCHEMA.md
|
||||
PROMPTS.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 19. Acceptance criteria
|
||||
|
||||
Этап считается принятым, если выполнены все условия:
|
||||
|
||||
### Функционально
|
||||
|
||||
* localhost GUI запускается;
|
||||
* можно ввести ключ, модель и вопрос;
|
||||
* backend успешно вызывает Responses API; ([OpenAI Платформа][1])
|
||||
* модель возвращает structured JSON по schema; ([OpenAI Платформа][1])
|
||||
* JSON проходит валидацию минимум в 90% тестовых кейсов;
|
||||
* сохраняются traces;
|
||||
* route hint summary отображается в UI;
|
||||
* есть история запросов;
|
||||
* есть eval-mode на локальном наборе кейсов.
|
||||
|
||||
### Архитектурно
|
||||
|
||||
* frontend не ходит напрямую в OpenAI API с ключом; ([OpenAI Платформа][2])
|
||||
* prompts версионируются;
|
||||
* schema версионируется;
|
||||
* normalizer отделён от router;
|
||||
* код модульный и пригоден к дальнейшей интеграции.
|
||||
|
||||
### Качественно
|
||||
|
||||
На стартовом eval-наборе целевые ориентиры:
|
||||
|
||||
* `schema_validation_pass_rate >= 90%`
|
||||
* `intent_class_accuracy >= 80%`
|
||||
* `route_hint_accuracy >= 75%`
|
||||
* `causal_flag_accuracy >= 80%`
|
||||
* `high_confidence_error_rate <= 10%`
|
||||
|
||||
---
|
||||
|
||||
## 20. Порядок реализации
|
||||
|
||||
### Этап 1
|
||||
|
||||
Поднять backend-proxy и test connection.
|
||||
|
||||
### Этап 2
|
||||
|
||||
Сделать GUI с input/output блоками.
|
||||
|
||||
### Этап 3
|
||||
|
||||
Сделать prompt manager и schema loader.
|
||||
|
||||
### Этап 4
|
||||
|
||||
Сделать `POST /api/normalize` и structured JSON parsing.
|
||||
|
||||
### Этап 5
|
||||
|
||||
Сделать route hint adapter и validation panel.
|
||||
|
||||
### Этап 6
|
||||
|
||||
Сделать history + trace logging.
|
||||
|
||||
### Этап 7
|
||||
|
||||
Сделать eval mode и загрузку тестовых кейсов.
|
||||
|
||||
### Этап 8
|
||||
|
||||
Подготовить README и пример prompt presets.
|
||||
|
||||
---
|
||||
|
||||
## 21. Что Codex должен сгенерировать
|
||||
|
||||
Codex должен выдать:
|
||||
|
||||
1. Полностью рабочий localhost-проект.
|
||||
2. Frontend + backend.
|
||||
3. JSON schema `normalized_query_v1`.
|
||||
4. Стартовые prompt-файлы:
|
||||
|
||||
* system
|
||||
* developer
|
||||
* domain
|
||||
* fewshot
|
||||
5. Примеры test cases.
|
||||
6. README с инструкцией запуска.
|
||||
7. Пример `.env.example`.
|
||||
8. Пример trace storage.
|
||||
9. Минимальные тесты:
|
||||
|
||||
* schema validation
|
||||
* route hint adapter
|
||||
* normalize endpoint
|
||||
* prompt builder
|
||||
|
||||
---
|
||||
|
||||
## 22. Ключевое архитектурное правило
|
||||
|
||||
Самое важное правило этого этапа:
|
||||
|
||||
**LLM — это semantic front-end, а не исполнитель бизнес-логики.**
|
||||
|
||||
LLM должна:
|
||||
|
||||
* нормализовать,
|
||||
* структурировать,
|
||||
* классифицировать,
|
||||
* подсказывать route hint.
|
||||
|
||||
LLM не должна:
|
||||
|
||||
* сама принимать окончательное orchestration-решение;
|
||||
* сама лезть в данные;
|
||||
* сама становиться вашим retrieval engine.
|
||||
|
||||
---
|
||||
|
||||
Если хочешь, следующим сообщением я дам **сразу вторую часть ТЗ**: уже не про playground, а про **встраивание normalizer’а в существующий router/orchestration pipeline**.
|
||||
|
||||
[1]: https://platform.openai.com/docs/api-reference/responses/list?ref=test-ippon.ghost.io&utm_source=chatgpt.com "Responses | OpenAI API Reference"
|
||||
[2]: https://platform.openai.com/docs/api-reference/chat/create%23chat-create-temperature?utm_source=chatgpt.com "Chat Completions | OpenAI API Reference"
|
||||
Reference in New Issue
Block a user