Hermes Agent 核心运行系统调用流程--源码分析

Hermes Agent 核心运行系统调用流程--源码分析本文基于当前仓库实现梳理 Hermes Agent 从入口层到结果交付的真实调用链 重点覆盖 核心运行系统 AIAgent Prompt Builder Prompt Caching Context Compression Provider Runtime Resolution Tool Dispatch Session Storage Response

大家好,我是讯享网,很高兴认识大家。这里提供最前沿的Ai技术和互联网信息。



本文基于当前仓库实现梳理 Hermes Agent 从入口层到结果交付的真实调用链,重点覆盖:

  • 核心运行系统 AIAgent
  • Prompt Builder / Prompt Caching / Context Compression
  • Provider / Runtime Resolution
  • Tool Dispatch
  • Session Storage
  • Response Delivery(CLI / gateway / cron)

不展开单个 tool 的内部业务逻辑,重点描述"谁调用谁、数据如何流动、哪些状态被缓存或持久化"。


 
   
    
     
入口层 

CLI: cli.py Gateway: gateway/run.py Cron: cron/scheduler.py

运行时解析 hermes_cli/runtime_provider.py hermes_cli/auth.py

核心 Agent 初始化 run_agent.py -> AIAgent.init()

系统提示词装配 AIAgent._build_system_prompt() agent/prompt_builder.py

同步 agent loop AIAgent.run_conversation()

模型响应二分 无 tool_calls -> 最终响应 有 tool_calls -> tool dispatch -> tool result 回填 -> 下一轮

上下文管理 agent/prompt_caching.py agent/context_compressor.py

持久化 hermes_state.py / gateway/session.py

结果交付 CLI Rich/TUI Gateway adapter.send(…) Cron output file + auto delivery

 
   
    
     

2.1 CLI 路径

入口主要在 cli.py

  1. HermesCLI.chat() 先调用 _ensure_runtime_credentials()
  2. _ensure_runtime_credentials() 通过 resolve_runtime_provider() 解析 provider、api_mode、base_url、api_key。
  3. _init_agent() 在首次使用或路由变化时创建 AIAgent(…)
  4. HermesCLI.chat() 调用 self.agent.run_conversation(…)
  5. 返回结果后,CLI 负责把 reasoning / response / TTS / streaming 内容显示到终端。

关键点:

  • CLI 会在 provider、model、route、credential 变化时重建 agent,而不是复用旧 client。
  • CLI 恢复会话时,会先从 SessionDB 取历史消息,再交给 AIAgent 继续运行。

相关位置:

  • cli.py:2169 _ensure_runtime_credentials()
  • cli.py:2269 _init_agent()
  • cli.py:6309 HermesCLI.chat()

2.2 Gateway 路径

入口主要在 gateway/run.py

  1. 收到平台消息后,SessionStore.get_or_create_session(source) 建立/获取会话。
  2. build_session_context(…)build_session_context_prompt(…) 生成平台上下文。
  3. session_store.load_transcript(session_id) 读取历史对话。
  4. _run_agent(…) 内部解析 runtime、构造或复用 AIAgent
  5. 调用 agent.run_conversation(message, conversation_history=agent_history, …)
  6. 将新消息写回 transcript / SQLite,并把最终结果返回给 adapter。

关键点:

  • Gateway 不把 session context 写进持久化的 system prompt,而是作为 ephemeral_system_prompt 每轮临时注入,避免破坏 prompt cache 前缀。
  • Gateway 会按 session_key + agent config signature 缓存 AIAgent,尽量复用同一个 agent 实例,保持 system prompt 和 tool schema 稳定。

相关位置:

  • gateway/run.py:2308 获取/创建 session
  • gateway/run.py:2342 构造 context prompt
  • gateway/run.py:2435 加载 transcript
  • gateway/run.py:6647 创建/复用 AIAgent
  • gateway/run.py:6856 调用 run_conversation()

2.3 Cron 路径

入口主要在 cron/scheduler.pyrun_job(job)

  1. 构造 cron 专用 prompt(包含 skill 展开、cron 执行提示)。
  2. resolve_runtime_provider() 解析运行时 provider。
  3. 创建 AIAgent(…, platform="cron", disabled_toolsets=["cronjob", "messaging", "clarify"], skip_memory=True)
  4. 在线程池里执行 agent.run_conversation(prompt)
  5. 生成 markdown output 文档并保存到 ~/.hermes/cron/output/…
  6. 如配置了 deliver,调用 _deliver_result() 发送到目标平台。

关键点:

  • cron 是 headless 执行,不允许 clarify。
  • cron 同样接入 SessionDB,因此历史可被 session_search 检索。
  • cron 有"无活动超时"机制,不是简单 wall-clock timeout。

相关位置:

  • cron/scheduler.py:512 run_job()
  • cron/scheduler.py:623 runtime 解析
  • cron/scheduler.py:643 创建 AIAgent
  • cron/scheduler.py:678 调用 run_conversation()
  • cron/scheduler.py:199 _deliver_result()

运行时解析由 hermes_cli/runtime_provider.py 统一封装,CLI / gateway / cron 都走这里。

3.1 入口函数

统一入口:

  • resolve_runtime_provider(...) in hermes_cli/runtime_provider.py:566

它返回一个 runtime dict,典型字段包括:

  • provider
  • api_mode
  • base_url
  • api_key
  • command / args(外部进程型 provider)
  • credential_pool
  • requested_provider

3.2 解析步骤

resolve_runtime_provider() 的主流程:

  1. resolve_requested_provider() 先决定"用户想要哪个 provider"。
  2. _resolve_named_custom_runtime() 先尝试命名 custom provider。
  3. resolve_provider() in hermes_cli/auth.py 解析最终 provider 名称。
  4. _resolve_explicit_runtime() 处理显式 api_key/base_url 覆盖。
  5. 如有 credential pool,优先从 pool 取 runtime credential。
  6. 按 provider 类型进入对应分支:
    • nous -> resolve_nous_runtime_credentials()
    • openai-codex -> resolve_codex_runtime_credentials()
    • copilot-acp -> resolve_external_process_provider_credentials()
    • anthropic -> 走 Anthropic token 解析
    • API-key provider -> resolve_api_key_provider_credentials()
    • 其他 -> _resolve_openrouter_runtime()

3.3 auth.py 的职责

hermes_cli/auth.py 主要负责:

  • resolve_provider():决定 provider 名称
  • resolve_codex_runtime_credentials():读取/刷新 Codex token
  • resolve_nous_runtime_credentials():刷新 Nous portal access token,并确保短期 inference key 可用
  • resolve_api_key_provider_credentials():读取 API-key 类 provider 的密钥和 base_url
  • resolve_external_process_provider_credentials():解析 copilot-acp 这类本地子进程 provider

关键位置:

  • hermes_cli/auth.py:790 resolve_provider()
  • hermes_cli/auth.py:1174 resolve_codex_runtime_credentials()
  • hermes_cli/auth.py:1683 resolve_nous_runtime_credentials()
  • hermes_cli/auth.py:2084 resolve_api_key_provider_credentials()
  • hermes_cli/auth.py:2122 resolve_external_process_provider_credentials()

3.4 运行时解析的输出如何进入 AIAgent

三个入口都会把 runtime dict 展开为 AIAgent(...) 参数:

  • api_key
  • base_url
  • provider
  • api_mode
  • command / args
  • credential_pool

随后 AIAgent.__init__() 决定使用哪类 client:

  • anthropic_messages -> Anthropic native client
  • codex_responses -> Responses API / raw codex path
  • 其他 -> OpenAI-compatible client

核心类位于 run_agent.py

  • AIAgent 定义:run_agent.py:470
  • __init__()run_agent.py:487
  • run_conversation()run_agent.py:6801
  • chat()run_agent.py:9170

4.1 初始化时完成的事情

AIAgent.__init__() 不是只做 client 构造,它会一次性初始化整套运行时状态:

  1. 保存 model / provider / api_mode / iteration budget。
  2. 基于 provider/base_url 判断实际 API 模式。
  3. 创建底层 LLM client。
  4. 调用 get_tool_definitions(...) 加载当前会话可用工具。
  5. 初始化 SessionDB 会话行(如果传入了 session_db)。
  6. 初始化 todo store、memory store、memory provider plugin。
  7. 初始化 context compressor。
  8. 计算 prompt caching 开关。
  9. 建立 _cached_system_prompt 缓存槽。
  10. 建立 session log 文件路径和 _session_messages 缓冲区。

4.2 初始化时和本题流程直接相关的状态

  • self.tools
    • 来自 model_tools.get_tool_definitions()
  • self.valid_tool_names
    • 当前会话真实可调用的工具名集合
  • self._cached_system_prompt
    • 会话级稳定 system prompt 快照
  • self.context_compressor
    • 长会话压缩器
  • self._session_db
    • SQLite 会话存储
  • self._memory_store / self._memory_manager
    • memory 注入和外部 memory provider
  • self._use_prompt_caching
    • 是否启用 Anthropic/OpenRouter prompt cache 标记

AIAgent._build_system_prompt() 是总装函数,位于:

  • run_agent.py:2609

真正的提示词拼装细节在:

  • agent/prompt_builder.py

5.1 组装顺序

_build_system_prompt() 的拼接顺序非常明确:

  1. Agent identity
    • 优先 SOUL.md
    • 否则 DEFAULT_AGENT_IDENTITY
  2. tool-aware guidance
    • 仅当对应 tool 存在时才注入 memory/session_search/skills guidance
  3. Nous subscription prompt
  4. tool-use enforcement
    • 按模型名和 config 决定是否注入
  5. 调用方传入的 system_message
  6. 内建 memory / user profile
  7. 外部 memory provider prompt block
  8. skills system prompt
  9. project context files
  10. 冻结时间戳 / session id / model / provider
  11. platform hint

5.2 prompt_builder.py 提供的核心能力

5.2.1 上下文文件发现与注入

build_context_files_prompt() 负责扫描并注入项目上下文文件:

  • .hermes.md / HERMES.md
  • AGENTS.md
  • CLAUDE.md
  • .cursorrules / .cursor/rules/*.mdc
  • SOUL.md

关键特性:

  • 有 prompt injection 扫描:_scan_context_content()
  • 有截断:_truncate_content()
  • 有优先级:只取一种 project context 类型

关键位置:

  • agent/prompt_builder.py:55 _scan_context_content()
  • agent/prompt_builder.py:807 load_soul_md()
  • agent/prompt_builder.py:920 build_context_files_prompt()
5.2.2 Skills 注入

build_skills_system_prompt() 会构建"可用技能索引",供模型在系统提示词里看到。

它有两层缓存:

  1. 进程内 LRU cache
  2. 磁盘 snapshot:.skills_prompt_snapshot.json

注意:

  • 这是"skills 索引构建缓存",不是模型 provider 的 prefix cache。
  • 它的目标是减少每次扫描 skills/ 目录的成本。

关键位置:

  • agent/prompt_builder.py:505 build_skills_system_prompt()

5.3 会话级 system prompt 稳定策略

Hermes 为了维持 prefix cache 命中,不会每轮都重建 system prompt。

策略是:

  1. 首轮调用时构建并缓存到 self._cached_system_prompt
  2. 持续会话时,如果有 SessionDB.system_prompt,优先复用库里的快照
  3. 只有在 context compression 后才调用 _invalidate_system_prompt() 并重建

相关位置:

  • run_agent.py:6953 首轮构建/复用 system prompt
  • run_agent.py:2929 _invalidate_system_prompt()

这一层涉及三种"缓存",需要区分:

6.1 会话级 system prompt 缓存

AIAgent._cached_system_prompt 管理。

作用:

  • 保证同一 session 内 system prompt 文本稳定
  • 避免 memory/context/skills 每轮重建后发生微小漂移

6.2 Skills prompt 构建缓存

agent/prompt_builder.py 内部管理。

作用:

  • 加速 skills 索引生成
  • 不直接参与 provider prefix cache

6.3 Provider 级 prompt cache

真正的 provider prefix cache 逻辑在:

  • agent/prompt_caching.py

入口函数:

  • apply_anthropic_cache_control()agent/prompt_caching.py:41

策略:

  • 最多放 4 个 cache_control 断点
  • system prompt 1 个
  • 最近 3 条非 system message 3 个

run_conversation() 里,API 消息构造完成后,如果当前 session 启用了 prompt caching,则调用:

  • run_agent.py:7239-7244

这就是当前仓库里"保持 prefix cache"的实际执行点。


AIAgent.run_conversation() 是核心同步循环,整体是:

 
        
    
          
准备消息 

↓ 拼 API payload ↓ 调用模型 ↓ 有 tool_calls ? ├─ 否 -> 最终响应 -> 持久化 -> 返回 └─ 是 -> 执行 tools -> tool result 写回 messages -> 下一轮

 

7.1 进入循环前的准备

主要步骤:

  1. 恢复 primary runtime(如果上轮触发了 fallback)。
  2. 清洗用户输入中的 surrogate 字符。
  3. 拷贝 conversation_history 到本轮 messages
  4. 去掉旧 budget warning。
  5. 从历史中恢复 todo store。
  6. 追加本轮 user message。
  7. 复用或构建 _cached_system_prompt
  8. 进行 preflight compression。
  9. 从 memory provider / plugin hook 获取额外上下文。

相关位置:

  • run_agent.py:6833-6938
  • run_agent.py:6953-6991
  • run_agent.py:6994-7050
  • run_agent.py:7064-7085

7.2 单轮 API 调用前,如何拼 payload

每次循环会把内部 messages 转成 api_messages

  1. 对当前 user message 注入 external memory / plugin context
  2. assistant message 里的 reasoning 映射成 provider 能理解的字段
  3. 移除内部字段:reasoningfinish_reason_thinking_prefill
  4. 对 strict provider 清理 Codex 专用 tool fields
  5. 前置 system prompt
  6. 注入 prefill_messages
  7. 应用 Anthropic/OpenRouter prompt cache 标记
  8. 做 tool_call/tool_result 完整性修复
  9. 调用 _build_api_kwargs() 产出 provider-specific kwargs

关键位置:

  • run_agent.py:7169-7250
  • run_agent.py:5256 _build_api_kwargs()

7.3 _build_api_kwargs() 如何分发到不同 API 形态

_build_api_kwargs()self.api_mode 分三路:

  1. anthropic_messages
    • 走 Anthropic adapter
  2. codex_responses
    • system prompt 变成 instructions
    • history 变成 Responses input
    • tools 转成 Responses schema
    • parallel_tool_calls=True
  3. chat_completions
    • 标准 OpenAI-compatible messages + tools
    • 对 GPT-5 / Codex 会把第一条 system role 改写成 developer

关键位置:

  • run_agent.py:5256-5330
  • run_agent.py:5367-5379

7.4 模型返回后,先做什么

模型返回后会进入一系列规范化/防御逻辑:

  • 处理 incomplete / empty / reasoning-only 情况
  • 修正 hallucinated tool name
  • 校验 tool args JSON
  • 去重 tool calls
  • 限制同轮 delegate_task 数量

然后才决定进入:

  • tool 分支
  • final response 分支

相关位置:

  • run_agent.py:8590-8775
  • run_agent.py:8845-8977

7.5 chat() 只是外层薄封装

AIAgent.chat() 只是:

  1. run_conversation()
  2. 取出 result["final_response"]

位置:

  • run_agent.py:9170

8.1 tool schema 收集

model_tools.py 在 import 时就会执行 _discover_tools()

  1. import tools/*.py
  2. 每个 tool 模块通过 registry.register(…) 自注册
  3. 之后构建 TOOL_TO_TOOLSET_MAPTOOLSET_REQUIREMENTS

位置:

  • model_tools.py:132 _discover_tools()
  • model_tools.py:170 调用 _discover_tools()

8.2 get_tool_definitions() 如何做 availability gating

get_tool_definitions(…) 负责给模型暴露"当前会话真实可见的 tools"。

步骤:

  1. 根据 enabled_toolsets / disabled_toolsets 解析 tool 名集合
  2. registry.get_definitions(…)
  3. 用每个 tool 的 check_fn 做可用性过滤
  4. execute_code 动态重建 schema,只列出当前 sandbox 中真实可用的 tools
  5. browser_navigate 清理失效的 cross-tool 描述
  6. 把最终可用 tool 名写入 _last_resolved_tool_names

位置:

  • model_tools.py:234 get_tool_definitions()

8.3 模型发出 tool_calls 后的调用链

run_conversation() 中,如果 assistant_message.tool_calls 非空:

  1. 先校验 tool name 和 JSON 参数
  2. 生成 assistant message 并附加到 messages
  3. _execute_tool_calls(…)

位置:

  • run_agent.py:8590-8775
  • run_agent.py:5948 _execute_tool_calls()

8.4 并行与串行执行策略

_execute_tool_calls() 会根据 _should_parallelize_tool_batch() 决定走:

  • _execute_tool_calls_sequential()
  • _execute_tool_calls_concurrent()

并行条件大致是:

  • 多个 tool call
  • 不包含 clarify
  • 只包含并行安全工具
  • 或 path-scoped tool 且目标路径不冲突

位置:

  • run_agent.py:262 _should_parallelize_tool_batch()
  • run_agent.py:5948 _execute_tool_calls()
  • run_agent.py:6045 _execute_tool_calls_concurrent()
  • run_agent.py:6261 _execute_tool_calls_sequential()

8.5 agent-level tool 与 registry-level tool 的分界

AIAgent._invoke_tool() 先拦截 agent 级工具:

  • todo
  • session_search
  • memory
  • clarify
  • delegate_task
  • memory provider tools

其他工具才走:

  • handle_function_call(…) in model_tools.py

位置:

  • run_agent.py:5971 _invoke_tool()
  • model_tools.py:459 handle_function_call()

8.6 handle_function_call() 做什么

handle_function_call() 是 registry 的同步分发入口:

  1. coerce_tool_args() 按 JSON Schema 纠正参数类型
  2. 对 read/search loop 做计数重置
  3. 执行 plugin pre_tool_call hook
  4. registry.dispatch(…)
  5. 执行 plugin post_tool_call hook
  6. 返回 JSON string

注意:

  • todo / memory / session_search / delegate_task 在这里会返回"必须由 agent loop 处理"的 stub,因为它们依赖 agent-level state。

位置:

  • model_tools.py:372 coerce_tool_args()
  • model_tools.py:459 handle_function_call()

核心类:

  • agent/context_compressor.py:53 ContextCompressor

9.1 初始化

AIAgent.init() 会创建 self.context_compressor,传入:

  • model
  • provider
  • base_url
  • api_key
  • context_length override
  • threshold / protect_last_n / summary_model 等 config

位置:

  • run_agent.py:1186

9.2 压缩触发点

当前实现里至少有三类触发:

  1. Preflight compression
    • 本轮 API 还没发出,粗估请求已经超过阈值
  2. 正常循环中的 post-tool compression
    • 本轮 tool 执行后,根据真实 token 使用量判断
  3. 上下文错误恢复
    • provider 返回 payload too large / context length exceeded 等错误时,进入压缩重试路径

本题主链里最核心的是前两种。

位置:

  • run_agent.py:6994 preflight compression
  • run_agent.py:8827 post-tool compression

9.3 _compress_context() 的动作

_compress_context() 不是只改 messages,它还会处理 session 边界。

主流程:

  1. flush_memories() 先给模型一次机会把值得保留的信息写入 memory
  2. 调用 ContextCompressor.compress(messages, current_tokens=…)
  3. 追加 todo snapshot
  4. _invalidate_system_prompt()
  5. 重建 system prompt
  6. 若启用 SessionDB
    • end_session(old_session_id, "compression")
    • 创建新 session_id
    • create_session(parent_session_id=old_session_id)
    • 继承并自动编号 title
    • update_system_prompt(new_session_id, new_system_prompt)
  7. 更新压缩后的 token 估算
  8. 重置 file read dedup cache

位置:

  • run_agent.py:5853 _compress_context()

9.4 ContextCompressor.compress() 的内部算法

真实算法不是"简单保留头尾 + 做摘要",而是:

  1. 先裁剪老旧 tool result
  2. 保护头部消息
  3. 按 token budget 保护尾部消息
  4. 对中间消息做结构化摘要
  5. 修复 tool_call / tool_result 配对完整性

摘要模板包含:

  • Goal
  • Constraints & Preferences
  • Progress
  • Key Decisions
  • Relevant Files
  • Next Steps
  • Critical Context

位置:

  • agent/context_compressor.py:155 _prune_old_tool_results()
  • agent/context_compressor.py:253 _generate_summary()
  • agent/context_compressor.py:565 compress()

这里有两套相关但不重复的状态层。

10.1 SessionDB:结构化、可检索的长期存储

实现位于:

  • hermes_state.py

核心设计:

  • SQLite
  • WAL mode
  • sessions 表 + messages
  • messages_fts FTS5 虚表
  • 支持 parent_session_id 链接 compression continuation

关键位置:

  • hermes_state.py:41 sessions
  • hermes_state.py:71 messages
  • hermes_state.py:93 FTS5 定义
  • hermes_state.py:115 SessionDB

主要接口:

  • create_session()
  • end_session()
  • update_system_prompt()
  • append_message()
  • get_messages_as_conversation()
  • search_messages()

10.2 AIAgent 如何写入 SessionDB

每次 turn 结束时调用:

  • _persist_session()

它会做两件事:

  1. _save_session_log() 写 JSON session snapshot
  2. _flush_messages_to_session_db() 把未刷新的消息增量写入 SQLite

_flush_messages_to_session_db()_last_flushed_db_idx 避免重复写入。

位置:

  • run_agent.py:1869 _persist_session()
  • run_agent.py:1882 _flush_messages_to_session_db()

10.3 SessionStore:gateway 的会话路由与 transcript 兼容层

实现位于:

  • gateway/session.py

它负责:

  • 根据 SessionSource 生成 session_key
  • 管理 session reset policy
  • 维护 SessionEntry
  • 管理 transcript(SQLite + JSONL)
  • 生成 gateway 用的 session context prompt

关键位置:

  • gateway/session.py:202 build_session_context_prompt()
  • gateway/session.py:692 get_or_create_session()
  • gateway/session.py:942 append_to_transcript()
  • gateway/session.py:970 rewrite_transcript()
  • gateway/session.py:1002 load_transcript()

10.4 SessionDBSessionStore 的关系

可以把两者理解成:

  • SessionDB
    • 面向 agent / search / 压缩 continuation
    • 是结构化 SQLite 正式存储
  • SessionStore
    • 面向 gateway 平台 session 生命周期
    • 维护 session_key 与当前 session_id 的映射
    • 同时保留 JSONL transcript 兼容层

也就是说:

  • AIAgent 直接写 SessionDB
  • gateway 通过 SessionStore 管理"当前聊天应该落在哪个 session_id 上"

11.1 CLI display

CLI 的交付不是简单 print(final_response),而是一套 callback + streaming UI:

  1. _init_agent()AIAgent 注入:
    • tool_progress_callback
    • tool_start_callback
    • tool_complete_callback
    • stream_delta_callback
    • thinking_callback
    • reasoning_callback
  2. HermesCLI.chat() 在线程中执行 agent.run_conversation(…)
  3. 运行过程中:
    • streaming token 通过 _stream_delta(…) 渲染
    • reasoning 可单独显示
    • tool progress 可实时显示
  4. 结束后:
    • 若没走 streaming,则用 Rich Panel(…) 包裹最终响应
    • 可选 TTS 播放

相关位置:

  • cli.py:2340-2378 注入 callbacks
  • cli.py:6481 调用 run_conversation()
  • cli.py:6621-6644 reasoning display
  • cli.py:6645-6678 最终 response panel

11.2 Gateway delivery

Gateway 的交付链分两段:

第一段:_run_agent() 负责生成 agent 结果

它会:

  1. 构造/复用 AIAgent
  2. 绑定 tool_progress_callback / step_callback / stream_delta_callback / status_callback
  3. run_conversation()
  4. 处理 transcript 持久化
  5. 更新 SessionStore.last_prompt_tokens
  6. 返回最终 response

关键位置:

  • gateway/run.py:6647-6683
  • gateway/run.py:6856
  • gateway/run.py:2996-3078
第二段:平台 adapter 负责真正发送

Gateway 外层收到 _run_agent() 的返回值后,会:

  • 在普通模式下调用 adapter.send(…)
  • 在 streaming 模式下由 stream consumer 边生成边发送
  • 如响应里包含 MEDIA: 或本地文件路径,调用 _deliver_media_from_response(…)
  • 如需要自动语音回复,走 _send_voice_reply(…)

关键位置:

  • gateway/run.py:7273 queued message 场景下的 adapter.send(…)
  • gateway/run.py:3080-3098 already streamed 场景下的后处理
  • gateway/run.py:4287 _send_voice_reply()
  • gateway/run.py:4345 _deliver_media_from_response()

11.3 Cron delivery

cron 的结果交付分三步:

  1. run_job() 返回 (success, output_doc, final_response, error)
  2. save_job_output() 先把 markdown 文档落盘
  3. 如果需要对外发送,_deliver_result(job, content, adapters, loop) 再做平台投递

_deliver_result() 细节:

  • _resolve_delivery_target(job)
  • 优先使用 gateway live adapter(支持 E2EE 等)
  • 失败时 fallback 到 standalone _send_to_platform(…)
  • 先抽取 MEDIA: 标签,附件作为原生文件发送

位置:

  • cron/scheduler.py:199 _deliver_result()
  • cron/scheduler.py:856-873 tick 内触发保存与投递


13.1 system prompt 必须尽量稳定

这直接关系到:

  • Anthropic/OpenRouter prefix cache
  • 多轮会话成本
  • gateway 复用 cached agent 的收益

因此:

  • gateway 的动态上下文放到 ephemeral_system_prompt
  • plugin context 放到 user message
  • 只有 compression 后才主动重建 system prompt

13.2 tool_call / tool_result 配对必须完整

Hermes 在两个地方都做了防御:

  • API 调用前 _sanitize_api_messages()
  • compression 后 ContextCompressor._sanitize_tool_pairs()

否则 Anthropic / OpenAI / strict provider 都可能拒绝请求。

13.3 session persistence 不是"最后一次统一保存",而是多层增量保存

当前实现同时维护:

  • JSON session snapshot
  • SQLite messages/session rows
  • gateway transcript JSONL 兼容层

目标是:即使中途中断、压缩、provider 异常,也尽量不丢会话。


Hermes 的核心运行系统可以概括为:

入口层先通过 runtime_provider + auth 解析可执行 runtime,再由 AIAgent 初始化稳定的 tool surface、system prompt 和 context compressor;随后 run_conversation() 以同步 loop 反复执行"模型调用 -> tool dispatch -> tool result 回填",并在整个过程中用 SessionDB/SessionStore 持久化状态,最后由 CLI、gateway 或 cron 各自的 display/delivery 层把结果送到用户。

小讯
上一篇 2026-04-16 22:32
下一篇 2026-04-16 22:30

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/267078.html