Charnorm
NOTE
Статус: Live (HEAD
5e4ce54, 2026-05-06). BC введён в цикле Charnorm LLM gateway (ADR-0044, CLOSED 2026-04-29). Отдельный workercmd/charnorm-workerобрабатывает batch’и характеристик.
LLM-нормализация имён характеристик: на входе сырые (supplier, supplierCode, displayName) от ingestion; на выходе — единое имя характеристики из catalog’а. Использует Claude Sonnet через platform/llm (CLIProxy + sashabaranov SDK).
Назначение
Привести зоопарк имён характеристик от поставщиков (например, «Цвет», «Color», «Окраска корпуса», «Цветовая гамма») к каноническому имени из catalog/characteristic. Без charnorm’а matcher Tier-1/2/3 захлёбываются на noise’е поставщикских названий.
Статус документа
- Тип знания:
current service - Статус реализации:
cmd/charnorm-workerотдельный процесс +internal/core/charnorm/{domain,app,infra}BC. Idempotency черезinputs_hash. - Текущее место кода:
backend/internal/core/charnorm/,backend/cmd/charnorm-worker/,backend/internal/platform/llm/(CLIProxy adapter). - Что читать дальше:
../../20-architecture/adr/0044-llm-gateway-char-pipeline.md.
Область действия
Входит:
- Чтение
offer_characteristic_raw(наполняется ingestion’ом). - Промпт-инжиниринг и retries для Sonnet через
platform/llm. - Маппинг
(supplier, supplierCode, displayName) → CharacteristicName. - Запись результата в
char_name_mappingсinputs_hash(идемпотентность). - Метрики:
charnorm_requests_total,charnorm_llm_tokens_used_total.
Не входит:
- Нормализация значений характеристик (это catalog/characteristic).
- Сами LLM вызовы — abstracted через
platform/llm.Client. - Принятие решений по матчингу — это matching BC.
Публичный контракт
Вход
- Ticker внутри
cmd/charnorm-workerзапускаетNormalizer.RunBatchкаждые N минут (envCHARNORM_TICK_INTERVAL). RunBatchчитает unprocessed строкиoffer_characteristic_raw.
Выход
- Запись в
char_name_mapping(PG). - Outbox events
charnorm.mapping_resolved.v1. - Метрики Prometheus.
Внутренняя архитектура
domain/mapping.go—CharNameMappingaggregate +ComputeInputsHash(supplier, supplierCode, displayName, model, promptVersion).domain/prompt.go— versioned prompt template (promptVersionучаствует в hash).app/Normalizer.RunBatch— основной use case.infra/llm/— wrapper надplatform/llm.Client.infra/pg/— repos для raw + mapping.
Malformed LLM responses
PromptVersion=6 явно требует от LLM возвращать JSON даже для неясных характеристик: низкая confidence, needs_review=true, без вопросов и пояснений вне JSON. Это защищает прогрев от ответов вида “нужно больше контекста”.
Если после всех parse-retry ответ всё равно невалидный JSON, Normalizer не дропает chunk бесконечно. Он создаёт низкоуверенный review-mapping:
canonical_name = fallback_<supplier>_<supplier_code>(или hash suffix, если код нельзя безопасно привести к canonical key);value_type = string;confidence = 0.051,needs_review = true.
Значение 0.051 намеренно выше stale-retry порога ListUnmapped (<=0.050), чтобы один и тот же supplier code не возвращался в LLM на каждом тике и не сжигал токены. Такие записи остаются видимыми для модерации и не считаются автоодобренными.
Зависимости
- PostgreSQL —
offer_characteristic_raw,char_name_mapping. platform/llm— Anthropic Claude Sonnet через CLIProxy.- catalog/characteristic — read-only словарь канонических characteristics.
Хранилище
| Таблица | Read/Write |
|---|---|
offer_characteristic_raw | Read (наполняется ingestion’ом) |
char_name_mapping | Write (inputs_hash idempotency UNIQUE) |
outbox_events | Write |
Конфигурация
| Env var | Default | Описание |
|---|---|---|
CHARNORM_TICK_INTERVAL | 5m | Интервал между батчами |
CHARNORM_BATCH_SIZE | 50 | Размер батча на тик |
CHARNORM_LLM_MODEL | claude-sonnet-4-6 | Имя модели; меняет inputs_hash |
CHARNORM_LLM_TIMEOUT | 30s | Timeout на одну mapping-операцию |
Локальный запуск
cd backend
go run ./cmd/charnorm-workerТребует CLI_PROXY_URL (CLIProxy LLM-gateway, см. tracium_charnorm_llm_gateway_execution).
Тестирование
- Unit:
go test ./internal/core/charnorm/... - Integration:
-tags=integrationдляinfra/pg/(testcontainers). - Prompt regression:
prompt_test.gosnapshot’ит шаблон, изменение требует bumppromptVersion.
Наблюдаемость
- Metrics:
charnorm_requests_total{outcome},charnorm_llm_tokens_used_total{direction},charnorm_llm_calls_total{result}. - Phase logs:
charnorm.batch.phaseчерезStartPhase.
Связанные документы
- ADR:
0044. - Memory:
tracium_charnorm_llm_gateway_execution.md. - Соседи: matching BC (потребитель), catalog/characteristic (словарь).