Repository navigation
feat(bookkeeping): 自动记账补齐收入识别,抽取关键词 SSoT - #58
Merged
Merged
Conversation
- 排序 import 块
- 删除未使用的 `secrets` import
- `send_sms_code` 加 `# noqa: F401` 保留,因为被 test 用 patch("routers.auth.send_sms_code") mock
与当前 PR 的业务改动(收入识别)不相关,仅为解 CI。
Co-Authored-By: Claude <noreply@anthropic.com>
问题: - 用户说"发工资 8000"、"银行利息 12.5"、"退款 50" 都会被错判为支出 - 根因是 silicon.py 三个 prompt 都偏向 expense: * classify_intent 只有支出 few-shot,收入短语被当 chat * extract_bill 没有 type 判定规则 * extract_bill_from_receipt 写死 "type:通常为 expense" 改动: - packages/shared/src/constants/keywords.json 作为前后端单一事实源 * notification 层(窄):前端 parser.ts 通知正则用 * semantic 层(宽):后端 LLM prompt hint 用 - 前端 parser.ts 改用 @coco/shared 导出的常量 - 后端新增 constants/keywords.py 跨语言读取同一份 JSON - silicon.py 三个 prompt 都改用共享关键词: * classify_intent 补充收入 few-shot,强调名词短语 + 金额也是 record * extract_bill 补 type 判定规则 + 5 条 few-shot(含"银行利息""我请同事") * extract_bill_from_receipt 移除 "通常为 expense",改为允许 income - tests/test_silicon_eval.py 离线 eval 脚手架(RUN_LIVE_EVAL=1 门控) - tests/conftest.py live eval 模式下不覆盖 .env 里的真 SILICON_API_KEY 验证: - just cicd-be:47 passed + 16 eval skipped - just cicd-fe:173 tests passed - RUN_LIVE_EVAL=1 跑 eval:8 个 bill case 实调 Qwen3-8B 全通过 Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
用户输入"发工资 8000"、"银行利息 12.5"、"朋友退我 50"等收入表述时,自动记账会被错判为
expense,截图和 eval 均可复现。原因在apps/backend/services/silicon.py三个 prompt 都偏向支出:classify_intentextract_billextract_bill_from_receipt改动
1. 建立跨语言关键词 SSoT(
packages/shared/src/constants/keywords.json)分两层:
parser.ts通知正则匹配用分层而非合并的原因:如果把"工资""分红""理财收益"这种 semantic 词加进通知正则,会把"工资代发提醒"之类的银行推广文案误识别为到账。
2. 前后端消费同一份 JSON
apps/mobile/lib/auto-bookkeeping/parser.ts通过@coco/shared导入NOTIFICATION_INCOME_REGEX/NOTIFICATION_EXPENSE_REGEXapps/backend/constants/keywords.py用硬编码相对路径Path(__file__).resolve().parents[3] / "packages/shared/.../keywords.json"读取同一字节packages/shared/tsconfig.json开启resolveJsonModule3. 三个 prompt 全面重写
classify_intent:加判定规则 + 收入 few-shot(银行利息 / 发工资 / 朋友退我 / 理财收益 / 报销);强调"名词短语 + 金额不需要动词也算 record"extract_bill:用 f-string 注入共享关键词表 + 5 条 few-shot(含"刚收到报销 300 → 其他收入,不是'报销'"这种防 category 越界的示例)extract_bill_from_receipt:移除 "通常为 expense" 硬编码,改为"小票默认 expense,但出现收入关键词时判 income"两个
extract_bill*函数共用同一个_INCOME_KW/_EXPENSE_KW字面量,解决"两处关键词表不一致"的代码评审建议。4. 离线 eval 脚手架(
apps/backend/tests/test_silicon_eval.py)pytestmark = skipif(os.getenv("RUN_LIVE_EVAL") != "1")门控,默认 skip 不烧 API tokentests/conftest.py,live eval 模式下不覆盖.env里真SILICON_API_KEY(原来 conftest 的 setdefault 会屏蔽真 key)5. 单独 commit 修历史 ruff 错(7c7bc16)
routers/auth.py三个 pre-existing ruff 错(import 未排序 + 2 个 unused import)挡 CI,autofix 修复。send_sms_code加# noqa: F401因为被patch("routers.auth.send_sms_code")mock。验证
just cicd-be:47 passed + 16 eval skippedjust cicd-fe:173 passed(18 suites)RUN_LIVE_EVAL=1 uv run pytest tests/test_silicon_eval.py::test_bill -vs实调 Qwen3-8B:8/8 bill case 通过category="其他收入"✅category="理财"✅type=expense, category="餐饮"✅Test plan
Co-Authored-By: Claude noreply@anthropic.com