第1946篇:AI Agent框架的未来——从工具调用到自主决策的演进路线
第1946篇:AI Agent框架的未来——从工具调用到自主决策的演进路线
去年有段时间我特别迷Agent,觉得把大模型和工具组合一下,什么问题都能解决。后来被现实打了几次脸,才慢慢理解了Agent能做什么、不能做什么,以及框架的设计取舍在哪里。
这篇文章不是Agent入门教程,是我对这个方向的思考,以及在Java工程实践中的判断。
Agent框架的本质问题
现有的Agent框架,包括LangChain、LangGraph、AutoGen、CrewAI、Spring AI的Agent支持,本质上都在解决同一个问题:如何让LLM可靠地完成需要多步骤、多工具配合的复杂任务。
但解决这个问题的方式产生了根本性的分歧:
规划后执行(Plan-and-Execute):先让模型生成一个完整的任务计划,然后逐步执行。好处是整体逻辑清晰,坏处是计划生成阶段容易出错,一旦计划错了后面全错。
ReAct循环(Reason-Act-Observe):每步都思考-行动-观察,动态调整下一步。更灵活,但也更容易进入死循环,调试起来也更难。
多Agent协作:把任务分给不同专职Agent,有个编排Agent协调。理论上更强,实际上Agent间通信和状态同步是噩梦,调试成本极高。
我在实际项目里踩过所有这些坑,回过头来看,框架的选择不是核心,任务的清晰定义才是核心。
ReAct模式的Java实现
先从最基础的ReAct Agent说起,理解底层机制:
@Service
public class ReactAgent {
@Autowired
private ChatClient chatClient;
@Autowired
private ToolRegistry toolRegistry;
private static final int MAX_ITERATIONS = 10;
private static final String REACT_SYSTEM_PROMPT = """
你是一个任务执行助手,按照 思考-行动-观察 的循环来完成用户的任务。
每次输出格式:
思考:(分析当前情况,决定下一步行动)
行动:工具名称(参数)
当你认为任务完成时:
思考:(确认任务已完成)
最终答案:(给出最终结果)
可用工具:
{{tools_description}}
""";
public AgentResult execute(String userTask) {
String toolsDescription = toolRegistry.getDescription();
String systemPrompt = REACT_SYSTEM_PROMPT.replace(
"{{tools_description}}", toolsDescription);
List<Message> history = new ArrayList<>();
history.add(new SystemMessage(systemPrompt));
history.add(new UserMessage(userTask));
StringBuilder fullThinking = new StringBuilder();
for (int iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
// 请求模型思考
String modelOutput = chatClient.prompt()
.messages(history)
.call()
.content();
history.add(new AssistantMessage(modelOutput));
fullThinking.append("=== 迭代 ").append(iteration + 1).append(" ===\n");
fullThinking.append(modelOutput).append("\n");
// 检查是否完成
if (modelOutput.contains("最终答案:")) {
String finalAnswer = modelOutput.substring(
modelOutput.indexOf("最终答案:") + 5).trim();
return AgentResult.success(finalAnswer, fullThinking.toString(), iteration + 1);
}
// 解析并执行工具调用
ToolCall toolCall = parseToolCall(modelOutput);
if (toolCall == null) {
// 没有工具调用也没有最终答案,可能模型输出格式有问题
log.warn("无法解析模型输出,迭代: {}", iteration);
continue;
}
String toolResult = executeToolCall(toolCall);
String observation = "观察:" + toolResult;
history.add(new UserMessage(observation));
fullThinking.append(observation).append("\n");
}
return AgentResult.failure("超过最大迭代次数", fullThinking.toString());
}
private ToolCall parseToolCall(String modelOutput) {
// 解析 "行动:tool_name(参数)" 格式
Pattern pattern = Pattern.compile("行动:(\\w+)\\((.*)\\)");
Matcher matcher = pattern.matcher(modelOutput);
if (matcher.find()) {
String toolName = matcher.group(1);
String params = matcher.group(2);
return new ToolCall(toolName, params);
}
return null;
}
private String executeToolCall(ToolCall toolCall) {
ToolExecutor executor = toolRegistry.getExecutor(toolCall.getToolName());
if (executor == null) {
return "错误:工具 " + toolCall.getToolName() + " 不存在";
}
try {
return executor.execute(toolCall.getParams());
} catch (Exception e) {
return "工具执行出错:" + e.getMessage();
}
}
}用Spring AI的Function Calling做更可靠的Agent
上面那个ReAct用字符串解析工具调用,很脆。生产上应该用Function Calling:
@Service
public class FunctionCallingAgent {
@Autowired
private ChatClient chatClient;
/**
* 基于Function Calling的Agent循环
* 比ReAct字符串解析更可靠
*/
public String run(String task, List<Object> tools) {
List<Message> messages = new ArrayList<>();
messages.add(new SystemMessage("你是一个任务助手,使用提供的工具完成用户的任务。"));
messages.add(new UserMessage(task));
// Agent循环
for (int i = 0; i < 10; i++) {
ChatResponse response = chatClient.prompt()
.messages(messages)
.tools(tools.toArray())
.call()
.chatResponse();
AssistantMessage assistantMessage = response.getResult().getOutput();
messages.add(assistantMessage);
// 没有工具调用,说明任务完成
if (assistantMessage.getToolCalls().isEmpty()) {
return assistantMessage.getContent();
}
// 执行所有工具调用
for (AssistantMessage.ToolCall toolCall : assistantMessage.getToolCalls()) {
String toolResult = executeToolById(toolCall, tools);
messages.add(new ToolResponseMessage(List.of(
new ToolResponseMessage.ToolResponse(
toolCall.id(),
toolCall.name(),
toolResult
)
)));
}
}
return "任务未完成:超过最大循环次数";
}
private String executeToolById(AssistantMessage.ToolCall toolCall, List<Object> tools) {
// Spring AI会通过反射自动找到对应的@Tool方法并执行
// 这里的工具执行由框架处理
return "工具结果占位符";
}
}计划-执行模式(适合复杂任务)
对于复杂任务,Plan-and-Execute模式更稳:
@Service
public class PlanAndExecuteAgent {
@Autowired
private ChatClient chatClient;
@Autowired
private FunctionCallingAgent executor;
@Autowired
private List<Object> availableTools;
/**
* Plan-and-Execute模式
* 先生成完整计划,再逐步执行
*/
public TaskResult execute(String complexTask) {
// Phase 1: 生成执行计划
ExecutionPlan plan = generatePlan(complexTask);
log.info("生成计划: {} 步", plan.getSteps().size());
// Phase 2: 逐步执行
List<StepResult> stepResults = new ArrayList<>();
String context = "";
for (int i = 0; i < plan.getSteps().size(); i++) {
ExecutionPlan.Step step = plan.getSteps().get(i);
String stepPrompt = buildStepPrompt(step, context, complexTask);
String stepResult = executor.run(stepPrompt, availableTools);
stepResults.add(new StepResult(step.getDescription(), stepResult));
context = buildContext(stepResults); // 累积上下文
log.info("步骤 {}/{} 完成", i + 1, plan.getSteps().size());
}
// Phase 3: 汇总结果
return summarizeResults(complexTask, stepResults);
}
private ExecutionPlan generatePlan(String task) {
String planningPrompt = """
请分析以下任务,生成详细的执行计划。每个步骤要明确、可执行。
输出JSON格式:
{
"steps": [
{"id": 1, "description": "步骤描述", "expectedOutput": "预期输出"},
...
]
}
任务:%s
""".formatted(task);
return chatClient.prompt()
.user(planningPrompt)
.call()
.entity(ExecutionPlan.class);
}
private String buildStepPrompt(
ExecutionPlan.Step step,
String previousContext,
String originalTask) {
return String.format("""
原始任务:%s
之前步骤的结果:
%s
当前需要完成的步骤:%s
预期输出:%s
请使用可用工具完成这个步骤。
""",
originalTask,
previousContext.isEmpty() ? "无" : previousContext,
step.getDescription(),
step.getExpectedOutput()
);
}
}多Agent协作架构
多Agent是Agent框架里最难的部分,也是最容易过度设计的部分。先分享一个我们内部用的简化版本:
关键设计原则:每个专职Agent有明确的职责边界,通过消息而不是共享状态通信,编排Agent不做具体业务,只做调度。
@Service
public class MultiAgentOrchestrator {
@Autowired
private Map<String, SpecialistAgent> specialists;
@Autowired
private ChatClient chatClient;
/**
* 多Agent编排
*/
public String orchestrate(String userRequest) {
// Step 1: 分析请求,决定需要哪些Agent参与
List<AgentTask> tasks = decomposeRequest(userRequest);
// Step 2: 并行执行独立任务
List<CompletableFuture<AgentResult>> futures = tasks.stream()
.map(task -> CompletableFuture.supplyAsync(() -> {
SpecialistAgent agent = specialists.get(task.getAgentType());
if (agent == null) {
return AgentResult.failure("Agent不存在: " + task.getAgentType());
}
return agent.execute(task.getInstruction());
}))
.collect(Collectors.toList());
// Step 3: 等待所有任务完成
List<AgentResult> results = futures.stream()
.map(f -> {
try {
return f.get(120, TimeUnit.SECONDS);
} catch (TimeoutException e) {
return AgentResult.failure("Agent执行超时");
} catch (Exception e) {
return AgentResult.failure("Agent执行异常: " + e.getMessage());
}
})
.collect(Collectors.toList());
// Step 4: 汇总所有Agent的结果
return synthesizeResults(userRequest, tasks, results);
}
private List<AgentTask> decomposeRequest(String request) {
String decompositionPrompt = """
分析以下用户请求,确定需要哪些专职Agent参与处理。
可用的Agent类型:data(数据查询)、document(文档处理)、code(代码相关)
输出JSON:
[
{"agentType": "data", "instruction": "具体给这个Agent的指令"},
...
]
用户请求:%s
""".formatted(request);
return chatClient.prompt()
.user(decompositionPrompt)
.call()
.entity(new ParameterizedTypeReference<List<AgentTask>>() {});
}
}Agent框架的核心挑战
坦白说,现在的Agent框架在几个关键点上都还不够成熟:
可靠性问题:Agent任务链越长,出错概率越高。一个10步的Agent任务,每步成功率95%,整体成功率只有60%。这在很多生产场景里是不可接受的。
可调试性问题:Agent出错了,怎么定位是哪个步骤的问题?目前大多数框架的调试工具都很原始。我们内部加了详细的步骤日志和可视化trace,但这需要额外投入。
成本失控问题:Agent循环调用的成本很难预估。有时候一个复杂任务会触发几十次LLM调用,成本比预期高10倍。要加硬性的token预算限制。
幂等性问题:Agent重试的时候,如果前几步已经产生了副作用(比如发了邮件、写了数据库),重试会导致重复执行。这个问题很难通用地解决,必须在业务层面处理。
什么时候用Agent,什么时候不用
这是我现在判断AI工程师成熟度的一个指标:能不能说清楚这个任务为什么要用Agent,而不是更简单的方案。
不该用Agent的场景:
- 任务流程固定、可以预先写死步骤的 → 用工作流/状态机
- 只需要一次LLM调用就能完成的 → 直接调用
- 对实时性要求高、延迟要在1秒以内的 → Agent太慢
- 任何涉及资金操作、合同签署等高风险的 → 必须有人工审核节点
适合用Agent的场景:
- 任务目标明确但路径不固定(数据分析、研究报告)
- 需要迭代和自我修正(代码生成-测试-修复循环)
- 流程分支复杂,写死逻辑维护成本高
- 处理量不大但每个任务都比较复杂(适合每任务独立一个Agent循环)
我对Agent框架未来的判断
短期(1-2年):框架层面会有标准化,MCP协议会成为工具接入的标准,Agent间通信也会出现类似的标准。可靠性问题会通过更好的验证机制、回滚能力改善,但不会根本解决。
中期(3-5年):推理模型的进步会让Agent的规划能力显著提升,很多现在需要精心提示词才能可靠运行的场景,会变成开箱即用。自主决策的"自主度"会提高,但完全自主的Agent在高风险领域仍然是奢望。
长期:这个我没有把握预测,变量太多。但有一点我比较确定:Agent不会取代应用开发,而是会成为应用架构的一个组件,和数据库、消息队列一样,有明确的边界和适用场景。
当前的优先级应该是:把确定性高的部分用Agent可靠地实现,不要追求全自动,"AI辅助人工决策"往往比"AI全自动决策"更实用也更安全。
