智能体(Agent)构建智能体开发
i++) {log.info("现在是第"+currentStep+"最大"+maxSteps);// 单步执行String result="现在是第"+currentStep+"步结果是"+stepResult;这个就是不断地循环直到大模型满意就跳出把results返回。然后results就是给用户输出的信息。为止;补充:你每次调用工具后,ToolResponseMessage 里的最后一条信息
下面来写一下开发流程:

第一层是BaseAgent我们来看一下BaseAgent的代码:
package com.yupi.yuaiagent.agent;
import cn.hutool.core.util.StrUtil;
import com.yupi.yuaiagent.agent.model.AgentState;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* 抽象基础代理类,用于管理代理状态和执行流程。
* <p>
* 提供状态转换、内存管理和基于步骤的执行循环的基础功能。
* 子类必须实现step方法。
*/
@Data
@Slf4j
public abstract class BaseAgent {
// 核心属性
private String name;
// 提示词
private String systemPrompt;
private String nextStepPrompt;
// 代理状态
private AgentState state = AgentState.IDLE;
// 执行步骤控制
private int currentStep = 1;
private int maxSteps = 10;
// LLM 大模型
private ChatClient chatClient;
// Memory 记忆(需要自主维护会话上下文)
private List<Message> messages = new ArrayList<>();
/**
* 运行代理
*
* @param userPrompt 用户提示词
* @return 执行结果
*/
public String run(String userPrompt) {
// 1、基础校验
if (state != AgentState.IDLE) {
throw new IllegalStateException("Agent is not in IDLE state");
}
if (userPrompt == null) {
throw new NullPointerException("userPrompt is null");
}
// 2、执行,更改状态
this.state = AgentState.RUNNING;
// 记录消息上下文
messages.add(new UserMessage(userPrompt));
// 保存结果列表
List<String> results = new ArrayList<>();
try {
// 执行循环
for (int i = 0; i <maxSteps && state!=AgentState.FINISHED; i++) {
log.info("现在是第"+currentStep+"最大"+maxSteps);
currentStep++;
// 单步执行
String stepResult=step();
String result="现在是第"+currentStep+"步结果是"+stepResult;
results.add(result);
}
// 检查是否超出步骤限制
if (currentStep >= maxSteps) {
state = AgentState.FINISHED;
results.add("这是第"+currentStep+"步已经结束了噢");
}
return String.join("\n", results);
} catch (Exception e) {
state = AgentState.ERROR;
log.error("什么垃圾大模型");
return "大模型调用错误可能是";
}finally {
// 3、清理资源
cleanup();
}
}
/**
* 运行代理(流式输出)
*
* @param userPrompt 用户提示词
* @return 执行结果
*/
/**
* 定义单个步骤
*
* @return
*/
public abstract String step();
/**
* 清理资源
*/
protected void cleanup(){};
// 子类可以重写此方法来清理资源
}
注释都写的很清楚,这是底座。
下面是ReActAgent的代码:
package com.yupi.yuaiagent.agent;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
/**
* ReAct (Reasoning and Acting) 模式的代理抽象类
* 实现了思考-行动的循环模式
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Slf4j
public abstract class ReActAgent extends BaseAgent {
/**
* 处理当前状态并决定下一步行动
*
* @return 是否需要执行行动,true表示需要执行,false表示不需要执行
*/
public abstract boolean think();
/**
* 执行决定的行动
*
* @return 行动执行结果
*/
public abstract String act();
/**
* 执行单个步骤:思考和行动
*
* @return 步骤执行结果
*/
@Override
public String step() {
try {
// 先思考
boolean shouldAct = think();
if (!shouldAct) {
return "思考完成 - 无需行动";
}
// 再行动
return act();
} catch (Exception e) {
// 记录异常日志
e.printStackTrace();
return "步骤执行失败:" + e.getMessage();
}
}
}
ReactAgent就是思考然后判断是否要行动。
下面是ToolCallAgent:
代码比较复杂如下:
package com.yupi.yuaiagent.agent;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import com.alibaba.dashscope.threads.messages.Messages;
import com.yupi.yuaiagent.agent.model.AgentState;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.ToolResponseMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.tool.ToolCallingManager;
import org.springframework.ai.model.tool.ToolExecutionResult;
import org.springframework.ai.tool.ToolCallback;
import java.util.List;
import java.util.stream.Collectors;
/**
* 处理工具调用的基础代理类,具体实现了 think 和 act 方法,可以用作创建实例的父类
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Slf4j
public class ToolCallAgent extends ReActAgent {
// 可用的工具
private final ToolCallback[] availableTools;
// 保存工具调用信息的响应结果(要调用那些工具)
private ChatResponse toolCallChatResponse;
// 工具调用管理者
private final ToolCallingManager toolCallingManager;
// 禁用 Spring AI 内置的工具调用机制,自己维护选项和消息上下文
private final ChatOptions chatOptions;
public ToolCallAgent(ToolCallback[] availableTools) {
super();
this.availableTools = availableTools;
this.chatOptions =DashScopeChatOptions.builder().
withInternalToolExecutionEnabled(true).
build();
this.toolCallingManager=ToolCallingManager.builder().build();
}
/**
* 处理当前状态并决定下一步行动
*
* @return 是否需要执行行动
*/
@Override
public boolean think() {
// 1、校验提示词,拼接用户提示词
if (StrUtil.isNotBlank(getSystemPrompt()))
{
UserMessage userMessage = new UserMessage(getSystemPrompt());
getMessageList().add(userMessage);
}
// 2、调用 AI 大模型,获取工具调用结果
List<Message> userMessageList = getMessageList();
Prompt prompt=new Prompt(userMessageList,this.chatOptions);
try {
ChatResponse chatResponse = getChatClient().prompt(prompt)
.system(getSystemPrompt())
.tools(availableTools)//不会去调用工具只会输出用什么工具
.call()
.chatResponse();
// 记录响应,用于等下 Act
this.toolCallChatResponse=chatResponse;
// 3、解析工具调用结果,获取要调用的工具
// 助手消息
AssistantMessage assistantMessage =chatResponse.getResult().getOutput();
// 获取要调用的工具列表
List<AssistantMessage.ToolCall> toolCalls = assistantMessage.getToolCalls();
// 输出提示信息
String result=assistantMessage.getText();
log.info(getName()+"的思考"+result);
log.info(getName()+"选择了"+toolCalls.size()+"个工具");
String collect = toolCalls.stream()
// 修正语法错误:补全lambda括号、修正方法名、格式化符
.map(toolCall -> String.format(
"工具名称:%s,参数:%s", // %s小写(大写会全转大写)
toolCall.name(), // 正确的getter方法名(不是name())
toolCall.arguments() // 正确的getter方法名(不是arguments())
))
// 用换行符拼接所有工具调用信息
.collect(Collectors.joining("\n"));
log.info(collect);
// 如果不需要调用工具,返回 false
if (collect.isEmpty()){
getMessages().add(assistantMessage);
return false;
}else {
// 只有不调用工具时,才需要手动记录助手消息,因为你在act的时候也会加助手消息,而act的时候的那个助手消息就包含think的时候的助手消息
return true;
}
} catch (Exception e) {
log.info(getName()+"思考过程遇到了问题"+e.getMessage());
getMessages().add(new AssistantMessage("处理时遇到了错误"+e.getMessage()));
return false;
}
}
private <E> List<E> getMessageList() {
return List.of();
}
/**
* 执行工具调用并处理结果
*
* @return 执行结果
*/
@Override
public String act() {
if (!toolCallChatResponse.hasToolCalls()){
return "没有工具调用";
}
// 调用工具
Prompt prompt=new Prompt( getMessageList(),this.chatOptions);
ToolExecutionResult toolExecutionResult = toolCallingManager.executeToolCalls(prompt, toolCallChatResponse);
// 记录消息上下文,conversationHistory 已经包含了助手消息和工具调用返回的结果
setMessages(toolExecutionResult.conversationHistory());
// 判断是否调用了终止工具
ToolResponseMessage toolResponseMessage = (ToolResponseMessage) CollUtil.getLast(toolExecutionResult.conversationHistory());
boolean doTerminate = toolResponseMessage.getResponses().stream().anyMatch(response -> response.name().equals("doTerminate"));
if (doTerminate){
// 任务结束,更改状态
setState(AgentState.FINISHED);
}
String results = toolResponseMessage.getResponses().stream()
.map(response -> "工具 " + response.name() + " 返回的结果: " + response.responseData())
.collect(Collectors.joining("\n"));
return results;
}
}
然后我再把Manus类也展示出来,再把启动类也展示出来,然后在一起讲。
package com.yupi.yuaiagent.agent;
import com.yupi.yuaiagent.advisor.MyLoggerAdvisor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.stereotype.Component;
/**
* 大猴子的 AI 超级智能体(拥有自主规划能力,可以直接使用)
*/
@Component
public class YuManus extends ToolCallAgent {
public YuManus(ToolCallback[] allTools, ChatModel dashscopeChatModel) {
super(allTools);
this.setName("yuManus");
String SYSTEM_PROMPT = """
You are YuManus, an all-capable AI assistant, aimed at solving any task presented by the user.
You have various tools at your disposal that you can call upon to efficiently complete complex requests.
""";
this.setSystemPrompt(SYSTEM_PROMPT);
String NEXT_STEP_PROMPT = """
Based on user needs, proactively select the most appropriate tool or combination of tools.
For complex tasks, you can break down the problem and use different tools step by step to solve it.
After using each tool, clearly explain the execution results and suggest the next steps.
If you want to stop the interaction at any point, use the `terminate` tool/function call.
""";
this.setNextStepPrompt(NEXT_STEP_PROMPT);
this.setMaxSteps(20);
// 初始化 AI 对话客户端
ChatClient chatClient = ChatClient.builder(dashscopeChatModel)
.defaultAdvisors(new MyLoggerAdvisor())
.build();
this.setChatClient(chatClient);
}
}
package com.yupi.yuaiagent.agent;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class YuManusTest {
@Resource
private YuManus yuManus;
@Test
public void run() {
String userPrompt = """
我的另一半居住在上海静安区,请帮我找到 5 公里内合适的约会地点,
并结合一些网络图片,制定一份详细的约会计划,
并以 PDF 格式输出""";
String answer = yuManus.run(userPrompt);
Assertions.assertNotNull(answer);
}
}
1. 初始化阶段(Spring 容器启动时)
-
Spring 初始化
YuManus- Spring 通过构造器注入
ToolCallback[] allTools和ChatModel dashscopeChatModel - 调用
super(allTools),将工具列表传递给父类ToolCallAgent - 设置核心配置参数:
this.setName("yuManus")→ 设置代理的名称this.setSystemPrompt(SYSTEM_PROMPT)→ 设置系统级提示词,定义代理的角色和行为准则this.setNextStepPrompt(NEXT_STEP_PROMPT)→ 设置下一步提示词,指导代理如何规划后续动作this.setMaxSteps(20)→ 设置最大思考步数,防止无限循环
- 初始化对话客户端:
ChatClient chatClient = ChatClient.builder(dashscopeChatModel).defaultAdvisors(new MyloggerAdvisor()).build()- 封装
ChatModel,并添加日志拦截器,用于后续和大模型的交互
- Spring 通过构造器注入
-
ToolCallAgent初始化- 接收
YuManus传来的ToolCallback[],保存到成员变量availableTools - 初始化
toolCallingManager→ 负责管理工具调用的生命周期 - 初始化
chatOptions→ 配置大模型的调用参数(如是否启用内部工具执行)
- 接收
-
ReActAgent初始化- 继承自
BaseAgent,初始化对话历史和思考状态
- 继承自
-
BaseAgent初始化- 初始化基础的代理状态,如当前步数、终止条件等
2. 执行入口
- 触发
BaseAgent.run()- 这是整个代理的顶层入口方法
- 方法内部会启动一个循环,直到达到
maxSteps或任务结束
3. 核心执行链
-
BaseAgent.run()调用BaseAgent.step()step()是一个抽象方法,定义了 “单步思考 - 执行” 的流程- 具体实现由子类
ReActAgent提供
-
ReActAgent.step()执行 ReAct 核心逻辑- 先调用
think()方法,让 AI 基于systemPrompt、对话历史和nextStepPrompt思考下一步该做什么 - 再调用
act()方法,执行思考出的动作 - 这两个方法在
ToolCallAgent中被重写
- 先调用
-
ToolCallAgent.think()决策- 基于当前对话历史和系统提示,决定下一步是否需要调用工具
- 返回思考结果(如 “需要调用文件读取工具”)
-
ToolCallAgent.act()执行- 根据
think()的结果,从availableTools中选择对应的ToolCallback - 调用工具并获取结果
- 将结果返回给
ReActAgent.step()
- 根据
4. 循环与终止
- 回到
BaseAgent.run()- 将
act()的结果加入对话历史 - 检查是否达到
maxSteps或任务完成 - 如果未完成,重复执行
step(),直到终止条件满足
- 将
先看这里:
下面是对上面那四步的一种解释,看完再去理解上面那四步更容易。
继承关系看第一个图就可以懂
这些代码的流程堪称非常无敌狗屎的复杂,首先我来梳理一下。当搞清所有代码的时候,我们先来看第三条那个执行链,但出现继承这种的时候,一般执行的不是方法体,而是重写这个方法体的方法,很简单方法体没办法执行呀,直接找这个方法体被那个子类里面的方法重写了然后执行哪个类里面这样同名的方法。来我们来看执行链。
首先就是BaseAgent.run() 调用 BaseAgent.step(),但这个step是方法体,所以找子类的step,ReActAgent.step() 是重写了BaseAgent.step()所以执行这个方法,这个方法里面又有两个方法体所以执行子类里面重写这两个方法体的方法,ToolCallAgent.think()和ToolCallAgent.act()重写了ReActAgent.step() 里面的act和think方法所以执行这两个方法。
总的来说最终是执行ToolCallAgent.think()和ToolCallAgent.act()这俩方法和其他父类里面除了step()和act()和think的方法。
来看执行的流程:
看第一条:
用户只需要传入userPrompt就可以它会放入
List<Message> messages = new ArrayList<>();这个集合中,这个集合是上下文;
// 核心属性 private String name; private final ToolCallback[] availableTools; // 提示词 private String systemPrompt; private String nextStepPrompt; private ChatClient chatClient; private int maxSteps
分析所有的类需要赋值的有这六个参数,除了private final ToolCallback[] availableTools;都在BaseAgent类,而它在 ToolCallAgent里面,下面来讲什么时候赋的值。
Spring 初始化 YuManus时
availableTools:
- Spring 通过构造器注入
ToolCallback[] allTools和ChatModel dashscopeChatModel - 调用
super(allTools),将工具列表传递给父类ToolCallAgent
name:
this.setName("yuManus")→ 设置代理的名称
systemPrompt:
this.setSystemPrompt(SYSTEM_PROMPT)→ 设置系统级提示词,定义代理的角色和行为准则
nextStepPrompt:
this.setNextStepPrompt(NEXT_STEP_PROMPT)→ 设置下一步提示词,指导代理如何规划后续动作
maxSteps:
this.setMaxSteps(20)→ 设置最大思考步数,防止无限循环
chatClient:
ChatClient chatClient = ChatClient.builder(dashscopeChatModel).defaultAdvisors(new MyloggerAdvisor()).build()。
所以赋值都是在YuManus里面实现的。
-
ToolCallAgent初始化- 接收
YuManus传来的ToolCallback[],保存到成员变量availableTools - 初始化
toolCallingManager→ 负责管理工具调用的生命周期 - 初始化
chatOptions→ 配置大模型的调用参数(如是否启用内部工具执行)
- 接收
-
ReActAgent初始化- 继承自
BaseAgent,初始化对话历史和思考状态
- 继承自
-
BaseAgent初始化- 初始化基础的代理状态,如当前步数、终止条件等
然后下一步看上面那个核心执行链往下就可以看懂。
现在来开始分析每一个代码:
分析
ToolCallAgent这个类应该就可以因为他是最复杂的其它的看注解绝对可以看懂。
来看Think()方法:
public boolean think() {
// 1、校验提示词,拼接用户提示词
if (StrUtil.isNotBlank(getSystemPrompt()))
{
UserMessage userMessage = new UserMessage(getSystemPrompt());
getMessageList().add(userMessage);
}
// 2、调用 AI 大模型,获取工具调用结果
List<Message> userMessageList = getMessageList();
Prompt prompt=new Prompt(userMessageList,this.chatOptions);
try {
ChatResponse chatResponse = getChatClient().prompt(prompt)
.system(getSystemPrompt())
.tools(availableTools)//不会去调用工具只会输出用什么工具
.call()
.chatResponse();
// 记录响应,用于等下 Act
this.toolCallChatResponse=chatResponse;
// 3、解析工具调用结果,获取要调用的工具
// 助手消息
AssistantMessage assistantMessage =chatResponse.getResult().getOutput();
// 获取要调用的工具列表
List<AssistantMessage.ToolCall> toolCalls = assistantMessage.getToolCalls();
// 输出提示信息
String result=assistantMessage.getText();
log.info(getName()+"的思考"+result);
log.info(getName()+"选择了"+toolCalls.size()+"个工具");
String collect = toolCalls.stream()
// 修正语法错误:补全lambda括号、修正方法名、格式化符
.map(toolCall -> String.format(
"工具名称:%s,参数:%s", // %s小写(大写会全转大写)
toolCall.name(), // 正确的getter方法名(不是name())
toolCall.arguments() // 正确的getter方法名(不是arguments())
))
// 用换行符拼接所有工具调用信息
.collect(Collectors.joining("\n"));
log.info(collect);
// 如果不需要调用工具,返回 false
if (collect.isEmpty()){
getMessages().add(assistantMessage);
return false;
}else {
// 只有不调用工具时,才需要手动记录助手消息,因为你在act的时候也会加助手消息,而act的时候的那个助手消息就包含think的时候的助手消息
return true;
}
} catch (Exception e) {
log.info(getName()+"思考过程遇到了问题"+e.getMessage());
getMessages().add(new AssistantMessage("处理时遇到了错误"+e.getMessage()));
return false;
}
}
每次BaseAgent里面的那个循环都会调用Step()方法,所以每次循环都会调用think和act方法,
getMessages().add这个Messages是在BaseAgent里面定义的
List<Message> messages = new ArrayList<>();是用来存放上下文的,
如果不需要调用工具会有一个assistantMessage用来存放信息,然后赋值给上下文,因为不需要调用工具也会有一个回应呀,然后存入上下文,并且返回fasle那个ReactAgent里面就会执行
if (!shouldAct) {
return "思考完成 - 无需行动";
}
然后
private List<Message> getMessageList() {
return this.getMessages();
}
把上下文给这个messageList,因为我们在
ChatResponse chatResponse = getChatClient().prompt(prompt)
.system(getSystemPrompt())
.tools(availableTools)//不会去调用工具只会输出用什么工具
.call()
.chatResponse();
这里的这个prompt是
List<Message> userMessageList = getMessageList(); Prompt prompt=new Prompt(userMessageList,this.chatOptions);
可以看到把给Ai大模型的是getMessageList这个集合相当于所以就把上下文放到这里面就可以,而且每次放上下文都会覆盖原来的内容,那么就有疑问了系统propmt怎么办,他会从新加到MessageList()里面具体看第一行代码就可以,这样就保证了每次只有一个系统提示词不会重复。
然后再看
if (collect.isEmpty()){
getMessages().add(assistantMessage);
return false;
}else {
// 只有不调用工具时,才需要手动记录助手消息,因为你在act的时候也会加助手消息,而act的时候的那个助手消息就包含think的时候的助手消息
return true;
}
刚才讲的是当collect.isEmpty()成立的时候,那么当else呢,此时返回true就会调用act对吧
boolean shouldAct = think();
if (!shouldAct) {
return "思考完成 - 无需行动";
}
// 再行动
return act();
所以执行act方法
public String act() {
if (!toolCallChatResponse.hasToolCalls()){
return "没有工具调用";
}
// 调用工具
Prompt prompt=new Prompt( getMessageList(),this.chatOptions);
ToolExecutionResult toolExecutionResult = toolCallingManager.executeToolCalls(prompt, toolCallChatResponse);
// 记录消息上下文,conversationHistory 已经包含了助手消息和工具调用返回的结果
setMessages(toolExecutionResult.conversationHistory());
// 判断是否调用了终止工具
ToolResponseMessage toolResponseMessage = (ToolResponseMessage) CollUtil.getLast(toolExecutionResult.conversationHistory());
boolean doTerminate = toolResponseMessage.getResponses().stream().anyMatch(response -> response.name().equals("doTerminate"));
if (doTerminate){
// 任务结束,更改状态
setState(AgentState.FINISHED);
}
String results = toolResponseMessage.getResponses().stream()
.map(response -> "工具 " + response.name() + " 返回的结果: " + response.responseData())
.collect(Collectors.joining("\n"));
return results;
}
注释都写的很清楚。
ToolResponseMessage toolResponseMessage = (ToolResponseMessage) CollUtil.getLast(toolExecutionResult.conversationHistory());
boolean doTerminate = toolResponseMessage.getResponses().stream().anyMatch(response -> response.name().equals("doTerminate"));
这是获取调用工具后的结果也就是调用完工具的信息,当Ai最后一次调用工具,也就是现在的结果它满意的时候它会输出doTerminate而且在最后一行所以就boolean doTerminate = toolResponseMessage.getResponses().stream().anyMatch(response -> response.name().equals("doTerminate"));判断最后。一行有没有这个单词有的话把状态改成终止这样BaseAgent就不会在进行循环了。
String results = toolResponseMessage.getResponses().stream()
.map(response -> "工具 " + response.name() + " 返回的结果: " + response.responseData())
.collect(Collectors.joining("\n"));
return results;解析出输出的结果如何返回把这个值。
这里有没有疑问为什么当
if (collect.isEmpty()){
getMessages().add(assistantMessage);
return false;
}else {
// 只有不调用工具时,才需要手动记录助手消息,因为你在act的时候也会加助手消息,而act的时候的那个助手消息就包含think的时候的助手消息
return true;
}
else里面不把assistangMessage加入上下文中,现在就来解答。
如果为true是不是要进行act方法对吧,来看act()方法里面的这一行
setMessages(toolExecutionResult.conversationHistory());
把toolExecutionResult.conversationHistory()这玩意放入上下文,这玩意是啥,来看源码:
package org.springframework.ai.model.tool;
import java.util.ArrayList;
import java.util.List;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.ToolResponseMessage;
import org.springframework.ai.chat.metadata.ChatGenerationMetadata;
import org.springframework.ai.chat.model.Generation;
public interface ToolExecutionResult {
String FINISH_REASON = "returnDirect";
String METADATA_TOOL_ID = "toolId";
String METADATA_TOOL_NAME = "toolName";
List<Message> conversationHistory();
default boolean returnDirect() {
return false;
}
static DefaultToolExecutionResult.Builder builder() {
return DefaultToolExecutionResult.builder();
}
static List<Generation> buildGenerations(ToolExecutionResult toolExecutionResult) {
List<Message> conversationHistory = toolExecutionResult.conversationHistory();
List<Generation> generations = new ArrayList();
Object var4 = conversationHistory.get(conversationHistory.size() - 1);
if (var4 instanceof ToolResponseMessage toolResponseMessage) {
toolResponseMessage.getResponses().forEach((response) -> {
AssistantMessage assistantMessage = new AssistantMessage(response.responseData());
Generation generation = new Generation(assistantMessage, ChatGenerationMetadata.builder().metadata("toolId", response.id()).metadata("toolName", response.name()).finishReason("returnDirect").build());
generations.add(generation);
});
}
AssistantMessage assistantMessage = new AssistantMessage(response.responseData());
Generation generation = new Generation(assistantMessage, ChatGenerationMetadata.builder().metadata("toolId", response.id()).metadata("toolName", response.name()).finishReason("returnDirect").build());这一行不就是把助手信息给上下文吗,所以不是不给而是晚给,如果早给了就重复了就多给了一次。
最后
for (int i = 0; i <maxSteps && state!=AgentState.FINISHED; i++) {
log.info("现在是第"+currentStep+"最大"+maxSteps);
currentStep++;
// 单步执行
String stepResult=step();
String result="现在是第"+currentStep+"步结果是"+stepResult;
results.add(result);
}
这个就是不断地循环直到大模型满意就跳出把results返回。然后results就是给用户输出的信息。
为止;
补充:
你每次调用工具后,ToolResponseMessage 里的最后一条信息,才是要展示给用户的内容。
✔ CollUtil.getLast () 就是为了拿到这一条。
更多推荐



所有评论(0)