Spring AI 智能体模式(第二部分):AskUserQuestionTool —— 行动前先澄清的智能体
Spring AI 智能体模式(第二部分):AskUserQuestionTool —— 行动前先澄清的智能体

传统的 AI 交互遵循一种常见模式:你提供提示词,AI 做出假设,然后生成回复。当这些假设与你的需求不匹配时,你只能反复修正。每一次假设都会造成返工——浪费时间和上下文。

如果你的 AI 智能体能在给出答案之前,主动向你提出澄清性问题,会怎样?
AskUserQuestionTool 正是为此而生。它允许 AI 智能体在回答之前提出澄清性问题,以交互方式收集需求,并从一开始就创建符合你实际需求的规格说明。
Spring AI 的实现将这种交互模式带入了 Java 生态,并确保了大语言模型的可移植性——你只需定义一次问题处理器,就能与 OpenAI、Anthropic、Google Gemini 或任何其他支持的模型一起使用。
这是我们 Spring AI 智能体模式系列的第二部分。在第一部分中,我们探讨了智能体技能——那些能扩展 AI 功能的模块化能力。现在,我们来研究 AskUserQuestionTool,它将 AI 智能体转变为可以交互式收集需求的协作伙伴。
🚀 想直接开始?跳到入门指南部分。
AskUserQuestionTool 的工作原理
AskUserQuestionTool 是 spring-ai-agent-utils 工具包的一部分,它是 Claude Code 的 AskUserQuestion 工具的一种可移植、基于 Spring AI 的实现,能让 AI 智能体在执行过程中向用户提出选择题。

该工具遵循一个”提问-回答”的工作流:
- AI 生成问题 —— 智能体确定需要输入信息,并构造问题(每个问题包含问题文本、标题、2-4 个选项以及 multiSelect 标志),然后调用 askUserQuestion 工具函数。
- 用户提供答案 —— 你自定义的处理器接收这些问题,通过你的用户界面展示它们,收集答案,并将答案返回给 AI。
- 提出更多问题 —— 如有必要,重复第 1 步和第 2 步,以收集更多用户反馈。
- AI 结合上下文继续 —— 智能体利用这些答案来提供量身定制的解决方案。
每个问题都支持:
- 单选或多选 —— 可选择一个选项,也可组合多个选项。
- 自由文本输入 —— 用户始终可以提供预定义选项之外的自由文本。
- 丰富的上下文 —— 每个选项都包含描述,解释其影响和权衡。
💡 可移植且与模型无关 —— 无供应商锁定。与那些绑定特定大语言模型平台的实现不同,这个 Spring AI 实现可以跨众多大语言模型提供商工作,让你可以在不重写代码或问题处理器的情况下切换模型。
💡 与 MCP 启发式交互的关系 —— AskUserQuestionTool 充当了一种在智能体内部实现交互式用户输入的本地化方法,在概念上类似于 MCP 启发式交互能力。MCP 启发式交互允许 MCP 服务器通过 JSON schema 请求结构化的用户输入,而 AskUserQuestionTool 则直接在你的智能体内部提供了相同的交互模式,无需依赖 MCP 服务器。对于由服务器驱动的场景,Spring AI 也通过 @McpElicitation 注解提供了完整的 MCP 启发式交互支持。
示例:旅行推荐助手
以下是该工具在旅行推荐用例(来自 ask-user-question-demo)中的实际工作方式:
USER: 下一个该去欧盟哪个国家旅行?
Interests: 旅行时你的主要兴趣是什么?
1. 历史与文化 - 博物馆、历史遗迹、建筑
2. 自然与户外 - 徒步、海滩、山脉、国家公园
3. 美食与饮品 - 烹饪体验、葡萄酒产区、美食之旅
4. 城市与都市 - 都市探索、购物、夜生活
(输入以逗号分隔的数字,或键入自定义文本)
1,2
Season: 你计划什么时间旅行?
1. 春季 - 3月至5月 - 温和气温,游客较少
2. 夏季 - 6月至8月 - 温暖天气,旅游旺季
3. 秋季 - 9月至11月 - 更凉爽的气温,秋色
4. 冬季 - 12月至2月 - 圣诞集市,冬季运动
(输入一个数字,或键入自定义文本)
3
Budget: 你这次旅行的大致预算是多少?
1. ...
...
ASSISTANT: 基于你希望在秋季旅行,对历史、文化和自然感兴趣,
并选择中等预算,同时寻求热门景点与小众体验相结合,以下是一些
可以考虑的欧盟国家:
1. **葡萄牙** - 里斯本的历史街区、杜罗河谷的葡萄酒收获季、
阿尔加维海岸线。消费适中,秋季气温宜人。
2. **希腊** - 古迹遗址、美丽海岛,秋季仍然温暖适合游泳,
且游客较少。
3. **斯洛文尼亚** - 布莱德湖、朱利安阿尔卑斯山、壮丽的秋色。
比邻近的奥地利或意大利更实惠。
智能体通过交互式问题全面收集了需求,然后才提供个性化推荐——无需任何假设,也无需反复迭代。
入门指南
1. 添加依赖:
<dependency>
<groupId>org.springaicommunity</groupId>
<artifactId>spring-ai-agent-utils</artifactId>
<version>0.3.0</version>
</dependency>
2. 配置你的智能体:
ChatClient chatClient = chatClientBuilder
.defaultTools(AskUserQuestionTool.builder()
.questionHandler(this::handleQuestions)
.build())
.build();
3. 参考下面的控制台或 Web 示例来实现你的 QuestionHandler。
当智能体需要澄清时,它会自动调用该工具,并使用答案来提供量身定制的解决方案。
💡 演示项目:ask-user-question-demo
QuestionHandler 示例
基于控制台的 QuestionHandler
一个基于控制台的实现:
private static Map<String, String> handleQuestions(List<Question> questions) {
Map<String, String> answers = new HashMap<>();
Scanner scanner = new Scanner(System.in);
for (Question q : questions) {
System.out.println("\n" + q.header() + ": " + q.question());
for (int i = 0; i < q.options().size(); i++) {
Option opt = q.options().get(i);
System.out.printf(" %d. %s - %s%n", i + 1, opt.label(), opt.description());
}
System.out.println(q.multiSelect()
? " (输入以逗号分隔的数字,或键入自定义文本)"
: " (输入一个数字,或键入自定义文本)");
String response = scanner.nextLine().trim();
// 解析数字选择或将其作为自由文本使用
try {
String[] parts = response.split(",");
List<String> labels = new ArrayList<>();
for (String part : parts) {
int index = Integer.parseInt(part.trim()) - 1;
if (index >= 0 && index < q.options().size()) {
labels.add(q.options().get(index).label());
}
}
answers.put(q.question(), labels.isEmpty() ? response : String.join(", ", labels));
} catch (NumberFormatException e) {
answers.put(q.question(), response);
}
}
return answers;
}
该处理器显示选项,接受数字选择(如 “1,2”)或自由文本(如 “中等预算”),并将答案返回给智能体。
基于 Web 的 QuestionHandler
对于 Web 应用,可使用 CompletableFuture 来桥接异步 UI 交互与同步的 QuestionHandler API。通过 WebSocket/SSE 将问题发送到你的前端,并在 future.get() 上阻塞。当用户通过 REST 端点提交答案后,再完成这个 future。
结语
AskUserQuestionTool 将 AI 智能体从基于假设的响应者转变为协作伙伴,在行动之前收集需求,从而在第一次尝试时就给出符合你需求的答案。
本系列的后续内容:
- TodoWriteTool —— 透明地跟踪多步骤工作流
- 子智能体编排 —— 分层多智能体架构
- A2A 集成 —— 使用 Agent2Agent 协议构建可互操作的智能体
- 子智能体扩展框架(即将推出) —— 协议无关的智能体编排
立即开始实验:ask-user-question-demo。
资源
- GitHub 仓库:spring-ai-agent-utils
- AskUserQuestionTool 文档:AskUserQuestionTool
- Spring AI 文档:docs.spring.io/spring-ai
- 演示项目:ask-user-question-demo - 基于控制台的交互式提问(即本文)
- Claude 智能体 SDK:用户输入文档
系列链接
- 第一部分:智能体技能 - 模块化、可复用的能力
- 第二部分:AskUserQuestion 工具(本文) - 交互式工作流
- 第三部分:TodoWriteTool - 结构化规划
- 第四部分:子智能体编排 - 分层智能体架构
- 第五部分:A2A 集成 - 使用 Agent2Agent 协议构建可互操作的智能体
- 即将推出:子智能体扩展框架(即将推出) - 协议无关的智能体编排
相关 Spring AI 博客
- 动态工具发现 —— 实现 34-64% 的 token 节省
- 工具参数增强 —— 在工具执行期间捕获大语言模型的推理过程
【注】本文译自:Spring AI Agentic Patterns (Part 2): AskUserQuestionTool - Agents That Clarify Before Acting