张胜宇
|
2a55269e20
|
feat(W34-W36): 客服双通道口径分离收口 + 会签 20/21/22 落地 + 演示启动器修复
W34 · 会签 20/21/22 三项落地(先立单、经授权、后动手)
- 会签 20(白名单外):runtime_config_service 新增 load_collection_routes() /
collection_routes() / _first_collection_name(),首次消费既有 JSON 列 collection_routes;
消费方 customer_service 走「配置优先、缺失回落代码常量」。零 DDL;该列当前全为 None
⇒ 实际走回落路径,行为与改动前一致。
- 会签 21(类 3 + 融合层):retrieval_fusion 新增 fuse_rrf() + RRF_K(排名融合,只吃名次
不吃分数 ⇒ 异质分数不可能污染判定分,best_vector_score 仍只取向量路原始 cosine);
knowledge_search_service::search() 新增 literal_parallel: bool = False(默认值使行为
逐字等同现状)。工具层透传未做 —— 那需改 KnowledgeSearchInput 契约(extra="forbid"),
超出本单范围。
- 会签 22(发布配置 + bootstrap):customer_service 新增 INTENT_MARKET_QUOTE 常量 +
TREND_WHITELIST_INTENT_CANDIDATES(按优先级回落)+ _trend_whitelist_intent()
(运行时自检 + 自动回落,强于「仅报错」)。发布配置 customer_service:market_quote
(release 260,allowed_tools=['query_fund_trend'])已写入并回读校验(9 → 10 行)。
刻意未加入 supported_intents:授权维度与判定维度解耦,不动判定分布。
- 阶段 0:customer_service_rules 新增 normalize_query() + QUERY_SYNONYMS + 等级代号大写
(纯函数;同义表只收纯书写差异,语义类同义留待金标 A/B 后逐条加;调用方默认不启用)。
W35 · 判定口径与融合口径分离(修 A-01 / C-04 / I-02 / E-04 四条)
- _dual_route_output 返回值新增 vector_order(向量路原始 doc_id 顺序、去重);
- 新增 _vector_decision_hits() 据此还原「判定序列」(带向量分的 basic 补位块回补首位;
无 vector_order / 空 / id 全对不上 ⇒ 返回 None 回落原分支);
- _answer_from_knowledge 的 score / gap 与原文直返的 best 改从向量路原始序列取。
语义边界(刻意):_evidence_pack / _exit_clarify / _answer_from_evidence 仍吃融合序列
—— 融合的收益只留在「给哪些块、什么顺序」,符合三层分数分离约束。
W36 · 选块口径归一(收口最后一条 E-01)
- 新增 _pack_order():order 命中的块排前,其余按原相对顺序追加在后;
- _evidence_pack 新增 order= 参数,三处遍历 hits → ordered,top 由 hits[0] → ordered[0];
- _answer_from_knowledge 传入 order=[judge 的 doc_id 序列];judge is None ⇒ None
(开关关闭时逐字零改动)。order 只当排序键、不当过滤器 ⇒ 证据包成员集合不变。
演示环境与文档
- start.ps1 / demo.ps1 默认端口 8000 → 8099(与 README / docs/06,07,09,14,15,32 /
tools/smoke_check.py / login_console.py 的全仓口径对齐;字节级定长替换,保住
UTF-8 BOM + CRLF,字节数不变);
- portal/README.md 更正 fin_nav_history 过期口径(「0 行」→ 实测 2494 行 / 20 个产品 /
nav_date 覆盖 2026-03-18—2026-09-13)。
测试(新增 3 个文件、补强 2 个)
- 新增 tests/unit/service/test_decision_scope_w35.py(10 条)、
tests/unit/service/test_evidence_pack_order_w36.py(13 条)、
tests/unit/service/test_customer_service_trend_chart_inv8.py(INV-8 字面级判定,
纳入 pytest 门禁,此前只在 jsdom 脚本里覆盖);
- 补强 tests/unit/core/test_customer_service_rules.py(normalize_query 7 条)与
tests/integration/test_customer_service_trend_chart_persistence.py(图内每个数字
都必须在答复正文出现过,判定口径与 INV-8 单测一致)。
验证
- 全量 pytest:2642 passed / 3 skipped / 0 failed(基线 2629 + 新增 13);
- 55 条金标真实链路 A/B 四组:off / norm / dual / on 均 55/55 = 100%
(改前 dual 92.7%、on 90.9%);M-4 事实正确率恒 100%、M-7—M-10 全 0;
- 红线四条守住:融合/精排层仍不持 Milvus 客户端(INV-1)、阈值一字未动、零 DDL;
- 三个实验开关 CS_DUAL_ROUTE / CS_RERANK / CS_QUERY_NORM 仍默认关闭。
|
2026-09-22 18:05:59 +08:00 |
|
lzf_0626
|
404f8f6aa5
|
固化接口体检脚本,并交付双击即用的启动 bat
## tools/portal_api_check.py(新)
把 2026-09-13 那轮"照着接口内容把前端测一遍"的验证固化成可重复跑的脚本。
当时靠这套验证查出 6 个真缺陷,但它们只存在于一次会话里,下次改动没人会重跑:
- `K002`/`K003` 是裸信封,前端按 `payload.data` 取 -> 知识库页显示"已入库 0 块 / 为空"
- 委托/成交详情页照着建表字段写,而接口返回视图没带那些列 -> 5 行永远显示 `--`
- 配置项/路由规则的 `PUT` 要 `If-Match`,却没有端点能返回该 digest -> 首次编辑必然 409
- 回复模板 `scene` 只校验长度不校验枚举 -> 非法值撞数据库 CHECK、冒成 500
- 路由规则表单固定 `max_attempts=2` 且 `fallbacks` 为空 -> 后端必然 422
- 模型端点手填 ID -> 未激活的 ID 直接 422
与 `e2e_smoke_test.py` 分工互补:后者测**业务链路通不通**,本脚本测**接口契约对不对**
(状态码、信封形状、字段名与前端期望是否一致)。
三档,默认只跑第一档:
- 默认只读 41 项(不动数据)
- `--write` 加测写操作:配置项 ETag 链路、`max_attempts` 越界、知识库上传+失效、
回复模板非法枚举、敏感词、推广物料全链路
- `--dangerous` 再加测会改生效配置的操作(激活配置版本会整版本替换,默认不跑,
脚本内注明了恢复办法)
实测:只读 39/39、写入档 54/54 全绿。
## 桌面一键启动(双击即用)
桌面 `启动金融Agent平台.bat` + 仓库 `启动平台.bat`,由
`tools/make_launcher_bat.py` 生成,只负责"双击"这一层,启动逻辑复用 `start.ps1`
(不重复实现,避免两边漂移)。参数可透传:`-Port 8100` / `-NoBrowser` / `-SkipPriceSync`。
不要手写这个 bat:必须同时满足 **GBK 编码 + CRLF 换行 + 无 BOM**。生成器自己
读回来校验这三条。踩过的坑:用 `write_bytes` 直接落盘时没转 CRLF,cmd 对 LF-only
批处理会行边界错乱,把 `echo` 的说明文字当命令执行(实测报
`AT 命令已弃用`、`']' 不是内部或外部命令`)。
## start.ps1 的三处修复
1. **解释器探测选错环境(真机双击失败的主因)**
原先只验证 `--version` 成功就选中,结果挑到一个 Python 3.10 环境:
本项目用了 `datetime.UTC`(3.11+)且依赖 `asyncmy`,启动当场 ImportError ——
而报错发生在**行情刷新**那一步,看起来像"行情源坏了"。
现在实测两项:**版本 >= 3.11** + `import fastapi, sqlalchemy, asyncmy, pydantic` 通过,
并在跳过时打印具体原因。
2. **`Select-Object -First 1` 掐断 native 管道**
`& $exe -c ... 2>&1 | Select-Object -First 1` 拿到首个对象后停掉上游管道,
等于把进程掐了、`$LASTEXITCODE` 变脏,于是**每个候选都被误判成"无法执行"**
(连装好的 jr_py313 也被跳过)。改为先整体接住输出、再在结果上取行。
3. **幂等 + 就绪探测 + Docker 自动拉起**
重复双击不再起第二个 API/Worker(API 按端口、Worker 按进程判断);
起完等 `/internal/health/ready` 真正应答才报成功;Milvus 不可达时尝试拉起
Docker Desktop 并最多等 60 秒(它不常驻,是"知识检索静默降级"最常见的原因)。
## 实测
- `启动平台.bat` 重复执行:解释器正确选中 jr_py313、依赖检查全 OK、行情已刷新、
两个服务识别为已在跑并跳过、就绪探测 1 秒
- `-Port 8199` 冷启动:新起 API 窗口,8199 的 `/internal/health/ready` 与 `/portal/` 均 200,
测试后已清理
- `ruff check app tests tools alembic hq.py` -> All checks passed
- `start.ps1` 语法解析通过(BOM 已保留)、bat 三项编码约束校验通过
文档同步:`AGENTS.md`(启动方式、bat 生成器、解释器探测两个坑)、
`docs/44-演示流程.md` §0.3/§0.4(双击启动、两条自检线的分工)。
|
2026-09-14 01:59:46 +08:00 |
|