Agent 不是多角色聊天,而是让大模型在边界内完成任务
Agent 这个词现在被用得很乱。有人把它理解成“会自己思考的 AI”,有人把它理解成“多个角色互相讨论”,也有人认为只要给大模型接几个工具,就已经是在做 Agent。
但从工程角度看,Agent 最重要的不是“看起来多自主”,而是:
它能不能在明确边界内,稳定完成一个多步骤任务。
这才更接近真实 AI 应用开发。

一、普通大模型调用解决的是“回答”,Agent 解决的是“任务”
普通 LLM 调用一般是这样的:
用户输入一个问题,模型返回一段文本。
比如用户问:
帮我写一段求职信。
模型直接生成一段求职信。
这个过程没有问题,但它本质上还是一次文本生成。模型并不知道用户的真实简历细节有没有支撑这段求职信,也不知道目标 JD 的关键要求是什么,更不知道哪些内容不能夸大。
RAG 往前走了一步:它会先检索知识库、文档或数据库,再让模型基于材料回答。它主要解决的是“回答有没有依据”。
但 Agent 要解决的不是单次回答,而是任务推进。它不只是“查资料再回答”,而是要根据任务目标,在多个步骤之间做选择:
它可能需要先判断用户意图,再决定要不要查询订单;
它可能需要先检索售后政策,再判断是否能退款;
它可能需要生成一个草稿,但不能直接提交;
它可能需要发现证据不足,然后暂停,要求用户补充信息。
也就是说,Agent 面向的不是单次回答,而是一个可执行的任务过程。
所以我更愿意把 Agent 看成一个系统问题:
Agent 不是把 prompt 写得更像人,而是把模型放进一个可以行动、可以观察、可以被约束的系统里。
二、Agent 和 Workflow 的区别
我不太建议一上来就从“自主规划”理解 Agent。
Anthropic 在《Building effective agents》里把 agentic systems 分成 workflow 和 agent。Workflow 是 LLM 和工具按照预设代码路径被编排;Agent 则是 LLM 可以动态决定自己的流程和工具使用方式。它们都属于 agentic system,但工程含义不同。
这个区分很重要。
如果你的任务路径本来就很清楚,比如:
- 解析 JD
- 解析简历
- 匹配能力项
- 找出缺口
- 生成定制简历
- 做证据检查
- 输出风险提示
那它更适合先做成 workflow,而不是一上来就交给 Agent 自己规划。
Workflow 的好处是可控、可测、可复盘。
Agent 的价值在于处理那些路径不固定、步骤数量不确定、需要根据中间结果不断调整的任务。
比如客服场景里,用户可能问的是物流、退款、发票、商品参数、投诉、优惠券、售后政策,也可能把多个问题混在一起。系统很难提前写死所有路径,这时 Agent 才有更明确的价值。
换成代码视角,区别更明显:
Workflow 的下一步主要由开发者写死。
Agent 的下一步主要由模型根据当前状态决定。
这不是说 Agent 没有代码控制,而是说代码负责提供工具、状态和边界,模型负责在这些边界里选择下一步。
但这不代表 Agent 可以无限自由。恰恰相反,Agent 越能行动,越需要边界。
三、用代码理解 Agent
从代码角度看,Agent 不是一个神秘概念。
它可以先理解成:
Agent = 一个由 LLM 驱动下一步决策的任务循环。
这里的“循环”不是说所有框架源码都必须写成 while,而是说 Agent 的运行语义大致相同:模型决定下一步,应用执行工具,工具结果写回状态,模型再基于新状态继续判断。
while (!state.isFinished()) {
AgentDecision decision = llm.decideNextStep(state, availableTools);
if (decision.isFinalAnswer()) {
return decision.answer();
}
if (decision.isToolCall()) {
policyGate.check(user, decision.toolName(), decision.arguments());
ToolResult result = toolExecutor.execute(
decision.toolName(),
decision.arguments()
);
state.addToolResult(result);
traceLog.record(decision, result);
}
if (decision.needHumanApproval()) {
return pauseForHumanReview(state);
}
}
这不是某个 Agent 框架的完整源码,而是 Agent 的核心运行语义。
普通 LLM 是:
String answer = llm.chat(userQuestion);
return answer;
RAG 是:
List<Document> docs = retriever.search(userQuestion);
String answer = llm.chat(userQuestion, docs);
return answer;
Workflow 是:
JdInfo jd = parseJd(input);
ResumeInfo resume = parseResume(input);
MatchResult match = matchResumeToJd(jd, resume);
RewriteResult rewrite = rewriteResume(match);
RiskReport risk = checkEvidence(rewrite);
return result;
Agent 是:
AgentState state = new AgentState(userGoal);
while (state.canContinue()) {
AgentDecision decision = model.decide(state, tools);
switch (decision.type()) {
case CALL_TOOL -> {
ToolResult result = executeTool(decision);
state.observe(result);
}
case ASK_USER -> {
return askUserForMoreInfo(decision.question());
}
case NEED_APPROVAL -> {
return waitForHumanApproval(decision.action());
}
case FINAL -> {
return decision.finalAnswer();
}
}
}
区别就在这里:
Workflow 的下一步是代码写死的。
Agent 的下一步是模型根据当前状态决定的。
这也对应了 Anthropic 对 workflow 和 agent 的区分:前者按预设路径执行,后者由模型动态决定流程和工具使用。
代码上,一个 Agent 至少有 5 个对象
不要先想 LangGraph、CrewAI、AutoGen。先想这 5 个类。
(1)AgentState:任务状态
public class AgentState {
private String goal;
private int step;
private List<Message> messages;
private List<ToolCallRecord> toolCalls;
private Map<String, Object> facts;
private boolean finished;
private boolean needHumanApproval;
}
它回答一个问题:
任务现在进行到哪一步了?
没有 AgentState,就不是连续任务,只是一次问答。
(2)AgentTool:工具
public interface AgentTool {
String name();
String description();
ToolResult execute(Map<String, Object> arguments);
}
比如电商客服 Agent 里可以有:
public class GetOrderTool implements AgentTool {
public String name() {
return "get_order";
}
public String description() {
return "根据 orderId 查询当前用户的订单状态";
}
public ToolResult execute(Map<String, Object> args) {
String orderId = (String) args.get("orderId");
// 查数据库 / 调接口
return orderService.getOrder(orderId);
}
}
Spring AI 的 Tool Calling 也是类似思想:模型提出工具调用请求,应用程序负责解析、执行工具、再把结果返回给模型。模型不是直接操作你的数据库。
(3)AgentDecision:模型决定下一步
public sealed interface AgentDecision permits CallTool, FinalAnswer, NeedHumanApproval {
}
public record CallTool(
String toolName,
Map<String, Object> arguments
) implements AgentDecision {
}
public record FinalAnswer(
String answer
) implements AgentDecision {
}
public record NeedHumanApproval(
String action,
String reason
) implements AgentDecision {
}
这里就是 Agent 和普通程序最大的区别。
普通程序是你写:
先查订单,再查政策,再生成回复。
Agent 是模型返回:
{
"type": "CALL_TOOL",
"toolName": "get_order",
"arguments": {
"orderId": "123456"
}
}
然后你的后端决定:
这个工具存不存在?
这个用户有没有权限?
这个 orderId 是不是他的?
这个动作需不需要人工确认?
(4)PolicyGate:权限边界
public class PolicyGate {
public void check(User user, String toolName, Map<String, Object> args) {
if (toolName.equals("submit_refund")) {
throw new NeedHumanApprovalException("退款提交必须人工确认");
}
if (toolName.equals("get_order")) {
String orderId = (String) args.get("orderId");
if (!orderService.belongsToUser(orderId, user.id())) {
throw new AccessDeniedException("不能查询他人订单");
}
}
}
}
边界不是 prompt 里写一句“不要越权”,而是代码里真的拦住。
OWASP 的 Excessive Agency 风险,本质就是 LLM 系统被授予过多功能、权限或自主性后,可能造成破坏性动作;所以工具权限、人工确认、最小授权必须在系统层实现。
(5)AgentRunner:核心循环
public class AgentRunner {
private final LlmClient llm;
private final ToolRegistry toolRegistry;
private final ToolExecutor toolExecutor;
private final PolicyGate policyGate;
private final TraceLog traceLog;
public AgentResult run(User user, String goal) {
AgentState state = new AgentState(goal);
while (!state.isFinished() && state.getStep() < 10) {
AgentDecision decision = llm.decideNextStep(state, toolRegistry.availableTools());
if (decision instanceof FinalAnswer finalAnswer) {
state.finish();
return AgentResult.success(finalAnswer.answer());
}
if (decision instanceof NeedHumanApproval approval) {
return AgentResult.waitingForApproval(approval.action(), approval.reason());
}
if (decision instanceof CallTool callTool) {
policyGate.check(user, callTool.toolName(), callTool.arguments());
ToolResult result = toolExecutor.execute(
callTool.toolName(),
callTool.arguments()
);
state.addToolCall(callTool, result);
traceLog.record(state, callTool, result);
state.nextStep();
}
}
return AgentResult.failed("Agent stopped: max steps reached.");
}
}
OpenAI Agents SDK 里所谓 agent loop,本质也是:处理工具调用,把结果送回 LLM,然后继续运行直到任务完成;同时配套 guardrails、sessions、tracing 等工程能力。
用电商客服理解一次完整执行
用户问:
我的订单签收三天了,商品破损,可以退吗?
Agent 第一次判断:
{
"type": "CALL_TOOL",
"toolName": "get_order",
"arguments": {
"orderId": "A1001"
}
}
后端执行:
policyGate.check(user, "get_order", args);
ToolResult order = getOrderTool.execute(args);
state.addToolResult(order);
工具返回:
{
"orderId": "A1001",
"status": "SIGNED",
"signedDaysAgo": 3,
"productCategory": "electronics"
}
Agent 第二次判断:
{
"type": "CALL_TOOL",
"toolName": "get_refund_policy",
"arguments": {
"category": "electronics"
}
}
工具返回:
{
"category": "electronics",
"returnWindowDays": 7,
"needDamagePhoto": true,
"autoRefundAllowed": false
}
Agent 第三次判断:
{
"type": "FINAL",
"answer": "你的订单签收 3 天,仍在 7 天售后窗口内。但商品破损需要上传图片凭证,我可以先帮你生成退款申请说明,提交退款前需要你确认。"
}
这就是一个最小 Agent 的运行过程。
它不是一次性回答,而是:
看当前状态
→ 决定查订单
→ 得到订单结果
→ 决定查政策
→ 得到政策结果
→ 判断不能直接退款
→ 给出受边界约束的答案
所以,从代码视角看,Agent 不是让模型直接控制系统,而是让模型提出下一步动作,再由应用程序判断、执行、记录和约束。
四、Agent 的核心不是“自主”,而是工具、状态和边界
一个更工程化的 Agent 定义可以是:
Agent = LLM + Tools + State + Control Loop + Guardrails
拆开看:
LLM 负责理解任务和选择下一步。
Tools 负责连接数据库、订单系统、知识库、搜索服务等外部能力。
State 负责记录任务进展、工具调用历史和中间结果。
Control Loop 负责把模型决策、工具执行和结果反馈串起来。
Guardrails 负责限制模型不能越权、不能乱调用工具、不能直接执行高风险动作。
这里最容易被忽略的是工具调用的安全边界。
Spring AI 官方文档对 tool calling 的说明很清楚:虽然通常说 tool calling 是模型能力,但实际执行工具调用逻辑的是客户端应用。模型只能请求工具调用并提供参数,真正执行工具、返回结果的是应用程序本身;模型并不会直接获得工具背后的 API 权限。
这句话非常关键。
因为它说明 Agent 不是让模型直接控制系统,而是让模型提出行动意图,再由应用层判断是否执行。
比如电商客服 Agent 面对“我的订单能退吗?”这个问题时,它不应该直接回答“可以退”。
更合理的方式是:先查询订单,再查询售后政策,再结合订单状态、商品类目和平台规则生成回复。如果涉及退款提交,就只能生成草稿,不能直接执行。
这才是可上线的 Agent。
五、Agent 的真正风险:从“回答错误”变成“行动越界”
普通大模型回答错,风险主要在内容层。
Agent 一旦接入工具,风险就进入系统层。
它可能查错数据,调用错工具,传错参数,泄露敏感信息,执行不该执行的操作,或者在错误前提下连续行动。
OWASP LLM Top 10 里专门列出了 Prompt Injection、Insecure Plugin Design、Excessive Agency 等风险。其中 Excessive Agency 指的是给 LLM 过多、未受约束的行动自主权,可能破坏可靠性、隐私和信任。
这也是为什么我不赞成一开始就做“全自动 Agent”。Agent 安全不能只靠 prompt,而必须靠工具权限、参数校验、人工确认和审计日志这些系统层设计。
真正的工程顺序应该是:
先让模型会读。
再让模型会查。
再让模型会生成草稿。
再让模型在低风险场景自动执行。
最后才考虑高风险动作的半自动化或自动化。
对于工具权限,我更倾向于分四层:
READ:只读查询,可以自动执行。
例如查询订单状态、查询物流、检索政策文档。
DRAFT:只生成草稿,不真正提交。
例如生成退款说明、工单回复、邮件草稿。
WRITE_REVIEW:会改变系统状态,必须人工确认。
例如提交退款申请、修改用户资料、发送正式邮件。
DANGEROUS:默认禁止。
例如删除数据、批量修改权限、执行任意命令。
如果一个 Agent 系统没有这个权限分层,那它本质上还不能算生产级 Agent,只是一个接了工具的聊天机器人。
六、一个更接近真实项目的 Agent 示例
假设我们要做一个跨境电商客服 Agent。
用户问:
我这个订单已经签收三天了,商品有破损,能不能退?
一个不可靠的 AI 可能会直接回答:
一般情况下,签收七天内可以退货。
这句话听起来合理,但它不一定正确。
因为真实判断至少需要几个条件:
订单是否真实存在?
订单是不是当前用户的?
商品类目是什么?
是否支持无理由退货?
破损是否需要上传凭证?
当前是否超过售后时间?
平台政策和商家政策是否冲突?
是否需要人工客服介入?
所以更合理的 Agent 流程应该是:
用户问题
→ 意图识别:售后 / 退款 / 商品破损
→ 查询订单状态
→ 检索售后政策(RAG 在这里是证据工具)
→ 检查商品类目
→ 判断是否需要图片凭证
→ 生成客服回复
→ 标注证据来源
→ 如果涉及退款提交,进入人工确认
→ 记录整次 Agent Run
在这个流程里,模型不是凭常识回答,而是在工具和证据的约束下完成任务。
这就是 Agent 相比普通聊天机器人的真正区别:它不是凭常识直接回答,而是在工具、证据和权限边界内推进任务。
七、为什么不要一开始做多 Agent
很多 Agent 教程喜欢从多 Agent 开始:
一个产品经理 Agent,一个架构师 Agent,一个开发者 Agent,一个测试 Agent,大家互相讨论,最后输出结果。
这种演示很容易吸引眼球,但工程价值未必高。
多数真实业务问题,不是靠“多几个角色说话”解决的,而是靠更清楚的任务边界、更可靠的工具、更稳定的状态记录和更严格的输出校验解决的。
多 Agent 只有在这些场景下才更有必要:
不同角色确实需要不同职责;
不同 Agent 拥有不同工具权限;
需要一个 Agent 审查另一个 Agent 的输出;
任务路径复杂到单一 workflow 难以维护;
系统需要长期运行和异步协作。
否则,多 Agent 很可能只是增加延迟、成本和调试难度。
所以第一篇不应该从多 Agent 开始,而应该先讲清楚单个 Agent 如何完成任务、如何调用工具、如何记录状态、如何控制边界。
八、我对 Agent 的第一性原则
如果让我用一句话定义 Agent,我不会说它是“自主智能体”。
我更愿意说:
Agent 是一个让大模型在工具、状态和权限边界内完成任务的工程系统。
这个定义不够炫,但更适合真实开发。
因为 Agent 的难点从来不只是“让模型更聪明”,而是:
它能调用什么工具;
它不能调用什么工具;
它每一步是否有依据;
它的工具调用是否可追踪;
它在证据不足时能不能停下来;
它在高风险动作前能不能交给人;
它失败后能不能复盘。
所以 Agent 专题不应该从框架开始,不应该从多 Agent 开始,也不应该从“让 AI 自己干活”开始。
它应该先回答一个更基础的问题:
当我们说要做 Agent 时,我们到底是在做一个聊天机器人,还是在做一个可控的任务执行系统?
如果只是聊天,普通 LLM 就够了。
如果只是查资料,RAG 就够了。
如果路径固定,Workflow 就够了。
如果任务路径不确定,需要工具、状态、反馈和权限边界,才真正进入 Agent。
下一篇,我会解释 Agent 核心术语:ReAct、Tool Calling、State、Memory、Workflow 到底是什么?
参考资料
- Anthropic:Building effective agents
- OpenAI Agents SDK:Agent loop、Tools、Sessions、Tracing、Guardrails
- Spring AI Reference:Tool Calling
- OWASP LLM Top 10:Excessive Agency
- ReAct:Synergizing Reasoning and Acting in Language Models
- Toolformer:Language Models Can Teach Themselves to Use Tools
我是 Ryan,一个专注于可信 AI 应用工程的开发者,我的个人技术博客,研究如何让 AI 生成从“看起来对”走向“有证据、可追溯、可验证”。
更多推荐




所有评论(0)