ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

我们把 Hermes Agent 的记忆系统拆开看了:AI Agent 到底该怎么“记住”事情?

我们把 Hermes Agent 的记忆系统拆开看了:AI Agent 到底该怎么“记住”事情? 1. 为什么你的 Agent 总是“失忆”从 Hermes Agent 的五层记忆平面说起如果你正在搭建 AI Agent大概率遇到过这种尴尬用户昨天刚说过“我对花生过敏”今天 Agent 推荐餐厅时又热情地推了一道宫保鸡丁。或者更常见的Agent 能流畅回答当前这一轮但一旦你问“我们上周聊的那个方案进展如何”它就开始一本正经地胡说八道。这不是模型不够聪明而是记忆系统没设计好。很多开发者第一反应是“往 prompt 里多塞点历史”结果上下文越塞越长成本飙升、延迟爆炸prompt cache 频繁失效最后 Agent 反而变得更不稳定。Hermes Agent 的记忆系统之所以值得拆开看就是因为它把“记忆”这件事从“一个数据库表”升级成了五条记忆平面每条平面解决不同的问题边界清晰。这五条平面分别是内置事实记忆MEMORY.md / USER.md、会话搜索记忆state.db FTS5、外部 Provider 记忆Honcho / Mem0 / Hindsight 等插件、上下文压缩记忆ContextEngine compressor session lineage、程序性记忆Skills slash command curator。事实记忆解决“用户是谁、长期偏好是什么”会话搜索解决“过去某次对话里说过什么”Provider 记忆解决“语义相似、用户画像、知识图谱”上下文压缩解决“窗口满了怎么不断线”Skills 解决“复杂流程不该写进事实记忆”。这套架构的核心洞察是生产级记忆系统首先是缓存边界设计。什么内容常驻 system prompt什么内容按需搜索什么内容只在当前 API 调用里临时注入这三者的边界如果模糊记忆越多 Agent 越容易崩。本文会带你从零接入这套思路给出可复制的配置片段、Skills 挂载示例并完整演示一次记忆写入与召回验证流程帮你判断自己的 Agent 该在何处落记忆。2. TaoToken 前置准备给 Agent 记忆系统接上稳定的模型调用底座在动手拆记忆系统之前得先解决一个现实问题Agent 的每一轮对话、每一次记忆召回后的上下文注入都要调用大模型。如果模型调用层不稳定记忆系统再优雅也跑不起来。我试过在本地直接调各家 API切换模型时改代码改到崩溃后来把调用层统一收敛到 TaoToken 上Base URL 和 Key 一套配置走天下切换模型只改一个 Model ID 字符串。TaoToken 在这里扮演的角色是统一的模型接入层它本身不是记忆系统但它是记忆系统能稳定运行的前提。你可以把它理解成 Agent 的“电源插座”记忆模块负责存和取TaoToken 负责把取出来的记忆连同当前对话一起送给模型再把模型输出拿回来。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点固定为 https://taotoken.net/api 注意 API 地址后面不加任何 UTM 参数保持干净。为什么记忆系统特别依赖稳定的模型层因为记忆召回往往发生在对话中途比如用户问了一个需要历史上下文的问题Agent 要先搜索 state.db、再调用 Provider 做语义检索、再把结果 fenced 注入当前 user message 的 API copy。这一串操作里只要模型调用超时或报错整个召回链路就断了用户体验就是“Agent 又失忆了”。所以前置准备阶段我建议先把模型调用跑通再往上叠记忆模块。具体操作上你需要先拿到 API Key。进入控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 在 API Keys 页面创建一个新 Key复制保存。然后验证模型对话是否正常可以打开模型对话页面 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 直接测试确认返回正常。如果你打算长期跑编码类 Agent可以了解 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 它更适合高频调用的场景。这一步的关键是先把 Base URL、Key、Model ID 三件套固定下来后面所有记忆模块的配置都复用这套。很多人在记忆系统调试时把模型调用和记忆逻辑混在一起排查结果分不清是模型挂了还是记忆没召回前置准备就是把这个变量先锁死。3. 可复制配置Hermes Agent 记忆模块的 JSON/TOML 片段与 Skills 挂载现在进入正题。Hermes Agent 的记忆系统配置核心在于把五条平面分别声明清楚而不是揉成一坨。下面给出可直接复制的配置片段路径和字段名保持与 Hermes Agent 源码结构一致你可以按自己的项目目录调整。首先是主配置文件config.toml它声明了记忆平面的开关和 Provider 接入方式[agent] name hermes-memory-demo model claude-sonnet-4-20250514 base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY [memory.builtin] enabled true memory_file ./memory/MEMORY.md user_file ./memory/USER.md max_tokens 800 freeze_on_session_start true [memory.session_search] enabled true db_path ./state/state.db fts_table session_fts search_tool session_search max_results 5 [memory.provider] enabled true plugin honcho endpoint https://api.honcho.dev api_key_env HONCHO_API_KEY inject_as memory-context fence true [memory.context_engine] enabled true compressor summary session_split_threshold 0.85 preserve_tool_pairs true [skills] enabled true dir ./skills curator auto这里有几个字段值得单独说。freeze_on_session_start true是 Hermes Agent 保护 prompt cache 的关键MEMORY.md 和 USER.md 在会话开始时加载一次后就冻结中途不再改动这样 system prompt 的哈希值保持稳定缓存不会失效。inject_as memory-context配合fence true意思是外部 Provider 召回的内容不会直接写进 system prompt而是用memory-context标签包裹后注入到当前 user message 的 API copy 里只在这一次调用生效。接下来是 Skills 的挂载示例。Skills 承担程序性记忆比如“如何生成周报”“如何排查部署失败”这些流程不该写进事实记忆。一个 Skill 的目录结构如下{ name: weekly-report, description: 根据 state.db 中的会话记录生成周报, trigger: [周报, weekly report], steps: [ 调用 session_search 检索本周会话, 按项目分组摘要, 输出 Markdown 格式周报 ], memory_access: { read: [session_search], write: [] } }注意memory_access.write是空数组这是刻意的Skills 只读记忆不写事实记忆避免程序性流程污染 MEMORY.md。如果你用 Cline MCP 或 Claude Code 接入配置里同样要写全三件套。以 Claude Code 的settings.json为例{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-your-taotoken-key, ANTHROPIC_MODEL: claude-sonnet-4-20250514 } }如果你用 Codex对应的auth.json里也要把 Base URL、Key、Model ID 三件套写全缺一个都会导致 401 或模型找不到。配置完成后记忆模块的加载顺序是先读 MEMORY.md / USER.md 冻结进 system prompt再初始化 state.db 和 FTS5 索引然后加载 Provider 插件最后挂载 Skills。这个顺序不能乱否则 Provider 可能在数据库还没就绪时就尝试写入。4. 验证请求一次完整的记忆写入与召回流程实测配置写好了得验证它真的能记住事情。下面演示一次完整的记忆写入与召回流程你可以跟着操作。第一步写入一条事实记忆。假设用户说“我下个月要搬到上海以后推荐本地服务优先考虑上海”。这条信息应该进 MEMORY.md 还是 USER.md判断标准是跟用户身份和长期偏好相关的进 USER.md跟项目或任务相关的进 MEMORY.md。搬家属于用户长期状态写入 USER.mdecho - 用户计划下个月搬到上海本地服务推荐优先上海 ./memory/USER.md第二步触发一次会话搜索。假设三天后用户问“我之前说的搬家计划是什么时候”。Agent 的session_search工具会去 state.db 里检索from hermes.memory import session_search results session_search( query搬家 上海 计划, db_path./state/state.db, limit5 ) for r in results: print(r.session_id, r.timestamp, r.snippet)预期输出会返回包含“搬家”“上海”关键词的历史会话片段按时间倒序排列。FTS5 的优势是即使你搜“搬家”也能命中“搬到上海”这种表述因为它做了分词和倒排索引。第三步验证 Provider 召回与 fenced 注入。当用户问“推荐个上海本地的健身房”Agent 会先调用 Provider 做语义检索Honcho 返回用户画像里“偏好安静、不喜欢人多”的标签然后这段内容被包裹成memory-context sourcehoncho trustexternal 用户偏好安静环境不喜欢人多嘈杂的场所。 /memory-context这段memory-context不会进 system prompt而是拼接到当前 user message 的 API copy 里随本次请求发给模型。你可以用下面的代码验证注入是否生效import requests payload { model: claude-sonnet-4-20250514, messages: [ {role: system, content: open(./memory/USER.md).read()}, {role: user, content: memory-context source\honcho\用户偏好安静环境/memory-context\n推荐个上海本地的健身房} ] } resp requests.post( https://taotoken.net/api/v1/messages, headers{x-api-key: sk-your-key, anthropic-version: 2023-06-01}, jsonpayload ) print(resp.json()[content][0][text])如果返回的推荐里出现了“安静”“人少”“非高峰时段”这类关键词说明 Provider 记忆成功影响了本次生成。实测下来这套流程从写入到召回大约 200 毫秒主要耗时在 Provider 的网络请求上本地 FTS5 搜索基本在 10 毫秒内完成。第四步验证上下文压缩。当会话 token 超过session_split_threshold默认 0.85时ContextEngine 会触发压缩把早期对话摘要成一段 summary同时保留工具调用配对。你可以通过查看 state.db 里的session_lineage表确认压缩是否发生SELECT session_id, parent_session_id, compressed_at, summary_tokens FROM session_lineage ORDER BY compressed_at DESC LIMIT 3;如果看到新的 session_id 带着 parent_session_id 指向旧会话说明 session split 正常工作了。5. 本篇常见错排查401、local proxy failed、reading choices 与 OAuth 报错记忆系统调试时报错往往不在记忆逻辑本身而在模型调用层。下面按真实报错逐个排查。401 Unauthorized最常见。先检查TAOTOKEN_API_KEY环境变量是否真的被读取到很多人把 Key 写进配置文件但忘了 export。然后确认 Base URL 是https://taotoken.net/api注意结尾没有斜杠也没有多余的/v1有些 SDK 会自动拼/v1/messages你手动再加就变成/v1/v1/messages。如果你用 Claude Code检查settings.json里的ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY是否都填了缺一个就 401。local proxy failed这个报错通常出现在你本地起了代理但配置没对齐。检查你的 HTTP_PROXY / HTTPS_PROXY 环境变量是否指向了一个没启动的端口。记忆系统里 Provider 插件如果走了本地代理代理挂了就会报这个。解决办法是确认代理进程在跑或者干脆在配置里把 Provider 的 endpoint 直连。reading choices 报错这个一般出现在解析模型返回时。如果你用的是 OpenAI 兼容格式的 SDK但模型返回的是 Anthropic 格式解析choices字段就会失败。检查你的请求路径和响应格式是否匹配。用 TaoToken 时确认你调的是/v1/messagesAnthropic 格式还是/v1/chat/completionsOpenAI 格式两者返回结构不同。OAuth 相关报错如果你用 Claude Code 或 Codex 的 OAuth 登录方式但同时又配了 API Key两者会冲突。建议统一用 API Key 方式把 OAuth token 清掉。Codex 的auth.json里如果同时有oauth_token和api_key优先走 OAuth导致你的 Base URL 配置被忽略。删掉 OAuth 字段只留三件套。记忆召回为空如果模型调用正常但召回没结果先查 state.db 里有没有数据再查 FTS5 索引是否建了。Hermes Agent 的 FTS5 表需要手动初始化一次CREATE VIRTUAL TABLE IF NOT EXISTS session_fts USING fts5( content, session_id, timestamp );如果表存在但搜不到可能是分词问题中文需要确认 FTS5 用了 unicode61 分词器。Provider 注入污染 system prompt如果你发现 system prompt 里混进了外部召回内容检查inject_as和fence配置。正确行为是外部内容只进 user message 的 API copy不进 system prompt。如果配错了prompt cache 会频繁失效成本飙升。6. 从记忆平面到生产级 Agent把边界感变成你的架构习惯拆完 Hermes Agent 的记忆系统最值得带走的不是某段配置而是那种边界感。小事实常驻 prompt大历史进数据库语义记忆交给 Provider长上下文交给 ContextEngine复杂流程交给 Skillsrecall 只在当前 API 调用里 fenced 注入。这套拆分之所以能跑起来是因为每一层都清楚自己该管什么、不该管什么。如果你正在设计自己的 Agent 记忆系统建议先从最小可用版本开始MEMORY.md USER.md 做事实记忆state.db FTS5 做会话搜索这两层就能覆盖 80% 的场景。等遇到语义检索需求时再接 Provider遇到上下文爆炸时再上 ContextEngine。不要一上来就把五层全堆上去那样调试成本太高。实际落地时模型调用层建议用 TaoToken 统一收敛Base URL 固定https://taotoken.net/apiKey 从控制台 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 获取接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 可以查到各语言的完整示例。如果你跑的是长期编码类 AgentCoding Plan 比按量调用更划算如果只是验证模型对话和记忆召回模型对话页面就够用。最后留一个我踩过的坑Skills 的memory_access.write一定要留空。我一开始图省事让 Skill 直接写 MEMORY.md结果程序性流程把事实记忆污染得乱七八糟用户偏好里混进了一堆“如何生成周报”的步骤。记住事实记忆和程序性记忆是两种东西别让它们互相串门。
返回列表