本文介绍了LangSmith Agent Builder的记忆系统构建过程,该系统将记忆表示为文件,利用文件系统让Agent可以方便地读取和修改记忆。文章详细阐述了如何利用AGENTS.md、agent skills等行业标准来定义Agent的指令集和技能,以及如何使用虚拟文件系统来存储和管理Agent的记忆,并分享了构建该记忆系统过程中的经验教训。
我们如何构建 Agent Builder 的记忆系统
什么是 LangSmith Agent Builder?LangSmith Agent Builder 是一个无需代码的 agent 构建器。它构建于 Deep Agents harness 之上。它是一个面向 技术能力较弱 的市民开发者的托管式 Web 解决方案。在 LangSmith Agent Builder 中,构建者将创建一个 agent 来自动化特定的工作流程或他们一天中的一部分工作。示例包括 电子邮件助手 和 文档助手 等。

早期,我们有意识地选择将记忆作为平台的一部分来优先考虑。这不是一个显而易见的选择——大多数 AI 产品最初发布时没有任何形式的记忆,即使添加了记忆,也 尚未像某些人预期的那样改变产品。我们优先考虑它的原因是由于我们用户的使用模式。
与 ChatGPT、Claude 或 Cursor 不同,LangSmith Agent Builder 不是一个通用的 agent。相反,它是专门为让构建者自定义 agent 以执行特定任务而设计的。在通用 agent 中,你正在执行各种可能完全不相关的任务,因此从与 agent 的一个会话中获得的知识可能与下一个会话无关。当 LangSmith Agent 正在执行任务时,它会一遍又一遍地执行相同的任务。从一个会话中获得的经验教训以更高的速率转化为下一个会话。实际上,如果不存在记忆,那将是一种糟糕的用户体验——这意味着你必须在不同的会话中一遍又一遍地向 agent 重复自己。
在考虑记忆对于 LangSmith Agent 到底意味着什么时,我们求助于第三方对记忆的定义。COALA 论文 将 agent 的记忆分为三个类别:
程序性(Procedural):可以应用于工作记忆以确定 agent 行为的规则集
语义性(Semantic):关于世界的客观事实
情景性(Episodic):agent 过去行为的序列

我们如何构建我们的记忆系统
我们在 Agent Builder 中将记忆表示为一组文件。这是一个有意的选择,旨在利用模型 擅长使用文件系统 这一事实。这样,我们可以轻松地让 agent 读取和修改其记忆,而不必赋予它专门的工具——我们只需让它访问文件系统即可!
在可能的情况下,我们尝试使用行业标准。我们使用 AGENTS.md 来定义 agent 的核心指令集。我们使用 agent skills 来为 agent 提供针对特定任务的特定专业指令。没有子代理标准,但我们使用 类似于 Claude Code 的格式。对于 MCP 访问,我们使用自定义的 tools.json 文件。我们使用自定义的 tools.json 文件而不是标准的 mcp.json 的原因是,我们希望允许用户仅向 agent 提供 MCP 服务器中的一部分工具,以避免上下文溢出。
我们还允许用户(和 agent 自己)将其他文件写入 agent 的记忆文件夹。这些文件也可以包含任意知识,agent 可以在运行时引用这些知识。agent 会在工作时编辑这些文件,“ in the hot path ”。

实际上,我们不使用真实的文件系统来存储这些文件。相反,我们将它们存储在 Postgres 中,但以文件系统的形式将其公开给 agent。我们这样做是因为 LLM 非常擅长使用文件系统,但从基础设施的角度来看,使用数据库更容易且更有效。这个“虚拟文件系统”是 DeepAgents 原生支持的 ——并且是完全可插拔的,因此你可以引入你想要的任何存储层(s3、MySQL 等)。

之所以可以在没有任何代码或任何特定领域语言 (DSL) 的情况下构建复杂的 agent,是因为我们在底层使用了像 Deep Agents 这样的通用 agent harness。Deep Agents 抽象了许多复杂的上下文工程(如 summarization, tool call offloading, and planning ),并让你通过相对简单的配置来引导你的 agent。
这些文件很好地映射到 COALA 论文中定义的记忆类型。程序性记忆——驱动核心 agent 指令——是 AGENTS.md 和 tools.json。语义记忆是 agent skills 和其他知识文件。唯一缺失的记忆类型是情景记忆,我们认为对于这些类型的 agent 来说,它没有其他两种记忆那么重要。
文件系统中 agent 记忆是什么样的
我们可以看看我们一直在内部使用的真实 agent——一个在 LangSmith Agent Builder 上构建的 LinkedIn 招聘人员。
: 定义核心 agent 指令
subagents/ : 仅定义一个子代理 linkedin_search_worker:在主 agent 完成搜索校准后,它将启动此 agent 来寻找约 50 名候选人。
tools.json : 定义一个可以访问 LinkedIn 搜索工具的 MCP 服务器
目前记忆中还有其他 3 个文件,代表不同候选人的 JD。当我们使用 agent 处理这些搜索时,它已经更新并维护了这些 JD。

记忆编辑如何工作:一个具体的例子
为了更具体地说明记忆如何工作,我们可以通过一个说明性的例子。
开始:
你从一个简单的 AGENTS.md 开始:
总结会议记录。
第一周:
该 agent 生成段落摘要。你纠正它:“使用项目符号”。该 agent 编辑它的 AGENTS.md 为:
格式偏好 用户喜欢用于摘要的项目符号,而不是段落。
第二周:
你要求 agent 总结另一次会议。它读取其记忆并自动使用项目符号。无需提醒。在此会话期间:“最后单独提取行动项。”记忆更新:
格式偏好 用户喜欢用于摘要的项目符号,而不是段落。在最后单独的部分提取行动项。
第四周:
两种模式自动应用。你继续添加改进,因为新的极端情况浮出水面。
第三个月:
该 agent 的记忆包括通过使用积累的更多偏好、术语、区别、重复的概念、会议处理和极端情况更正。记忆文件可能如下所示:
会议摘要偏好 ## 格式 - 使用项目符号,而不是段落 - 在最后单独的部分提取行动项 - 对决策使用过去时 - 在顶部包含时间戳 ## 会议类型 - 工程会议:高亮显示技术决策和理由 - 计划会议:强调优先级和时间表 - 客户会议:编辑敏感信息 - 短会议(<10 分钟):仅关键点 ## 人员 - Sarah Chen(工程主管)- 关注技术细节 - Mike Rodriguez (PM) - 关注业务影响 ...
AGENTS.md 通过更正自行构建,而不是通过预先文档化。我们以迭代方式获得了适当详细的 agent 规范,而用户从未手动更改 AGENTS.md。
构建此记忆系统的经验教训
在此过程中,我们吸取了几个教训。
最难的部分是 prompting
构建一个可以记住事情的 agent 最难的部分是 prompting。在几乎所有 agent 表现不佳的情况下,解决方案是改进 prompt。通过这种方式解决的问题示例:
agent 没有记住它应该记住的时候
agent 在不应该记住的时候记住了
agent 向 AGENTS.md 写入了太多内容,而不是写入 skills
agent 不知道 skills 文件的正确格式
... 还有很多
我们有一个人全职从事记忆的 prompting(这是团队的很大一部分)。
验证文件类型
有几个文件有它们需要遵守的特定模式(tools.json 需要有有效的 MCP 服务器,skills 需要有正确的文件头等)。我们看到 Agent Builder 有时会忘记这一点,因此生成了无效的文件。我们添加了一个步骤来明确验证这些自定义形状,并且,如果验证失败,将任何错误抛回给 LLM,而不是提交文件。
Agent 擅长向文件中添加内容,但不擅长压缩
Agent 在工作时编辑其记忆。他们非常擅长向文件中添加特定内容。然而,他们不擅长的一件事是意识到何时压缩知识。例如:我的电子邮件助手一度开始列出它应该忽略冷酷外展的所有特定供应商,而不是更新自己以忽略所有冷酷外展。
显式 prompting 有时仍然对最终用户有用
即使 agent 能够Update its memory as it worked, there were still several cases where (as an end user) we found it useful to prompt the agent explicitly to manage its memory. One such case was at the end of its work to reflect on the conversation and update its memory for any things it may have missed. Another case was to prompt it to compact its memory, to solve for the case where it was remembering specific cases but not generalizing.
人工智能辅助
我们对记忆的所有编辑都是人机协作的——也就是说,在更新之前需要明确的人工批准。这主要是为了最大限度地减少 prompt 注入的潜在攻击媒介。我们确实向用户公开了一种关闭它的方法(“yolo 模式”),以防他们不太担心这一点。
这实现了什么
除了更好的产品体验外,以这种方式表示记忆还可以实现许多事情。
无代码体验
无代码构建器的一个问题是,它们要求你学习一种不熟悉的 DSL,这种 DSL 不能很好地随着复杂性而扩展。通过将 agent 表示为 markdown 和 json 文件,agent 现在采用了一种 (a) 大多数技术能力较弱的人都熟悉的格式,(b) 更具可扩展性。
更好的 agent 构建
记忆实际上可以带来更好的 agent 构建体验。Agent 构建是高度迭代的——在很大程度上是因为在尝试之前你不知道 agent 会做什么。记忆使迭代更容易,因为你可以只用自然语言提供反馈,它就会自行更新,而不是每次都手动更新 agent 配置。
可移植的 agent
文件非常便携!这使你可以轻松地将在 agent 构建器中构建的 agent 移植到其他 harness(只要它们使用相同的文件约定)。出于这个原因,我们尝试尽可能多地使用标准约定。例如,我们希望可以轻松地在 Deep Agents CLI 中使用在 agent 构建器中构建的 agent。或者完全使用其他 agent harness,如 Claude Code 或 OpenCode。
未来方向
我们有很多想要实现的记忆改进,但在发布之前我们没有足够的时间或足够的信心来实现。
情景记忆
Agent Builder 缺失的一种 COALA 记忆类型是情景记忆:agent 过去行为的序列。我们计划通过将以前的对话作为 agent 可以与之交互的文件系统中的文件来公开来实现这一点。
后台记忆过程
目前,所有记忆都在“热路径”中更新;也就是说,当代理运行时。我们希望添加一个在后台运行的进程(可能是一些 cron 作业,每天运行一次左右)来反思所有对话并更新记忆。我们认为这将捕获代理未能立即识别的项目,并且对于概括特定知识特别有用。

/remember
我们希望公开一个明确的 /remember 命令,以便你可以 prompt agent 反思对话并更新其记忆。我们发现自己偶尔这样做会带来很大的好处,因此希望使其更容易并受到更多鼓励。
语义搜索
虽然能够使用 glob 和 grep 搜索记忆是一个很好的起点,但在某些情况下,允许 agent 对其记忆进行语义搜索会提供一些收获。
不同级别的记忆
目前,所有记忆都是特定于该 agent 的。我们没有用户级别或组织级别记忆的概念。我们计划通过向 agent 公开代表这些类型记忆的特定目录,并 prompt agent 使用和更新这些记忆来实现这一点。
结论
如果构建具有记忆的 agent 听起来很有趣,请尝试 LangSmith Agent Builder。如果你想帮助我们构建这个记忆系统,我们正在招聘。
- 原文链接: x.com/hwchase17/status/2...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!