☰
我们如何构建 Agent Builder 的记忆系统:用 TaoToken 统一 Key 打通 LangSmith 与 Deep Agents
2026/10/3 12:02:57 网站建设 项目流程

1. 从一次“失忆”事故说起:Agent Builder 记忆系统到底解决什么问题

你可能遇到过这种场景:花了一下午调教好的 Agent,第二天打开,它像换了个人。昨天刚说过的“摘要用项目符号、行动项单独列在末尾”,今天又变回一大段文字。这不是模型变笨了,而是它根本没有把上一次的经验留下来。

LangSmith Agent Builder 的记忆系统,本质上就是给 Agent 装一个“可读写的笔记本”。它把记忆表示成一组文件,让模型用自己最擅长的方式——读写文件系统——来管理记忆。这个选择很关键:模型不需要学习一套专用工具,只要给它文件访问权限,它就能自己读、自己改。

这套记忆系统适合谁?三类人最值得关注。第一类是正在做垂直任务 Agent 的开发者,比如邮件助手、文档助手、招聘筛选助手,这些任务会反复执行,经验能跨会话复用。第二类是想把 Agent 从“一次性对话”升级成“长期协作伙伴”的团队。第三类是已经在用 Deep Agents 或类似 harness、想搞清楚上下文工程怎么落地的人。

它和通用 Agent 的记忆有什么不同?ChatGPT、Claude 这类通用助手,你这次让它写代码、下次让它查资料,两次会话可能毫无关系,学到的经验迁移率很低。但 Agent Builder 面向的是特定任务,Agent 一遍又一遍做同一件事,一次会话里的教训有很高概率在下次用得上。没有记忆,用户就得反复重复自己,体验会非常糟。

LangSmith 团队借用了 COALA 论文对记忆的分类:程序性记忆(规则集,决定 Agent 行为)、语义性记忆(关于世界的事实)、情景性记忆(过去行为的序列)。在 Agent Builder 里,程序性记忆对应AGENTS.md和tools.json,语义性记忆对应 agent skills 和其他知识文件,情景性记忆暂时没做,他们认为对这类任务型 Agent 来说前两类更重要。

真正让这套系统跑起来的,是底层 Deep Agents harness 对上下文工程的抽象——摘要、工具调用卸载、规划这些复杂逻辑都被封装了,你只需要用相对简单的配置去引导 Agent。而要把这套链路真正跑通、并且能追踪每一次记忆读写,你需要一个稳定的模型调用通道。这就是 TaoToken 出场的地方:统一 Key 和 API 通道,把 LangSmith 的追踪和 Deep Agents 的模型调用串成一条线。

下面我会从环境准备开始,一步步给出可复制的配置片段,再走一遍记忆召回链路的验证,最后把常见的报错对照着排一遍。目标很明确:让你能复现从写入到检索的完整闭环。

2. TaoToken 前置准备:统一 Key 与 Base URL 的接入配置

在动手配记忆系统之前,先把模型调用通道理顺。LangSmith 负责追踪记忆读写链路,Deep Agents 负责组织AGENTS.md上下文,但这两者最终都要调用模型。如果每个组件各配一套 Key、各写一个 Base URL,排查问题时你会分不清是记忆逻辑错了还是调用通道断了。用 TaoToken 统一 Key 和 API 通道,能把变量收敛到一个地方。

先明确三个核心件,后面所有配置都围绕它们展开:

配置项值说明
Base URLhttps://taotoken.net/api所有模型调用的统一入口,不加 UTM
API Key在控制台创建形如sk-...,只存环境变量,别写进代码
Model ID按需选择例如claude-sonnet-4-5、gpt-4o等,以控制台可用列表为准

第一步,去控制台创建 Key。打开https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=api_keys,登录后新建一个 Key,复制出来。这个 Key 就是你后面所有组件的通行证。

第二步,把它写进环境变量。我习惯用.env文件管理,避免污染全局 shell。在项目根目录建一个.env:

# .env TAOTOKEN_API_KEY=sk-你的真实key TAOTOKEN_BASE_URL=https://taotoken.net/api TAOTOKEN_MODEL=claude-sonnet-4-5 # LangSmith 追踪 LANGCHAIN_TRACING_V2=true LANGCHAIN_API_KEY=lsv2_你的langsmith_key LANGCHAIN_PROJECT=agent-builder-memory # Deep Agents 相关 AGENTS_MD_PATH=./agents/AGENTS.md

注意TAOTOKEN_BASE_URL结尾不要带斜杠,很多 SDK 拼接路径时会因此产生双斜杠,导致 404。这是我自己踩过的坑,排查了半天才发现是 URL 末尾多了个/。

第三步,如果你用的是 Claude Code 这类工具,配置方式略有不同。Claude Code 读取的是settings.json,路径通常在~/.claude/settings.json。把模型通道指向 TaoToken:

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的真实key", "ANTHROPIC_MODEL": "claude-sonnet-4-5" } }

这里有个容易混淆的点:Claude Code 用的是ANTHROPIC_*前缀的环境变量,而通用 SDK 用的是OPENAI_*或自定义前缀。别把两套混用,否则会出现“Key 明明对,但一直 401”的情况。

第四步,如果你用 Cline 或带 MCP 的编辑器,配置里同样要写全三件套。以 Cline 的 MCP 配置为例,在cline_mcp_settings.json里:

{ "mcpServers": { "taotoken-gateway": { "command": "npx", "args": ["-y", "@taotoken/mcp-server"], "env": { "TAOTOKEN_BASE_URL": "https://taotoken.net/api", "TAOTOKEN_API_KEY": "sk-你的真实key", "TAOTOKEN_MODEL": "claude-sonnet-4-5" } } } }

Base URL、Key、Model ID 三件套一个都不能少。少 Base URL 会走默认官方地址,少 Model ID 会报模型不存在,少 Key 直接 401。

第五步,验证通道是否通。写一个最小脚本:

import os from openai import OpenAI client = OpenAI( base_url=os.environ["TAOTOKEN_BASE_URL"], api_key=os.environ["TAOTOKEN_API_KEY"], ) resp = client.chat.completions.create( model=os.environ["TAOTOKEN_MODEL"], messages=[{"role": "user", "content": "只回复两个字:通了"}], ) print(resp.choices[0].message.content)

跑通会打印“通了”。如果这一步就失败,先别往下走记忆系统,把通道问题解决掉。通道是地基,地基不稳,后面 LangSmith 追踪出来的链路全是断的。

关于接入文档,完整的环境变量说明和 SDK 用法在https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=doc,遇到参数不确定时对着查。

3. 可复制配置:用 AGENTS.md 与 Deep Agents 组织记忆文件

通道通了,接下来搭记忆系统的骨架。核心思路是:把记忆表示成文件,用AGENTS.md定义核心指令,用 skills 提供任务级专用指令,用tools.json定义 MCP 工具访问。这些文件在物理上存在 Postgres 里,但以文件系统的形状暴露给 Agent——DeepAgents 原生支持这种“虚拟文件系统”,而且完全可插拔,换成 S3、MySQL 都行。

先看目录结构。一个典型的 Agent 记忆文件夹长这样:

agents/ linkedin_recruiter/ AGENTS.md tools.json subagents/ linkedin_search_worker.md skills/ candidate_screening.md knowledge/ jd_backend.md jd_frontend.md

AGENTS.md是程序性记忆的核心,定义 Agent 的行为规则。一个初始版本可以很简单:

# 会议总结助手 ## 任务 总结会议记录,输出结构化摘要。 ## 格式 - 使用项目符号,而不是段落 - 在末尾单独提取行动项目 - 对决策使用过去时 - 在顶部包含时间戳

这个文件不是一次性写死的,而是随着使用被 Agent 自己编辑。第 1 周你纠正它“用项目符号”,它就把这条写进AGENTS.md;第 2 周你要求“末尾单独提取行动项目”,它再追加一条。三个月后,这个文件会积累出格式偏好、领域术语、参会人员角色、会议类型处理等大量细节,而用户从未手动改过它。

tools.json定义 MCP 工具访问。LangSmith 没用标准的mcp.json,而是自定义了tools.json,原因是想允许用户只给 Agent 一个 MCP 服务器里工具的子集,避免上下文溢出:

{ "mcpServers": { "linkedin": { "command": "npx", "args": ["-y", "@linkedin/mcp-server"], "allowedTools": ["search_people", "get_profile"] } } }

注意allowedTools这个字段,它就是这个自定义格式的价值所在。标准mcp.json会把整个服务器的工具都暴露出来,上下文很快被撑爆。

subagents/目录放子 Agent 定义。LangSmith 用了类似 Claude Code 的格式(当时没有子 Agent 标准):

# linkedin_search_worker ## 角色 在主 Agent 校准搜索条件后,启动本 Agent 寻找约 50 名候选人。 ## 输入 - 搜索关键词 - 地点限制 - 经验年限 ## 输出 候选人列表,每人包含姓名、当前职位、匹配理由。

skills/目录放任务级专用指令,对应语义性记忆。每个 skill 文件需要遵守特定格式,通常带前言(frontmatter):

--- name: candidate_screening description: 根据 JD 筛选候选人 --- ## 筛选标准 1. 技能匹配度优先于年限 2. 有相关行业经验加分 3. 跳槽频率过高需标注

knowledge/目录放任意知识文件,Agent 运行时可以参考,也会在工作时“在热路径中”编辑它们。比如几个 JD 文件,随着搜索推进被 Agent 更新维护。

把这些文件接进 Deep Agents,配置大致如下:

from deepagents import create_deep_agent agent = create_deep_agent( agents_md_path="./agents/linkedin_recruiter/AGENTS.md", tools_json_path="./agents/linkedin_recruiter/tools.json", subagents_dir="./agents/linkedin_recruiter/subagents", skills_dir="./agents/linkedin_recruiter/skills", knowledge_dir="./agents/linkedin_recruiter/knowledge", model="claude-sonnet-4-5", base_url="https://taotoken.net/api", api_key=os.environ["TAOTOKEN_API_KEY"], )

这里base_url和api_key直接复用前面配好的 TaoToken 通道,模型调用和记忆读写走同一条链路,LangSmith 追踪时才能把两者关联起来。

有一个关键设计要强调:所有记忆编辑都是人在回路(Human-in-the-loop)的,更新前需要人工批准。这主要是为了减少提示注入的攻击面。LangSmith 也提供了关闭这个功能的选项(他们内部叫“yolo 模式”),但在生产环境我不建议关。记忆文件是 Agent 能自己写的,如果被恶意输入诱导写入危险指令,下次会话就会执行,这个风险不值得省那点确认成本。

文件类型需要显式验证。tools.json必须是合法的 MCP 服务器配置,skills 必须有正确的前言。LangSmith 发现 Agent 有时会忘记这些约束,生成无效文件,所以他们加了一步显式验证:验证失败就把错误抛回给 LLM,而不是提交文件。这个模式值得抄,你可以在自己的 harness 里加一个 schema 校验层。

4. 验证记忆召回链路:从写入到检索的完整闭环

配置搭好了,现在走一遍完整闭环,确认记忆真的能写入、能召回。这一步是整个系统能不能用的分水岭——很多人的 Agent 看起来有记忆,实际上只是把历史对话塞进上下文,根本没做持久化和检索。

先准备一个最小可复现的场景。用会议总结助手,初始AGENTS.md只有一行:

总结会议记录。

第一次运行,给一段会议记录,观察 Agent 输出。它大概率会生成段落式摘要。这时你纠正它:“使用项目符号而不是段落。”关键来了:Agent 应该把这条偏好写进AGENTS.md,而不是只记在当前会话里。

验证写入是否发生。检查AGENTS.md内容,应该变成:

# 格式偏好 用户更喜欢项目符号而不是段落来写摘要。

如果文件没变,说明记忆写入链路断了。常见原因是 Agent 没有文件系统写权限,或者人在回路审批被跳过但没落盘。回到 Deep Agents 配置检查knowledge_dir和AGENTS.md的路径是否正确挂载。

第二次运行,换一段完全不同的会议记录,不提任何格式要求。观察 Agent 是否自动使用项目符号。如果用了,说明召回成功——它读取了AGENTS.md,把上次的偏好应用到了新会话。

再叠加一层。这次要求:“在末尾单独提取行动项目。”AGENTS.md应该追加:

# 格式偏好 用户更喜欢项目符号而不是段落来写摘要。 在末尾单独提取行动项目。

第三次运行,两种模式都应该自动应用。到这里,从写入到检索的闭环就通了。

现在打开 LangSmith,看追踪链路。在LANGCHAIN_PROJECT=agent-builder-memory这个项目下,你应该能看到每次运行的 trace。重点看两个 span:一个是读取AGENTS.md的步骤,一个是模型调用。读取步骤的输入输出能让你确认 Agent 到底读到了什么内容;模型调用的 prompt 里应该包含AGENTS.md的内容。如果 trace 里看不到文件读取,说明记忆没有真正进入上下文,只是被写进了存储但没被召回。

一个更严格的验证方法:手动改AGENTS.md,加一条新规则,比如“短会议(少于 10 分钟)只列出要点”,然后不重启 Agent,直接发一段短会议记录。如果 Agent 应用了新规则,说明它每次运行都实时读取记忆文件,而不是缓存在内存里。这个特性对多会话场景很重要。

验证召回质量时,注意一个陷阱:Agent 可能“记住”了但没“泛化”。LangSmith 团队发现,他们的邮件助手曾经开始列出所有应该忽略的冷接触供应商,而不是更新自己“忽略所有冷接触”。这是典型的记住了具体案例但没抽象出规则。解决办法是显式提示 Agent 压缩记忆,把具体案例归纳成通用规则。你可以在验证时故意制造这种情况,看 Agent 会不会掉进去,再决定要不要加压缩步骤。

如果你想在验证阶段直接和模型对话、快速试 prompt,可以用模型对话入口:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=model_chat。把AGENTS.md的内容贴进去,手动模拟召回,能更快定位是 prompt 问题还是链路问题。

验证通过的标准很简单:新会话不提要求,Agent 自动应用旧偏好;LangSmith trace 里能看到记忆文件被读取并进入 prompt;手动改记忆文件后,不重启也能生效。三条都满足,闭环就成了。

5. 常见报错排查:401、local proxy failed 与 reading choices 对照

链路跑起来之前,报错是常态。这一节把最常见的几类错误对照着排一遍,每个都给出真实报错文本和定位思路。

401 Unauthorized。报错通常长这样:

openai.AuthenticationError: Error code: 401 - {'error': {'message': 'Invalid API key', 'type': 'invalid_request_error'}}

先查 Key 有没有正确加载。最常见的原因是.env没被读取,或者环境变量名拼错。用echo $TAOTOKEN_API_KEY确认。如果 Key 是对的,检查 Base URL 是不是https://taotoken.net/api,末尾别带斜杠。还有一种情况:Claude Code 用了ANTHROPIC_API_KEY,但你在.env里只写了TAOTOKEN_API_KEY,两套变量没对上。Claude Code 场景下要确保settings.json里的env块写的是ANTHROPIC_API_KEY。

local proxy failed。报错类似:

Error: local proxy failed to connect: dial tcp 127.0.0.1:7890: connect: connection refused

这个错误说明某个组件在尝试走本地代理端口,但那个端口没有服务在监听。检查你的 shell 里有没有残留的HTTP_PROXY、HTTPS_PROXY、ALL_PROXY环境变量。用env | grep -i proxy看一眼。如果有,unset掉再重试。很多 SDK 会默认读取这些变量,即使你没主动配。

reading 'choices'。报错长这样:

TypeError: Cannot read properties of undefined (reading 'choices')

这通常意味着 API 返回的结构和 SDK 预期的不一致。可能原因有三个:一是 Base URL 配错了,请求打到了非兼容端点,返回了 HTML 或错误 JSON;二是 Model ID 写错了,服务端返回错误对象而不是正常的 completion 结构;三是流式和非流式模式混用。先确认TAOTOKEN_BASE_URL是https://taotoken.net/api,再确认 Model ID 在控制台可用列表里。打印完整响应体(print(resp))能看到真实返回,比猜快得多。

OAuth 相关报错。如果你用的是 Codex 或带 OAuth 的工具,可能遇到:

Error: OAuth token expired or invalid

这类工具通常有自己的认证流程,和 API Key 是两套。检查~/.codex/auth.json是否存在且格式正确:

{ "base_url": "https://taotoken.net/api", "api_key": "sk-你的真实key", "model": "claude-sonnet-4-5" }

Base URL、Key、Model ID 三件套写全。如果工具同时支持 OAuth 和 API Key,优先用 API Key,链路更短、排查更简单。

记忆文件写入失败。报错可能是:

PermissionError: [Errno 13] Permission denied: './agents/AGENTS.md'

检查文件路径是否存在、进程是否有写权限。如果用的是虚拟文件系统(Postgres 存储),检查数据库连接和表结构。DeepAgents 的虚拟文件系统是可插拔的,存储层配置错了也会报类似错误。

LangSmith trace 里看不到记忆读取。这不是报错,但比报错更隐蔽。表现是运行正常,但 trace 里只有模型调用,没有文件读取 span。原因通常是记忆文件路径没挂载对,或者 Agent 根本没触发读取逻辑。检查agents_md_path等配置是否指向真实存在的文件,再确认 Deep Agents 版本支持你用的文件约定。

排查顺序建议固定下来:先验通道(最小脚本调通),再验配置(三件套写全),再验文件(路径和权限),最后验追踪(LangSmith 能看到完整链路)。按这个顺序走,大部分问题能在前三步定位。接入相关的完整文档在https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=doc,报错信息拿去搜通常能找到对应说明。

6. 长期编码与 Agent 场景:把记忆系统用起来

记忆系统跑通之后,真正的价值在于长期使用。LangSmith 团队的经验里有一条特别值得记:Agent 擅长向文件添加内容,但不擅长压缩。他们的邮件助手曾经开始列出所有应该忽略的冷接触供应商,而不是更新自己“忽略所有冷接触”。这是典型的记住了具体案例但没泛化。

解决办法有两个。一是显式提示 Agent 压缩记忆,比如在会话结束时说“反思这次对话,把学到的通用规则更新到记忆里,具体案例归纳成规则”。二是加一个后台记忆进程,用 cron 每天跑一次,反思所有对话并更新记忆。LangSmith 计划做这个,你如果自建系统可以提前实现。

另一个实用技巧是/remember命令。LangSmith 想暴露一个显式的/remember,让用户主动提示 Agent 反思对话并更新记忆。在自建系统里,你可以用一个简单的触发词实现类似效果,比如用户输入“记住这次的经验”时,强制走一遍记忆写入流程。

对于长期编码和 Agent 场景,记忆系统的可移植性很重要。因为记忆是 markdown 和 json 文件,你可以把在 Agent Builder 里构建的 Agent 移植到 Deep Agents CLI,甚至其他 harness(只要文件约定一致)。LangSmith 特意用了尽可能多的标准约定,就是为了这个。你在设计自己的记忆系统时,也尽量用AGENTS.md、skills 这类通用格式,别自创一套 DSL——DSL 不能很好地随复杂度扩展,这是无代码构建器的通病。

如果你要跑长期的编码 Agent,建议用 Coding Plan 这类按周期计费的方式,比按 token 计费更可控:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=coding_plan。记忆系统会让 Agent 的上下文越来越长,调用量会上去,提前规划好计费方式能避免月底账单惊吓。

最后说一个我自己的做法:每次给 Agent 加新能力时,先手动在AGENTS.md里写一条规则,跑一次验证它能被召回,再让 Agent 自己维护。这样能确保记忆链路始终是通的,而不是等到积累了几十条规则后才发现某一条从来没生效过。记忆系统的可靠性,靠的是一次次小验证堆出来的。

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

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

立即咨询