Skip to content

Agent 机制与构建(Agentic System)

前面几章,我们一直在和 AI “对话”。这一章,我们要进入一个新层次:让 AI 自己行动。

Agent 不是“更聪明的聊天机器人”。差别在于:它能在后台自主执行多步操作,并根据中间结果调整下一步。

要理解 Agent,你需要知道它内部是怎么运转的。

先判断:脚本、Workflow,还是 Agent?

做自动化时,不要一上来就问“怎么做 Agent”。先问一个更朴素的问题:这件事的执行路径是不是固定的?

如果路径固定,优先用脚本或传统自动化。比如每天把一个文件复制到备份目录、把 CSV 转成 Excel、按固定格式重命名图片。这类任务不需要 Agent,写清楚规则就能稳定执行。

如果路径大体固定,但其中某一步需要 AI 判断,可以用 Workflow(工作流)。比如“先提取会议录音,再生成摘要,再让人工确认待办事项”。每一步是什么很清楚,只是某些步骤用 AI 来完成。

如果路径不固定,Agent 才开始有价值。比如“帮我调查这个 bug 的原因”,它可能先读日志,再搜代码,再跑测试,发现方向不对后换一条路径。这种任务需要根据环境反馈不断调整,固定流程很难提前写死。

可以用一个简单的判断:

  • 脚本:规则明确,输入输出稳定。
  • Workflow:步骤明确,中间需要 AI 处理内容。
  • Agent:目标明确,但路径需要边走边判断。

Agent 的灵活性来自不确定性。它能自己调整,也可能自己跑偏。高风险流程里,可确定的部分仍然应该交给代码、测试和审批;让 Agent 负责探索、调度和补全,而不是替代所有确定性执行。

Agent 内部机制:Loop、Run、Snapshot

Loop:感知→思考→行动→观察

Agent 的基本结构是一个循环(Loop)。每一轮循环包含四个步骤:

  1. 感知(Perceive):读取当前状态:用户说了什么、环境是什么样、上一步的结果是什么。
  2. 思考(Think):分析当前状态,决定下一步该做什么。
  3. 行动(Act):执行一个具体操作:调用工具、写文件、发请求。
  4. 观察(Observe):检查行动的结果,更新状态。

然后回到第 1 步,开始下一轮循环。直到任务完成或遇到无法继续的情况。

用伪代码表示:

text
while (任务未完成) {
  当前状态 = 感知()
  下一步 = 思考(当前状态)
  结果 = 行动(下一步)
  更新状态(结果)
}

这个循环可能执行 3 次,也可能执行 30 次。每次循环都是一次“试错+调整”的过程。

你也可以把 Agent 理解成一个非确定性的 REPL。普通 REPL 是“读入、执行、输出、继续”;Agent 多了一步环境观察,并且下一步怎么做由模型判断。它像一个会自己调度工具的工作流执行器,但这个执行器不是完全确定的。

Run:一次完整的任务执行

Run 是指从接收任务到完成(或失败)的整个过程。一次 Run 包含多轮 Loop。

比如你让 Agent “帮我整理今天的会议纪要”,一次 Run 可能是:

  • Loop 1:读取会议录音文件。
  • Loop 2:调用语音转文字工具。
  • Loop 3:提取重点信息和待办事项。
  • Loop 4:格式化输出。
  • Loop 5:写入文件。

每一轮 Loop 都在推进任务,直到最终完成。

Snapshot:上下文快照

Agent 在执行过程中,需要记住很多东西:用户的需求、已经做了什么、中间结果是什么。这些信息的集合就是一个快照(Snapshot)。

Snapshot 的作用:

  • 上下文恢复:如果 Agent 中断了(比如网络问题),可以从 Snapshot 恢复,不需要从头开始。
  • 回退:如果某一步做错了,可以回退到之前的 Snapshot。
  • 调试:你可以查看每个 Snapshot,理解 Agent 的决策过程。

Memory:Agent 的记忆系统

Snapshot 解决了“执行过程中的状态管理”,但 Agent 还面临另一个问题:它怎么记住过去发生的事情?

这就是记忆系统(Memory)要解决的问题。

短期记忆:对话上下文

每次和 AI 对话,你们的聊天记录就是短期记忆。模型的上下文窗口(Context Window)决定了它能“记住”多少内容。

问题在于:上下文窗口是有限的。当对话变长,早期的内容会被截断。你可能遇到过这种情况:聊了几十轮之后,AI 忘了你最开始说的需求。

应对方式:

  • 摘要压缩:让 AI 定期总结之前的对话,用摘要替代完整历史。
  • 重点信息提取:把事实、决策、约束单独记录下来,每次请求时带上。
  • 滑动窗口:只保留最近 N 轮对话,更早的自动丢弃或归档。

长期记忆:跨会话保存的事实与偏好

短期记忆在对话结束后就消失了。长期记忆是跨会话的:Agent 下次启动时,还能检索到你上次告诉它的偏好、项目事实或历史决策。

这里要和 Rules 文件、SOUL.md 这类配置区分开。它们更像持久化指令或项目治理规则,用来约束 Agent 怎么工作;长期记忆更像可检索的信息记录,用来保存“你是谁、项目做过什么决定、哪些事实下次还要用”。不要把会变化的动态事实长期塞进规则文件里,否则容易过期,也会把隐私和错误信息固定到每次对话中。

实现长期记忆的常见方式:

  • 专门的记忆文件:把用户偏好、项目事实、历史决策写入可维护的记录文件,并定期清理过期内容。
  • 工作区检索:如果信息已经在项目文件、日志或文档里,优先让 Agent 实时检索,而不是把内容复制进记忆。
  • 向量数据库:把文本转换成向量(Embedding),存入数据库。查询时通过语义相似度检索相关内容。这是 RAG 的基本原理,后面的附录会详细讲。
  • 结构化数据库:把用户偏好、历史决策等存入传统数据库。

记忆系统的实际问题

在构建有记忆的 Agent 时,你会遇到几个现实问题:

信息过载:记住所有东西不现实,也不好用。Agent 需要学会“遗忘”:丢弃过时的、不再相关的信息。

信息冲突:用户在不同时间说了矛盾的话。Agent 需要判断哪个是最新的、最准确的。

隐私风险:记住的信息越多,泄露的风险越大。敏感信息不该进入长期记忆。

幻觉放大:如果 Agent 基于错误的记忆做出判断,错误会被放大。记忆的内容也需要验证。

提醒:记忆不是越多越好。给 Agent 记住太多东西,反而可能让它变得混乱。重点是记住正确的东西,而不是所有东西

很多时候,最好的“记忆”不是让 Agent 记住一切,而是让项目本身有清晰结构。文档、日志、目录命名、任务记录写清楚了,Agent 可以随时检索最新的一手信息。长期记忆更适合保存少量稳定偏好和关键决策,不适合变成用户人生履历。

Tool Use:让 AI 真的“动手”

Agent 要能行动,就需要工具使用(Tool Use)。没有工具,Agent 就只是一个聊天机器人。

常见工具:

  • 文件系统:读写文档、整理资料。
  • 终端命令:跑脚本、执行构建、安装依赖。
  • 外部 API:拉取数据、调用服务、发送通知。
  • 浏览器:访问网页、提取信息。

当你告诉 Agent “帮我把这段代码跑一下”,它不是在“模拟”运行,而是真的调用了终端执行命令。

一个工具调用的过程:

text
Agent 决定需要调用什么工具
  → 构造工具调用的参数
  → 执行工具
  → 获取结果
  → 基于结果决定下一步

工具设计:把确定性交给工具

工具不是越大越好。一个好工具,应该把确定性的事情做稳定,把不确定的判断留给 Agent。

设计工具时,可以抓住几个原则:

  • 职责单一:一个工具只做一类事。read_filewrite_filerun_test 比“项目管理工具”更容易被正确调用。
  • 参数清楚:参数名要直接,类型要稳定。不要让 Agent 在一个长字符串里自己猜路径、命令和选项。
  • 返回可判断:结果里要能看出成功、失败、错误原因和下一步线索。只返回一段模糊文本,会让 Agent 很难修正。
  • 副作用可控:读取、预览、写入、删除最好分开。危险操作要放到 Ask 或人工确认之后。
  • 失败可恢复:工具失败时,要给出明确错误,而不是静默失败。Agent 只有看到问题,才可能调整下一步。

这就是为什么高风险流程不能完全靠自然语言描述。自然语言适合表达意图,工具负责把确定动作做稳。

提醒:工具权限要最小化。能不开放的,就先不开放。你不会给实习生无限的公司权限,同理,Agent 的工具权限也需要控制。

MCP:工具的聚合标准

当你有多个工具需要接入 Agent 时,逐个适配会很麻烦。MCP(Model Context Protocol)是一个开放协议,它把各种工具统一成标准格式,让 Agent 能自动理解和调用。你不需要为每个工具写专门的适配代码。

权限模型:Ask、Skip、Deny

当 Agent 在后台自主执行时,需要先回答一个问题:哪些操作要你确认?

一个常见的权限模型是三级:

  • Ask(询问):执行前必须得到你的确认。适用于不可逆操作:删除文件、发送邮件、发布代码。
  • Skip(跳过):不需要确认,直接执行。适用于低风险操作:读取文件、运行测试、格式化代码。
  • Deny(禁止):不允许执行。适用于高风险操作:访问敏感目录、执行危险命令。

配置权限的原则:

  • 默认保守:不确定的操作,默认 Ask。
  • 逐步放开:用熟了之后,把高频低风险操作改为 Skip。
  • 永远禁止:某些操作永远不该自动执行,保持 Deny。
text
读取文件 → Skip(低风险,直接执行)
运行测试 → Skip(低风险,直接执行)
修改代码 → Ask(中风险,确认后执行)
删除文件 → Ask(高风险,确认后执行)
格式化硬盘 → Deny(永远不允许)

安全意识

Agent 能“动手”意味着它也可能“犯错”。安全不是事后补救,而是从一开始就该考虑的事情。

零信任

不要默认 Agent 的输出都是对的。尤其是:

  • 代码:AI 生成的代码可能有 bug,也可能有安全漏洞。
  • 建议:AI 给出的操作建议可能不适合你的具体场景。
  • 信息:AI 可能基于过时或错误的信息做出判断。

原则:永远验证,永远不盲信。

数据脱敏

敏感信息不该直接喂给 Agent:

  • 密码、密钥、Token。
  • 个人隐私数据(身份证号、手机号等)。
  • 公司内部机密。

如果必须涉及敏感数据,先做脱敏处理:用占位符替代真实值。

权限边界

上一节讲的权限模型,本质上就是在划定安全边界。Agent 能做什么、不能做什么,需要明确。

记住这个原则:Agent 的权限应该小于你的权限。它不需要知道所有事情,也不需要能做所有事情。

动手练习:实现一个简单的 Agent Harness

现在,我们动手实现一个最简单的 Agent Harness(Agent 运行框架)。不需要复杂的框架,用最基础的代码就能理解 Agent 的基本机制。

用你熟悉的语言(JavaScript、Python、或其他),实现以下功能:

第一步:定义工具

创建一个工具注册表,至少包含三个工具:

  • 读取文件
  • 写入文件
  • 执行命令

每个工具接收参数,返回执行结果。先用模拟数据,不需要真的读写文件。

第二步:实现 Loop

实现一个循环函数,接收用户任务描述,按以下流程执行:

  1. 感知:获取当前状态(任务描述、历史执行记录)。
  2. 思考:决定下一步做什么。调用 LLM,让它根据当前状态选择工具和参数。
  3. 行动:调用对应的工具。
  4. 观察:把工具返回的结果记录到历史中。
  5. 判断:任务是否完成?未完成则回到第 1 步,已完成则返回结果。

设置一个最大循环次数,防止死循环。

第三步:运行

用一个具体任务测试你的实现,比如“读取 config.json 并写入备份”。观察它的执行过程:每一轮循环做了什么,历史记录是怎么增长的。

进阶扩展

基础版本跑通之后,试着加入以下功能:

  • 权限检查:为每个工具设置权限级别(Ask/Skip/Deny),执行前检查是否需要用户确认。
  • 错误处理:工具调用失败时怎么办?重试?跳过?终止?
  • Snapshot:每执行 N 步保存一次状态快照,支持回退到之前的快照。

这个练习的价值在于:通过亲手实现,你会理解 Agent 的 Loop 是怎么运转的。框架和库只是对这些基本模式的封装。

小结

  • Agent 的基本机制是 Loop(感知→思考→行动→观察),一次 Run 包含多轮 Loop。
  • 先判断任务适合脚本、Workflow 还是 Agent;不是所有自动化都需要 Agent。
  • Memory 让 Agent 能“记住”过去的事情,分短期记忆和长期记忆两种。
  • Tool Use 让 Agent 从“能想”变成“能做”。
  • 工具设计要清楚、稳定、可恢复,把确定性的动作交给工具。
  • MCP 把各种工具统一成标准格式,让 Agent 能自动理解和调用。
  • 权限模型(Ask/Skip/Deny)控制 Agent 能做什么、不能做什么。
  • 安全意识:零信任、数据脱敏、最小权限。
  • 动手实现 Agent Harness 是理解 Agent 机制的最好方式。

练习

  1. 用你熟悉的编程语言,实现一个简化版的 Agent Loop(参考上面的实现步骤)。
  2. 为你实现的 Agent 加入权限检查:哪些工具调用需要确认,哪些可以直接执行。
  3. 为其中一个工具写清楚输入参数、返回结果、失败时的错误信息。
  4. 思考一个你日常工作中的重复任务,先判断它适合脚本、Workflow 还是 Agent,再画出流程图,标注每一步需要什么工具。

延伸阅读

CC-BY 4.0 Licensed