1. 为什么你的 Agent 每次重启都像失忆如果你正在本地调试 AI Agent大概率遇到过这种场景上一轮对话里 Agent 刚学会用某个工具处理一类任务关掉进程再启动它又变回一张白纸同样的错误再犯一遍。这不是模型不行而是大多数开源 Agent 的“循环”只做到了输入到输出没有把这一轮的经验沉淀成下一轮能直接复用的上下文。Hermes-Agent 想解决的就是这件事。它把执行循环设计成“做、学、改、存”的闭环每次任务结束会触发技能创建、记忆整理、上下文压缩并为下一次会话留下可追溯的 lineage。对本地调试来说这意味着你可以观察到一个 Agent 如何从一次对话里提炼出可复用的东西而不是每次从零开始。这篇内容聚焦工程落地从run_conversation入口进去一路走到 Prompt Caching 真正生效中间需要哪些配置、怎么验证缓存命中、常见报错怎么排。适合已经在本地跑过 Agent、想搞清楚闭环学习循环到底在哪一步发生的人。我会给出一份可复制的config.toml骨架以及接入统一 Key/API 通道的配置方式最后用一轮对话验证缓存是否按预期命中。需要先说明一点闭环学习循环不是玄学它由几个具体机制拼起来——Prompt 构建时注入稳定的系统前缀、Preflight 压缩控制上下文窗口、Prompt Caching 复用稳定前缀、lineage 追踪保证压缩后仍可追溯。下面按执行顺序拆。2. 前置准备统一 Key 与 API 通道在动config.toml之前先把模型调用通道理顺。Hermes-Agent 支持多种 provider 模式chat_completions、anthropic_messages 等本地调试时如果每个 provider 都单独配 Key切换和排障会很乱。我习惯用一个统一的 API 通道来收敛TaoToken 的 API 地址是https://taotoken.net/apiKey 在控制台生成。先去控制台创建一个 API Key然后确认你要用的模型名。如果你主要跑 Anthropic 系的模型来验证 Prompt Caching注意缓存是 Anthropic 特有的能力provider 模式要选anthropic_messages。如果你只是先跑通循环用 chat_completions 模式也行但缓存验证那一步会看不到效果。这一步的目标只有一个拿到一个能用的 Key 和一个明确的 base_url后面写进config.toml。不要在这一步纠结模型选型先把链路跑通。3. 可复制的 config.toml 骨架下面这份骨架是我本地调试时用的字段按 Hermes-Agent 的配置习惯组织。你把它放到项目根目录或~/.hermes/下按注释替换成自己的值即可。# config.toml - Hermes-Agent 本地调试骨架 [provider] # 统一走一个 API 通道避免多 Key 混乱 mode anthropic_messages # 验证 Prompt Caching 用这个模式 base_url https://taotoken.net/api api_key sk-你的TaoToken密钥 model claude-sonnet-4-20250514 # 换成你实际可用的模型名 [agent] max_iterations 90 # 迭代预算接近时注入预算警告 task_id_prefix local-debug # 方便 trajectory 追踪 [context] preflight_threshold 0.5 # 超过窗口 50% 触发预检压缩 gateway_compress_threshold 0.85 # turn 间更激进的压缩阈值 protect_recent_tokens 20000 # 压缩时保护最近 20K token [prompt_caching] enabled true # Anthropic 专用打断点标记 stable_prefix true # 系统提示来自稳定来源才可缓存 [persistence] state_db ./hermes_state.db # SQLiteFTS5 全文搜索 memory_dir ./memory # 记忆 flush 到磁盘几个关键点解释一下。mode决定 API 消息的转换格式选anthropic_messages才能走到prompt_caching.py的断点标记逻辑。preflight_threshold是预检压缩的触发线官方默认在窗口 50% 处检查低于这个值不会压缩方便你观察原始上下文。stable_prefix是缓存能否命中的前提——系统提示如果每次都变缓存永远打不中。写完之后先别急着跑确认base_url没有多余斜杠api_key没有引号包裹错误。这两个地方是后面 401 报错的高频来源。4. 从 run_conversation 到缓存生效的完整链路配置就绪后进入核心链路。run_conversation是 AIAgent 类的入口方法所有 CLI、Gateway、Python Library 的调用最终都汇聚到这里。单轮执行大致分这几步我按顺序说清楚每一步和缓存的关系。第一步任务 ID 生成。如果没传task_id会自动生成一个唯一 ID用于 trajectory 追踪。这一步不影响缓存但后面导出 trajectory 分析压缩点时要靠它。第二步追加用户消息到会话历史格式是 OpenAI 消息格式。此时历史里是原始消息还没有系统提示。第三步Prompt 构建。这是缓存能否命中的关键。prompt_builder.py会注入几个稳定来源SOUL.md人格、MEMORY.md 和 USER.md提示记忆、相关 Skills过程记忆、上下文文件.hermes.md、AGENTS.md再加上工具 schema。注意这些来源的内容在多次调用之间是稳定的所以拼出来的系统前缀一致Anthropic 才能缓存。如果你发现缓存命中率低先查这一步注入的内容是不是每次都变。第四步Preflight 压缩检查。如果上下文超过模型窗口的 50%触发context_compressor.py。压缩过程是先 flush 记忆然后对中间 turn 做结构化摘要Goal、Constraints、Progress、Key Decisions 模板保护最近 20K token 和工具对最后生成新的 lineage ID。压缩会改变上下文但因为是结构化摘要而非粗暴截断缓存前缀的稳定性在压缩后仍能维持。第五步构建 API 消息并应用 Prompt Caching。prompt_caching.py在稳定前缀处打断点标记告诉 Anthropic 这部分可以复用。断点位置决定了缓存粒度系统提示和工具 schema 通常是最值得缓存的部分。第六步可中断 API 调用。后台线程发 HTTP 请求主线程监控中断和超时。这一步是实际消耗 token 和产生缓存命中的地方。第七步解析响应。如果含tool_calls走工具注册表分发Agent 级工具memory、session_search、delegate_task、todo先拦截普通工具走 pre_tool_call 钩子、危险命令审批、执行、post_tool_call 钩子然后把工具结果追加到历史循环回第五步。如果是纯文本响应结束循环。第八步持久化。消息存到 SQLite记忆 flush 到磁盘触发 nudge技能创建、记忆整理生成 trajectory 记录。整个链路里缓存生效依赖第三、第五步的配合稳定前缀加断点标记。压缩在第四步介入但通过 lineage 保证连贯性。这就是闭环学习循环的执行基础——每一轮结束后Agent 已经完成了一次经验提炼下一轮的 Prompt 会自动加载优化后的上下文。5. 验证一轮对话后的缓存命中配置和链路都清楚了现在动手验证。启动 Hermes-Agent 后先跑一轮简单对话观察缓存是否命中。# 启动后输入一个需要工具调用的任务 hermes 帮我读取当前目录下的 README.md总结成三句话任务结束后用 trajectory 导出这一轮的记录 /trajectory export --task-id local-debug-001导出的 JSON 里重点看两个字段usage里的cache_creation_input_tokens和cache_read_input_tokens。第一轮对话通常cache_creation_input_tokens有值、cache_read_input_tokens为 0因为缓存是这一轮刚创建的。再跑第二轮相似任务 再读一次 README.md这次提取所有二级标题第二轮结束后再导出如果cache_read_input_tokens明显大于 0说明稳定前缀被复用了缓存命中。如果两轮都是 creation 没有 read回到第 4 节第三步查系统提示是否稳定。还可以用/debug prompt查看实际注入的 Prompt 内容确认 SOUL、MEMORY、Skills 这些来源在两次调用间是否一致。我试过把 MEMORY.md 里加一个时间戳结果缓存直接不命中排查了半天才发现是前缀变了。压缩验证用/compress手动触发CLI 会显示压缩前后的 token 数。如果看到类似Preflight compression at 52% - new lineage child session的输出说明压缩和 lineage 都在工作。压缩后再跑一轮用/memory insights --days 7搜索跨压缩的历史确认 session_search 仍能追溯到压缩前的内容。6. 本篇常见错排查调试过程中有几个报错反复出现我按现象、原因、处理列一下。401 或 403 报错先查api_key是否正确、有没有多余空格或引号。如果 Key 没问题检查base_url是不是https://taotoken.net/api末尾不要加斜杠。Anthropic 模式下还要确认模型名拼写正确。缓存始终不命中最常见的原因是系统提示前缀不稳定。检查 MEMORY.md、USER.md、Skills 里有没有动态内容时间戳、随机 ID、每次变化的文件列表。另一个原因是mode没选anthropic_messageschat_completions 模式走不到断点标记逻辑。Preflight 压缩不触发确认preflight_threshold设置合理如果上下文没到窗口 50% 就不会压缩。另外检查protect_recent_tokens是不是设得太大导致可压缩空间不足。工具调用死锁多工具并发时如果出现卡住检查是不是异步工具没有正确桥接。Hermes 用 ThreadPoolExecutor 并发执行多工具异步工具通过model_tools.py内部桥接如果自定义工具里混用了不兼容的异步模式可能死锁。先禁用自定义工具用内置工具跑通再逐个加回。trajectory 导出为空确认task_id传对了或者用/trajectory list看有哪些可用 ID。如果state_db路径不可写持久化会失败trajectory 也就没有记录。预算警告频繁出现max_iterations默认 90如果任务复杂容易接近上限。可以适当调高但更推荐优化任务拆解让 Agent 在预算内完成。接近上限时注入的警告是引导 Agent 总结输出不是报错。排障时如果卡在接入层可以直接看接入文档对照配置项如果怀疑是模型本身的问题用模型对话单独发一条请求验证通道是否正常。7. 把闭环跑成习惯闭环学习循环的价值不在于一次配置而在于你能否持续观察和调优。我的做法是每次调试新任务后都导出 trajectory看压缩点在哪、缓存命中率多少、lineage 有没有正确生成。时间长了你会发现Agent 的“记忆”确实在增长但上下文窗口没有膨胀这就是 Preflight 压缩和 lineage 追踪配合的结果。如果你打算长期跑编码类或 Agent 类任务可以考虑用 Coding Plan 把调用额度固定下来避免调试到一半额度不够。验证模型行为时用模型对话单独发请求比在完整 Agent 里排查更快。接入配置和 Key 管理都在控制台和 API Keys 页面文档里有各 provider 模式的字段说明。最后留一个实用技巧把stable_prefix相关的来源文件SOUL、MEMORY、Skills纳入版本管理每次改动都记录 diff。这样当缓存命中率突然下降时你能快速定位是哪个文件的前缀变了。闭环要跑得稳稳定前缀是地基。
