Hermes Agent 的上下文与内存存储:从 Prompt Cache 到长期记忆的技术实现 很多 Agent 系统把「上下文」和「记忆」混在一起讲历史消息是记忆用户偏好是记忆RAG 召回也是记忆压缩摘要也叫记忆。Hermes Agent 的实现更清楚它把这些东西拆成几层各自有明确边界Prompt context本轮要发给模型的上下文。Session history完整会话事实用来恢复、搜索、审计。Context compression长上下文里的中段摘要用来继续当前任务。Curated memoryMEMORY.md/USER.md里的长期稳定事实。External memory providerHoncho、Mem0、Hindsight、Supermemory 等外部长期记忆后端。Session search从历史会话里找过去发生过什么。这套设计的核心不是「尽量多记」而是「不同类型的信息进入不同存储平面」。一句话架构Hermes 的上下文管线可以理解成用户输入 - canonical messages[] 记录真实对话 - system prompt 使用会话级缓存 - external memory prefetch 临时注入当前 user message - api_messages 发给模型 - assistant/tool 结果回写 messages[] - JSON SQLite 增量落库 - 必要时压缩上下文并切出 continuation session - 完整 turn 成功后同步外部 memory provider这个流程里最重要的分离是messages[]是事实日志api_messages是请求视图。messages[]里保存的是用户真正说了什么、模型真正调用了什么工具、工具真正返回了什么。api_messages是每次 API call 前临时构造出来的副本它可以加入 system prompt、memory prefetch、plugin context、provider 兼容修复但这些内容不会污染持久化 transcript。System Prompt分层构建但会话内保持稳定Hermes 的 system prompt 不是每一轮都重新拼一遍。run_agent.py里的_build_system_prompt_parts()把 prompt 拆成三层层内容变化频率stable身份、工具规则、技能规则、平台提示、模型行为规则会话级稳定context当前项目的上下文文件例如.hermes.md、HERMES.md、调用方传入的 system message会话级稳定volatileMEMORY.md/USER.md快照、外部 memory provider 的静态说明、时间戳、model/provider 信息会话启动时确定这个命名有点反直觉volatile不是每轮变化而是「相对 stable/context 更可能随 session 改变」。真正运行时Hermes 会把完整 system prompt 缓存在_cached_system_prompt里。继续会话时如果 SQLite 里已经有system_promptHermes 会优先复用存储的 prompt snapshot而不是从磁盘重新读取 memory 再拼一次。原因很直接Anthropic / OpenRouter 这类 provider 的 prompt cache 依赖前缀字节稳定。哪怕MEMORY.md中途被更新了也不会在同一会话里改 system prompt否则缓存前缀会失效。对应源码位置模块关键点run_agent.py_build_system_prompt_parts()拆出 stable/context/volatilerun_agent.py_build_system_prompt()组装完整 promptrun_agent.pyrun_conversation()首轮构建并保存继续会话复用 DB 中的system_prompthermes_state.pysessions.system_prompt持久化 prompt snapshotContext Files项目上下文进入 prompt但先做注入扫描项目级上下文文件由agent/prompt_builder.py负责扫描比如.hermes.md、HERMES.md、SOUL identity 等。它不是简单把文件读进 prompt而是先做安全扫描ignore previous instructionssystem prompt overridehidden HTML comment / hidden div读取.env、credentials 的模式curl/wget 携带 secret 的 exfiltration 模式不可见 unicode 控制字符如果命中风险Hermes 不会把原文注入 system prompt而是替换成一个 blocked 提示。这一点很关键项目上下文文件本质上是高权限 prompt 输入安全等级接近 system prompt。Built-in MemoryMEMORY.md和USER.md是冻结快照Hermes 的内置长期记忆由tools/memory_tool.py实现。它只有两个文件文件存什么例子~/.hermes/memories/MEMORY.mdAgent 自己学到的稳定事实项目惯例、工具 quirks、环境事实~/.hermes/memories/USER.md用户画像和偏好用户喜欢中文、希望直接给结论它们不是完整日志也不是任务进度。Hermes 的MEMORY_GUIDANCE明确要求用户偏好、稳定约定、环境事实可以写 memory。PR 号、commit SHA、一次性任务结果、临时 TODO 不应该写 memory。工作流、命令组合、排错路径应该写成 skill而不是 memory。内置 memory 的实现有几个值得注意的点。3.1 字符预算不是 token 预算MemoryStore默认限制memory_char_limit: 2200user_char_limit: 1375它用字符数限制而不是 token 数。原因是字符数不依赖具体模型简单、可预测、跨 provider 一致。3.2 条目分隔符是§多个 memory entry 不是 YAML list也不是 JSON array而是用\n§\n分隔。这样 entry 可以多行同时文件仍然保持 Markdown 友好。3.3 写入前做注入/外泄扫描memory 会被注入未来 system prompt所以 Hermes 在add()/replace()前会扫描内容prompt injection忽略旧指令、角色劫持、隐藏用户可见性secret exfiltrationcurl/wget 带环境变量、读取.env等SSH 后门相关路径invisible unicode命中后直接拒绝写入。3.4 原子写避免并发读到半截文件写入不是open(w)覆盖文件而是写临时文件 - flush fsync - atomic_replace(tmp, target)再配合.lock文件做跨进程互斥。这样并发 agent 读 memory 时要么看到旧完整文件要么看到新完整文件不会看到被截断的中间状态。3.5 会话内 memory 是冻结快照MemoryStore.load_from_disk()会读取MEMORY.md/USER.md并生成_system_prompt_snapshot。format_for_system_prompt()返回的是这个快照而不是 live entries。这意味着本会话中调用memory(actionadd)会立刻写磁盘但不会马上改变当前 system prompt。下一次新 session 才会读到新的 memory。这是一个很务实的取舍牺牲「立刻进入 prompt」的实时性换取会话内 prompt cache 稳定。External Memory Provider统一生命周期最多一个外部后端除了内置MEMORY.md/USER.mdHermes 还有外部 memory provider 机制抽象定义在agent/memory_provider.py编排器在agent/memory_manager.py。外部 provider 的核心生命周期是initialize(session_id, hermes_home, platform, user_id, chat_id, ...) system_prompt_block() on_turn_start(turn_number, message) prefetch(query) sync_turn(user_content, assistant_content) queue_prefetch(query) on_pre_compress(messages) on_session_switch(new_session_id, parent_session_id, reset, ...) on_session_end(messages) shutdown()Hermes 有一个很强的限制同一时间只允许一个 external provider。内置 memory 可以一直存在但 Honcho、Hindsight、Mem0、OpenViking、RetainDB、Supermemory 这类外部 provider 只能启用一个。原因不是功能不够而是工程上的控制避免多个 provider 都向模型暴露工具造成 tool schema 膨胀。避免同一条 turn 被多个后端写入语义冲突。避免多个召回结果同时注入当前上下文稀释任务焦点。MemoryManager.add_provider()会拒绝第二个非 builtin provider并记录 warning。Memory Prefetch临时注入 user message不进 system prompt每轮对话开始后Hermes 会先通知 memory provideron_turn_start(...)然后调用prefetch_all(original_user_message)得到的 recall 结果不会改 system prompt而是在构造api_messages时临时追加到当前 user message 后面用户原始输入 memory-context [System note: The following is recalled memory context, NOT new user input...] 召回内容 /memory-context这个设计解决两个问题保护 prompt cachesystem prompt 不动cache 前缀稳定。保护 transcriptrecall 只是本轮 API 请求视图不写入messages[]不会污染恢复后的历史。Hermes 还做了两层防护sanitize_context()会去掉 provider 输出里已有的memory-context、系统 note、嵌套上下文块。StreamingContextScrubber会在流式输出时跨 chunk 擦除memory-context防止模型把内部 recall 泄漏给用户。这说明 Hermes 把外部 memory 当成「高价值但不完全可信的上下文源」而不是直接拼到高权限 system prompt。Session Store完整会话事实进入 SQLiteHermes 的会话持久化在hermes_state.py默认数据库是~/.hermes/state.db主要表结构包括表用途sessionssession 元数据、source、model、system_prompt、parent_session_id、token/cost、titlemessages完整消息历史包含 role、content、tool_calls、tool_call_id、reasoning 等messages_ftsFTS5 全文索引messages_fts_trigram面向 CJK / substring 的 trigram 索引state_meta状态元数据它不是简单 SQLite 连接而是做了几件生产化处理。6.1 WAL 模式 网络文件系统 fallback默认启用 WAL支持 gateway 多线程读写。但 WAL 在 NFS、SMB、部分 FUSE 文件系统上可能报locking protocol。Hermes 不会直接崩而是 fallback 到journal_modeDELETE。这会牺牲并发性能但能保证/resume、/history、session_search这些功能可用。6.2 应用层写锁与 jitter retrySQLite 的 busy handler 是确定性等待多个 Hermes 进程竞争写锁时容易 convoy。SessionDB._execute_write()用BEGIN IMMEDIATE - 写入 - commit 失败 database locked / busy: - 20-150ms random jitter - retry up to 15 times这比单纯拉长 SQLite timeout 更适合多 agent / gateway 场景。6.3 增量落库避免重复写消息run_agent.py维护_last_flushed_db_idx。每次_persist_session()调用都会保存 JSON session log。调用_flush_messages_to_session_db()。只从max(conversation_history_len, _last_flushed_db_idx)开始写新消息。这样即使多个 exit path 都触发持久化也不会把同一条消息重复写进 SQLite。6.4 多模态内容会降级为可搜索文本如果消息 content 是图片或多模态结构SQLite 不会直接保存 base64 大对象。Hermes 会对 multimodal tool result 保存 text summary。对 image part 保存[screenshot]。对 list content 提取 text block。这样 session store 仍然适合恢复、搜索和审计而不会被图片 payload 撑爆。Context Compression不是删除历史而是切 session 链Hermes 的上下文压缩由agent/context_compressor.py实现并通过run_agent.py的_compress_context()调用。触发条件来自配置compression: enabled: true threshold: 0.50 target_ratio: 0.20 protect_first_n: 3 protect_last_n: 20实际运行时还会结合模型 context length、provider 返回的prompt_tokens、工具 schema token 估算来判断是否压缩。压缩算法大致分四步Cheap pre-pass先压缩旧 tool result比如把长终端输出变成一行摘要。保护头部system prompt 和最早的关键消息保留。保护尾部按 token budget 保留最近上下文并强制保留最后一个 user message避免当前任务被压进摘要里。总结中段用 auxiliary compression model 生成结构化 handoff summary。生成的 summary 不是普通摘要而是带强约束的 checkpointActive TaskGoalConstraints PreferencesCompleted ActionsActive StateIn ProgressBlockedKey DecisionsResolved QuestionsPending User AsksRelevant FilesRemaining WorkCritical Contextsummary 前面还会加一段SUMMARY_PREFIX明确告诉后续模型这是旧上下文的 handoff不是新的用户请求。压缩后为什么要切出新 sessionHermes 压缩后不会只在内存里替换messages[]。它会对旧 session 调用commit_memory_session()让 memory provider 抽取旧 session 的信息。把旧 session 标记为end_reason compression。生成新的session_id。创建新 session row并设置parent_session_id old_session_id。把压缩后的 messages 写入新 session。通知 context engine 和 memory provider这是 compression-driven session switch不是 fresh reset。这个设计很重要。它让历史有一条 lineage原始 session --compression-- continuation session --compression-- 下一段 continuation session恢复会话时Hermes 可以通过resolve_resume_session_id()/get_compression_tip()找到压缩链的最新 tip而不是把用户带回已经结束的旧 session。换句话说Hermes 的压缩不是「删历史」而是「把当前可运行上下文迁移到一个 continuation session同时保留旧 session 的审计记录」。Session Search过去发生过什么不写进 memoryHermes 明确要求任务进度、会话结果、临时结论不要写进MEMORY.md。那以后用户问「上次那个问题怎么处理的」怎么办答案是session_search。tools/session_search_tool.py的流程是FTS5 搜索 messages - 按 session 聚合 top matches - 加载相关 session 的 conversation - 围绕匹配点截断到约 100k chars - 调用 auxiliary.session_search model 总结 - 返回聚焦摘要这和 memory 的边界很清楚问题用什么用户长期偏好是什么USER.md环境/项目稳定事实是什么MEMORY.md上次任务发生了什么session_search当前长上下文快爆了怎么办ContextCompressor当前问题相关的语义记忆是什么external memory provider prefetch三类“记住”的存储边界Hermes 的三类记住Hermes 的记忆系统最值得借鉴的是边界设计而不是某个单点实现。会话历史回答过去发生过什么存储位置~/.hermes/state.db ~/.hermes/sessions/session_id.json典型用途/resume/history/branchsession_searchgateway 多平台会话恢复debug / audit长期记忆回答以后每次都该知道什么存储位置~/.hermes/memories/MEMORY.md ~/.hermes/memories/USER.md典型用途用户偏好环境事实长期项目约定工具 quirks外部记忆回答当前问题相关的过往知识是什么存储位置取决于 providerHonchoHindsightMem0OpenVikingRetainDBSupermemoryByteRoverHolographic典型用途语义召回多 session 事实抽取provider 自带的 memory graph / hybrid search / summarization为什么 memory prefetch 不直接写 system prompt这是 Hermes 在工程上很成熟的点。如果每轮都把外部 memory recall 拼到 system prompt会带来几个问题Prompt cache 失效system prompt 前缀每轮都变。权限边界变模糊外部 provider 返回内容等同 system 指令风险太高。会话恢复污染如果 recall 被持久化下一次 resume 会把旧 recall 当成用户/assistant 历史。召回错误难隔离provider 一次错召回会污染整个 session而不是只影响当前 API call。所以 Hermes 选择把 recall 包在memory-context中临时追加到当前 user message。它的语义是「参考资料」不是「新用户输入」也不是「系统规则」。为什么 built-in memory 写入后不立刻刷新 prompt这也是 prompt cache 驱动的取舍。如果用户在第 5 轮说「记住我以后都用 SOTA AI 作为公众号作者名」memory tool 会马上写USER.md或MEMORY.md。但是当前 session 的 system prompt 已经缓存。如果立刻刷新system prompt 字节变化上游 prefix cache 失效继续会话时同一 session 的 system prompt snapshot 和 DB 中已存版本不一致多 gateway agent 复用时更难推理。所以 Hermes 的策略是写磁盘立即生效于未来 session当前 session 通过 tool response 知道写入成功但 system prompt 不变。这和很多「实时长期记忆」实现不同。Hermes 更偏向稳定性和可恢复性。实现上的关键不变量如果要复刻 Hermes 的上下文/记忆架构我认为有 7 条不变量最重要。不变量 1system prompt 是会话快照同一个 session 内system prompt 应该尽量不变。需要变更时例如 context compression必须显式 invalidation并把新 prompt snapshot 写入 session store。不变量 2canonical transcript 不能被临时 recall 污染持久化的messages[]应该只包含真实对话和工具执行事实。外部 memory、plugin context、临时 steer 都应该只进入 API 请求副本。不变量 3长期 memory 只放稳定事实如果一个事实 7 天后会过期它不应该进 memory。任务结果和过程应该进 session history流程方法应该进 skill。不变量 4压缩摘要必须明确“不是新请求”summary 里经常会包含用户原话。如果没有SUMMARY_PREFIX和 end marker弱模型很容易把摘要里的旧请求当成本轮新请求重复执行。不变量 5压缩不能切断 tool_call / tool_result 对Hermes 在压缩前后都做 tool pair 修复不能留下 orphan tool result也不能留下没有 result 的 tool_call。否则很多 provider 会直接 400或者更糟返回空响应。不变量 6压缩要保留最后一个 user message当前任务如果被压进 summary模型会收到「只回答 summary 后面的最新用户消息」这类指令但后面已经没有真正 user message 了任务就会丢失。不变量 7外部记忆失败不能阻断用户任务MemoryManager对prefetch、sync_turn、queue_prefetch都是 best-effort。外部 provider 挂了用户对话仍然应该继续。源码锚点关注点文件主对话循环、system prompt、API 请求装配、压缩触发、落库run_agent.py上下文压缩抽象agent/context_engine.py默认压缩器、summary 模板、头尾保护、tool pair 修复agent/context_compressor.py内置MEMORY.md/USER.mdtools/memory_tool.py外部记忆 provider 抽象agent/memory_provider.py记忆 provider 编排agent/memory_manager.pySQLite session store、FTS、压缩链、resumehermes_state.py历史会话语义搜索tools/session_search_tool.pygateway session key、thread/shared session、JSONL fallbackgateway/session.pyprompt builder、memory/skill/session_search 行为规则agent/prompt_builder.py结论Hermes Agent 的上下文与内存设计不是单纯把更多内容塞进 prompt而是把信息按生命周期拆开本轮需要的进api_messages。会话真实发生的进state.db和 session JSON。当前上下文太长的进压缩 handoff summary。长期稳定事实进MEMORY.md/USER.md。可召回的语义记忆交给 external memory provider。过去任务细节交给session_search。这套设计的本质是工程化的上下文治理让模型看到足够的信息但不给它错误的权限让系统记住该记的东西但不把临时状态变成永久负担。学AI大模型的正确顺序千万不要搞错了2026年AI风口已来各行各业的AI渗透肉眼可见超多公司要么转型做AI相关产品要么高薪挖AI技术人才机遇直接摆在眼前有往AI方向发展或者本身有后端编程基础的朋友直接冲AI大模型应用开发转岗超合适就算暂时不打算转岗了解大模型、RAG、Prompt、Agent这些热门概念能上手做简单项目也绝对是求职加分王给大家整理了超全最新的AI大模型应用开发学习清单和资料手把手帮你快速入门学习路线:✅大模型基础认知—大模型核心原理、发展历程、主流模型GPT、文心一言等特点解析✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑✅开发基础能力—Python进阶、API接口调用、大模型开发框架LangChain等实操✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经以上6大模块看似清晰好上手实则每个部分都有扎实的核心内容需要吃透我把大模型的学习全流程已经整理好了抓住AI时代风口轻松解锁职业新可能希望大家都能把握机遇实现薪资/职业跃迁这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】