Skip to content

feat(advisor): financial advisor skill (LLM-reasoning) - #50

Merged
Tarasusrus merged 17 commits into
mainfrom
feature/advisor-snapshot
May 6, 2026
Merged

feat(advisor): financial advisor skill (LLM-reasoning)#50
Tarasusrus merged 17 commits into
mainfrom
feature/advisor-snapshot

Conversation

@Tarasusrus

Copy link
Copy Markdown
Owner

Summary

  • Auto-routed AdvisorSkill (ADR-002) для покупочных решений: вопрос → snapshot (один SQL CTE) → forecast → LLM → Markdown с вердиктом Да/Нет/Условно + 3 ключевые цифры в THB
  • 4 phase epic simpleAI-ws8 закрыты: snapshot layer (blg), scaffold+manifest (cyb), Run+LLM (yvq), tests+lint (rvs)
  • Property-based тесты на pgregory.net/rapid (test-only dep) + golangci-lint = 0 issues

Архитектура

  • internal/budget/model.goAdvisorSnapshot + MinTxForConfidence
  • internal/budget/store.goGetAdvisorSnapshot (один SQL CTE: tx global, debt global, recurring chat-scoped — асимметрия задокументирована в SQL)
  • internal/skills/advisor_skill.go — skill + manifest + Run + helpers (computeForecastRemaining, buildAdvisorPrompt, parseAdvisorLLMResponse, formatAdvisorReply)
  • Currency: amount × rates[cur] / rates[THB]; THB rate отсутствует → friendly error, прочие → slog.Warn + skip
  • Friendly fallback на каждой стадии (rates / snapshot / llm / parse) — без panic
  • slog: skill=advisor, chat_id, question (200 рун), verdict, free_cash_thb, duration_ms

Code review WARNINGS закрыты

  • UTF-8 safe truncation (truncateRunes)
  • Telegram Markdown escape для LLM-полей
  • chatID отсутствует в ctx → slog.Warn
  • testdata/rapid/ в .gitignore

Test plan

  • go test ./internal/budget/ ./internal/skills/ — green (rapid property tests)
  • golangci-lint run ./... — 0 issues
  • go build ./... + go vet ./... — green
  • Manual smoke на dev (4 сценария):
    • «можем купить велосипед за 25000?» → happy path, verdict
    • «можем купить за 50000 руб?» → обе валюты в выводе
    • «купил молоко за 50» → НЕ роутится в advisor (budget.add_expense)
    • low_data сценарий → verdict='Условно'
  • Проверка slog-записи skill=advisor

🤖 Generated with Claude Code

Tarasusrus and others added 17 commits May 4, 2026 20:03
Реализует epic simpleAI-ws8 — auto-routed skill для покупочных решений.

Phase 1 (snapshot, simpleAI-blg):
- AdvisorSnapshot + MinTxForConfidence в budget.model
- Store.GetAdvisorSnapshot — один SQL CTE: budget_transaction (global,
  MTD), budget_debt (global, status='active'+direction='owe', due_date<=eom),
  budget_recurring (chat-scoped, enabled, next_date<=eom). Конверсия
  через rates[currency]/rates['THB']; THB rate отсутствует → error,
  прочие отсутствующие → slog.Warn + skip.

Phase 2 (scaffold, simpleAI-cyb):
- AdvisorSkill + Manifest (positive triggers + negative phrase про budget)
- Регистрация в plugin.Registry рядом с BudgetSkill
- advisorStore interface — узкий контракт для тестируемости

Phase 3 (run+llm, simpleAI-yvq):
- Run: parse → rates → conversion → snapshot → forecast → prompt → LLM →
  JSON parse → Markdown
- Friendly fallback на каждой стадии (rates / snapshot / llm / parse)
- slog: skill='advisor', chat_id, question (truncated 200 рун),
  verdict, free_cash_thb, duration_ms

Phase 4 (tests+lint, simpleAI-rvs):
- Property-based тесты на pgregory.net/rapid (FreeCash/LowData
  invariants, currency-conversion consistency, parse roundtrip+rejection,
  format reply contract, ForecastRemaining bound)
- golangci-lint = 0 issues

Code review WARNINGS закрыты:
- UTF-8 safe truncation (truncateRunes)
- Telegram Markdown escape для LLM полей (verdict/explanation/recommendation)
- chatID отсутствует в ctx → slog.Warn
- testdata/rapid/ в .gitignore

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…budget

Smoke на dev: «Планирую купить байк» роутился в budget.add_expense
(amount=0 → ошибка). Manifest descriptions недостаточно различали
PLANNING покупку (advisor) и RECORDING покупки (budget.add_expense).

- advisor: русские триггеры (планирую/хочу/думаю/стоит ли/хватит ли/
  потянем/что приоритетнее), явное past-tense разделение
- budget: past-tense маркеры (купил/потратил/заплатил), negative
  phrase «Do NOT use for purchase advice — use advisor skill»

Closes simpleAI-9wq.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bug simpleAI-q49: «хочу купить блендер» уходило в budget.add_expense
вместо advisor → "Ошибка: amount must be positive".

Причина: LLM-роутер игнорировал negative phrase в budget manifest и
positive trigger в advisor manifest — позиция в prompt слабее чем
явное правило.

Фикс: блок ROUTING RULES выводится ДО списка инструментов:
1. future-purchase intent («хочу/планирую/думаю купить», «стоит ли»,
   «можем ли позволить», «хватит ли») → advisor.
2. past-tense («купил», «потратил», «заплатил») → budget.add_expense.
3. нет суммы + нет past-tense глагола → НЕ add_expense.

Тест TestBuildToolsSystemPrompt_ContainsRoutingRules проверяет
маркеры и позицию rules перед списком tools.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
simpleAI-yza (P2): Observability UI — Langfuse self-hosted
  блокируется существующими 0ya (compose) и 8h8 (инструментация)
  референс: /home/malinovskiy.t/GolandProjects/assister/langfuse/

simpleAI-wr7 (P1): Eval Suite — golden-set routing + harness + baseline
  подзадачи: cts (структура), 85c (harness), 578 (golden_set), lpy (baseline)
  триггер: q49 baselines нет — не знаем сколько таких кейсов
  референс: /home/malinovskiy.t/GolandProjects/assister/evals/

simpleAI-4fc (P2): Refactor по образцу assister/rag_mm
  подзадачи: 5mi (prompts→files), ckb (split budget_skill), 2vw (split agent/service)
  блокируется wr7 — рефакторим только когда есть guard от регрессий
  референс: assister/rag_mm/{configs/agents,dr_tools,pipelines}/

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Изолированный compose deploy/langfuse/ (web+worker+postgres+clickhouse+redis+minio).
UI на :3001, postgres на :5433, остальные порты на 127.0.0.1. Init seed создаёт
org simpleAI / project rag-mm / admin user из env. Корневой .env.example дополнен
LANGFUSE_HOST/PUBLIC_KEY/SECRET_KEY для будущей инструментации (simpleAI-8h8).

Закрывает simpleAI-0ya.
Минимальный async HTTP-клиент Langfuse ingestion API (internal/observability)
+ интеграция в agent.Service: trace на запрос, generation на каждый LLM-вызов,
span на каждый tool call. nil-Tracer безопасен — без env LANGFUSE_* агент
работает как раньше.

Init из env LANGFUSE_HOST/PUBLIC_KEY/SECRET_KEY в main.go, события буферизуются
в канал и шлются батчами раз в 2 сек (или 100 событий). Smoke verified —
trace со spans/generations виден в http://localhost:3001/project/rag-mm/traces.

Закрывает simpleAI-8h8.
Расширил deploy/langfuse/README.md (как смотреть трейсы, что под капотом,
как отключить, ограничения) + раздел Observability в корневом README.

Закрывает simpleAI-11s.
evals/ на верхнем уровне репо: README, пустой golden_set.jsonl, runs/.gitkeep.
ADR-003 (local) фиксирует jsonl-схему кейса, append-only процесс, baseline tracking.
.gitignore: evals/runs/* кроме .gitkeep и baseline-*.json.

Подготовка к Eval Suite epic (simpleAI-wr7) — разблокирует harness (85c) и golden_set (578).
internal/agent/parse.go — публичный API (ParseCalls, BuildToolsSystemPrompt, ParsedCall) для approach B (parse-only): один LLM-вызов на кейс, парсим первый tool call, skills не выполняем.

evals/eval.go — типы Case/Result/Run/Summary/Diff + Summarize (accuracy, per-skill, per-tag, failed_ids) + DiffRuns (regressed/improved) + WriteRun/ReadRun (jsonl с meta+summary в последней строке).

evals/cmd/routing/main.go — CLI с -input/-out/-tag/-limit/-prev/-dry-run, per-case timeout 60s, имя run-файла <timestamp>_<promptHash[:12]>.jsonl.

evals/eval_test.go — table-tests на все метрики, edge cases (empty/invalid/deprecated/round-trip).

Разблокирует simpleAI-578 (golden_set ≥20) и simpleAI-lpy (baseline run).
Покрыты 6 классов из DoD: future_purchase/advisor (7), past_tense/add_expense (4),
summary (3), forecast (2), list_transactions (3), edge cases (5). Bug q49 покрыт r001.
Парсится harness'ом, schema ADR-003.
Accuracy 0.83 (20/24) на golden_set из 24 кейсов. Прогон выполнен на
Ollama-fallback (qwen) — DEEPSEEK_API_KEY не сконфигурирован локально.
3 fail из-за low-quality LLM, 1 routing-неточность r017 → simpleAI-399.
r001 PASS — регрессия simpleAI-q49 не воспроизводится.

.gitignore: разрешить baseline-*.jsonl и BASELINE.md (выровнено с harness).
…leAI-7o2)

- deploy.yml: пробрасывает LANGFUSE_HOST/PUBLIC_KEY/SECRET_KEY из GH Secrets в .env на сервере
- langfuse.go: Warn вместо Info при missing keys + поля host_set/public_key_set/secret_key_set для диагностики
- bd: closed simpleAI-7o2

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Tarasusrus
Tarasusrus merged commit 8b19cd2 into main May 6, 2026
2 checks passed
@Tarasusrus
Tarasusrus deleted the feature/advisor-snapshot branch May 6, 2026 03:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant