Files
group_xinghuo_jinrong/docs/memory/tests/2026-09-13-advisor-e2e
zhanghongyu_0626 188bf6a438 feat(analyst_agent): Add support for recent days queries and enhance SQL hint generation
- Introduced `_recent_days_series_hint` to handle queries related to "最近N天" for time series data aggregation.
- Added `_cn_num_to_int` function to convert Chinese numerals to integers for better query parsing.
- Updated `_nl_sql_hints` to incorporate the new hint generation logic, ensuring accurate SQL output for recent days queries.
- Enhanced documentation to reflect these changes and improve clarity on the new functionalities.
2026-09-13 22:36:19 +08:00
..

TEST-AD-001 · 理财师线(顾问 Agent)端到端包

当前结论(2026-09-13):

  • Part A 缺口补测(真实 HTTP):31 PASS / 4 FAIL / 0 SKIP / 10 INFO,退出码 1。 4 条 FAIL 全部来自 AD8 接缝取证组,是预期内的取证结果,不计入通过率分母(见下「AD8 单列」)。
  • Part B 浏览器(09-advisor-pages.mjs 收复后复跑):17 PASS / 0 FAIL / 0 SKIP,退出码 0。
  • Part C 回归基线(advisor_e2e_smoke.py 原样未改):63 PASS / 0 FAIL / 0 SKIP,退出码 0。

读数纪律(沿用 TEST-CT-001 / TEST-AN-003): ① INFO 不是 PASS,不得计入通过率分母;② AD8 的 4 条 FAIL 是「取证」不是「退化」,单列不入分母;③ 本线既有基线脚本一个字都没改 —— 回归对照的前提就是它不变。

⚠️ 与既有覆盖的关系(如实声明,勿夸大本包的新增性): 本线此前并非零覆盖。advisor_e2e_smoke.py 已覆盖 /api/advisor-agent/* 的写操作主链路(63 条),docs/memory/tests/2026-09-12-advisor-agent-e2e 已覆盖 KYC 与会话。 本包新增的是三块此前无脚本级覆盖的面:① 接缝取证(build_advisor_tools 的 5 个工具调真实 service,AD8);② 无前端调用方的端点(AD9 四条,实测接口可用但全仓无引用);③ 代客下单链路(AD10,对应前端浅覆盖点 AdvisorCustomersPage 的代客入口从未被点)。


产物

产物 路径 位置
企业级测试日志 TEST-LOG-2026-09-13-AD-001.md 本包
缺口补测脚本(AD7–AD10) scripts/dev/advisor_gap_e2e_smoke.py 仓库内(本轮新建)
回归基线脚本(原样未改) scripts/dev/advisor_e2e_smoke.py 仓库内(既有)
浏览器脚本(本轮收复进仓库) scripts/e2e/09-advisor-pages.mjs 仓库内(原在仓库外 C:/Users/Windows/e2e-jinrong/)

结果明细 _raw/(逐用例原始记录,未加工)

文件 内容 结果
ad-gap.md AD7–AD10 逐条矩阵(期望 / 实测 / 证据) 31 PASS / 4 FAIL / 10 INFO
results-09-advisor.json 09-advisor-pages.mjs 的原生 JSON 结果(Part B) 17 PASS / 0 FAIL
09-advisor-pages.stdout.txt 同轮终端原始输出 退出码 0
_partc-advisor.md Part C 回归基线报告(advisor_e2e_smoke.py) 63 PASS / 0 FAIL
_partc-advisor.stdout.txt 同轮终端原始输出 退出码 0
shots/ Part B 四张页面截图(09-advisor-*.png) —

复跑一致性: AD8 的 4 条 FAIL 在本轮多次复跑中稳定复现,且对照组 8-01/8-02 稳定 PASS —— 这两点共同排除了"探针本身写错"这一解释(见下)。


AD8 —— 接缝取证组(4 FAIL 是预期结果,不计入分母)

这是一组「把读代码的推断变成运行取证」的用例,不是回归。 判据是能否稳定复现,不是 PASS。

build_advisor_graph 构造的 5 个工具里,有 3 个(占 4 条用例)接到了不存在的 service 方法:

用例 工具 工具内写的是 真实 API 实测异常
8-03 manage_kyc_session(action="chat") kyc_service.chat(...) kyc_session_service.py:140 chat_session AttributeError: 'KycSessionService' object has no attribute 'chat'
8-04 manage_kyc_session(action="get") kyc_service.get_session(session_id=) kyc_session_service.py:133 get_session(session_id, *, auth) —— 缺 keyword-only auth TypeError: missing 1 required keyword-only argument: 'auth'
8-05 search_templates template_service.search(...) TemplateService 只有 reload/try_render/list_published_prompts,无 search AttributeError: no attribute 'search'
8-06 compliance_check compliance_service.check(text=, scene=) compliance_check_service.py:38 check_text(payload, *, trace_id, advisor_id)(连调用形态都不同) AttributeError: no attribute 'check'

两个对照组(8-01 持仓 / 8-02 净值)稳定 PASS —— 同一条探针路径、同一个 invoke 方法、同样的真实 service 注入,只有接错的那三个失败。这正是排除"探针写错"的关键证据。

为什么一直没被发现(8-07,本组最值得记的一条)

build_advisor_graph 在本仓是孤儿代码:全仓唯一调用方是 tests/test_step11_agent_graph.py:113,而它在 :114-117 给四个 service 全注入 Mock()。

Mock() 对任意属性访问都返回可调用对象,于是 kyc_service.chat(...)、template_service.search(...)、compliance_service.check(...) 在测试里全部"成功"。实测 8-07:同一调用在 Mock 下返回 ok → <Mock name='mock.chat()' id=...>。

这正是盘点里「19 个 test_sprint*.py 伪造全部 Core 数据源 → 结构上不可能发现接缝不匹配」的具体实例:不是测试没覆盖,而是测试用的替身把错误吃掉了。

严重度定位(不高报)

整支 agent_graph.py 是孤儿代码(无生产调用方)⇒ 定为潜在缺陷,不列 P0/P1。但它同时也是"测试给出假绿"的实证,故必须记账。


缺陷与发现(报告侧;本轮不修)

ADV 缺陷-3 —— 三处工具绑定错误(P3,孤儿代码)

见上表。根因已逐条定位到真实 service 的方法名与签名(含行号)。修复方向(供修复轮参考,本轮不动):把工具内调用改为 chat_session / get_session(session_id, auth=...) / script_template_service 的真搜索 / check_text(payload, trace_id=..., advisor_id=...),并让 test_step11_agent_graph.py 改用真实 service 或严格的 spec= Mock,否则改完仍会被遮蔽。

ADV 缺陷-4 —— 四条端点可用但无消费方(P3,观察)

端点 前端调用方(实测)
GET /api/advisor-agent/dashboard/ping 无
GET /api/advisor-agent/allocation/ping 无
POST /api/advisor-agent/guard/check 有
POST /api/advisor-agent/copy/track 有

两个 ping 端点实测 module/status 回显正确({'module': 'dashboard', 'status': 'ready'}),属可用但无消费方。不构成故障,记录以备清理或接入。


已验证转绿的正面证据(本包价值最高的部分)

项 取证方式 结果
KYC 会话链路端到端可用 AD7:建会话 → 读视图 → chat → complete,全链 HTTP 200 ✅
v1.0 的 500 已修复且可复现验证 7-02(GET /sessions/{id},v1.0 时 500)→ HTTP 200;7-04(POST /sessions/{id}/chat,v1.0 时 500)→ HTTP 200 ✅ 双点回归
agent_message.created_at 无 NULL(v1.0 500 的根因面) 7-05 直连库:实际 2 行,NULL 的 seq_no=[] ✅
状态机严格 7-09 completed 后再 chat → 409/40901;7-10 completed 后再 complete → 409/40901 ✅ 非法迁移被拒
越权与不存在的会话都不静默放行 7-06 非归属顾问读同一会话 → 403/40302;7-07 不存在 session → 404/40401 ✅
代客下单的归属校验 10-03 非名下客户 CUST-1004 → 403 AUTH_403_NOT_ASSIGNED;10-05 不存在的 CUST-000000 → 403(非静默放行);10-02a 名下客户回显 customer_id='CUST-1001' 一致 ✅
通道冒用被矩阵层拦下 10-06 用 customer 型 token 冒用 advisor 通道 → 403 AUTH_403_AGENT_MISMATCH ✅
缺头即拒 10-04 缺 X-Agent-Type → 401 AUTH_401_MISSING_AGENT_TYPE ✅
提示词注入被拦 9-04 → HTTP 400 / 40002 ✅
安全文本放行的枚举契约 9-03a action='passed'(拦截值为 'blocked');9-03b 放行时 guard_type=None ✅

一处期望订正(我方,非产品): 9-03a 首跑我把期望写成 action='pass' 而 FAIL。查源码后确认真实枚举是 'passed'(input_guard_service.py:22),拦截是 'blocked'(input_guard.py:111)。是我的期望错,不是产品错 —— 已订正并补 9-03b 区分"放行"与"未命中规则"两件事。


复现三连

# 0) 前置:uvicorn 8000 + MySQL 在跑
curl -s http://127.0.0.1:8000/api/ready      # 期望 ok=true

# 1) AD7–AD10 缺口补测(退出码 0 无 FAIL / 1 有 FAIL / 2 前置失败)
#    注意:AD8 是取证组,预期 4 条 FAIL ⇒ 退出码 1 属预期
python scripts/dev/advisor_gap_e2e_smoke.py --report D:/tmp/e2e-gap/ad-gap.md

# 2) 只跑 AD8 接缝取证(最快复现那 4 条)
python scripts/dev/advisor_gap_e2e_smoke.py --only AD8

# 3) 回归基线(必须保持退出码 0)
python scripts/dev/advisor_e2e_smoke.py --report D:/tmp/e2e-gap/_partc-advisor.md

# 4) 浏览器(须 Vite 5173;串行执行,勿与其他包并发)
cd scripts/e2e && node 09-advisor-pages.mjs

数据副作用: 本线 Part A 建了 KYC 会话、发了 copy/track 留痕,均落在 jinrong_agent 的追加型表(按语义不回滚)。Part C 回归基线 advisor_e2e_smoke.py 会写 Core 交易表 —— 该表已在 Phase 6 按 snapshot.sql 还原并逐表 CHECKSUM 校验通过(见横切包 XC-001 §6)。

剩余风险 / 未覆盖

# 项 说明
1 AD8 修法未经实施验证 本轮只取证。修复后需同时改测试替身(改真实 service 或 spec= Mock),否则仍被遮蔽
2 7-03 用例号缺位 AD7 现有 7-01→7-02→7-04,无 7-03(历史编号沿革,非丢失用例)
3 7-05 的判定面偏窄 只验 created_at 非 NULL(2 行),未覆盖 agent_message 的其它列约束
4 代客下单未走写入侧 AD10 只验到"受理与归属",未实际提交一笔代客交易(那属客户线写表,与 CT-001 的还原口径耦合)
5 无前端调用方的两条 ping 端点 记录在案,未判定该删该接