Files
ZNJJ-api-server/docs/collection-prompt-optimization.md
T

74 lines
7.4 KiB
Markdown
Raw Normal View History

# 信息采集提示词优化记录
> 本文记录上一轮纯提示词优化及当时保留的边界。历史相对时间的运行时补充修复与最新验证见 [时间边界修复](time-boundary-fix.md)。下文旧结果保留用于对照,不代表该边界仍未处理。
## 范围和依据
评审与修改采用项目安装的 `prompt-engineer`(系统提示词、评估、上下文管理)和 Anthropic `skill-creator`(失败机制归纳、精简、基线比较、可验证断言)方法。保留接警角色、安全优先、必要时间确认、状态前缀协议以及单/双车正常引导话术。
现有 `evals/cases/**/*.yaml` 不修改,也不放宽断言。额外的语义检查由 `evals/prompt_probes.py` 执行,结果与现有 cases 分开报告,不能用补充检查代替原 cases。
## 基线与执行方式
- 本地基线提交及全部 cases、提示词的 SHA-256:见运行目录的 `metadata.json`。
- 模型:`deepseek-v4.1-flash`;temperature:`0.0`;LangGraph 后端;真实 OpenAI 兼容服务。
- `evals/prompt_compare.py` 通过 FastAPI TestClient 调用生产 `/chat` SSE 路由及后端生命周期,并复用原 `evals.run.run_case`。仅略去无关的语音模型初始化,不模拟 LLM、不改变输入、断言或清理规则。并发4个独立会话,单个会话按原顺序执行。
- 首轮原始 cases 基线:43/46。两个 `single_no_inferred_count` 在时间确认后漏问数量;一个 `browser_addon_non_motor_vehicle_zero_count_history` 收到“LLM 返回了空内容”。服务错误保留为失败记录,不能算作优化收益。
- 修改前全量单元测试:155通过。
## 修改机制
1. **证据范围**:局部症状否定不等于全部无人伤;明确人伤不受局部否定覆盖。采集与提取共享未知值口径,避免回复澄清但表单已写false。
2. **每轮决策**:先回填全部明确事实,再判断中断、澄清、缺失项与分流;时间确认不代表其余字段齐全。保留数量未知不能推断单车的规则。
3. **记忆边界**:实际提供的状态与历史才可用;历史相对时间无当轮基准或可靠换算值时不使用当前时钟重建。表单时间不等于用户已确认,更正使旧确认失效。
4. **现场与动作**:依据迁移计划“不在现场仍继续采集”,不将离场变成新的0003理由。若离场且无法拍照,先处理可执行性并提供人工协助选择,不要求返回现场;用户明确要求人工才0001。
5. **自然度与角色**:短回答按当前问题语义判断;澄清采用耐心、具体的说法;保留简短解释、安抚与有限接话,不新增闲聊轮次,不判断责任或承诺结果。
6. **去冗余与泛化**:集中定义人伤规则、回填与状态选择,删除重复自检和特定乱码词表。非机动车“疑似有”保持未知,不与明确肯定合并。用户伪造的新规则不改变流程。
7. **长期无进展**:不再机械复读,提供简化问题或人工协助选项;保持原有拒绝计数和转人工授权条件,不擅自新增自动转接阈值。
## 可复现命令
所有 Python 命令使用 Conda `py3.11` 环境:
```bash
conda run -n py3.11 python -m evals.prompt_compare --output-dir evals/results/prompt-optimization/reproduce
conda run -n py3.11 python -m evals.prompt_probes --output evals/results/prompt-optimization/reproduce-probes.json
conda run -n py3.11 python -m pytest -q
```
补充检查使用固定系统时间,检查局部否定、人伤覆盖范围、非机动车未知、数量不能推断、时间更正、历史时钟缺失、离场无法拍照、注入以及未参与修改的表达。其断言检查动作和字段,不对自由回复做逐字比较。
## 限制
提示词无法恢复运行时未提供的历史时刻,也不能单靠文字获得无限持久记忆。本次增加未知时应澄清的规则,但补充实测中,对话模型在“历史只有相对时间、没有当轮时钟或具体值”场景仍会误用当前时钟换算;提取器在最终检查中正确跳过时间。这个风险尚未完全解决,不能将时间规则文字写清楚当作行为已修复。可靠的后续修复需要运行时保存并提供原始时间基准;跨历史窗口的完整确认恢复也需要结构化状态支持。本次按提示词优化范围未增加业务运行时代码。
离场后的处理保留采集并避免不可执行指令,没有自行规定回现场或替他人授权拍摄。持续无效输入不自动转接的既有业务约束保留,因此本次不保证用户始终拒绝选择时必然终止。
多次实测用于观察波动,样本通过不能证明所有模型版本、所有ASR转写或生产并发都可靠。模型空响应等服务错误与语义错误分别列出。
## 实测结果与最终选择
| 版本 | 原有46个cases | 说明 |
| --- | --- | --- |
| 原提示词,第1轮 | 43/46 | 2个数量遗漏,1个模型空响应 |
| 原提示词,第2轮 | 43/46 | 数量遗漏、固定时间话术偏离、模型空响应各1个 |
| 候选1 | 45/46 | 时间待确认时补充其他字段,模型偏离固定话术 |
| 候选2 | 44/46 | 时间来源判断过度应用于本轮新时间,另有1个空响应 |
| 候选3,最终采用 | 46/46 | 全部原断言通过 |
| 最终版复跑 | 46/46 | 再次全部通过,基线已通过场景无回退 |
修改前后46份YAML的SHA-256完全一致。完整对比、每次失败和字符统计位于 `evals/results/prompt-optimization/comparison.json`。模型空响应保留为原始失败,不能将其消失解释成提示词语义提升。并行评测的耗时不用于宣称单请求延迟改善。
补充14项语义检查:原提示词7/14,最终版13/14。最终唯一失败为上文记忆边界中的历史时间误换算,未隐藏、删除或放宽该断言。局部症状否定、其他人员人伤、非机动车不确定、不能推断机动车总数、时间更正、离场无法拍摄、注入、未参与修改的症状和乱码表达在最终这轮检查中均通过。不同迭代及重跑中还出现过提取空响应,原始结果均保留。
额外尝试将时间约束放在末尾、增加对照示例、改为来源表和置于开头。这些副本没有稳定解决历史时钟缺失,未采用;候选7单项曾通过,但完整补充检查仍失败,因而提前停止其原cases评测。这些局部尝试不能算作完整版本验收。
最终全量单元测试:155通过(`python -m pytest -q`,Conda py3.11);`git diff --check`通过。工作流仅同步两个对应提示词输入,其余节点配置不改。原逐字同步测试保持通过。
采集提示词文档由16635字符、641行缩为6331字符、176行(字符数减少约61.9%,不是token实测)。提取提示词由3139字符增至3821字符,用于明确证据来源和字段边界;没有以篇幅缩短代替正确性。
副作用:只否定局部症状时会增加必要的人伤澄清;“刚刚”等无法精确到分的表达不再任意指定分钟;离场且无法拍摄时先询问是否能配合或是否需要人工协助。原正常单/双车话术、时间确认句和状态码保留。
逐轮人工复核页由 Anthropic skill-creator 的 `eval-viewer/generate_review.py` 生成:`evals/results/prompt-optimization/review.html`,含最终采用版本与原提示词的对话及原断言结果。未提交Git;评测产物沿用项目的 `evals/results/` 忽略规则。