之前研究过 claude code 的设计,用 Java 写了一个乞丐版的 claude code 开源地址 jooj。Claude code 的 tools 都设计的非常精巧。所以想逐个研究一下。大家共同学习。
AskUserQuestion
是最常见到的 tools 之一。
作用
AskUserQuestion 是 Claude Code 内置的结构化提问工具。它不是让 Claude 输出一段问题字符串等用户回复,而是把问题渲染成一个交互式选择面板 ------ 用户看到的是一组预设选项(卡片形式),而不是一段纯文字提问。
它解决的核心问题是「AI 与用户之间的高效对齐」:
- 降低用户负担 ------ 从「打字回答」变成「点选项」,响应时间大幅缩短
- 结构化输入 ------ Claude 拿到的是明确的枚举值,不用再解析自然语言
- 收敛歧义 ------ 通过预设选项引导用户在明确的方案之间选择,避免「随便你决定」式的模糊回答
- 保底逃生舱 ------ 系统始终自动附加「其它」选项,允许用户输入自定义文本,避免「选项不合口味只能退出」
一个具体例子
在展开触发条件、技术实现、prompt 细节之前,先看一个具体场景,感受一下「不用 AskUserQuestion 会怎样 vs 用了会怎样」。
场景 :用户对 Claude 说 「帮我给这个应用加个用户登录」。
这个需求描述得很不完整 ------ 用哪种认证方式没定、登录凭证存哪里没定。Claude 既不能瞎猜(用户可能有团队规范),也没法直接从代码里读出来(新功能没先例)。
反例:如果没有 AskUserQuestion
Claude 只能用一段自由文本把问题甩回去,大概长这样:
「你想用什么认证方式?我建议 JWT,但也可以用会话 cookie 或 OAuth。另外登录凭证存哪里,httpOnly cookie 还是 localStorage?」
用户会遇到几个问题:
- 认知负担高 ------ 一段长文字里塞了 2 个决策 + 5 个选项,需要用户先解析题目再回答
- 回答成本高 ------ 要么打一段字回复(「JWT + httpOnly」),要么去网上搜「JWT vs 会话 cookie」看两小时再回来
- Claude 解析成本高 ------ 拿到「就 JWT 吧,cookie 那个」这种回复,还得反推用户到底选了哪个,可能理解错
- 推荐值淹没在文字里 ------ Claude 说「建议 JWT」,但和其它选项混在一起,用户容易忽略
- 没有兜底 ------ 如果用户想用一个 Claude 没提到的方案(比如免密邮件链接),要么另起一段解释,要么被 Claude 的三选一绑架
核心痛点:这种纯文本形式,让「协作对齐」变成了一次昂贵的自然语言往返。
用 AskUserQuestion 是怎么解决的
Claude 会构造一个包含 两个问题 的调用:
第一个问题 ------
之前研究过 claude code 的设计,用 Java 写了一个乞丐版的 claude code 开源地址 jooj。Claude code 的 tools 都设计的非常精巧。所以想逐个研究一下。大家共同学习。
AskUserQuestion
是最常见到的 tools 之一。
作用
AskUserQuestion 是 Claude Code 内置的结构化提问工具。它不是让 Claude 输出一段问题字符串等用户回复,而是把问题渲染成一个交互式选择面板 ------ 用户看到的是一组预设选项(卡片形式),而不是一段纯文字提问。
它解决的核心问题是「AI 与用户之间的高效对齐」:
- 降低用户负担 ------ 从「打字回答」变成「点选项」,响应时间大幅缩短
- 结构化输入 ------ Claude 拿到的是明确的枚举值,不用再解析自然语言
- 收敛歧义 ------ 通过预设选项引导用户在明确的方案之间选择,避免「随便你决定」式的模糊回答
- 保底逃生舱 ------ 系统始终自动附加「其它」选项,允许用户输入自定义文本,避免「选项不合口味只能退出」
一个具体例子
在展开触发条件、技术实现、prompt 细节之前,先看一个具体场景,感受一下「不用 AskUserQuestion 会怎样 vs 用了会怎样」。
场景 :用户对 Claude 说 「帮我给这个应用加个用户登录」。
这个需求描述得很不完整 ------ 用哪种认证方式没定、登录凭证存哪里没定。Claude 既不能瞎猜(用户可能有团队规范),也没法直接从代码里读出来(新功能没先例)。
反例:如果没有 AskUserQuestion
Claude 只能用一段自由文本把问题甩回去,大概长这样:
「你想用什么认证方式?我建议 JWT,但也可以用会话 cookie 或 OAuth。另外登录凭证存哪里,httpOnly cookie 还是 localStorage?」
用户会遇到几个问题:
- 认知负担高 ------ 一段长文字里塞了 2 个决策 + 5 个选项,需要用户先解析题目再回答
- 回答成本高 ------ 要么打一段字回复(「JWT + httpOnly」),要么去网上搜「JWT vs 会话 cookie」看两小时再回来
- Claude 解析成本高 ------ 拿到「就 JWT 吧,cookie 那个」这种回复,还得反推用户到底选了哪个,可能理解错
- 推荐值淹没在文字里 ------ Claude 说「建议 JWT」,但和其它选项混在一起,用户容易忽略
- 没有兜底 ------ 如果用户想用一个 Claude 没提到的方案(比如免密邮件链接),要么另起一段解释,要么被 Claude 的三选一绑架
核心痛点:这种纯文本形式,让「协作对齐」变成了一次昂贵的自然语言往返。
用 AskUserQuestion 是怎么解决的
Claude 会构造一个包含 两个问题 的调用:
第一个问题 ------

需要配置第三方服务
第二个问题 ------

用户在界面上看到的是两张卡片,每张卡片顶部是那个短标签(「认证方式」/「凭证存储」),下面是 3 个 / 2 个选项 + 一个自动追加的「其它」。用户点两下选完,Claude 拿到的返回值大致是:
- 第一个问题 → 用户选了 JWT(推荐)
- 第二个问题 → 用户选了 httpOnly cookie(推荐)
决策时间从几分钟压到几秒。这就是 AskUserQuestion 存在的意义 ------ 不是「让 AI 问问题」,而是「让协作的每一次澄清都变得低成本」。
对照一下两种形式解决了反例里的哪些痛点
| 反例痛点 | AskUserQuestion 的解法 |
|---|---|
| 认知负担高 | 拆成 2 张独立卡片,一次聚焦一个决策 |
| 回答成本高 | 点选项而不是打字,权衡说明直接标在选项下 |
| Claude 解析成本高 | 返回值是明确的选项文本,不用做自然语言解析 |
| 推荐值淹没在文字里 | 「(推荐)」后缀 + 前置位置,第一眼看到 |
| 没有兜底 | 「其它」自动追加,用户想输入自定义方案永远有出口 |
这个对照本质上就是 AskUserQuestion 每个设计点的存在理由 ------ 每一条都对应一个自由文本对话解决不了的痛点。带着这个直觉,再往下看触发条件、技术实现和 prompt 细节,会发现每一条约束都对应到这里的某个具体痛点。
触发条件
工具的官方说明里明确写了触发边界:只有在你被卡住,而这个决策又真正属于用户时才使用。
三类该问的场景:
- 无法从请求推断 ------ 需求本身模糊(比如「帮我加个登录」,没说 OAuth 还是 JWT)
- 无法从代码推断 ------ 现有代码里没有先例可以模仿
- 没有合理默认值 ------ 涉及品味 / 业务规则 / 架构分叉,不该由 AI 拍板
三类不该问的场景:
- 答案能从代码里读出来 ------ 该花时间读代码,而不是打断用户
- 只有一种明显合理的做法 ------ 直接做,提交信息里说明理由即可
- 在计划模式里问「方案 OK 吗」 ------ 这是 ExitPlanMode 的职责,用 Ask 是重复
一个典型反模式:避免「这个方案 OK 吗 / 我可以继续吗」这类元问题。ExitPlanMode 本身就是「请求批准」,Ask 用来做这个纯属重复。
技术实现
从工具的入参定义反推,它的核心结构可以用文字描述如下:
Claude 调用这个工具时,传入一个 问题列表 (1 到 4 个问题)。列表里每一项是一个 问题对象,包含四个部分:
- 问题文本 ------ 完整的问题文本,以问号结尾
- 卡片短标签 ------ 显示在卡片顶部的短标签,最多 12 个字符
- 是否多选 ------ 布尔值,控制是否允许多选(默认单选)
- 选项列表 ------ 2 到 4 个选项
每个选项本身又包含三个字段:
- 选项文本 ------ 用户看到的选项显示文本(1 到 5 个字)
- 选项说明 ------ 这个选项含义 / 权衡的说明
- 视觉预览 ------ 可选:当选项差异需要「可视化对比」时(比如两个示意图、两段代码),聚焦这个选项时界面会渲染这段内容
几个关键设计点:
- 一次可以问 1-4 个问题 ------ 支持批量决策(比如「选认证方式 + 选凭证存储」一次问完),但不允许无脑打包 10 个问题轰炸用户
- 每个问题 2-4 个选项 ------ 强制 Claude 做初步归类,把 N 种可能收敛到少数几个可点选项,而不是甩一张长清单给用户
- 「其它」是隐式选项 ------ 用户端自动追加,Claude 不用手动列。这保证了「Claude 想到的选项 ≠ 全部」时用户不会被卡死
- 推荐值机制 ------ 如果 Claude 有倾向,把它放第一个选项 + 文本后追加「(推荐)」,用户可以一眼看到并快速采纳
- 返回值结构 ------ 用问题文本作为 key,映射到用户选择的选项文本;另有一个字段承载用户在视觉预览场景下额外写的注释
视觉预览字段 是一个有意思的进阶点 ------ 当选项之间的差异需要「可视化对比」(比如两个界面示意图、两种代码风格),把内容塞在这个字段里,界面会在聚焦某个选项时渲染出来。这对「选哪种 API 设计 / 选哪种排版」这种问题特别有用。
与 EnterPlanMode / ExitPlanMode 的分工:
- 计划模式里,用 AskUserQuestion 澄清「选哪种方案」(在方案定稿之前)
- 计划模式里,不要用 AskUserQuestion 问「我的方案 OK 吗」(用 ExitPlanMode)
- 非计划模式里,用 AskUserQuestion 处理任何需要用户拍板的技术分叉
三个工具串起来是一条完整的决策流水线:Ask 澄清 → EnterPlanMode 展开 → ExitPlanMode 拍板。
prompt 详解
工具官方说明里每一句都在给 Claude 塞一条行为约束,逐条拆一下:
约束 1:严格的适用边界(开篇第一句)
Use this tool only when you are blocked on a decision that is genuinely the user's to make: one you cannot resolve from the request, the code, or sensible defaults.
这句话在训练 Claude「不要主动打扰」------ 遇到不确定,第一反应应该是先查代码、先用合理默认值,而不是甩问题给用户。
约束 2:「其它」逃生舱的透明化
Users will always be able to select "Other" to provide custom text input
系统不是把这个选项藏起来让 Claude 假装不知道 ------ 而是明确告诉 Claude「其它会自动加,你不用列」。这样 Claude 不会浪费一个选项去手写「自定义」。
约束 3:多选参数的语义
Use multiSelect: true to allow multiple answers to be selected for a question
对应场景:选多个功能开关 / 多个环境 / 多个要修的文件。默认单选保护用户不被过多选择卡住。
约束 4:推荐值的表达形式
If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label
有意思的点:推荐值不是单独字段,而是通过「约定俗成的位置 + 后缀」实现的。好处:
- 保持入参定义简单,不引入一个「是否推荐」的布尔字段
- 界面侧只用渲染选项文本,不用做特殊处理
- Claude 要表态必须写进选项文本,无法藏在元数据里 ------ 用户一眼能看见
约束 5:与计划模式的时序关系
Plan mode note: To switch into plan mode, use EnterPlanMode (not this tool). Once in plan mode, use this tool to clarify requirements or choose between approaches BEFORE finalizing your plan. Do NOT use this tool to ask "Is my plan ready?", "Should I proceed?", or otherwise reference "the plan" in questions --- the user cannot see the plan until you call ExitPlanMode for approval.
这段是最有教学价值的 ------ 明确了整套流程的时序:
- 计划模式里,先用 Ask 澄清方案分叉(如「选 A 还是 B」)
- 澄清完后,用 EnterPlanMode 落一份完整方案
- 最后一步 用 ExitPlanMode 请求批准 ------ 不要再用 Ask 问「OK 吗」
尤其注意原文最后半句 ------ 「用户在你调用 ExitPlanMode 之前根本看不到方案」------ 这才是「不要在计划模式里问『方案 OK 吗』」的真正原因 :不是重复,而是用户根本没东西可批。
三个工具各司其职:Ask 澄清 / EnterPlanMode 展开 / ExitPlanMode 拍板。这套约束本质上是在阻止 Claude 在计划模式里绕回来用 Ask 做「批准」这件事。
约束 6:卡片短标签是必填字段(结构层强制)
Very short label displayed as a chip/tag (max 12 chars). Examples: "Auth method", "Library", "Approach".
这是一个交互约束 ------ 界面里每个问题渲染成一张卡片,卡片顶端的标签用这个短字符串,而不是完整的问题文本。这就要求 Claude 把长问题浓缩成一个短标签(比如「登录流程应该用哪种认证方式?」的短标签就是「认证方式」)。
约束 7:问题必须以问号结尾
Should be clear, specific, and end with a question mark.
看似很小的一条,但决定了界面的自然度 ------ 问句语气 vs 陈述语气对用户的心理暗示完全不同。这也间接强制 Claude 把内容组织成「真正的疑问」而不是「疑似指令」。
小结:AskUserQuestion 的精妙之处,不在于它「让 AI 问用户问题」这个功能本身,而在于它通过入参结构约束 + prompt 约束,把**「什么时候问 / 怎么问 / 用什么形式呈现 / 和谁配合」** 全都规范住了。相当于把「AI 提问」这个泛用能力,收敛成一个可预测、可组合、可维护的交互原语。
需要配置第三方服务
第二个问题 ------
用户在界面上看到的是两张卡片,每张卡片顶部是那个短标签(「认证方式」/「凭证存储」),下面是 3 个 / 2 个选项 + 一个自动追加的「其它」。用户点两下选完,Claude 拿到的返回值大致是:
- 第一个问题 → 用户选了 JWT(推荐)
- 第二个问题 → 用户选了 httpOnly cookie(推荐)
决策时间从几分钟压到几秒。这就是 AskUserQuestion 存在的意义 ------ 不是「让 AI 问问题」,而是「让协作的每一次澄清都变得低成本」。
对照一下两种形式解决了反例里的哪些痛点
| 反例痛点 | AskUserQuestion 的解法 |
|---|---|
| 认知负担高 | 拆成 2 张独立卡片,一次聚焦一个决策 |
| 回答成本高 | 点选项而不是打字,权衡说明直接标在选项下 |
| Claude 解析成本高 | 返回值是明确的选项文本,不用做自然语言解析 |
| 推荐值淹没在文字里 | 「(推荐)」后缀 + 前置位置,第一眼看到 |
| 没有兜底 | 「其它」自动追加,用户想输入自定义方案永远有出口 |
这个对照本质上就是 AskUserQuestion 每个设计点的存在理由 ------ 每一条都对应一个自由文本对话解决不了的痛点。带着这个直觉,再往下看触发条件、技术实现和 prompt 细节,会发现每一条约束都对应到这里的某个具体痛点。
触发条件
工具的官方说明里明确写了触发边界:只有在你被卡住,而这个决策又真正属于用户时才使用。
三类该问的场景:
- 无法从请求推断 ------ 需求本身模糊(比如「帮我加个登录」,没说 OAuth 还是 JWT)
- 无法从代码推断 ------ 现有代码里没有先例可以模仿
- 没有合理默认值 ------ 涉及品味 / 业务规则 / 架构分叉,不该由 AI 拍板
三类不该问的场景:
- 答案能从代码里读出来 ------ 该花时间读代码,而不是打断用户
- 只有一种明显合理的做法 ------ 直接做,提交信息里说明理由即可
- 在计划模式里问「方案 OK 吗」 ------ 这是 ExitPlanMode 的职责,用 Ask 是重复
一个典型反模式:避免「这个方案 OK 吗 / 我可以继续吗」这类元问题。ExitPlanMode 本身就是「请求批准」,Ask 用来做这个纯属重复。
技术实现
从工具的入参定义反推,它的核心结构可以用文字描述如下:
Claude 调用这个工具时,传入一个 问题列表 (1 到 4 个问题)。列表里每一项是一个 问题对象,包含四个部分:
- 问题文本 ------ 完整的问题文本,以问号结尾
- 卡片短标签 ------ 显示在卡片顶部的短标签,最多 12 个字符
- 是否多选 ------ 布尔值,控制是否允许多选(默认单选)
- 选项列表 ------ 2 到 4 个选项
每个选项本身又包含三个字段:
- 选项文本 ------ 用户看到的选项显示文本(1 到 5 个字)
- 选项说明 ------ 这个选项含义 / 权衡的说明
- 视觉预览 ------ 可选:当选项差异需要「可视化对比」时(比如两个示意图、两段代码),聚焦这个选项时界面会渲染这段内容
几个关键设计点:
- 一次可以问 1-4 个问题 ------ 支持批量决策(比如「选认证方式 + 选凭证存储」一次问完),但不允许无脑打包 10 个问题轰炸用户
- 每个问题 2-4 个选项 ------ 强制 Claude 做初步归类,把 N 种可能收敛到少数几个可点选项,而不是甩一张长清单给用户
- 「其它」是隐式选项 ------ 用户端自动追加,Claude 不用手动列。这保证了「Claude 想到的选项 ≠ 全部」时用户不会被卡死
- 推荐值机制 ------ 如果 Claude 有倾向,把它放第一个选项 + 文本后追加「(推荐)」,用户可以一眼看到并快速采纳
- 返回值结构 ------ 用问题文本作为 key,映射到用户选择的选项文本;另有一个字段承载用户在视觉预览场景下额外写的注释
视觉预览字段 是一个有意思的进阶点 ------ 当选项之间的差异需要「可视化对比」(比如两个界面示意图、两种代码风格),把内容塞在这个字段里,界面会在聚焦某个选项时渲染出来。这对「选哪种 API 设计 / 选哪种排版」这种问题特别有用。
与 EnterPlanMode / ExitPlanMode 的分工:
- 计划模式里,用 AskUserQuestion 澄清「选哪种方案」(在方案定稿之前)
- 计划模式里,不要用 AskUserQuestion 问「我的方案 OK 吗」(用 ExitPlanMode)
- 非计划模式里,用 AskUserQuestion 处理任何需要用户拍板的技术分叉
三个工具串起来是一条完整的决策流水线:Ask 澄清 → EnterPlanMode 展开 → ExitPlanMode 拍板。
prompt 详解
工具官方说明里每一句都在给 Claude 塞一条行为约束,逐条拆一下:
约束 1:严格的适用边界(开篇第一句)
Use this tool only when you are blocked on a decision that is genuinely the user's to make: one you cannot resolve from the request, the code, or sensible defaults.
这句话在训练 Claude「不要主动打扰」------ 遇到不确定,第一反应应该是先查代码、先用合理默认值,而不是甩问题给用户。
约束 2:「其它」逃生舱的透明化
Users will always be able to select "Other" to provide custom text input
系统不是把这个选项藏起来让 Claude 假装不知道 ------ 而是明确告诉 Claude「其它会自动加,你不用列」。这样 Claude 不会浪费一个选项去手写「自定义」。
约束 3:多选参数的语义
Use multiSelect: true to allow multiple answers to be selected for a question
对应场景:选多个功能开关 / 多个环境 / 多个要修的文件。默认单选保护用户不被过多选择卡住。
约束 4:推荐值的表达形式
If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label
有意思的点:推荐值不是单独字段,而是通过「约定俗成的位置 + 后缀」实现的。好处:
- 保持入参定义简单,不引入一个「是否推荐」的布尔字段
- 界面侧只用渲染选项文本,不用做特殊处理
- Claude 要表态必须写进选项文本,无法藏在元数据里 ------ 用户一眼能看见
约束 5:与计划模式的时序关系
Plan mode note: To switch into plan mode, use EnterPlanMode (not this tool). Once in plan mode, use this tool to clarify requirements or choose between approaches BEFORE finalizing your plan. Do NOT use this tool to ask "Is my plan ready?", "Should I proceed?", or otherwise reference "the plan" in questions --- the user cannot see the plan until you call ExitPlanMode for approval.
这段是最有教学价值的 ------ 明确了整套流程的时序:
- 计划模式里,先用 Ask 澄清方案分叉(如「选 A 还是 B」)
- 澄清完后,用 EnterPlanMode 落一份完整方案
- 最后一步 用 ExitPlanMode 请求批准 ------ 不要再用 Ask 问「OK 吗」
尤其注意原文最后半句 ------ 「用户在你调用 ExitPlanMode 之前根本看不到方案」------ 这才是「不要在计划模式里问『方案 OK 吗』」的真正原因 :不是重复,而是用户根本没东西可批。
三个工具各司其职:Ask 澄清 / EnterPlanMode 展开 / ExitPlanMode 拍板。这套约束本质上是在阻止 Claude 在计划模式里绕回来用 Ask 做「批准」这件事。
约束 6:卡片短标签是必填字段(结构层强制)
Very short label displayed as a chip/tag (max 12 chars). Examples: "Auth method", "Library", "Approach".
这是一个交互约束 ------ 界面里每个问题渲染成一张卡片,卡片顶端的标签用这个短字符串,而不是完整的问题文本。这就要求 Claude 把长问题浓缩成一个短标签(比如「登录流程应该用哪种认证方式?」的短标签就是「认证方式」)。
约束 7:问题必须以问号结尾
Should be clear, specific, and end with a question mark.
看似很小的一条,但决定了界面的自然度 ------ 问句语气 vs 陈述语气对用户的心理暗示完全不同。这也间接强制 Claude 把内容组织成「真正的疑问」而不是「疑似指令」。
小结:AskUserQuestion 的精妙之处,不在于它「让 AI 问用户问题」这个功能本身,而在于它通过入参结构约束 + prompt 约束,把**「什么时候问 / 怎么问 / 用什么形式呈现 / 和谁配合」** 全都规范住了。相当于把「AI 提问」这个泛用能力,收敛成一个可预测、可组合、可维护的交互原语。