需求回音壁 - 意图确认官
> Agent 最贵的错误是方向性错误。一次问清,胜过十次返工。
本技能只干一件事:在动手之前,判定"我到底该不该问、该问什么、问完算不算数"。
不是让 Agent 变得爱说话,而是让它懂得什么时候闭嘴、什么时候必须开口。
何时触发
- 用户请求里有没说全的关键参数(要动谁的数据、什么时间范围、什么口径、输出给谁看)
- 请求里出现模糊动词:整理一下 / 帮我看看 / 优化一下 / 催一下 / 差不多就行
- 请求里出现主观词:好的 / 重要的 / 重点的 / 合适的 / 快一点
- 即将执行不可逆动作:发消息、改数据库、下单、付款、覆盖文件、对外发布
- 同一件事反复沟通两轮以上还没收敛
- 用户明说:「先确认一下」「别猜」「问清楚再干」「需求回音壁」「意图确认」
- 主动触发:任何非平凡任务的起手式。先跑一遍闸门,便宜(毫秒级),别省。
不触发:纯知识问答、用户已给出完整参数、用户明确说"你自己决定别问我"。
一句话原则
Agent 的问题不是"问得太少",而是"该问的没问、不该问的问了、问过的又问了"。
三层漏斗各司其职:
- 能默认的,别问 - 用常识默认值填,然后在交付物里标注"我假设了 X"
- 必须问的,一次问完 - 按"错了后果多严重"排序,不超过 3 个
- 想不清楚的,边做边确认 - 先出最小样例让用户看到,再决定要不要全量做
四步流程
Step 1 - 建槽位(Slot)
把请求拆成一组"待确认的信息位"。每个槽位必须打四个标:
| 属性 | 含义 | 取值 |
|---|---|---|
criticality |
这点错了,后果多严重 | 0-1 |
filled / value |
是否已从原话或上下文拿到 | bool |
default / default_confidence |
常识默认值 + 我有多信它 | 0-1 |
uncertainty_type |
属于哪类不确定 | epistemic / intentional / aleatoric |
answer_predictability |
用户答案有多可预测 | 0-1,越高越不必问 |
reversibility |
错了能不能撤回 | reversible / costly / irreversible |
options |
候选解释(给了就能让用户点选) | list |
关键判据:criticality >= 0.85 或 reversibility = irreversible,且无可信默认值,则该槽位无条件要问(硬闸门,见 Step 3)。
Step 2 - 量化不确定度
三类不确定性的定性区分(这是本技能与其他"澄清 prompt"的分水岭):
| 类型 | 人话 | 典型信号 | 处置 |
|---|---|---|---|
| 认知 epistemic | 我根本不知道这件事 | 缺外部事实:权限、名单、对方公司有哪些部门、这个季度有没有这笔预算 | 先 RAG / 调工具,查不到再问 |
| 意图 intentional | 我没搞懂用户想干什么 | 参数缺失、动词模糊、口径不明 | 主动问(最该问的一类) |
| 随机 aleatoric | 我控制不了环境 | 对方会不会回、物流会不会延误、市场怎么走 | 别问(问了也没用),改做风险声明 |
综合不确定度:
U_total = l1-U_epistemic + l2-U_intentional + l3-U_aleatoric (权重之和 = 1)
场景决定权重 —— 谁最贵,谁权重最大:办公助理意图权重高(0.60)、研究认知权重高(0.45)、医疗认知权重高(0.50)、运营/自动驾驶随机权重高(0.50)。详见 scripts/clarify_gate.py 的 LAMBDA_PRESETS。
> 重要实现细节:权重只对"实际存在的类"归一化。只有一类不确定时,该类权重恢复为 1,U_total 表达该类真实水平(否则纯意图歧义会被固定权重压死在阈值之下,阈值路径形同虚设——这是回测抓出的 bug,见文末)。
> 认知不确定可以靠"查"消掉,不一定要靠"问"。先查后问,是省钱的第一条。
Step 3 - 过闸门(三分档 + 一条红线)
U_total --+-- 命中硬闸门? --是--> ASK(红线,无条件问)
+-- <= low -----------------------> ECHO_EXECUTE 回音确认后直接干
+-- < high -----------------------> DEFAULT_EXECUTE 默认值干 + 标注假设 + 留修改入口
+-- >= high -----------------------> ASK 必须问(<=3 问,含等)
- 默认阈值
low=0.20, high=0.50。该区间已用 Qulac 数据集(198 个真实多解读查询)回测验证:HIGH 落在 [0.30, 0.50] 时,对"多解读分支"查询的澄清召回率 100%、误问率 0%;超过 0.50(如 0.55)开始漏掉两解读边界样本。详见references/backtest_qulac_report.md。 - 越贵的场景把
high压低(更容易触发追问),而不是把low抬高。财务立项用low=0.15 / high=0.40,医疗用low=0.10 / high=0.30,均落在已验证稳健带内。 - 硬闸门(红线)优先于阈值:哪怕 U_total 只有 0.01,只要命中"不可逆动作的关键参数缺失且无可信默认值",就必须问。这条不许绕过。
- 追问上限 = 3 轮。InfoQuest 回测验证:3 轮(容量 9)保留 4 项余量,可吸收真实对话噪声;原 2 轮(容量 6)刚好覆盖 5 项 checklist 但零安全余量。详见
references/backtest_infoquest_report.md。
Step 4 - 提问 或 留档
判定为 ASK 才真的开口。开口前先排价值序。
提问价值 V(Q) —— 期望不确定减少量(EUR)的工程化近似:
EUR 原式: V(Q) = U_current - Sum p(Ai|Q) * U_new(Ai) <- 需枚举用户所有可能答案,在线成本极高
工程近似: V(Q) ~ 严重度 x (1 - 清晰度) x (1 - 答案可预测性) x 严重度放大系数
直觉:答案越可预测,问出来能减少的不确定就越少,价值越低。所以"你是不是要上周的?"这种用户几乎必然回答"是"的问题,价值接近 0,那就别问,直接默认。
提问并发规则(references/question-strategy.md 详述,这是两份资料冲突处的调和):
| 问题形态 | 一轮问几个 | 理由 |
|---|---|---|
选择式(已给 options,用户点编号即可) |
可一次 <=3 个 | 回答成本低,一次问完省轮次 |
| 开放式(要用户重新组织语言) | 只问 1 个 | 连续追问会让用户弃用 |
| 有依赖(后一问取决于前一问答案) | 只问 1 个,必须串行 | 问了也是白问 |
> 已知差距(诚实标注):引擎当前硬编码"每轮 <=3 问"(选择式乐观),未实现上面的"开放式只问 1 个"自适应收缩。若将来实现 open 收缩,追问上限须同步上调到 5 轮以上才保留收敛能力(InfoQuest 回测:每轮 1 问时需 5 轮才 100% 覆盖 5 项)。
问句写法:有候选就给选项("1. 我负责的客户 2. 全部客户 3. 指定名单"),让用户点一下,而不是让他重说一段话。这一条直接对治"用户宁愿自己手动干"。
回音卡(本技能的交付物)
无论走哪一档,都要回音。回音卡把 Agent 的理解摊开在用户面前:
[我读到的] <- 从原话/上下文确定的,用户可以核对我有没有听错
[我猜的] <- 我用了默认值的,用户可以一键推翻
[我要做的] <- 我接下来打算干什么,用户可以喊停
[我不确定的] <- 风险敞口,用户知道哪里可能出问题
成品话术模板见 templates/echo_card.md。
为什么叫"回音壁":不是 Agent 在自言自语,而是把理解撞回给用户。用户在 Agent 动手前的一瞬间看到理解偏了,成本几乎为零;等交付物出来才发现偏了,成本是一次返工。
使用脚本
在技能目录下运行(scripts/ 与文档均用相对路径):
# 构造任务 JSON(可参考 examples/ 下的样例)
python scripts/clarify_gate.py --task examples/office_email.json
# 跑内置演示
python scripts/clarify_gate.py --demo
# 输出 JSON(供上层 agent 继续编排)
python scripts/clarify_gate.py --task examples/finance_project.json --json
# 回归测试(47 项断言)
python scripts/test_clarify_gate.py
偏好槽位默认落在 .workbuddy/memory/clarify_preferences.json(同一问题绝不问第二遍)。用 --prefs <path> 换位置。
五个反模式(每一个都有实证来源)
- 不问就给冗长泛化清单 - InfoQuest 基准观察到的头号失败模式。所有主流模型都这样。看似有帮助,实则绕开了隐藏上下文。
- 把模糊当错误,甩一句"请提供更详细的信息" - 偷懒。正确做法是分担澄清责任:给 2-3 个合理候选解释让用户选。
- 一次抛 7 个问题 - 测试用户原话:"我宁愿自己手动整理。" 必须问的 <=3,其余用默认值 + 标注。
- 同一个问题问第二遍 - 最让人恼火的一类。偏好槽位必须持久化。
- 陷入反复追问的死循环 - Agent 反复问、用户反复给同一个回答。必须设追问上限(本技能 = 3 轮)。
边界
- 本技能不替代"该查就查":认知不确定性优先用工具消解,别拿问题去烦用户。
- 本技能不替代"该问就问":硬闸门是红线,不能因为"怕打扰"就跳过。
- 随机不确定性不靠提问解决:问用户"明天会不会下雨"没有意义,改用风险声明 + 备选方案。
- 不适用于纯闲聊和纯知识问答。
- 引擎只做"判定",不做"提问":它输出该问什么、为什么问、按什么顺序问;真正向用户开口的是上层 Agent。
溯源与资料
- 原始资料要点与逐条出处:
references/evidence-and-sources.md(含四份原始资料、三篇论文、两本书的映射)。 - 两本书的框架提取与本技能映射:
references/book-frameworks.md(The Mom Test / Asking the Right Questions)。 - 槽位设计手册:
references/slot-design-playbook.md(含财务/办公/代码/研究四类模板)。 - 提问策略手册:
references/question-strategy.md。 - 第三方数据集与论文(不随包发布,附获取方式):
references/data-sources.md。 - 引擎
composite_uncertainty/question_value与公开资料的U_total/ EUR 公式逐字对上,交叉验证见evidence-and-sources.md。
回测验证(公开数据集)
本技能用两个公开数据集对阈值与收敛性分别做了真实回测,回测台在 scripts/backtest_qulac.py 与 scripts/backtest_infoquest.py,报告在 references/。回测直接暴露并修复了三个 bug:
- 加权公式把单类不确定压死:原公式用固定权重(意图=0.5),导致纯意图歧义下
U_total最高只到 0.42,永远够不到 HIGH=0.5,阈值路径形同虚设——Qulac 198 个多解读查询召回率 0%(该问全没问)。修复:权重只在实际存在的类上重新归一化,修复后召回率 100%。 - ASK 判定用了严格大于:
U_total恰等于 HIGH(两等可能解读,默认仅 50% 猜对)时落到默认执行,漏掉 10 个两解读样本(召回 94.9%)。修复:改为含等(>=),与"宁可问、别瞎猜"取向一致。 - 追问上限零余量:InfoQuest 1000 场景(每个场景 5 项必澄清 checklist)回测显示,2 轮(容量 6)虽 100% 收敛但没有任何安全余量。修复:上限提到 3 轮(容量 9,留 4 项余量)。
验证结论:默认 high=0.50 及全部场景阈值(医疗 0.30、代码 0.45、财务 0.40 等)均落在稳健带 [0.30, 0.50] 内。回归测试含三个守卫,锁死上述修复不复发。
诚实边界:
- Qulac / InfoQuest 是开放域对话与搜索查询的代理,非 Agent 任务原样;它们验证的是阈值 placement与轮次预算是否够收敛,不验证三类的权重绝对合理性。
- InfoQuest 回测用协作 oracle 用户(被问即如实作答),未跑原版的 LLM 用户模拟器与评判器;也未测"Agent 能否自行识别出正确的待澄清项"。这两项需 LLM-in-the-loop 评测,留作下一步。
- 每项回测的具体建模与局限,见对应报告的"诚实边界"段。
版权与署名
- 本技能为原创工具,由「七仔的AI工具箱」维护,可免费使用与二次分享;转载请注明出处。
- 技能内的方法论溯源(不确定性三分类、EUR 提问价值、澄清闸门等)参考了公开发表的论文与公开技术文章,仅提炼思想与方法框架,未包含任何原文摘录;具体出处见
references/evidence-and-sources.md。 - 第三方论文 PDF 与数据集不随本包分发,获取方式见
references/data-sources.md。
作者与联系方式
本 skill 由「七仔的AI工具箱」维护。欢迎就技能使用、问题反馈与二次分享交流:
- 微信公众号:七仔的AI工具箱
- 抖音号:七仔的AI工具箱
- CSDN 博客:七仔的AI工具箱
本 skill 可免费使用与二次分享;转载请注明出处「七仔的AI工具箱」。