☰
Agent 学习指南:收藏这份大模型架构拆解秘籍
2026/10/23 2:59:01 网站建设 项目流程

这篇文章深入浅出地介绍了 Agent 的工作原理,将 Agent 比作项目经理,将大模型比作大脑,将工具比作双手,通过宏观架构图和逐层拆解,详细解释了 Agent 如何通过循环、状态和工具来实现复杂任务。文章还详细介绍了记忆系统、工具描述、调用链路等关键机制,并提供了实用的使用建议和故障排除方法,帮助读者更好地理解和应用 Agent 技术。

你对 Agent 说:“帮我分析上月销售数据,生成一份报告。”

然后它沉默了两秒,开始自己干活:查数据库、算同比、发现西南区掉了 38%、下钻找原因、最后把报告写出来。全程没有人再插一句话。

这两秒和之后的每一步,就是这篇要拆的东西。先给结论:Agent 并不“聪明”,它只是把一个大模型塞进了一个循环里,循环外挂了状态和工具。你听过的所有名词——记忆、工具、技能、插件、OpenAPI、MCP、Function Calling——都不是并列的新物种,而是这条循环上的一个个零件。这篇先给你一张宏观架构图立住全局,再逐层拆到代码和数据格式,最后用同一条主线把所有零件串起来跑一遍。读完你会获得一种能力:任何 Agent 产品摆在面前,你都能说出它内部正在发生什么。

一、宏观架构:一个循环、三个角色、三个规范


先立一张“谁是谁”的地基图,不然后面一定会读成“一会儿说 Agent 一会儿说模型”。

三个角色,是包含与调用的关系,不是并列的三样东西:

  • Agent 是外壳(宿主程序)。它是一个程序,不是模型。负责跑循环、管状态、调模型、执行工具。想成项目经理:自己不写代码,但排活、盯进度、对接外部资源。
  • 模型是内嵌在 Agent 里的大脑。Agent 每转一圈循环,就把“任务 + 工具说明书 + 记忆”发给模型,模型回一段推理和决策。关键点:模型不联网、不碰数据库、不执行任何动作——它只输出文本。
  • 工具是 Agent 外部的双手。真正连数据库、发 HTTP 请求的是工具;而真正发起调用的是 Agent,不是模型。模型只是“说”了要调什么,Agent 拿着这句话去执行。

一句话记住分工:模型负责“想”,Agent 负责“管和调”,工具负责“做”。

三个规范,各管一段连接,不是三选一:

  • OpenAPI 管“工具怎么被描述”——把接口写成机器可读的说明书(叫什么、收什么参数、什么类型);
  • MCP(Model Context Protocol) 管“Agent 和工具服务怎么连上”——发现工具、传参数、回结果的通道,可以想成“工具界的 USB-C”:不管什么设备,插上就能用;
  • Function Calling(FC) 管“模型怎么表态”——模型把“我想调某工具、参数是某值”说成结构化文本的内置能力。

它们在三个不同位置上干活,所以根本不存在“选哪个”。记住这张图,后面每一层都是往这张图上挂细节。不过三个角色、三个规范此刻还只是一张“零件清单”——真正让零件转起来的是一条循环:下一节把零件装到循环上。

二、循环与状态:Agent 的骨架


先立一个地基事实,后面的所有机制都基于这个事实:大模型是无状态的。

一次调用结束,模型内部不留任何痕迹。它不保留上一轮的对话、不保留你的偏好、甚至不保留它自己刚说过的话。下一次调用开始时,它对世界的全部认知,就等于你这次塞进上下文窗口的那一段文本。窗口之外,一无所有。

所以在 Agent 的完整行动闭环里,首尾各站着一个记忆动作:

  • 回合开始前,有一个加载动作:从外部存储里捞出与该用户、该任务相关的记忆,拼进这次调用的输入;
  • 回合结束后,有一个写回动作:把本次值得留的结论提炼成结构化条目,存进外部存储。

记忆不在模型里,在模型外面的数据库或文件里;模型只是每次被“喂”到一部分。理解这一点,“为什么换个会话就忘”就不再神秘——换个会话时,加载流水线没把那条记忆捞出来,仅此而已。

一个 Agent 的完整行动闭环由六个站点组成:

  1. 加载记忆:Agent 从长期存储里捞出与本次任务相关的历史(比如“月报口径 = 同比”);

  2. 任务拆解:Agent 把目标交给模型,模型把大目标拆成可执行的子任务队列,Agent 记进状态对象;

  3. 执行与工具调用:模型挑一个子任务、选一个工具、生成参数来表态(tool_calls),Agent 按规范真正发起调用;

  4. 观察结果:Agent 把工具返回原样写回观察区,模型读它并判断是不是自己想要的结果;

  5. 达成判定:模型对照目标检查并表态,Agent 据此决定——完成了就退出循环,没完成回到第 3 步;

  6. 沉淀记忆:Agent 把本次关键结论提炼后写回长期存储,下次不用重算。

其中第 3、4、5 步构成一个可以转很多圈的回路,叫ReAct 循环(Reasoning + Acting:推理一步、行动一步、观察一步,再推理)。工作流没有这个回路——路径是人画死的;Agent 的价值和风险,也都来自这个回路。

状态对象:六站点共写一张工单

六个站点看起来各干各的,其实都在读写同一个状态对象(state)。你可以把它想成一张随任务流转的工单,循环每转一圈,工单上的字段就被更新一次。为什么必须有它?因为模型是无状态的——每次调用结束就清空,循环要想“越转越知道得多”,就必须有一块模型之外的公共记事本:

state = { "goal": ”分析 2026-09 销售数据并生成报告”, # 用户目标,全程不变 "memory": [ # 站点1 从长期记忆捞来的 {”id”: ”m_a”, ”text”: ”用户是华东区销售运营”}, {”id”: ”m_b”, ”text”: ”月报口径 = 同比”}, ], "plan": [], # 站点2 拆出的子任务队列 "observations": [], # 站点4 写入的工具返回 "done": False, # 站点5 的判定结果 "steps": 0, # 限流阀:转了几圈 }

有了状态对象,整个 Agent 就可以写成一段诚实的循环:

while not state["done"] and state["steps"] < MAX_STEPS: # 限流阀 reply = call_llm(messages=build(state), tools=TOOL_SCHEMAS) if reply.tool_calls: # 模型表态要调工具(站点3) for tc in reply.tool_calls: result = execute(tc.name, json.loads(tc.arguments)) # Agent 动手 state[”observations”].append(result) # 站点4 else: state[”done”] = judge(reply, state) # 站点5:对照 goal 判定 state[”steps”] += 1 save_memory(distill(state)) # 站点6:沉淀记忆

这段伪代码就是全文的地图:build(state) 里藏着记忆注入和工具说明书(第四、五节),reply.tool_calls 是 Function Calling(第三节),execute 是工具执行(第四节),load/save_memory 是记忆系统(第五节),MAX_STEPS 是限流阀(第六节)。任何 Agent 框架,剥掉包装都是这二十行。

到这里,把读者最容易混的两个“state”一次分清。窄义 state就是上面这张工单:循环内部的结构化工作状态,六站点共读共写。广义 state则是“存在模型外面、宿主程序可以用来拼窗口的所有持久化工作数据”的总称:这张工单和写到盘上的产物、本会话的逐字对话记录(transcript)、从 transcript 派生的压缩摘要、跨会话记忆库、配置与可读写文件。两者是包含关系:工单是广义总账的一个成员——还是其中结构化的核心;而工单每轮的变化都会被序列化进 transcript——那些 assistant 消息和 tool 消息,就是工单内容的外化。物理上这本总账散在多处(一张表存对话、几张表存记忆、若干文件存产物),概念上是一个夹子:state 是家庭账本夹,transcript 是夹子里最厚的流水账,工单是当下摊在桌上的那一页。

限流阀不是装饰。回路能转很多圈意味着它能转太多圈:模型陷入“再查一次就好了”的自我说服,步数和 Token 烧到天际。工程上必须设最大步数、Token 预算、工具白名单三道闸——这是 Agent 和工作流相比多出来的自由度所要付的账。

transcript 的边界还顺带回答了另一个常被问到的概念:会话是什么。一个会话 = 一条连续的对话线程,也就是一个任务窗口;会话的边界就是盘上这份记录的边界,每轮对话往后面长一段。明天新开一个任务(哪怕继续同一个话题),就是一个新会话——记录从空白开始,没有旧会话的一个字。“换个会话就忘”的根源就在这:不是记忆丢了,是新会话的记录本来就是空的。循环和账本都讲完了,还差一环:循环每转一圈和模型交接一次,那次交接的数据到底长什么样?下一节把这一次交接拆成四段 JSON。

三、一次调用的数据:模型怎么被调、怎么回答


很多人对 Agent 的想象是“Agent 和模型之间聊聊天”。真实情况是:两者之间传的永远是结构化的 JSON 文本,一段一段、有严格格式。一次带工具调用的回合,一共四段数据。我们用一个贯穿全文的例子:用户是华东区销售运营,月报口径是同比,任务是“分析上月销售数据”。

第一段:Agent 拼给模型的 messages

Agent(外壳程序)在调用模型前,要把“全部上下文”拼成一个 messages 数组。数组里每条消息有一个 role,常见四种:system(规则与记忆)、user(用户当轮输入)、assistant(模型历史发言)、tool(工具返回)。记忆就注入在 system 里:

{ "model": "some-llm", "messages": [ { "role": "system", "content": "你是销售数据分析助手,只读不写数据库。/n/n- [preference] 月报口径 = 同比(2026-08 用户明确指定)/n- [fact] 用户是华东区销售运营/n" }, { "role": ”user”, "content": "帮我分析上月销售数据,生成月报" } ], "tools": [ { "type": "function", "function": { "name": "query_database", "description": "在执行只读 SELECT 查询,返回 JSON 行", "parameters": { "type": "object", "properties": { "sql": { "type": "string" } }, "required": ["sql"] } } } ]}

注意三件事。第一, 块里那两条,就是加载流水线从长期存储捞出来的——它们不是模型“想起来的”,是 Agent 塞进去的。第二,tools 数组是工具说明书,每一轮都要重新塞一遍,这是实打实的 Token 成本。第三,这个数组就是模型的全部世界:数组里没有的,模型一律不知道。

这个数组还有另一个名字:本轮的上下文窗口——模型本轮能看的固定容量输入,超一个 token 都塞不下。上一节把广义 state 讲清楚之后,这里正好回答随之而来的问题:state 和窗口什么关系,能划等号吗?不能:窗口是 state 本轮裁出来的一份有损投影,不是 state 本身。

体量差决定了这一点。state 折成 token 可能是几十万上百万(逐字 transcript、每次工具返回、记忆库、盘上文件);窗口只有几十万的固定容量。每轮把 state 全量塞进窗口在物理上不可能,所以宿主每轮实际做的是“挑选 + 拼装”:

本轮窗口 ≈ system 提示 + 工具说明书 + 跨会话记忆片段 + 旧轮压缩摘要 + 近期轮次原文 + 你的新消息。

三个证据帮你把“投影”记牢。第一,在 state 里但不在窗口里的:被压成摘要的旧轮原文还在盘上,但窗口里本轮是摘要不是逐字;记忆库全量只有捞中的片段进得来;盘上文件不用工具读,就永远没有一个字进窗口。第二,在窗口里但不在 state 里的:system 提示和工具说明书每轮重建重塞,不属于本会话的对话记录;开局注入的记忆片段来自记忆库,不是本会话 transcript。第三,窗口每轮重建、state 持续累积:本轮调用结束窗口蒸发(模型忘光),盘上 state 多一段新记录;下一轮宿主再从新 state 拼一个新窗口。

还是仓库和工作台:state 是仓库,窗口是工作台。每天早上(每轮)从仓库搬料上台——只搬台上放得下、本轮用得着的;晚上(调用结束)台面清空,仓库还在且多了新存货。台面上的东西永远是“今早从仓库选出来的一批”,不是仓库本身。模型所谓的“全部世界”,其实就是台面上这一批。

第二段:模型回给 Agent 的不是答案,是 tool_calls

模型读完第一段,判断“我需要先查数据”。这时它返回的不是一段回答文字,而是一个结构化的“表态”——这就是 Function Calling:

{ "choices": [ { "message": { "role": "assistant", "content": null, "tool_calls": [ { "id": "call_01", "type": "function", "function": { "name": "query_database", "arguments": "{/"sql/": /"SELECT region, amount FROM sales WHERE month='2026-09'/"}" } } ] }, "finish_reason": "tool_calls" } ]}

这一段里有三个全篇最重要的细节,下面单独讲。这里先记住形状:模型用 tool_calls 字段说“我想调谁、参数是什么”,content 是 null,finish_reason 是 tool_calls。模型没有碰数据库,它只是把意图说成了 JSON。真正去执行的是 Agent。

第三段:Agent 把工具结果包成 tool 消息拼回去

Agent 解析出 name 和 arguments,真的去连数据库执行,拿到结果。然后它做一件很多人不知道的事:把结果包成一条 role 为 tool 的消息,拼回 messages 数组,连同上一段那条 assistant 消息一起,再调一次模型:

{ "messages": [ { "role": "system", "content": "……(同第一段,含 memory 块)" }, { "role": "user", "content": "帮我分析上月销售数据,生成月报" }, { "role": "assistant", "content": null, "tool_calls": [ { "id": "call_01", "…": "…" } ] }, { "role": "tool", "tool_call_id": "call_01", "content": "{/"region/": /"西南/", /"amount/": 620000, /"yoy/": -0.38}" } ]}

tool_call_id 必须和第二次数据里那个 id 对上——因为一轮里模型可能同时表态要调多个工具,Agent 并行执行后,要靠 id 把每份结果归还给对应的调用。而那条 assistant 的 tool_calls 消息必须留在历史里:删了它,tool 消息就成了无主之物,多数模型会直接报错或读不懂。

第四段:模型这才输出最终答复

模型第二次被调用时,看到了工具结果,于是给出真正的回答:这次 content 是文本,finish_reason 是 stop。Agent 把这段文本呈现给你,回合结束——然后写回流水线启动,把本次值得留的结论存进长期记忆。

三个最容易记错的细节

把上面四段浓缩成三句,值得背下来:

  1. **arguments 是字符串,不是对象。 注意第二段里 arguments 的值是一整个被转义的 JSON 字符串。Agent 拿到后还要再 json.loads 一次才能得到参数对象。无数“工具调用失败”的 bug 就出在少解析了这一层
    { “name”: “query_database”, “description”: “对销售库执行只读 SELECT 查询,返回 JSON 行”, “parameters”: { “type”: “object”, “properties”: { “sql”: { “type”: “string”, “description”: “只读 SELECT 语句” } }, “required”: [“sql”] } }

模型挑工具的方式不是查表,而是读描述做匹配——所以“description 即检索”:写得好坏直接决定选得对不对。坏写法是“查询数据”四个字,模型无从判断该不该用;好写法把“销售库、只读、SELECT、返回 JSON 行”这些判别信息给全。

这里还有一个真金白银的成本:说明书每一轮都要重新塞进 Prompt。30 个工具、每个 150 Token,光说明书每轮就吃掉 4500 Token,还没算对话历史和记忆。所以工程上有两个对策:按任务动态挂载工具(分析销售这轮就别塞 send_email),以及描述写到“够检索”即可、不啰嗦成小作文。

一次工具调用的完整链路

把“描述”到“真请求”拆开,是四棒接力:

  • 第一棒 · 工具描述:用某种规范把工具写成说明书——OpenAPI 和 MCP 的 Schema 都干这件事;
  • 第二棒 · 解析注入:Agent 把说明书翻译成文本塞进 Prompt,模型看到的不是接口、是一段文字(成本就在这一棒);
  • 第三棒 · 模型决策:模型输出“我要调 query_database,参数 sql=…”——这就是 Function Calling,输出的是结构化文本,不是真调用;
  • 第四棒 · 执行调用:Agent 解析这段结构化文本,真正发起请求或 MCP 调用,把结果写回 observations,供下一圈循环使用。

三个名词的归属由此清楚:OpenAPI 和 MCP 站在第

一、四棒(描述与通道),FC 站在第三棒(决策)。第一棒和第四棒发生在 Agent 一侧,第三棒发生在模型里——所以“模型调用工具”的准确说法是“模型表态、Agent 动手”。

能力三层:工具、技能、插件

工具之上还有两层经常被混用的概念,一次分清:工具是原子动作(query_database 这种单次调用);技能是流程加知识(“生成月报”= 先查数、再算同比、再按模板写,是一段可复用的剧本);插件是分发单元(把一组工具和技能打包给别人安装)。三层各管一件事:动作、流程、分发。混用的根源是拿分发层的词去描述动作层的事。

MCP:把连接和描述分开

最后说 MCP 为什么值得单独存在。没有它时,每接一个工具服务都要写一套定制对接代码;有了它,发现工具、传参、回结果都走统一协议——描述(OpenAPI 那类)解决“工具长什么样”,MCP 解决“怎么够到它”。一个 MCP Server 就像插座面板,后面接着若干工具;Agent 插上就能用,还能多个 Agent 共享同一面板。工具解决了“够得着”,可循环的首尾两站还空着——“记得住”挂在哪里?下一节拆这两站。

五、记忆:循环的首尾两站


现在看闭环的首尾两站。还是那个地基事实:模型无状态,记忆只能住在模型外面。所以“Agent 记得你”在工程上就是第二节立过的两条流水线:回合开始前加载、回合结束后写回。下面先拆加载,再拆写回。

但拆四道闸之前,先把一层机制讲透,不然闸门的位置会摆错:每轮加载的真是“记忆”吗?其实同时跑着两种机制。本会话的历史不走加载流水线,是直接读 state:看你按下发送之后发生了什么,宿主程序打开本会话在盘上的 transcript,把你这条新消息 append 到末尾,然后把整份内容(或压缩后的“摘要 + 近期原文”)序列化进 messages 数组发给模型。注意这个过程里没有什么:没有检索、没有打分、没有四道闸。历史本来就在本会话的记录里,而记录每轮都被直接拼进输入。所以 Agent“记得”本会话早前聊过什么,真相是:那些记录就在它本轮正在读的输入里——“记得” = 读到了本轮递到手上的会议纪要,而不是翻自己的脑子(模型没有脑子可翻:它无状态,调用一结束全部蒸发)。

跨会话的长期记忆:才走本文说的加载流水线,而且两条路。一条是会话开局直接注入:一份精炼的长期备忘在会话开始时就拼进 system 段,相当于跳过检索、直接占记忆预算;另一条是按需捞取:更细的每日记录默认不在上下文里,只有判断相关时才调记忆搜索工具——构造查询、检索、把命中片段读进上下文——正是下面四道闸的简化版。

一个比方:每轮对话都像见一位失忆的同事(模型无状态),但宿主在他坐下前把以往所有会议的完整纪要递到他手里。他“记得上次” = 读到了手里的纪要(直接读 state);纪要里没有的别的会议内容 = 得去档案室翻(记忆库检索,即下面四道闸)。

还有一个活例子:会话上下文溢出时,宿主下一轮递进来的是压缩摘要——旧 transcript 被提炼成摘要再注入,不是全量逐字。这正是第 6 篇讲的窗口管理动作,也说明每轮进窗口的未必是 state 全量。理解这两层,下面四道闸的位置就清楚了:它只管跨会话的长期记忆;本会话的记忆,根本不需要它。

加载管线四道闸

第一道闸:构造查询。拿什么去捞记忆?最直接的是用户当轮消息加任务描述。但原始消息往往太口语,工程上常先让模型把它改写成一句“检索意图”,比如把“上月西南区怎么样”改写成“西南区 2026-09 销售业绩 同比口径”。查询构造的质量,直接决定后面所有闸门的上限。

第二道闸:混合召回。只用向量语义检索会漏掉精确信息(“口径=同比”这种短事实,语义向量并不突出),只用关键词又漏掉同义改写。所以两路并跑:向量库按余弦相似度捞 Top-K(比如 20 条),结构化存储按关键词和字段(user_id、type)再补一批,去重合并。

第三道闸:重打分与阈值。语义相似度只说明“像”,不说明“该用”。综合分要叠加三个信号:重要度(被召回次数 hits、来源权重 weight)、新鲜度(写入时间 ts 越近越重)、类型匹配(当前是分析任务,preference 和 decision 类优先)。公式形如:综合分 = 相似度乘 w1 加 重要度乘 w2 加 新鲜度乘 w3。然后过一道阈值——低于阈值的宁可不用。宁缺毋滥是记忆系统的生命线:一条不相关的记忆注入进去,模型会认真地把它当前提用,比没有记忆更糟。

第四道闸:截断注入。上下文窗口的预算是有限的,而工具说明书、对话历史都在抢同一块地。所以给记忆一个 Token 预算(比如 600),按综合分从高到低装,装不下就跳过——注意是跳过而不是截断半条:半条记忆比没有记忆更危险。

代码:一个能跑的 load_memory

把四道闸写成代码,大概就是这样:

def load_memory(user_msg, budget_tokens=600, threshold=0.35): # 闸1:构造查询(这里简化为直接用用户消息) q = embed(user_msg) # 闸2:混合召回 = 向量语义 + 关键词/字段 cand = vector_store.query(q, top_k=20, filter={”user_id”: UID}) cand += sql_store.match_keywords(user_msg, user_id=UID) cand = dedup(cand) cand = [m for m in cand if m.superseded_by is None] # 过滤已作废 # 闸3:重打分 + 阈值 for m in cand: m.score = 0.5 * m.sim + 0.3 * importance(m) + 0.2 * freshness(m.ts) cand = [m for m in cand if m.score > threshold] cand.sort(key=lambda m: -m.score) # 闸4:Token 预算内截断,装不下整条跳过 picked, used = [], 0 for m in cand: cost = tokens(m.text) if used + cost > budget_tokens: continue picked.append(m) used += cost return picked

每一行都对应一道闸。superseded_by is None 那行是遗忘机制的接口:被新结论取代的旧记忆不作废删除,而是打标记,加载时过滤掉——保留删除链才能审计“当初为什么改口径”。filter user_id 那行是多用户隔离:记忆库是全公司共用的,捞错人的记忆比忘事严重得多。

注入到哪里、以什么格式

捞出来之后塞哪?两个选择,各有道理:

  • 塞进 system 段的 memory 块(本文例子用的方式):地位高、稳定,模型倾向于把它当长期前提;适合偏好、身份、口径这类慢变信息。
  • 塞成一条独立的 user 或 system 补充消息:适合与当轮任务强相关的 episodic 记忆(“上次我们分析到一半发现是大客户流失”),让它靠近当轮问题、注意力更集中。

格式上不要只塞裸文本。带上 type 和时间,模型才知道怎么用它:

<memory>- [preference | 2026-08] 月报口径 = 同比- [fact | 2026-07] 用户是华东区销售运营- [decision | 2026-10] 2026-09 西南区同比 -38%,主因大客户流失</memory>

时间戳不是装饰。当两条记忆冲突时(去年说看环比、今年说看同比),模型靠时间戳知道该信新的。没有时间的记忆块,冲突时模型只能瞎猜。

回合结束后:记忆是怎么被写回去的

加载讲透了,看写回。不是所有经历都配进长期记忆——一次任务会产生上千行原始信息(查询结果、报错、中间推理),全存下来等于往记忆里灌垃圾。写回的核心是一道晋升闸门加一步提炼。

晋升的触发条件常见四类:任务结束时的结论沉淀;用户显式说“记住”(这种 weight 直接拉高、来源标 user_explicit);同一信息被重复提到三次以上(说明稳定重要);高代价事件(出过事故的配置、被用户纠正过的错误)。

提炼是更关键的一步:存结论和约束,不存过程原文。那次分析任务讨论了很久、试了好几种下钻路径,但进长期库的只应有一句“2026-09 西南区同比 -38%,主因大客户流失”。把过程塞进去,三个月后召回时全是噪声。

提炼谁来做?让模型做。回合结束时,Agent 把本次轨迹摘要喂给模型,要求它按固定 schema 输出候选记忆条目:

{ "text": "月报口径 = 同比", "type": "preference", "source": "user_explicit", "confidence": 0.95 }

Agent 再补上 ts、hits、weight、embedding 等元数据落库。一条记忆的完整记录结构长这样:

{ "id": "m_b", "text": "月报口径 = 同比", "type": "preference", "source": "user_explicit", "ts": "2026-08-12T10:00:00Z", "hits": 7, "weight": 0.9, "superseded_by": null, "embedding": [0.021, -0.13, 0.08] }

每个字段都有用途:type 供召回时过滤,ts 和 hits 和 weight 供重打分与遗忘,superseded_by 供作废链,embedding 供语义检索。字段设计得越糙,加载管线就越做不精——第三道闸的每个信号都来自这些字段。

还有一个隐蔽的坑:带毒记忆。如果“主因大客户流失”是模型猜的、没经过工具返回校验就沉淀了下来,它会变成一条带毒记忆,之后每次月报都被捞出来当既定事实。对策是晋升前对结论型记忆做证据校验,并且让 source 为 task 的条目比 user_explicit 的权重更低、更容易被后续证据推翻。

存哪里:三种方案与组合

长期记忆落在哪?三种主流方案,软肋互补:

方案怎么存强项软肋
向量数据库记忆转向量,按语义相似度捞模糊回忆强,问“上次那个数据库决定”能捞到“选型:PostgreSQL”会捞回“差不多但不相关”的;难精确审计
SQLite 活动账本一条记忆一行,带 type、ts 字段精确、可审计、可 SQL 查询不懂语义,只能按字段查
文件系统写成 Markdown 主账本加按日期日志人能直接读改、能进版本控制检索靠 grep 或额外索引

真实产品里三者组合使用:文件当人能读的主账本,向量库当语义索引,SQLite 当活动流水。加载管线的第二道闸“混合召回”,正好就是向量库出语义候选、账本出精确候选,再合并——你看,存储选型不是三选一,而是给流水线的不同闸门供货。

它“忘”了,其实是四种不同的坏法

“忘”不是一种病,是四种不同的坏法,对症的药完全不一样:

第一种:没写进去。回合结束后写回流水线没触发——用户那句“记住”没被识别为显式指令,或晋升阈值太严。症状是“我明明说过”但库里根本没有这条。修法:给显式指令加高优先级触发器,用户说“记住”必须落库,不走概率。

第二种:写进了,但没命中。库里有,加载管线第二道闸没捞到——查询构造太口语、或向量索引没更新。症状是“有时候记得有时候不记得”,换个问法就好了。修法:优化查询改写、上混合召回。

第三种:捞到了,但没进注入名额。第

三、四道闸把它挤掉了——阈值太高、或 Token 预算被工具说明书和历史对话抢光。症状是长对话后期开始忘(窗口越挤越严重)。修法:给记忆设保底预算、动态卸载不相关工具描述。

第四种:注入了,但被忽略或冲突。记忆在 Prompt 里,却被淹没在长上下文中间,或与当轮信息矛盾时模型选了错的。症状是“它看到了但还是按错的来”。修法:把关键记忆放在 system 段和靠近当轮问题的位置、带时间戳让模型能判新旧、冲突时显式标注“以新为准”。

还有一个反直觉的设计:好的记忆系统必须会遗忘。只增不删三个月就变垃圾场:被推翻的旧记忆标记作废(取代链在加载管线里已经见过),长期未命中的按时间衰减降权,带毒的结论在晋升前就被证据校验拦下。遗忘不是缺陷,是记忆系统保持可信的手段。

下次你的 Agent“忘”了你,先别骂它记性差。按这四条逐个排查:库里有没有、召回没召回、注入没注入、模型用没用。定位到哪一种坏法,才知道该修哪一段代码。

把记忆挂回那条闭环:它本身也是工具

最后把视角拉高一层。一个能自己干活的 Agent,本质是“一个大模型塞进一个循环,循环外挂了状态和工具”:模型负责想,Agent 负责管和调,工具负责做。那个循环每转一圈,都要经历加载记忆、拆解任务、执行与工具调用、观察结果、达成判定、沉淀记忆六个站点——记忆正好挂在首尾两站:回合前加载、回合后写回。本文拆的就是这两站的内部。

还有一层容易忽略的事实:记忆的读写本身,常常也被注册成工具。recall_memory 和 save_memory 两个工具,和 query_database 走完全相同的 Function Calling 通道——模型在 tool_calls 里表态“我要recall_memory,参数是这句查询”,Agent 执行后把结果包成 tool 消息传回。这意味着记忆系统的可用性,一半取决于这两个工具的 description 写得好不好:描述含糊,模型该recall的时候不recall,你又会看到第一种“忘”。而如果记忆服务通过 M

站点典型失败症状对策
循环回路空转步数和 Token 烧到天际,“再查一次就好了”最大步数、Token 预算、工具白名单
拆解目标漂移做着做着去回答了别的问题每圈对照 state.goal 复检
调用参数错误工具报错、SQL 不合法schema 约束类型、执行前校验层
工具选错工具该查订单时去查了库存description 四要素写全、动态挂载
观察返回挤爆窗口长对话后期开始犯糊涂工具返回先摘要再入 observations
记忆带毒记忆同一个错误结论反复被当事实晋升前证据校验、作废链可回滚

这张表的用法很简单:Agent 出错时先定位到站点,再谈修法。“Agent 不稳定”不是一种病,是六个站点各自的病。

七、懂了原理之后:怎么让 Agent 更好干活


了解原理不是为了显摆,是为了换一种方式下指令。下面这几条习惯,每一条都对应前文的某个机制,今天就能用。

  1. 给上下文,别考它记性。模型的世界只有当轮那一个 messages 数组:你没塞的,它就不知道。所以任务开头把背景、口径、约束一次给全——“我是华东区销售运营,月报看同比口径,数据库只读”——别预设它“应该记得”。真想让它长期记住的,显式让它写回:说一句“记住这条”,触发显式写回闸门,比顺嘴提十句都管用。

  2. 把目标写成可验收的完成态。循环退不退出,靠站点 5 的达成判定对照 goal 检查。“帮我分析一下数据”会让模型自己也不知道算不算完成;“出一份 2026-09 月报:含总额、同比、异常下钻,800 字以内”就让判定有了依据。目标越可验收,回路空转越少。

  3. 派活前先扫一眼工具表。Agent 够得着什么,由工具表和权限边界决定。派活前确认两件事:需要的工具在不在——没挂 render_chart,它就只能用文字描述图;权限边界在哪——只读的 query_database 想误发邮件也发不了。很多“Agent 不聪明”的现场,其实是工具没挂对。

  4. 让回路转几圈,别在第一棒就掐断。ReAct 的价值在观察之后再判断:第一圈查到 -38%,第二圈的下钻才值钱。看到第一个中间输出就当最终答案去打断纠正,等于在接力赛中途抢棒。你要管的不是中间步骤,而是限流阀:最大步数、Token 预算、工具白名单,让它转、但转在阀里。

  5. 出错先定位站点,再谈修法。输出错了,先看站点 4 的观察:工具返回本身就错,是工具或数据的问题;返回对而模型读错,是模型的问题——两者修法完全不同。忘了就按四个断点排查:没写、没命中、没注入、被忽略。先定位病在哪,再开药,别笼统归成“Agent 不稳定”。

  6. 重要结论要证据,把带毒记忆拦在闸门外。没经过证据校验就沉淀的结论会变成带毒记忆,之后每次都被捞出来当事实。所以对关键数字多问一句:“这个数从哪来的?”让它指到工具返回,而不是自己的印象。这一问,能把大部分毒拦在晋升闸门之前。

这六件事共用一个底层心态:把 Agent 当一个需要喂上下文、需要明确验收标准、需要配好工具的无状态同事,而不是一个会读心、会意会的老员工。这样用,前面拆过的所有原理才真正变成你手里的生产力。

本篇核心术语表

术语白话解释
Agent(宿主程序)跑循环、管状态、调模型、执行工具的外壳程序,不是模型
大模型(LLM)内嵌在 Agent 里的大脑,只输出文本,不执行任何动作
工具(Tool)Agent 外部的原子动作,真正连数据库发请求的是它
状态对象(state)六站点共读共写的工单:goal、memory、plan、observations、done、steps
ReAct 循环推理、行动、观察再推理的回路,Agent 与工作流的根本区别
观察(observations)工具返回写进状态的字段,下一圈循环的输入
Function Calling模型把调用意图说成结构化 JSON 的内置能力,即第三棒表态
tool_calls模型返回里的调用意图字段;content 为 null 时表示中间态
tool 消息Agent 把工具结果包成的消息,靠 tool_call_id 与表态配对
OpenAPI工具描述规范:把接口写成机器可读说明书
MCPAgent 与工具服务之间的连接协议,工具界的 USB-C
技能(Skill)流程加知识的可复用剧本,位于工具之上的流程层
插件(Plugin)把一组工具与技能打包分发的单元
记忆加载 / 写回回合前捞记忆注入 Prompt、回合后提炼结论存库的两条流水线
记忆晋升满足触发条件并提炼成结论后才转存长期记忆的闸门
限流阀最大步数、Token 预算、工具白名单,防止回路空转
会话(Session)一条连续对话线程的边界 = 盘上 transcript 的边界;新开任务即新会话,记录从空白开始
Transcript本会话在盘上的逐字对话记录,state 最大的成员,每轮被直接拼进窗口
状态(state)两层含义:窄义 = 循环里的工单(state 对象),六站点共读共写;广义 = 模型外持久化工作数据的总称(transcript、压缩摘要、工单与产物、记忆库、配置);前者是后者的一个成员、结构化核心
上下文窗口本轮从 state 选材拼装、递到模型手里的固定容量输入,即本轮的 messages 数组;是 state 的有损投影,不是 state 本身
压缩摘要上下文溢出后从旧 transcript 派生的摘要,替代逐字原文进窗口,本身也是 state 的成员

大模型的知识又多又杂,到底怎么学?

做这行久了,被问最多的问题就一个:大模型的知识又多又杂,我到底先学啥?翻了一堆资料,看啥都像重点,结果啥都没学进去。今天把我自己一路摸出来的顺序捋一遍,零基础、应届生、转行的都适用。跟着走,至少方向不乱、不瞎忙,学完拿得出手。

第一阶段(10天):初阶应用

这一阶段就一个目标:把大模型真正"玩明白",不是只会聊天那种,而是能调教它、能用代码把大模型和业务接起来。

  • 大模型 AI 能干什么?
  • 大模型是怎样获得「智能」的?
  • 用好 AI 的核心心法
  • 大模型应用业务架构
  • 大模型应用技术架构
  • 代码示例:向 GPT-3.5 灌入新知识
  • 提示工程的意义和核心思想
  • Prompt 典型构成
  • 指令调优方法论
  • 思维链和思维树
  • Prompt 攻击和防范
  • …
第二阶段(30天):高阶应用

这阶段正式进实战,目标很实在:做出两个能拿出手的东西——一个私有知识库,一个 agent 对话机器人。

  • 为什么要做 RAG

  • 搭建一个简单的 ChatPDF

  • 检索的基础概念

  • 什么是向量表示(Embeddings)

  • 向量数据库与向量检索

  • 基于向量检索的 RAG

  • 搭建 RAG 系统的扩展知识

  • 混合检索与 RAG-Fusion 简介

  • 向量模型本地部署

  • …

走完这 30 天,Python 或 JavaScript 背景的基本能独立做一套 RAG 应用,简历上也敢写"大模型应用开发"了。

第三阶段(约20天):动手微调

学到这,你已经开始 “造” 模型了 —— 通过微调,搞出垂直领域的专用小模型。

  • 为什么要做 RAG
  • 什么是模型
  • 什么是模型训练
  • 求解器 & 损失函数简介
  • 小实验2:手写一个简单的神经网络并训练它
  • 什么是训练/预训练/微调/轻量化微调
  • Transformer结构简介
  • 轻量化微调
  • 实验数据集的构建
  • …

恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。

到此为止,大概2个月的时间。你从 “只会用” 变成 “能造” 的 AI 小子。那么你还想往下探索吗?

想要入局AI大模型赛道、抢占行业红利的朋友,微信扫描下方CSDN官方认证二维码,即可100%免费领取全套学习资料!

第四阶段(20天):商业闭环,部署落地

技术学完,落地才算数。这阶段带你搞明白大模型怎么真正跑起来、用起来。

  • 硬件选型
  • 带你了解全球大模型
  • 使用国产大模型服务
  • 搭建 OpenAI 代理
  • 热身:基于阿里云 PAI 部署 Stable Diffusion
  • 在本地计算机运行大模型
  • 大模型的私有化部署
  • 基于 vLLM 部署大模型
  • 案例:如何优雅地在阿里云私有部署开源大模型
  • 部署一套开源 LLM 项目
  • 内容安全
  • 互联网信息服务算法备案
  • …

想要入坑大模型的朋友,给大家准备了一份2026 年最新 AI 大模型全套学习资料:

1、大模型系统化学习路线

2、大模型学习视频教程

3、大模型学习书籍&电子文档

4、AI大模型最新行业报告

5、大模型项目实战&配套源码

6、2026大模型大厂面试真题

7、为什么要学习大模型?

我国在A大模型领域面临人才短缺,数量与质量均落后于发达国家。2023年,人才缺口已超百万,凸显培养不足。随着AI技术飞速发展,预计到2025年,这一缺口将急剧扩大至400万,严重制约我国AI产业的创新步伐。加强人才培养,优化教育体系,国际合作并进是破解困局、推动AI发展的关键。

8、适合谁学?
  • 传统后端 / Java / 前端开发,想转型 AI 应用
  • 大学生、应届生,想拿更好的 offer
  • 产品经理、运营,想武装职业竞争力
  • 技术负责人,想给团队落地提效

学习是反人性的,但回报是真金白银。技术会更新,赛道会切换,但只要你先动手,机会就永远站在你这边。

9、这些资料真的有用吗?

这份资料由我和鲁为民博士(北京清华大学学士和美国加州理工学院博士)共同整理,现任上海殷泊信息科技CEO,其创立的MoPaaS云平台获Forrester全球’强劲表现者’认证,服务航天科工、国家电网等1000+企业,以第一作者在IEEE Transactions发表论文50+篇,获NASA JPL火星探测系统强化学习专利等35项中美专利。本套AI大模型课程由清华大学-加州理工双料博士、吴文俊人工智能奖得主鲁为民教授领衔研发。

资料内容涵盖了从入门到进阶的各类视频教程和实战项目,无论你是小白还是有些技术基础的技术人员,这份资料都绝对能帮助你提升薪资待遇,转行大模型岗位。

想要入局AI大模型赛道、抢占行业红利的朋友,微信扫描下方CSDN官方认证二维码,即可100%免费领取全套学习资料!

好了,就写到这。路线是死的,人是活的,卡住了随时来问我。觉得有用就点个收藏,别让它进收藏夹吃灰——动起来比啥都强。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询