企业级测试日志 · TEST-2026-09-12-AN-002
问数模板原句命中 · UNION 规范化 · 分析助手 /analyze · 常用问法 UI
1. 文档元数据
| 字段 |
值 |
| 测试记录编号 |
TEST-2026-09-12-AN-002 |
| 缺陷/变更标题 |
答辩实测:模板 match_all 误绑涨跌幅口径;LLM UNION 缺括号 1064;改为 match_phrases + 问数页引导 |
| 文档版本 |
v1.2 |
| 创建日期 |
2026-09-12 |
| 关联分支 |
merger |
| 关联拍板 / TODO |
spec 2026-09-12-analyst-template-exact-phrases-design.md · 2026-09-12-analyst-query-visualization-design.md |
| 风险等级 |
LOW(模板层;未收录原句仍走 NL2SQL) |
| 缺陷类型 |
产品口径(模板)+ SQL 语法(UNION)→ 已修复 |
| 发现阶段 |
分析员问数答辩 walkthrough · analytics_query_log 留痕 |
| 修复阶段 |
单元测试 + 种子重灌 + 问数页 UI |
2. 环境与基线
| 字段 |
值 |
| 测试环境 |
development · 本机 Windows |
| 修复后测试基线 |
python -m pytest → 861+ passed, 1 skipped(含本日志 §7 增补) |
| 前端 |
cd web && npm run test → 27 passed(含 analystChartSpec.test.ts) |
| 种子 |
scripts/agent/seed-analyst-query-templates.sql(match_phrases + prompt_label + featured) |
3. 测试范围
| 区域 |
用例/文件 |
结论 |
| 原句模板匹配 |
tests/test_wave6_template_service.py(exact / 不 fuzzy / list_prompts) |
PASS |
| UNION 规范化 |
tests/test_wave6_sql_guard.py · normalize_union_all_sql |
PASS |
| 分析助手 |
tests/test_wave6_analyst_agent.py · tests/test_wave6_analyst_chart.py(含 chart_type 非字符串) |
PASS |
| 路由挂载 |
tests/test_main.py(/analyze · /template-prompts) |
PASS |
| 问数页 UI |
手工:推荐 Tag · 标星 · 最近成功 · 点击整句发问 |
待答辩复验 |
4. 答辩实测问题(已闭环)
| 现象 |
根因 |
修复 |
| 「净值最高/最低」返回涨跌幅极值 |
模板 match_all 命中 + SQL 按 daily_chg_pct |
净值/涨跌幅 分列收录原句;有 match_phrases 不再 match_all |
SQL 1064 near UNION ALL |
LLM 子查询未加括号 |
normalize_union_all_sql 于执行前 |
| 用户自由改字仍误命中 |
关键词泛化 |
仅 normalize 后与原句一致 命中 |
收录问句(种子 SEED · 答辩推荐点选):
- 净值:
目前净值最高和最低的两个产品
- 涨跌幅:
最新净值日涨跌幅最高和最低各一只产品
5. 变更文件索引
| 中文职责 |
路径 |
| 原句匹配与 prompt 列表 |
app/service/template_service.py |
| UNION 执行前规范化 |
app/service/sql_guard.py |
分析图表与 /analyze |
app/service/analyst_agent.py · app/service/analyst_chart.py |
| 模板问句 API |
GET /api/analyst/template-prompts · app/api/analyst.py |
| 常用问法 UI |
web/src/pages/analytics/AnalystQueryPage.tsx · web/src/utils/analystQueryHistory.ts |
6. 增补 · chart_type 类型安全(2026-09-12)
| 字段 |
值 |
| 缺陷 |
validate_chart_spec 对 data["chart_type"] 直接 .strip();LLM JSON 若返回 int/bool/list 会 AttributeError,/analyze 整段失败 |
| 根因 |
analyst_chart.py 未做字符串化 |
| 修复 |
str(data.get("chart_type") or "none").strip().lower() |
| 状态 |
已修复(v1.1) |
| 回归 |
tests/test_wave6_analyst_chart.py · test_validate_chart_type_non_string_coerced(整数 → 友好错误;" LINE " → line) |
| 风险 |
LOW(仅 malformed LLM 输出路径) |
6.1 同路径加固(v1.2 · 预防性)
| 项 |
问题 |
修复 |
y_fields |
LLM 有时返回字符串 "nav" 而非数组 → 校验报「不能为空」 |
_coerce_y_fields:字符串转单元素列表 |
x_field / series_field |
非字符串列名 |
_field_name:str() + strip |
classify_analysis_kind |
answer 非字符串时 .strip() 崩溃 |
str(answer or "").strip() |
/analyze degrade 分支 |
chart_type 非字符串时与 "none" 比较不准 |
与校验同口径 str(...).strip().lower() |
| 回归 | test_validate_y_fields_single_string · test_classify_analysis_kind_non_string_answer |
7. 修改记录
| 修改人 |
日期 |
说明 |
| Cursor Agent |
2026-09-12 |
初版 · 858 pytest · 27 Vitest |
| Cursor Agent |
2026-09-12 |
v1.2 · analyze JSON 字段 coercion(y_fields/x_field/classify)· +2 单测 |