Appearance
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)。每一轮循环包含四个步骤:
- 感知(Perceive):读取当前状态:用户说了什么、环境是什么样、上一步的结果是什么。
- 思考(Think):分析当前状态,决定下一步该做什么。
- 行动(Act):执行一个具体操作:调用工具、写文件、发请求。
- 观察(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_file、write_file、run_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
实现一个循环函数,接收用户任务描述,按以下流程执行:
- 感知:获取当前状态(任务描述、历史执行记录)。
- 思考:决定下一步做什么。调用 LLM,让它根据当前状态选择工具和参数。
- 行动:调用对应的工具。
- 观察:把工具返回的结果记录到历史中。
- 判断:任务是否完成?未完成则回到第 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 机制的最好方式。
练习
- 用你熟悉的编程语言,实现一个简化版的 Agent Loop(参考上面的实现步骤)。
- 为你实现的 Agent 加入权限检查:哪些工具调用需要确认,哪些可以直接执行。
- 为其中一个工具写清楚输入参数、返回结果、失败时的错误信息。
- 思考一个你日常工作中的重复任务,先判断它适合脚本、Workflow 还是 Agent,再画出流程图,标注每一步需要什么工具。
延伸阅读
- RAG 技术详解:向量检索与混合搜索 — Memory 和 RAG 的技术细节
- API 调用与 Function Calling — Tool Use 的底层实现
- 安全与安全性 Safety & Security — 安全意识的延伸