很多人用过 ChatGPT、豆包的聊天功能:你问一句,它答一句,这一轮交流就结束了。但如果你用 Cursor 写过代码,看它自己搜索代码、修改文件、运行测试直到通过;用 workbuddy 调研过一个课题,看它反复检索、阅读,最后交出一份报告——你用到的就是另一种形态的产品:AI Agent。
这些产品做的事情各不相同,但有一个共同点:不再停留在“一问一答”,而是能自己规划步骤、调用工具、根据执行结果调整做法。AI Agent 凭什么能自己完成任务?答案可以先浓缩成一个公式:AI Agent = 大语言模型(大脑)+ 上下文(眼睛)+ 工具(手脚)。
一、基本公式:大脑 + 眼睛 + 手脚
大语言模型是大脑,负责理解和决策:听懂你的要求、把任务拆成步骤、决定每一步做什么。它的能力来自两个阶段——预训练阶段读过海量资料,构成了它的世界知识;后训练阶段通过大量练习,固化了它的决策策略。GPT、Claude、豆包、Kimi 都属于这一类模型。
上下文是眼睛:模型做每一个判断时,能看到的全部信息。上下文的内容直接决定它能做出多好的判断。
工具是手脚:模型能做的所有外部操作。不只是调用几个现成接口,还包括按需加载的技能、动态生成的代码、把子任务委托给其他 Agent。
聊天式 AI 和 AI Agent 的差异,可以概括为下表:
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
二、上下文
Agent通过API调用大模型,本质是把一份“消息列表”发给它,主要包括以下部分内容:
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
一份简化的消息列表示例如下:
{
"messages": [
{"role": "system", "content": "你是财务助理,负责汇总公司收入"},
// ↑ system:岗位说明书,由产品开发者预先写好
{"role": "user", "content": "帮我统计今年前三个季度的收入总和"},
// ↑ user:你的提问内容
{"role": "assistant", "content": "我先查询各季度数据",
"tool_calls": [{"name": "查收入", "参数": {"季度": "Q1-Q3"}}]},
// ↑ assistant:模型上一轮的回复(含它发起的工具调用)
{"role": "tool", "content": "Q1:250 万美元;Q2:210 万欧元;Q3:180 万英镑"}
// ↑ tool:工具执行结果,由系统自动写入,不是你输入的
]
}
这份列表就是模型的全部上下文。注意:API 本身不保存对话记录,每一轮请求都要把完整历史重新传一遍。对话越长,这份列表就越长。而模型一次能处理的信息量有上限,称为上下文窗口。常见模型从几万到上百万 token 不等,一个 token 大致相当于一个汉字或一个英文单词片段。窗口就是视野的边界:装不下的内容,模型就看不见;上下文管理要做的,正是把有限窗口里最该看见的信息放进去。
RAG:给眼睛临时补充资料
模型的训练数据有截止日期,而且公司内部制度、个人私有资料本来就不在训练数据里。要让模型回答这类问题,做法是 RAG(检索增强生成):先把问题和资料库做一次检索,找出相关片段;把片段注入上下文;再让模型基于这些内容生成答案。三步分别对应“检索、增强、生成”。
注意:模型并没有因此“学会”RAG资料库中的东西,它只是在这一次回答时“看到”了相关片段。这也是 RAG 和训练的区别——一个临时,一个永久。
用户记忆:跨会话的持久记忆
会话内的上下文是临时的:对话关闭,内容就没了。要跨会话记住信息,需要把关键内容存成用户记忆。比如你订机票时说过“喜欢靠窗座位、要素食餐”,Agent 把这两条偏好存下来,下次订票时自动填进上下文。记忆是持久的,上下文是临时的,两者配合,Agent 才既记得你是谁,又看得见当前任务。
RAG、记忆和上下文是什么关系
读到这里需要澄清一个容易混淆的问题:RAG 和用户记忆本身并不是上下文的组成部分,它们是“往请求里补充信息”的两种机制。上下文指的是某一时刻发给模型的那份消息列表;RAG 和记忆的产出,最终会被写进这份列表里。对应关系如下:
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
所以,第一个 API 示例里出现的四个角色,就是消息列表的全部来源:system 由开发者写,user 是你的提问,assistant 是模型的回复,tool 是工具结果;RAG 和记忆不新增角色,它们的内容最终也以这四种角色之一出现在请求里,内容什么时候注入、要不要注入是由Agent决定的。对模型来说,它分不清一段文字是检索来的还是记忆来的——一切都是上下文。
三、工具与工具调用
工具调用的完整流程分四步:① Agent在请求里声明有哪些工具可用;② 模型自己决定要不要调用、调用哪个、传什么参数;③ Agent执行工具,把结果追加到上下文;④ 模型根据结果决定下一步。整个过程在 API 层面长这样(简化示例):
第一步,请求里声明有哪些工具可用(tools 部分由开发者预先配置,模型据此学会工具怎么用):
{
"tools": [
{"name": "查汇率", "description": "查询某货币兑美元的汇率",
"参数": {"货币": "文本,如\"欧元\""}}
],
"messages": [ /* 上面那份对话 */ ]
}
第二步,模型决定调用工具,返回的是调用请求而不是答案(注意:执行动作的是Agent,模型只是“下指令”):
{"tool_calls": [{"name": "查汇率", "参数": {"货币": "欧元"}}]}
第三、四步,Agent执行工具,把结果连同历史一起传回去(role 为 tool 的这条消息由Agent写入),模型给出最终回答:
{
"messages": [
/* ……之前的全部消息…… */
{"role": "assistant", "tool_calls": [{"name": "查汇率", "参数": {"货币": "欧元"}}]},
{"role": "tool", "content": "1 欧元 = 1.09 美元"}
]
}
→ 模型回复:“已换算,欧元收入折合 228.9 万美元。”
工具按用途可以分成五类:
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
工具生态方面,过去每个应用接入工具都要单独开发一遍,重复劳动很多。近两年出现的 MCP(模型上下文协议)是统一的工具接入标准:工具按标准做成插件,任何支持 MCP 的应用都能直接调用,接入接近“安装即用”。它的出现让工具生态开始像浏览器扩展一样积累,同一个工具可以被多个 Agent 共享。
四、Agent 如何一步步干活:ReAct 循环
第三节示例“请求—返回—回传”的往返,只发生了一次。真实任务往往要往返很多次,每次往返对应一轮“行动”和“观察”,再加上模型每次的内部思考,就构成了 Agent 执行任务的基本循环:思考 → 行动 → 观察结果 → 再思考。业内把这个模式称为 ReAct。
还是用第三节的例子,完整走一遍:你的任务是汇总三个季度的收入——250 万美元、210 万欧元、180 万英镑。下面每一步都同时说明两件事:用户在界面上看到什么,以及Agent 发给大模型的 API 里包含了什么。
第 1 轮 你发起提问,模型决定先查汇率
你在对话框输入任务。此刻 Agent 接收到的信息有三样:开发者预置的岗位说明书(system)、可用的工具清单(tools)、你的这条提问(user)。它把这三样组装成第一份 API 请求发给大模型:
// —— 第 1 轮 Agent 组装好的第一份请求 ——
{
"messages": [
{"role": "system", "content": "你是财务助理,负责汇总公司收入"},
// ↑ 岗位说明书:开发者预先写好,每次请求都带着
{"role": "user", "content": "三个季度收入:250 万美元、210 万欧元、180 万英镑,求总和"}
// ↑ 你的提问:此刻列表里只有这两条消息
],
"tools": [
{"name": "查汇率", "description": "查询某货币兑美元的汇率",
"参数": {"货币": "文本,如\"欧元\""}},
{"name": "代码计算", "description": "执行算术表达式",
"参数": {"算式": "文本,如\"1+2\""}}
]
// ↑ 工具清单:告诉模型它有哪些“手脚”、分别怎么用
}
模型读完这份列表,经过一轮思考,返回的内容不是答案,而是一个工具调用请求——它判断三种货币不能直接相加,需要先查两种外币的汇率:
// —— 第 1 轮 工具调用请求——
{"tool_calls": [
{"name": "查汇率", "参数": {"货币": "欧元"}},
{"name": "查汇率", "参数": {"货币": "英镑"}}
]}
// ↑ 模型的“思考结论”:先查汇率,再算总和
注意,模型这一步没有回答“总和是多少”。它认为自己缺少信息,决定先去查。这个判断就是循环里的“思考”,返回调用请求就是“行动”。用户界面上,Agent 此刻显示一行进度提示,比如“正在查询欧元、英镑汇率”。你能看到它没有直接给答案,而是先去查数据。
第 2 轮 工具执行、结果回填,模型决定算数
真正执行工具的不是模型,而是 Agent 的系统代码。它调用汇率接口拿到真实汇率(1 欧元 = 1.09 美元、1 英镑 = 1.27 美元),然后把模型上一轮的调用请求和这次的结果一起追加进消息列表,再次发给模型:
// —— 第 2 轮 ——
{
"messages": [
{"role": "system", "content": "你是财务助理,负责汇总公司收入"},
{"role": "user", "content": "三个季度收入:250 万美元、210 万欧元、180 万英镑,求总和"},
{"role": "assistant", "tool_calls": [
{"name": "查汇率", "参数": {"货币": "欧元"}},
{"name": "查汇率", "参数": {"货币": "英镑"}}]},
// ↑ 第 1 轮的调用请求:原样保留在历史里
{"role": "tool", "content": "1 欧元 = 1.09 美元"},
{"role": "tool", "content": "1 英镑 = 1.27 美元"}
// ↑ 本轮新增:工具执行结果,系统查完汇率后写入,这就是“观察”
]
}
模型这次“看到”了汇率,经过思考又返回一个调用请求:用代码计算工具求和。用户界面上,Agent 展示出查到的汇率,接着提示“正在计算……”。你看到的是:它查到了数据,现在要算数了。
第 3 轮 拿到结果,模型给出最终回答
Agent 执行代码计算工具,得到 687.4 万美元,回填进列表,第三次发给模型。这一次,模型返回的不再是工具调用,而是一段普通文本——最终答案:
// —— 第 3 轮 ——
{
"messages": [
{……前面所有消息原样保留……},
{"role": "assistant", "tool_calls": [{"name": "代码计算", "参数": {"算式": "250+210×1.09+180×1.27"}}]},
// ↑ 第 2 轮的调用请求,此刻作为历史回显
{"role": "tool", "content": "总和 = 687.4 万美元"}
// ↑ 第 2 轮的执行结果,此刻作为历史回显
]
}
→ 模型这次返回纯文本:“年度总收入约为 687.4 万美元。”
模型的回复里不再包含工具调用请求,Agent 判断任务完成,把答案展示给你。从你的视角看,整个过程是:你提一个问题,Agent 显示几行进度提示和中间数据,最后给出答案;但从 API 层面看,这中间发生了三轮请求、两次真实的工具执行。
三轮走完,能得出三条规律
第一,用户只做两件事:发起任务、收到结果。中间的“思考”发生在模型内部,用户看不到;用户看到的是 Agent 在界面上展示的进度提示和中间数据。展示哪些、不展示哪些,由产品设计决定——有的产品把每一步过程都列出来,有的只显示最终结果。
第二,循环本身由 Agent 系统代码驱动。组装请求、调用模型 API、执行工具、回填结果,这些步骤都不属于模型,属于 Agent 应用本身。模型只负责“看和想”,动手的是系统。
第三,模型每一轮都看着完整的消息列表做决策。列表逐轮变长、历史全部保留,这份完整记录称为轨迹。因为每轮都能看到轨迹,模型清楚任务进行到哪一步、用过什么方法、得到什么结果,不会重复执行已经完成的动作。循环何时结束?当模型的回复里不再包含工具调用请求时——它认为任务完成了。
五、从“能演示”到“能可靠干活”:Harness
演示里运行正常的 Agent,放到真实环境可能出现各种问题:选错工具、编造不存在的参数、出错后无法恢复。业内把解决这类问题的工程体系称为 Harness(直译为“马具”)——模型像一匹强健但不可预测的马,Harness 是缰绳和配套的保障系统。它的作用不是限制马的力气,而是把力气引导到正确的方向。以Harness工程视角展开,Agent=LLM+上下文+工具+约束+验证+纠正=model+Harness。
Harness 的三层保障,以“处理退款申请”的 Agent 为例:
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
按灵活程度划分,Agent 有两种典型使用模式:
✅ 工作流:步骤预先固化。
示例:订机票固定流程「查航班 → 选航班 → 填信息 → 支付」。
优势:安全可控,适合规则明确的标准化场景。
✅ 自主 Agent:由模型临场动态决定执行步骤。
示例:帮我调研一个陌生行业并输出行业简报。
优势:适配开放性、不确定性较强的复杂任务。
实际工程大多采用混合模式:
核心关键流程用工作流锁死;需要灵活研判的环节交给自主Agent;同时预留人工接管入口,高风险操作主动暂停、请求确认。
构建 Agent 系统的三条工程原则
🔹 保持简单能一步完成就不拆分为多步,流程链路越短,出错概率越低。
🔹 保持透明每一步执行过程可观测、可追溯,故障能够定位到具体环节。
🔹 设计好工具接口入参定义清晰,降低误用概率,从源头规避误操作。
直白来讲:Agent 项目风险大多不在于模型能力本身, 而来自「模型认知的行为」与「系统实际执行行为」之间的偏差。 优秀的工程保障,本质就是把这类偏差控制在可感知、可排查的范围之内。
市面上的主流产品,Harness 各是什么做法
Harness 不是理论概念,主流 Agent 产品都在做,只是侧重点不同:
🔹 Claude Code|终端编程 Agent
Harness特点:核心循环极简,复杂度收敛于Harness层;工具独立权限门控,拒绝优先;上下文多级压缩;限制子Agent嵌套深度;设计哲学:简化循环,强化Harness防护
🔹 Cursor|编程 Agent
Harness特点:聚焦上下文与运行隔离;基于代码结构分块检索,仅推送相关片段;先输出计划再执行;多Agent在隔离副本工作,开发者审阅合并
🔹 LangGraph|开发框架
Harness特点:显式状态图驱动;预定义节点、分支、循环;步骤存档可回溯重放;支持人工审批打断;适配强流程、高审计要求场景
🔹 OpenAI Agents SDK|开发框架
Harness特点:极简Harness;轻量Agent协作,依靠任务转交;内置输入输出护栏、运行追踪;上手门槛低,流程控制粒度偏粗
🔹 Dify、扣子(Coze)|低代码平台
Harness特点:Harness为可视化画布,拖拽编排流程,检索/插件均为现成节点;Dify开源可私有化,面向企业复杂流程;扣子零代码,生态强,侧重快速搭建与多渠道发布
🔹 WorkBuddy(腾讯)|桌面/办公 Agent
Harness特点:Harness作为核心引擎;规划器拆解任务、工具网关统一接入;跨会话记忆、全步骤轨迹记录;高危操作人工确认;分层按需注入上下文;支持长期定时任务循环
🔹 Trae(字节跳动)|编程Agent / AI IDE
Harness特点:MIT开源,模型可插拔;工具Docker容器隔离;完整轨迹记录,支持回放分析;主打透明、可复现
🔹 DeepSeek Harness(dsh)|开源Agent框架
Harness特点:理念
Agent = Model + Harness;一切皆插件,组件均可替换;沙箱隔离、敏感操作审批、全量事件日志;支持回放、续跑、会话分叉;前缀缓存降低长对话开销
对比可以发现一个共同点:约束、验证、纠正这三层保障每一款产品都做了,差别在于把保障放在哪一层:
-
Claude Code 放在权限门控和上下文压缩层 -
Cursor 放在上下文检索和运行隔离层 -
Trae 放在容器隔离和轨迹回放层 -
WorkBuddy 放在上下文组织和审批确认层 -
DeepSeek Harness 把每个环节都做成可替换的插件 -
LangGraph 放在流程图结构本身,低代码平台放在画布节点里。
选型的思路也因此清晰:
-
任务越开放,越需要 Claude Code、Cursor、Trae 这类“模型自主 + Harness 兜底”的路线; -
流程越固定、审计要求越高,越适合 LangGraph、Dify 这类“结构先行”的路线; -
需要自建系统或频繁更换模型,可以研究 WorkBuddy、DeepSeek Harness 这类把 Harness 做成核心能力的产品与框架。
写在最后
总结三个要点:AI Agent 由大语言模型(大脑)、上下文(眼睛)、工具(手脚)组成,模型只能基于看到的信息做判断;它靠“思考—行动—观察”的循环推进任务,每一轮都带着完整轨迹;而能不能可靠干活,关键在模型之外的 Harness——约束、验证、纠正。




