Spring AI中的多轮对话艺术:让大模型主动提问获取明确需求
本文介绍了Spring AI中实现多轮对话交互的艺术,通过AskUserQuestionTool工具让大模型能够主动提问获取用户明确需求。文章分析了单次交互存在的问题,如模糊输入处理和状态管理不足,并提出了基于Function Callback的主动问询设计方案。核心实现通过结构化问题和自定义交互处理分离责任,使AI能决定何时提问而开发者控制具体交互方式。文章还提供了项目创建指南,包括环境要求(S

Spring AI中的多轮对话艺术:让大模型主动提问获取明确需求
在日常我们与大模型交互的过程中,通常是我输入一个问题或者场景要求,然后大模型基于我给出的信息进行生成内容。这种方式很容易出现一个答非所问的场景(好像大模型并不能总是回答到我的心趴上🤣)
那么有什么好的解决办法吗?
熟练调教大模型的小伙伴,可能早就有自己的一套标准流程了 – 通过多次与大模型之间的多次问询回答,让大模型能更清晰的知道自己的诉求
那么如何让AI主动问询用户来获取更精确的信息呢?如果我开发的大模型应用,希望集成这样的能力,又可以怎么实现呢?
接下来我们看看,SpringAI中,如何通过巧妙的多轮对话艺术,来实现让大模型主动提问获取明确需求
一、方案设计
1.1 核心问题
在我们这个场景中,核心的问题点在于 如何让大模型在面对模糊需求时,能够主动发起询问,获取更详细的信息,从而提供更精准的响应。
常见的实现中,存在的问题如下:
- 单次交互试图解决复杂问题
- 对模糊输入不做处理直接响应
- 缺少多轮对话的状态管理
这些问题的根本原因在于没有建立起AI与用户之间的有效反馈循环,导致大模型无法获取足够的上下文信息,但是对于大模型而言,响应内容是对它的一个非常重要的考量指标,所以就很容出现大模型话说八道 答非所问等幻觉那问题
1.2 主动问询设计
好的设计应该主动适应用户,而不是让用户适应设计。
很多人认为大模型只能被动接收输入,实际上 Spring AI 提供了 AskUserQuestionTool 这个强大的工具,让AI能够主动向用户提出问题。
它是通过什么实现的呢?可以看下面这张图

- 通过Function Callback来实现,将
AskUserQuestionTool注册为大模型可回调使用的工具,通过这个工具来实现多轮问询应答
下面是这个工具的核心定义:
public class AskUserQuestionTool {
@Tool(
name = "AskUserQuestionTool",
description = "Use this tool when you need to ask the user questions during execution. This allows you to:\n1. Gather user preferences or requirements\n2. Clarify ambiguous instructions\n3. Get decisions on implementation choices as you work\n4. Offer choices to the user about what direction to take.\n\nUsage notes:\n- Users will always be able to select \"Other\" to provide custom text input\n- Use multiSelect: true to allow multiple answers to be selected for a question\n- If you recommend a specific option, make that the first option in the list and add \"(Recommended)\" at the end of the label\n"
)
public String askUserQuestion(@ToolParam(description = "Questions to ask the user (1-4 questions)") List<Question> questions, @ToolParam(description = "User answers collected by the permission component",required = false) Map<String, String> answers) {
this.validateQuestions(questions);
// 省略...
}
}
重点看一下这个工具的描述,将其翻译成中文,内容如下
在执行过程中需要向用户提问时,请使用此工具。这使您能够:
1. 收集用户偏好或需求
2. 明确含糊不清的指令
3. 在工作中就实施选择做出决策
4. 向用户提供选择,让他们决定要采取的方向。
使用须知:
- 用户始终可以选择“其他”来提供自定义文本输入
- 使用multiSelect: true,允许一个问题有多个答案选项
- 如果你推荐了一个特定选项,请将其作为列表中的第一个选项,并在标签末尾加上“(推荐)”
在这个工具类中,通过巧妙的设计,告诉大模型在具体响应之前,可以先进行用户问询
- 大模型将需要问询的内容,转换为结构化的
List<Question> - 通过设计一个
QuestionHandler来处理具体的用户问答交互流程,通过责任分离的设计思想,AI负责决定何时提问,具体的UI交互由开发者自定义。你可以将其适配到Web界面、移动端或任何其他平台。
因此具体的问询应答方式,完全是由应用方(即开发者)来控制的
接下来我们进入实战演练,看看如何实现这样的一个多轮问询
二、项目创建
2.1 基础环境要求
要体验SpringAI的问询机制,目前需要升级到SpringAI 2.x版本,同时我们的SpringBoot也可以升级到4.x
- SpringAI: 2.0.0-M2
- SpringBoot: 4.0.1
- JDK21/17:这两版本都可以
除了这几个基本依赖之外,我们可以选择一个支持Function Tool的大模型来作为这个实现的大脑中枢
我们这里选择智谱的大模型GLM-4.5-Flash (原因就是因为它免费,且效果还行,对所有想体验的小伙伴没有任何额外成本投入)
2.2 项目创建
接下来我们创建一个SpringAI应用,对于一个标准的SpringAI应用,在pom.xml配置中,你会看到下面这些基础版本指定,这个也没什么好说的
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.1</version>
<relativePath />
</parent>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-ai.version>2.0.0-M2</spring-ai.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<name>Central Portal Snapshots</name>
<id>central-portal-snapshots</id>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
接下来重点看一下我们这个项目所用到的几个核心依赖
<dependencies>
<dependency>
<groupId>org.springaicommunity</groupId>
<artifactId>spring-ai-agent-utils</artifactId>
<version>0.4.1</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-zhipuai</artifactId>
</dependency>
</dependencies>
- spring-ai-agent-utils: 这个就是SpringAI进行agent开发的关键依赖包
- spring-ai-starter-model-zhipuai: 这个是智谱大模型进行交互的依赖包
2.3 项目配置
依赖搞定之后,接下来就是在配置文件中,配置LLM访问的相关信息、以及agent相关配置参数,对应的配置文件 resources/application.yml
spring:
ai:
zhipuai:
# api-key 使用你自己申请的进行替换;如果为了安全考虑,可以通过启动参数进行设置
api-key: ${zhipuai-api-key}
chat: # 聊天模型
options:
model: GLM-4.7-Flash
三、核心实现
接下来我们进行快速体验,首先为了更好的观察应用与大模型之间的交互,我们实现一个LoggingAdvisor
3.1 交互日志打印: MyLoggingAdvisor
说明:这个实现非必需,不感兴趣的直接跳过
public class MyLoggingAdvisor implements BaseAdvisor {
private final int order;
public final boolean showSystemMessage;
public final boolean showAvailableTools;
private AtomicInteger cnt = new AtomicInteger(1);
private MyLoggingAdvisor(int order, boolean showSystemMessage, boolean showAvailableTools) {
this.order = order;
this.showSystemMessage = showSystemMessage;
this.showAvailableTools = showAvailableTools;
}
@Override
public int getOrder() {
return this.order;
}
@Override
public ChatClientRequest before(ChatClientRequest chatClientRequest, AdvisorChain advisorChain) {
System.out.println("======================= 第 " + cnt.getAndAdd(1) + " 轮 ====================================");
StringBuilder sb = new StringBuilder("\nUSER: ");
if (this.showSystemMessage && chatClientRequest.prompt().getSystemMessage() != null) {
sb.append("\n - SYSTEM: ").append(first(chatClientRequest.prompt().getSystemMessage().getText(), 300));
}
if (this.showAvailableTools) {
Object tools = "No Tools";
if (chatClientRequest.prompt().getOptions() instanceof ToolCallingChatOptions toolOptions) {
tools = toolOptions.getToolCallbacks().stream().map(tc -> tc.getToolDefinition().name()).toList();
}
sb.append("\n - TOOLS: ").append(ModelOptionsUtils.toJsonString(tools));
}
Message lastMessage = chatClientRequest.prompt().getLastUserOrToolResponseMessage();
if (lastMessage.getMessageType() == MessageType.TOOL) {
ToolResponseMessage toolResponseMessage = (ToolResponseMessage) lastMessage;
for (var toolResponse : toolResponseMessage.getResponses()) {
var tr = toolResponse.name() + ": " + first(toolResponse.responseData(), 1000);
sb.append("\n - TOOL-RESPONSE: ").append(tr);
}
} else if (lastMessage.getMessageType() == MessageType.USER) {
if (StringUtils.hasText(lastMessage.getText())) {
sb.append("\n - TEXT: ").append(first(lastMessage.getText(), 1000));
}
}
System.out.println("before: " + sb);
return chatClientRequest;
}
@Override
public ChatClientResponse after(ChatClientResponse chatClientResponse, AdvisorChain advisorChain) {
StringBuilder sb = new StringBuilder("\nASSISTANT: ");
if (chatClientResponse.chatResponse() == null || chatClientResponse.chatResponse().getResults() == null) {
sb.append(" No chat response ");
System.out.println("after: " + sb);
return chatClientResponse;
}
for (var generation : chatClientResponse.chatResponse().getResults()) {
var message = generation.getOutput();
if (message.getToolCalls() != null) {
for (var toolCall : message.getToolCalls()) {
sb.append("\n - TOOL-CALL: ")
.append(toolCall.name())
.append(" (")
.append(toolCall.arguments())
.append(")");
}
}
if (message.getText() != null) {
if (StringUtils.hasText(message.getText())) {
sb.append("\n - TEXT: ").append(first(message.getText(), 1200));
}
}
}
System.out.println("after: " + sb);
return chatClientResponse;
}
private String first(String text, int n) {
if (text.length() <= n) {
return text;
}
return text.substring(0, n) + "...";
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private int order = 0;
private boolean showSystemMessage = true;
private boolean showAvailableTools = true;
public Builder order(int order) {
this.order = order;
return this;
}
public Builder showSystemMessage(boolean showSystemMessage) {
this.showSystemMessage = showSystemMessage;
return this;
}
public Builder showAvailableTools(boolean showAvailableTools) {
this.showAvailableTools = showAvailableTools;
return this;
}
public MyLoggingAdvisor build() {
MyLoggingAdvisor advisor = new MyLoggingAdvisor(this.order, this.showSystemMessage,
this.showAvailableTools);
return advisor;
}
}
}
3.2 命令行的问询应答实现:CommandLineQuestionHandler
在前面的设计篇中介绍了AskUserQuestionTool中,设计了一个扩展点 QuestionHandler 由使用者来实现具体的问答交互方案,因此我们先实现一个基础的基于命令行的问答
CommandLineQuestionHandler:实现QuestionHandler接口,处理用户问题列表handle方法:遍历问题,显示选项供用户选择,支持单选/多选模式parseResponse方法:解析用户输入,将数字编号转换为对应选项标签,或直接返回自定义文本答案
/**
* 命令行问题处理器,实现 AskUserQuestionTool.QuestionHandler 接口
* 用于处理AI工具向用户提出的问题,支持单选、多选和自定义文本输入
*/
public class CommandLineQuestionHandler implements AskUserQuestionTool.QuestionHandler {
/**
* 处理传入的问题列表,逐个显示问题和选项,收集用户输入的答案
*
* @param questions 需要处理的问题列表
* @return 包含问题和对应答案的映射表
*/
@Override
public Map<String, String> handle(List<AskUserQuestionTool.Question> questions) {
Map<String, String> answers = new HashMap<>();
Scanner scanner = new Scanner(System.in);
for (AskUserQuestionTool.Question q : questions) {
// 显示问题标题和内容
System.out.println("\n" + q.header() + ": " + q.question());
// 获取并显示选项
List<AskUserQuestionTool.Question.Option> options = q.options();
for (int i = 0; i < options.size(); i++) {
AskUserQuestionTool.Question.Option opt = options.get(i);
System.out.printf(" %d. %s - %s%n", i + 1, opt.label(), opt.description());
}
// 根据是否为多选显示提示信息
if (q.multiSelect()) {
System.out.println(" (Enter numbers separated by commas, or type custom text)");
} else {
System.out.println(" (Enter a number, or type custom text)");
}
// 读取用户输入并解析答案
String response = scanner.nextLine().trim();
answers.put(q.question(), parseResponse(response, options));
}
return answers;
}
/**
* 解析用户输入的响应,根据选项索引或自定义文本返回对应的值
*
* @param response 用户输入的原始字符串
* @param options 可用的选项列表
* @return 解析后的答案字符串
*/
private static String parseResponse(String response, List<AskUserQuestionTool.Question.Option> options) {
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 < options.size()) {
labels.add(options.get(index).label());
}
}
// 如果没有找到有效的选项编号,则返回原始输入;否则返回选项标签的组合
return labels.isEmpty() ? response : String.join(", ", labels);
} catch (NumberFormatException e) {
// 如果输入不是数字,则将其视为自由文本
return response;
}
}
}
3.3 问询对话实现
创建一个简易聊天客户端,配置了三个Advisor:工具调用顾问、消息记忆顾问和自定义日志顾问(隐藏可用工具和系统消息)。
然后启动一个命令行循环,用户输入问题后通过聊天客户端处理并输出AI助手的回答
@Bean
CommandLineRunner commandLineRunner(ChatClient.Builder chatClientBuilder) throws IOException {
return args -> {
// 构建ChatClient实例,配置所需的工具和顾问
ChatClient chatClient = chatClientBuilder
// 设置默认工具,这里使用AskUserQuestionTool,它允许AI向用户提问
.defaultTools(AskUserQuestionTool.builder()
// 使用命令行问题处理器来处理AI向用户提出的问题
.questionHandler(new CommandLineQuestionHandler())
.build())
// 配置默认的顾问(拦截器),按顺序执行
.defaultAdvisors(
// 工具调用顾问:处理工具调用逻辑
ToolCallAdvisor.builder().conversationHistoryEnabled(false).build(),
// 消息记忆顾问:维护对话历史,使用消息窗口聊天记忆
// 位于工具调用顾问之后,以确保能够记住工具调用结果
MessageChatMemoryAdvisor.builder(
MessageWindowChatMemory.builder()
.maxMessages(500) // 最多保存500条消息
.build())
.build(),
// 自定义日志顾问:记录对话过程,可控制是否显示可用工具和系统消息
MyLoggingAdvisor.builder()
.showAvailableTools(true) // 显示可用工具列表
.showSystemMessage(true) // 显示系统消息
.build())
.build();
// 启动聊天循环的提示信息
System.out.println("\nI am your assistant.\n");
// 使用try-with-resources确保Scanner资源得到正确释放
try (Scanner scanner = new Scanner(System.in)) {
// 无限循环,持续接收用户输入并返回AI回复
while (true) {
System.out.print("\n$->USER: "); // 提示用户输入
// 获取用户输入,通过chatClient发送请求,指定对话ID,并输出AI回复
System.out.println("\n$->ASSISTANT: " +
chatClient.prompt(scanner.nextLine()) // 发送用户输入到AI
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, "113331")) // 设置对话ID以维护上下文
.call().content()); // 执行调用并获取AI回复内容
}
}
};
}
3.4 测试验证
直接启动项目,然后再控制台中输入我的原始诉求

下面是完整的文字版本输出内容
I am your assistant.
$->USER: 我准备设计一张锦鲤主题的微信红包封面
======================= 第 1 轮 ====================================
before:
USER:
- SYSTEM:
- TOOLS: ["AskUserQuestionTool"]
- TEXT: 我准备设计一张锦鲤主题的微信红包封面
after:
ASSISTANT:
- TOOL-CALL: AskUserQuestionTool ({"questions":[{"header": "设计风格", "multiSelect": false, "options": [{"description": "简约线条和现代色彩,适合日常使用", "label": "简约现代风"}, {"description": "传统水墨画风格,展现国潮韵味", "label": "国潮水墨风"}, {"description": "可爱的卡通形象,活泼有趣", "label": "可爱卡通风"}, {"description": "金色为主,配以传统纹样,显得高级", "label": "金色奢华风"}], "question": "你希望红包封面的设计风格是什么样的?"}, {"header": "使用场景", "multiSelect": true, "options": [{"description": "新年、春节等传统节日", "label": "传统节日"}, {"description": "婚礼、生日、庆典等喜庆场合", "label": "喜庆场合"}, {"description": "日常送礼、朋友间互动", "label": "日常互动"}, {"description": "商务场合、客户关系维护", "label": "商务场合"}], "question": "这个红包封面主要会在什么场合使用?"}, {"header": "颜色偏好", "multiSelect": false, "options": [{"description": "红色为主,配金色或白色", "label": "红金配色"}, {"description": "蓝色为主,配金色或白色", "label": "蓝金配色"}, {"description": "纯色背景,简洁大方", "label": "单色背景"}, {"description": "根据锦鲤自然色彩搭配", "label": "自然色彩"}], "question": "你更倾向于什么颜色搭配?"}, {"header": "文字内容", "multiSelect": false, "options": [{"description": "只放锦鲤图案,简洁大方", "label": "纯图案"}, {"description": "锦鲤图案+简单祝福语", "label": "图案+祝福语"}, {"description": "锦鲤图案+品牌或公司信息", "label": "图案+文字"}], "question": "红包封面是否需要添加文字内容?"}]})
- TEXT: 我来帮你设计锦鲤主题的微信红包封面!为了给你提供更符合需求的设计方案,我需要了解一些具体信息。
设计风格: 你希望红包封面的设计风格是什么样的?
1. 简约现代风 - 简约线条和现代色彩,适合日常使用
2. 国潮水墨风 - 传统水墨画风格,展现国潮韵味
3. 可爱卡通风 - 可爱的卡通形象,活泼有趣
4. 金色奢华风 - 金色为主,配以传统纹样,显得高级
(Enter a number, or type custom text)
1
使用场景: 这个红包封面主要会在什么场合使用?
1. 传统节日 - 新年、春节等传统节日
2. 喜庆场合 - 婚礼、生日、庆典等喜庆场合
3. 日常互动 - 日常送礼、朋友间互动
4. 商务场合 - 商务场合、客户关系维护
(Enter numbers separated by commas, or type custom text)
1
颜色偏好: 你更倾向于什么颜色搭配?
1. 红金配色 - 红色为主,配金色或白色
2. 蓝金配色 - 蓝色为主,配金色或白色
3. 单色背景 - 纯色背景,简洁大方
4. 自然色彩 - 根据锦鲤自然色彩搭配
(Enter a number, or type custom text)
1
文字内容: 红包封面是否需要添加文字内容?
1. 纯图案 - 只放锦鲤图案,简洁大方
2. 图案+祝福语 - 锦鲤图案+简单祝福语
3. 图案+文字 - 锦鲤图案+品牌或公司信息
(Enter a number, or type custom text)
2
======================= 第 2 轮 ====================================
before:
USER:
- SYSTEM:
- TOOLS: ["AskUserQuestionTool"]
- TOOL-RESPONSE: AskUserQuestionTool: "User has answered your questions: {\"这个红包封面主要会在什么场合使用?\":\"传统节日\",\"你希望红包封面的设计风格是什么样的?\":\"简约现代风\",\"你更倾向于什么颜色搭配?\":\"红金配色\",\"红包封面是否需要添加文字内容?\":\"图案+祝福语\"}"
after:
ASSISTANT:
- TEXT: 根据您的需求,我为您设计了一个**简约现代风、红金配色的锦鲤主题微信红包封面**,非常适合传统节日使用。
## 🎨 设计方案详情
### 📐 尺寸规格
- **主尺寸**: 1080×1920像素(符合微信红包封面标准)
- **安全区域**: 上下左右各留出100px,确保重要内容不被遮挡
### 🎯 设计元素
1. **背景**:
- 使用渐变红色背景(从深红到浅红),营造节日氛围
- 添加微妙的金色网格纹理,增加现代感
2. **锦鲤图案**:
- 选用简约线条风格的锦鲤剪影
- 锦鲤呈向上游动姿态,寓意"鱼跃龙门"
- 金色线条勾勒,与红色背景形成对比
3. **文字内容**:
- **主标题**: "福满锦鲤"(金色立体效果)
- **祝福语**: "年年有余,福运绵长"
- **装饰元素**: 水波纹、祥云等传统元素点缀
4. **品牌信息**(可选):
- 底部小字:"[您的品牌/姓名]祝您新年快乐"
### 🌈 色彩方案
- **主色**: #D32F2F(深红)→ #FFEB3B(金色渐变)
- **辅助色**: #FFF8E1(浅米色,用于文字背景)
### ✨ 设计亮点
- 简约现代的线条风格,避免过于繁复
- 红金配色经典大气,符合传统节日氛围
- 锦鲤向上游动的姿态,寓意积极向上
- 节奏感的布局,视觉平衡协调
### 📝 使用建议
- 适合春节、元宵节、中秋等传统节日发送
- 可用于亲友祝福、商务拜年、客户答谢等场合
- 红金配色既有传统韵味,又不失现代感
这个设计方案既保持了传统节日的喜庆氛围,又符合现代审美,相信会是一个很受欢迎的红包封面!您觉得这个设计方案如何?如果需要调整任何细节,请告诉我。
$->ASSISTANT: 根据您的需求,我为您设计了一个**简约现代风、红金配色的锦鲤主题微信红包封面**,非常适合传统节日使用。
## 🎨 设计方案详情
### 📐 尺寸规格
- **主尺寸**: 1080×1920像素(符合微信红包封面标准)
- **安全区域**: 上下左右各留出100px,确保重要内容不被遮挡
### 🎯 设计元素
1. **背景**:
- 使用渐变红色背景(从深红到浅红),营造节日氛围
- 添加微妙的金色网格纹理,增加现代感
2. **锦鲤图案**:
- 选用简约线条风格的锦鲤剪影
- 锦鲤呈向上游动姿态,寓意"鱼跃龙门"
- 金色线条勾勒,与红色背景形成对比
3. **文字内容**:
- **主标题**: "福满锦鲤"(金色立体效果)
- **祝福语**: "年年有余,福运绵长"
- **装饰元素**: 水波纹、祥云等传统元素点缀
4. **品牌信息**(可选):
- 底部小字:"[您的品牌/姓名]祝您新年快乐"
### 🌈 色彩方案
- **主色**: #D32F2F(深红)→ #FFEB3B(金色渐变)
- **辅助色**: #FFF8E1(浅米色,用于文字背景)
### ✨ 设计亮点
- 简约现代的线条风格,避免过于繁复
- 红金配色经典大气,符合传统节日氛围
- 锦鲤向上游动的姿态,寓意积极向上
- 节奏感的布局,视觉平衡协调
### 📝 使用建议
- 适合春节、元宵节、中秋等传统节日发送
- 可用于亲友祝福、商务拜年、客户答谢等场合
- 红金配色既有传统韵味,又不失现代感
这个设计方案既保持了传统节日的喜庆氛围,又符合现代审美,相信会是一个很受欢迎的红包封面!您觉得这个设计方案如何?如果需要调整任何细节,请告诉我。
我们可以将这个方案,拿来生成图片,比如下面是豆包、千问、元宝等不同平台的生成效果
| 模型 | 效果图 |
|---|---|
| 豆包 | ![]() |
| 元宝 | ![]() |
| 千问 | ![]() |
| 百度 | ![]() |
| ChatGPT | ![]() |
四、小结
本片内容通过设计+实例给大家演示了一下Spring AI中的多轮对话艺术,如何让大模型主动提问获取明确需求? 下面几部即可:
- 主动询问机制:使用AskUserQuestionTool让AI在信息不足时主动提问
- 灵活的响应处理:通过自定义QuestionHandler适配不同平台的交互方式
- 对话状态管理:利用MessageChatMemoryAdvisor维护多轮对话的上下文
- 工具组合使用:将询问工具与记忆顾问、日志顾问等配合使用,构建完整的交互体系
- 异步处理支持:在Web环境中使用SSE实现流畅的多轮对话体验
项目源码:rag-qa-bot
对于大模型应用开发感兴趣的小伙伴,或者对上面提到的知识点有疑惑的小伙伴,不妨看看以下几篇内容(每篇耗时不超过五分钟😊)
零基础入门:
- LLM 应用开发是什么:零基础也可以读懂的科普文(极简版)
- 大模型应用开发系列教程:序-为什么你“会用 LLM”,但做不出复杂应用?
- 大模型应用开发系列教程:第一章LLM到底在做什么?
- 大模型应用开发系列教程:第二章 模型不是重点,参数才是你真正的控制面板
- 大模型应用开发系列教程:第三章 为什么我的Prompt表现很糟?
- 大模型应用开发系列教程:第四章Prompt 的工程化结构设计
- 大模型应用开发系列教程:第五章 从 Prompt 到 Prompt 模板与工程治理
- 大模型应用开发系列教程:第六章 上下文窗口的真实边界
实战
更多推荐








所有评论(0)