5种AI Agent模式 - 详细解释和Java示例
1. 概述
当你用几行代码将LLM和自动执行能力结合起来时,你就已经有了一个基础的AI Agent —— 但这种agent通常提问即答,不知道如何自我纠正、不知道如何调用工具、不知道如何分工。本文解释5种设计模式,让agent更加“智能”:Reflection、Tool Use、Planning、Multi-Agent和ReAct。每种模式都有简短的、可运行的Java(Spring AI)代码示例,以及何时应该和不应该使用的说明。读完后,你能够为自己的问题选择合适的模式,而不是把所有东西都硬塞到一个巨大的prompt中。
在深入细节之前,下面的示例需要Spring AI的依赖:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
spring.ai.openai.api-key=${OPENAI_API_KEY}
spring.ai.openai.chat.options.model=gpt-4o-mini
注意: 本文代码演示的是模式的结构,不是生产产品 —— 当实际部署时,你需要添加重试、超时和日志记录。
2. Reflection模式:自我评论和修正答案
Reflection是最简单的模式:agent生成一个答案,然后用同一个LLM(或不同的LLM)给答案评分/评论,然后修正。这个循环类似于你写初稿,然后在发送前自己检查。
2.1. 工作流
- 生成:agent生成初始答案。
- 评论:agent(或另一个agent)扮演“审阅者”角色,指出错误。
- 修正:agent根据评论进行修改,可能重复2-3步直到达到质量要求。
@Service
public class ReflectionAgent {
private final ChatClient chatClient;
public ReflectionAgent(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
public String answerWithReflection(String question, int maxRounds) {
String draft = chatClient.prompt()
.user("简明扼要地回答问题:" + question)
.call()
.content();
for (int round = 0; round < maxRounds; round++) {
String critique = chatClient.prompt()
.user("""
你是一个严格的审阅者。指出以下答案中的错误和不足。
如果答案已经足够好,回复"OK"。
问题:%s
答案:%s
""".formatted(question, draft))
.call()
.content();
if (critique.strip().equalsIgnoreCase("OK")) {
break;
}
draft = chatClient.prompt()
.user("根据以下反馈修改答案:" + critique
+ "\n旧答案:" + draft)
.call()
.content();
}
return draft;
}
}
answerWithReflection生成初始草稿,然后循环最多maxRounds次:调用LLM充当审阅者进行评分,如果审阅者返回“OK”则停止,否则生成修改版本。结果是答案往往比只调用一次LLM更准确。
注意: Reflection消耗的LLM调用次数是平常的2-3倍。仅应用于需要高精度的任务(代码审查、计算、撰写合同),不应用于常规聊天,因为它很慢且成本高。
3. Tool Use模式:让agent调用外部工具
LLM不知道当前时间,无法访问数据库,无法精确计算大数字。Tool Use模式让agent在需要时“调用函数” —— LLM决定调用哪个tool,代码执行该tool然后将结果返回给LLM继续推理。
@Component
public class OrderTools {
private final OrderRepository orderRepository;
public OrderTools(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
@Tool(description = "根据订单号查询订单状态")
public String getOrderStatus(String orderId) {
return orderRepository.findById(orderId)
.map(Order::getStatus)
.orElse("找不到订单 " + orderId);
}
@Tool(description = "计算订单总金额,包含10%税费")
public double calculateTotal(double subtotal) {
return subtotal * 1.1;
}
}
@Service
public class CustomerSupportAgent {
private final ChatClient chatClient;
public CustomerSupportAgent(ChatClient.Builder builder, OrderTools orderTools) {
this.chatClient = builder
.defaultTools(orderTools)
.build();
}
public String handle(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.call()
.content();
}
}
@Tool将方法标记为LLM可以调用的函数,description帮助模型理解何时使用。当注册defaultTools(orderTools)时,Spring AI自动:将工具的schema发送给LLM,接收工具调用请求(JSON格式),执行相应的Java方法,然后将结果返回给LLM完成答案。
例如,用户问“订单ORD-001在哪里?”,agent自己决定调用getOrderStatus("ORD-001"),你不需要手动编写意图解析逻辑。
用户:订单ORD-001在哪里?
Agent:订单ORD-001当前状态是"配送中"。
用JUnit 5 + Mockito编写简单测试来检查tool正常运行,无需调用真实的LLM:
class OrderToolsTest {
private final OrderRepository repository = mock(OrderRepository.class);
private final OrderTools tools = new OrderTools(repository);
@Test
void shouldReturnStatusWhenOrderExists() {
when(repository.findById("ORD-001"))
.thenReturn(Optional.of(new Order("ORD-001", "配送中")));
String result = tools.getOrderStatus("ORD-001");
assertThat(result).isEqualTo("配送中");
}
}
注意: 在tool访问数据库或调用真实API之前,始终验证输入 —— 如果prompt不够清楚,LLM可能会传递错误格式的参数(例如空的orderId)。
4. Planning模式:将大任务分解为小步骤
对于复杂的请求(“编写比较3个供应商的报告,包含价格表和建议”),让LLM一次性完成容易遗漏步骤。Planning模式分为两个角色:Planner制定步骤列表,Executor依次执行每个步骤。
public record PlanStep(int order, String description) {}
@Service
public class PlannerAgent {
private final ChatClient chatClient;
public PlannerAgent(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
public List<PlanStep> createPlan(String goal) {
String json = chatClient.prompt()
.user("""
将下面的目标分解为最多5个执行步骤,
返回JSON数组格式[{"order":1,"description":"..."}]:
%s
""".formatted(goal))
.call()
.content();
return parseSteps(json);
}
}
@Service
public class ExecutorAgent {
private final ChatClient chatClient;
public ExecutorAgent(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
public String runPlan(String goal, List<PlanStep> steps) {
StringBuilder context = new StringBuilder();
for (PlanStep step : steps) {
String result = chatClient.prompt()
.user("目标:" + goal
+ "\n已完成的上下文:" + context
+ "\n执行步骤:" + step.description())
.call()
.content();
context.append("步骤 ").append(step.order())
.append(":").append(result).append("\n");
}
return context.toString();
}
}
PlannerAgent仅负责以JSON形式生成步骤列表,ExecutorAgent运行每个步骤并累积context,以便下一步知道之前做了什么。分离planner/executor有助于调试:如果结果错误,首先检查计划(是否合理),然后检查每个执行步骤。
"编写比较3个供应商的报告"的计划:
1. 收集每个供应商的价格和功能信息
2. 制作对比表
3. 分析优缺点
4. 提出建议
5. 编写执行摘要部分
注意: Planning模式在任务有许多相互依赖的步骤时最有效。对于单步任务(例如“总结这段文字”),添加planner只会减速并浪费不必要的token。
5. Multi-Agent模式:多个专业agent协作
Multi-Agent模式不是单一的“全能”agent,而是将工作分配给专业化的agent:研究agent、写作agent、审核agent等,然后由Orchestrator协调它们之间的流程。就像一个小团队的模型,每个人擅长一项工作。
@Service
public class ResearchAgent {
private final ChatClient chatClient;
public ResearchAgent(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
public String research(String topic) {
return chatClient.prompt()
.user("列出关于以下主题的5个最重要的要点:" + topic)
.call()
.content();
}
}
@Service
public class WriterAgent {
private final ChatClient chatClient;
public WriterAgent(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
public String write(String topic, String researchNotes) {
return chatClient.prompt()
.user("根据以下数据,编写一篇200字的文章,主题为'" + topic
+ "':" + researchNotes)
.call()
.content();
}
}
@Service
public class OrchestratorAgent {
private final ResearchAgent researchAgent;
private final WriterAgent writerAgent;
public OrchestratorAgent(ResearchAgent researchAgent, WriterAgent writerAgent) {
this.researchAgent = researchAgent;
this.writerAgent = writerAgent;
}
public String produceArticle(String topic) {
String notes = researchAgent.research(topic);
return writerAgent.write(topic, notes);
}
}
OrchestratorAgent不是自己调用LLM,而是协调:调用ResearchAgent获取原始数据,将其传给WriterAgent写成完整文章。每个agent有自己的prompt,针对一项特定工作进行优化,因此每个部分的质量通常比把所有内容堆入一个长prompt要好。
用mock编写测试来检查协调流程是否正确,不依赖LLM:
class OrchestratorAgentTest {
@Test
void shouldPassResearchNotesToWriter() {
ResearchAgent research = mock(ResearchAgent.class);
WriterAgent writer = mock(WriterAgent.class);
when(research.research("Spring AI")).thenReturn("note-A, note-B");
when(writer.write("Spring AI", "note-A, note-B")).thenReturn("完整文章");
OrchestratorAgent orchestrator = new OrchestratorAgent(research, writer);
String article = orchestrator.produceArticle("Spring AI");
assertThat(article).isEqualTo("完整文章");
verify(writer).write("Spring AI", "note-A, note-B");
}
}
注意: Multi-Agent增加了延迟(多个连续的LLM调用)和系统复杂性。只有当每个agent确实有明显不同的prompt/context时才应该分离 —— 过度分割(每个agent一句话)只会造成不必要的开销。
6. ReAct模式:推理交织的行动
ReAct(推理+行动)是结合Tool Use和推理循环的模式:agent思考(Thought)→行动(Action,例如调用tool)→观察结果(Observation)→重复直到有足够信息回答。与单纯的Tool Use(调用1个tool然后回答)不同,ReAct允许agent按灵活顺序调用多个tool,根据之前的observation自行决定下一步。
@Service
public class ReActAgent {
private final ChatClient chatClient;
private final List<Object> tools;
public ReActAgent(ChatClient.Builder builder, WeatherTool weatherTool, SearchTool searchTool) {
this.tools = List.of(weatherTool, searchTool);
this.chatClient = builder.defaultTools(tools.toArray()).build();
}
public String solve(String question) {
return chatClient.prompt()
.system("""
当需要真实数据时,回答前调用适当的tool。
逐步推理:Thought -> Action -> Observation -> Thought...
只有当掌握足够信息时才给出最终答案。
""")
.user(question)
.call()
.content();
}
}
对于问题“这个周末我去大叻应该带雨衣吗?”,agent可以自行推理:调用weatherTool.forecast("大叻")获取预报,观察结果“70%降雨”,然后回答 —— 整个Thought/Action/Observation序列在框架内部进行,你无需手动编写循环,因为Spring AI自动处理循环调用tool直到模型决定停止。
Thought: 需要了解大叻周末的天气
Action: forecast("大叻")
Observation: 降雨70%,18-22摄氏度
Thought: 应该带雨衣
Answer: 你应该带雨衣,预报显示大叻周末降雨概率70%。
注意: 如果agent不断调用tool但不收敛到答案,ReAct容易陷入“无限循环”。始终设置最大工具调用次数(
maxToolCalls或超时)以避免无法控制的API成本。
7. 5种模式的快速比较
| 模式 | 解决的问题 | 成本(LLM调用次数) | 何时使用 |
|---|---|---|---|
| Reflection | 答案质量低 | 高(2-3倍) | 需要高精度、可自检的任务 |
| Tool Use | LLM无法访问真实数据/系统 | 低-中等 | 需要查询、计算、调用API |
| Planning | 多步任务,容易遗漏 | 中等 | 复杂的结构化任务 |
| Multi-Agent | 单个agent专业性不足 | 高 | 清晰角色分工的pipeline(研究/写作/审核) |
| ReAct | 需要tool但步骤数未知 | 可变 | 需要灵活探索信息的任务 |
在实践中,这些模式并不互斥 —— 客户支持agent可以使用Tool Use查询订单、用Planning处理复杂请求、用Reflection检查敏感答案再发送。
8. 结论
上述5种模式 —— Reflection、Tool Use、Planning、Multi-Agent、ReAct —— 是构建能够自我纠正、与真实系统交互、处理复杂任务并灵活探索信息的AI Agent的基础构建块。你不需要对所有问题都使用全部5种;从Tool Use开始(几乎每个agent都需要),然后在任务更复杂时添加Planning或ReAct,只有当额外成本值得提升质量时才使用Reflection/Multi-Agent。根据问题选择正确的模式比试图将所有东西都硬塞到单个agent中更重要。