乐于分享
好东西不私藏

Hermes Agent 源码深度解构:一个"自进化"AI Agent的完整架构拆解

Hermes Agent 源码深度解构:一个"自进化"AI Agent的完整架构拆解

Hermes Agent 源码深度解构:一个"自进化"AI Agent的完整架构拆解


引言:为什么值得深读这份源码

Hermes Agent 是由 Nous Research 开源的 AI Agent 框架,口号是"self-improving AI agent"——自进化。这不是营销词汇,而是一套有真实代码支撑的设计目标:Agent 会在每次对话结束后自动评估自己,决定哪些经验值得写入技能库,哪些事情应该记录进记忆。

截止 v0.14.0,整个项目约 3 万行 Python 代码(不含 website 和测试),支持 200+ 模型接入,7 种终端后端,6 大即时通信平台,一套完整的技能(Skills)体系,以及一个 Curator 后台维护员。本文将从架构到代码逐层拆解,最后给出客观的优缺点评估。

输入层
CLI / TUI
消息网关TG/Discord/Slack...
核心 Agent
conversation_loop.py对话主循环
ContextEngine上下文压缩
MemoryManager记忆管理
Skills System技能系统
基础设施层
CredentialPool多凭证池
AuxiliaryClient后台 LLM
ErrorClassifier错误分类
LSP Client代码理解
模型层
chat_completions
anthropic_messages
bedrock_converse
codex_responses

一、项目全貌:目录结构与模块划分

hermes-agent-main/├── agent/                   # 核心 Agent 逻辑(~80 个模块)│   ├── conversation_loop.py  # 对话主循环(3900 行,全项目最大)│   ├── agent_init.py         # AIAgent.__init__ 实现(提取为独立模块)│   ├── context_engine.py     # 上下文引擎抽象基类│   ├── context_compressor.py # 默认压缩实现(LLM 摘要)│   ├── memory_manager.py     # 记忆管理器(多 Provider 编排)│   ├── curator.py            # 技能库后台维护员│   ├── background_review.py  # 对话后后台复审(写记忆/技能)│   ├── iteration_budget.py   # 迭代预算(线程安全计数)│   ├── credential_pool.py    # 多凭证池(同 Provider 故障转移)│   ├── lsp/                  # Language Server Protocol 集成│   └── ...(40+ 其他模块)├── tools/                   # 40+ 工具实现│   ├── delegate_tool.py      # 子 Agent 委派与并行│   ├── memory_tool.py        # 持久化记忆工具│   ├── browser_tool.py       # 浏览器自动化│   ├── mcp_tool.py           # MCP 协议集成│   ├── kanban_tools.py       # Kanban 任务管理│   └── ...├── acp_adapter/             # Agent Communication Protocol 适配器├── optional-skills/         # 可选技能包(迁移、MCP 等)├── toolsets/                # 工具集配置(分组管理工具)├── hermes_cli/              # CLI 入口与配置管理└── pyproject.toml           # 项目依赖(精确锁版本)

关键架构决策:单文件提取

agent_init.py 的开头注释直接说明了一个有趣的工程决策:

AIAgent.__init__ 是 60+ 参数、~1400 行的属性初始化代码。把它放在 run_agent.py 里会让那个文件无法管理,所以把它提取成 init_agent(agent, ...) 独立函数,AIAgent.__init__ 变成一个薄薄的转发器。

这反映了项目的演化路径——代码库是有机增长的,大模块在达到阈值后被拆分,同时通过 _ra() 懒加载保持测试 mock 路径不变。


二、对话主循环:conversation_loop.py 的设计

这是整个项目最复杂的文件,约 3900 行,负责驱动"一个用户轮次通过 Agent"。其核心职责链:

需要压缩

无需压缩

纯文本

工具调用

有余量

耗尽

有错误

compress

rotate_credential

fallback

abort

无错误

用户消息输入
系统提示构建\nsystem_prompt.py
预压缩检查\nshould_compress_preflight
上下文压缩\nContextEngine.compress
调用 LLM\nchat_completions /\nanthropicmessages /\nbedrock_converse /\ncodex_responses
流式响应解析
流式输出给用户
并行可行?
ThreadPoolExecutor\n并行执行工具
串行执行工具
工具结果汇总
迭代预算\nIterationBudget.consume
强制结束
API 错误?
ErrorClassifier\n分类错误
恢复策略
后置钩子\nBackground Review
轮次结束

工具分发(tool_dispatch_helpers.py)迭代预算消耗(IterationBudget.consume)错误分类 & 重试(error_classifier.py)后置钩子(后台记忆/技能复审、背景审查)

### 2.1 多传输层架构Hermes 支持 4 种 API 传输模式,通过 `api_mode` 字段在初始化时确定:| api_mode | 对应接口 | 适用场景 ||---|---|---|| `chat_completions` | OpenAI Chat API | OpenRouter、大多数三方 || `anthropic_messages` | Anthropic Messages API | 原生 Anthropic、AWS 兼容端 || `bedrock_converse` | AWS Bedrock Converse API | AWS 原生部署 || `codex_responses` | OpenAI Responses API | GPT-5.x、xAI Grok |自动检测逻辑在 `agent_init.py` 中,通过 base_url 的 hostname 和 provider 名称推断——例如 `api.anthropic.com` 自动选 `anthropic_messages`,`bedrock-runtime.*.amazonaws.com` 选 `bedrock_converse`。```mermaidflowchart LR    START([api_mode=?]) --> A{api_mode\n显式传入?}    A -- 是 --> DONE[使用指定值]    A -- 否 --> B{provider=anthropic\nor hostname=\napi.anthropic.com?}    B -- 是 --> C[anthropic_messages]    B -- 否 --> D{hostname 匹配\nbedrock-runtime\n*.amazonaws.com?}    D -- 是 --> E[bedrock_converse]    D -- 否 --> F{provider=openai-codex\nor hostname=api.x.ai\nor chatgpt.com/codex?}    F -- 是 --> G[codex_responses]    F -- 否 --> H{是 OpenAI 直连\n且模型需要\nResponses API?}    H -- 是 --> G    H -- 否 --> I[chat_completions\n默认]    style C fill:#d4edda    style E fill:#d1ecf1    style G fill:#fff3cd    style I fill:#f8d7da

对于 GPT-5.x 模型,代码还有一个特殊升级逻辑:如果 api_mode 是 chat_completions 且模型需要 Responses API,会自动升级——但 Azure OpenAI 除外(Azure 不支持 Responses API,代码有 _is_azure_openai_url() 专门排除)。

2.2 迭代预算(IterationBudget)

classIterationBudget:def__init__(self, max_total: int):self.max_total = max_total   # 父 Agent 默认 90self._used = 0self._lock = threading.Lock()defconsume(self) -> bool:withself._lock:ifself._used >= self.max_total:returnFalseself._used += 1returnTruedefrefund(self) -> None:  # execute_code 轮次退款,不消耗预算withself._lock:ifself._used > 0:self._used -= 1

设计亮点:父子 Agent 的预算是独立的。父 Agent 最多 90 次,每个子 Agent 最多 50 次(可配置)。execute_code(Python 脚本执行)调用会被退款——因为脚本执行本质是编程,而不是一次 LLM 决策。


三、上下文引擎:可插拔的压缩架构

context_engine.py 定义了一个抽象基类 ContextEngine,这是 Hermes 架构中最优雅的设计之一:

classContextEngine(ABC):# 状态字段(run_agent.py 直接读取)    last_prompt_tokens: int = 0    threshold_percent: float = 0.75# 75% 触发压缩    protect_first_n: int = 3# 保护前 N 条消息    protect_last_n: int = 6# 保护后 N 条消息    @abstractmethoddefshould_compress(self, prompt_tokens: int = None) -> bool: ...    @abstractmethoddefcompress(self, messages, current_tokens, focus_topic=None) -> List: ...

内置实现是 ContextCompressor(基于 LLM 摘要),通过 config.yaml 的 context.engine 字段可以切换到第三方引擎(如 LCM),引擎目录:plugins/context_engine/<name>/

默认实现

第三方插件

«abstract»

ContextEngine

+last_prompt_tokens: int

+threshold_percent: float = 0.75

+protect_first_n: int = 3

+protect_last_n: int = 6

+context_length: int

+compression_count: int

+update_from_response(usage)

+should_compress(prompt_tokens)

+compress(messages, focus_topic)

+get_tool_schemas() : List

+handle_tool_call(name, args) : str

+on_session_start(session_id)

+on_session_end(session_id, messages)

+update_model(model, context_length)

ContextCompressor

+name = "compressor"

-SUMMARY_RATIO = 0.20

-_SUMMARY_TOKENS_CEILING = 12000

-_IMAGE_TOKEN_ESTIMATE = 1600

+compress(messages)

-_prune_tool_outputs(messages)

-_summarize_middle(messages)

LCMEngine

+name = "lcm"

+get_tool_schemas() : ← lcm_grep/describe/expand

+compress(messages)

-_build_dag(messages)

值得注意的是,ContextEngine ABC 还定义了 get_tool_schemas() 接口——这意味着上下文引擎可以向 Agent 暴露自己的工具(如 LCM 的 lcm_greplcm_describe),Agent 在对话中可以直接调用这些工具与压缩引擎交互。这是一个非常优雅的设计:压缩引擎不只是被动执行压缩,它可以主动扩展 Agent 的能力边界。

3.1 ContextCompressor 的压缩策略

context_compressor.py 的注释中明确了核心设计决策:

  • • 结构化摘要模板:追踪 Resolved/Pending 问题
  • • 工具输出预剪枝:LLM 摘要前先做一次廉价的工具输出删减
  • • 比例摘要预算:摘要长度 = 被压缩内容长度 × SUMMARY_RATIO(0.20),上限 _SUMMARY_TOKENS_CEILING(12000 tokens)
  • • 图片占位:每张图片估算 1600 tokens,防止多模态对话压缩预算计算失准

压缩时插入的前缀明确告知模型这是"历史参考,非活跃指令":

SUMMARY_PREFIX = ("[CONTEXT COMPACTION — REFERENCE ONLY] Earlier turns were compacted ""into the summary below. This is a handoff from a previous context ""window — treat it as background reference, NOT as active instructions. ""Do NOT answer questions or fulfill requests mentioned in this summary; ""they were already addressed. ""IMPORTANT: Your persistent memory (MEMORY.md, USER.md) in the system ""prompt is ALWAYS authoritative and active — never ignore or deprioritize ""memory content due to this compaction note. ")

这个细节很关键:如果不显式区分,模型可能把摘要里的历史任务当作当前指令重新执行。

3.2 工具调用参数截断的坑

context_compressor.py 中有一段专门处理工具调用参数 JSON 截断的代码,注释说明了为什么不能简单地切断字符串:

def_truncate_tool_call_args_json(args: str, head_chars: int = 200) -> str:"""    MiniMax 等 provider 严格校验 tool call 参数 JSON,直接截断会产生:        {"path": "/foo/bar", "content": "# long markdown        ...[truncated]    即未闭合字符串 + 缺少结束括号 → 400 错误 → 会话永久卡住。    正确做法:解析 JSON,截断长字符串叶节点,重新序列化。    """

这是从真实 Bug(issue #11762)中提炼出的防御性代码。


四、记忆系统:三层架构

Hermes 的记忆系统分三层:

Agent 调用接口
MemoryManager编排层(memory_manager.py)最多 1 个外部 Provider
Provider 层
BuiltinProviderMEMORY.md / USER.md文件读写 + § 分隔符
ExternalProvider(可选)如 Honcho 辩证用户建模通过 HTTP API 同步
安全层
StreamingContextScrubber流式输出防 memory-context 标签泄漏
sanitize_context()非流式内容清洗

4.1 MemoryManager 的防注入机制

memory_manager.py 实现了一个 StreamingContextScrubber,专门应对流式输出中可能出现的 <memory-context> 标签注入问题:

classStreamingContextScrubber:"""    非流式 sanitize_context 无法处理跨 chunk 边界的标签:    <memory-context> 在一个 delta 开启,在另一个 delta 关闭,    内容会泄露到 UI 界面。    该 scrubber 维护一个状态机,跨 delta 追踪标签开关状态,    挡住被 memory context 包裹的内容。    """

这种防御是必要的:如果 AI 模型在生成响应时"输出"了一个 <memory-context> 标签,流式 UI 会直接把它渲染给用户,造成混乱甚至安全问题。

4.2 记忆写入与同步

每次对话轮次结束,MemoryManager.sync_all() 会被调用,把当前轮次的用户消息和助手响应同步给所有 provider:

defsync_all(self, user_content, assistant_content, *, session_id=""):for provider inself._providers:try:            provider.sync_turn(user_content, assistant_content, session_id=session_id)except Exception as e:            logger.warning("Memory provider '%s' sync_turn failed: %s", provider.name, e)

注意容错设计:一个 provider 失败不会阻断其他 provider。这在分布式系统设计中是标准模式,但在一个单进程 Agent 里做到这一点说明开发者考虑了外部 provider(如 Honcho HTTP API)可能不可用的场景。


五、技能系统(Skills):从"配方"到"自进化"

技能系统是 Hermes 区别于其他 Agent 框架的核心特性。每个技能是一个 SKILL.md 文件,遵循 agentskills.io 开放标准。

5.1 技能的加载机制

技能的触发(skill_preprocessing.py)在用户消息进入主循环前执行。当用户输入 /skill-name 时,对应的 SKILL.md 内容被注入到系统提示中,扩展 Agent 的当前能力。

技能分三类:

类型
位置
说明
Bundled
代码内置
随 Hermes 发布,不可修改
Hub
~/.hermes/skills/
通过 hermes skills install 安装
User-created
~/.hermes/skills/
Agent 自动创建/人工编写

5.2 Background Review:对话后的自我审视

这是"自进化"机制的核心实现,在 background_review.py 中:

_SKILL_REVIEW_PROMPT = ("Review the conversation above and update the skill library. Be ""ACTIVE — most sessions produce at least one skill update, even if ""small. A pass that does nothing is a missed learning opportunity, ""not a neutral outcome.\n\n"# ... 超过 80 行的详细提示 ...)

每次对话轮次结束后,Hermes 会 fork 一个子 Agent(使用 auxiliary_client,命中同一个 prompt cache),限制工具白名单为仅 memory 和 skill 管理工具,让它审阅整个对话并决定:

  • • 是否有值得持久化的记忆(关于用户偏好、行为等)
  • • 是否有值得写入技能库的经验(工作流、纠错记录、域知识)
Skill Library\n~/.hermes/skills/Memory Store\nMEMORY.md / USER.mdBackground Review\n(auxiliary fork)Prompt Cache主 Agent用户Skill Library\n~/.hermes/skills/Memory Store\nMEMORY.md / USER.mdBackground Review\n(auxiliary fork)Prompt Cache主 Agent用户轮次结束工具白名单:\nmemory / skill_manage\n禁止:delegate/clarify/send_messagealt[有值得保存的记忆]alt[有值得更新的技能]发送消息查询缓存(system prompt + 历史)命中缓存(75% cost reduction)调用 LLM + 工具执行流式返回响应fork(daemon 线程)\n传入:会话快照 + 工具白名单共享前缀缓存命中命中(近零增量成本)审阅对话\n决策:记忆 / 技能更新memory tool 写入skill_manage 写入/更新完成(异步,不阻塞主对话)

技能更新的优先级顺序(来自 prompt):

  1. 1. 更新当前对话中已加载的技能
  2. 2. 更新现有伞形技能(umbrella skill)
  3. 3. 在现有伞形技能下添加支持文件(references/templates/scripts)
  4. 4. 创建新的类级别伞形技能(严格禁止创建以 PR 编号、bug 字符串命名的一次性技能)

这个设计的工程考量很细致:后台复审使用 auxiliary_client,共享父 Agent 的 prompt cache 前缀,实现近乎零额外成本的缓存命中。

5.3 Curator:技能库的"定期维护员"

curator.py 是一个后台维护系统,定期(默认每 7 天)在 Agent 空闲时自动运行:

DEFAULT_INTERVAL_HOURS = 24 * 7# 7 天DEFAULT_MIN_IDLE_HOURS = 2# 至少空闲 2 小时才触发DEFAULT_STALE_AFTER_DAYS = 30# 30 天未用标记为 staleDEFAULT_ARCHIVE_AFTER_DAYS = 90# 90 天未用归档

Curator 的职责:

  • • 自动管理技能生命周期状态(active → stale → archived)
  • • 合并重叠技能,归档冗余条目(不自动删除,只归档,可恢复)
  • • 始终只操作用户创建的技能,绝不动 bundled/hub 技能

技能创建\n(用户手动 or Background Review)

30天未被调用

被调用\n(自动恢复)

90天未被调用\nCurator 每7天巡检

手动恢复\n(hermes curator restore)

hermes curator pin

hermes curator unpin

active
stale
archived
pinned
Pinned 技能跳过\n所有自动状态转换
只归档不删除\n~/.hermes/skills/.archive/
Bundled/Hub 技能\n永远保持 active\nCurator 不干预

首次运行逻辑有一个有趣的 UX 设计:如果从未运行过,不会立即触发,而是把 last_run_at 设为当前时间,让用户先运行一个完整的 7 天周期。防止 hermes update 后立即触发一次不必要的库维护。


六、子 Agent 委派系统:真正的并行 Agent

tools/delegate_tool.py 实现了父子 Agent 委派架构:

DELEGATE_BLOCKED_TOOLS = frozenset(["delegate_task",   # 禁止递归委派(MAX_DEPTH=1 默认)"clarify",         # 禁止用户交互"memory",          # 禁止写共享 MEMORY.md"send_message",    # 禁止跨平台副作用"execute_code",    # 子 Agent 委派旨在步骤分解,而非直接写脚本执行])

delegate_task\n子任务 A

delegate_task\n子任务 B

delegate_task\n子任务 C

子 Agent 禁用工具
delegate_task ❌
clarify ❌
memory ❌
send_message ❌
execute_code ❌
父 Agent (depth=0)\nIterationBudget: 90
子 Agent A (depth=1)\nIterationBudget: 50\n独立上下文
子 Agent B (depth=1)\nIterationBudget: 50\n独立上下文
子 Agent C (depth=1)\nIterationBudget: 50\n独立上下文
结果 A 汇总
结果 B 汇总
结果 C 汇总
默认 MAX_DEPTH=1\n可配置最大 3 层\n默认最多 3 个并发子 Agent

委派工具的设计亮点:

1. 防死锁保护子 Agent 在 ThreadPoolExecutor 的 worker 线程中运行,而父 Agent 的 stdin 交互回调存储在 threading.local() 中,不会被 worker 线程继承。如果子 Agent 遇到需要用户确认的命令,直接调用 input() 会死锁。解决方案:为每个 worker 线程注入一个 _subagent_auto_deny 回调,遇到危险命令直接拒绝而非等待用户输入。

2. 深度限制

MAX_DEPTH = 1# 默认:父(0) -> 子(1);孙子在默认配置下被拒绝

默认嵌套深度为 1(仅允许一层子 Agent),可通过配置调整,最大支持 3 层,防止无限递归。

3. 运行时暂停set_spawn_paused(True) 可以全局阻止新的委派,已运行的子 Agent 不受影响。这是 TUI 控制面板的功能。


七、多凭证池(CredentialPool)

credential_pool.py 实现了企业级的多凭证管理:

STRATEGY_FILL_FIRST = "fill_first"# 优先用第一个,满了再换STRATEGY_ROUND_ROBIN = "round_robin"# 轮询STRATEGY_RANDOM = "random"# 随机STRATEGY_LEAST_USED = "least_used"# 用得最少的优先# 不同错误码的冷却时间EXHAUSTED_TTL_401_SECONDS = 5 * 60# 401: 5 分钟冷却(可能是刷新过期)EXHAUSTED_TTL_429_SECONDS = 60 * 60# 429: 1 小时冷却(速率限制)EXHAUSTED_TTL_DEFAULT_SECONDS = 60 * 60# 其他: 1 小时

PooledCredential 数据类设计了一个特殊的 extra 字段存储 JSON 只读字段(如 token_typescope),通过重载 __getattr__ 透明暴露,保持 API 的整洁性而不需要为每个边缘字段都定义属性。


八、多平台消息网关

Hermes 通过一个 Gateway 进程支持 Telegram、Discord、Slack、WhatsApp、Signal、Email,关键设计是"统一会话管理":

  • • 每个平台聊天(chat_id)对应一个独立的 Agent 实例
  • • gateway_session_key 格式:agent:main:telegram:dm:123456
  • • 跨平台对话连续性:同一个 Agent 实例可以在 CLI、Telegram、Discord 之间切换,session 状态持久化

ACP 适配器

acp_adapter/ 目录实现了 Agent Communication Protocol(ACP),这是一个更底层的 Agent 间通信协议,支持 Copilot 等外部 Agent 系统的集成。


九、LSP 集成:代码理解的基础设施

agent/lsp/ 目录是 Language Server Protocol 的完整客户端实现,这在 AI Agent 里不常见:

lsp/├── client.py       # LSP 客户端(JSON-RPC over stdio)├── manager.py      # LSP 服务器生命周期管理├── workspace.py    # 工作区管理(诊断、补全)├── range_shift.py  # 文件编辑后的范围偏移计算└── servers.py      # 已知 LSP 服务器配置(pyright, rust-analyzer 等)

这让 Hermes 具备了 IDE 级别的代码分析能力:在编辑文件后可以通过 LSP 获取实时类型错误、符号引用,而不是等模型"猜测"代码是否正确。


十、依赖管理:供应链安全的工程实践

pyproject.toml 注释中有一段重要的依赖策略说明:

# 所有直接依赖使用精确版本锁(==X.Y.Z),禁止范围版本。# 原因:2026-05-12 mistralai 2.4.6 被注入恶意代码(Mini Shai-Hulud 蠕虫),# 如果我们用 "mistralai>=2.3.0,<3" 而不是精确锁定,每个安装都会自动拉取该版本。

这是对真实供应链攻击事件的直接响应。所有依赖精确锁版本,只有 Hermes 主动升级时新版本才会进入用户环境。

另一个有趣的决策:execute_code 子 Agent 禁止递归委派,部分原因也是防止通过动态生成的代码绕过工具白名单。


十一、工具生态:40+ 工具的组织方式

工具通过"toolset"系统分组管理:

TOOLSETS = {"core": ["read_file""write_file""bash", ...],   # 核心工具(默认启用)"browser": ["browser_navigate""browser_click", ...],  # 浏览器工具"moa": ["mixture_of_agents"],                        # MoA 混合 Agent"delegation": ["delegate_task"],                     # 子 Agent 委派"kanban": ["kanban_create""kanban_move", ...],     # 看板管理"computer_use": [...],                               # 计算机控制# ...}

MCP(Model Context Protocol)支持通过 tools/mcp_tool.py 实现,让 Hermes 能接入任意 MCP 服务器扩展工具集。这是一个合理的扩展点——不需要等 Hermes 自己实现特定工具,只要有对应的 MCP 服务器即可。


十二、系统提示构建:多层叠加

agent/system_prompt.py(在 agent_init.py 中引用)负责构建最终的系统提示。以下优先级顺序基于对 agent_init.py 和 system_prompt.py 的源码阅读推断:

  1. 1. SOUL.md(个人身份/人格文件)
  2. 2. AGENTS.md(工作区指令)
  3. 3. .cursorrules / CLAUDE.md 等(项目级上下文文件)
  4. 4. 技能内容(当前轮次激活的技能)
  5. 5. 记忆上下文(从 MemoryManager 拉取的相关记忆)
  6. 6. 平台提示(CLI / Telegram / Discord 的格式化提示)
  7. 7. 工具说明

ephemeral_system_prompt 参数允许注入一个临时系统提示,它不会被保存进 trajectory 文件,专门用于批处理场景,避免用户个人数据(SOUL.md 等)污染训练数据。


十三、Trajectory 系统:训练数据管道

agent/trajectory.py 负责把对话记录保存为 JSONL 格式:

每条 trajectory:{  "role": "user"|"assistant"|"tool",  "content": "...",  "tool_calls": [...],  // 可选  "tool_call_id": "...", // 可选}

这直接服务于 Nous Research 的核心业务:用真实用户 + Agent 的交互轨迹训练更好的工具调用模型。ephemeral_system_prompt 的设计和 skip_context_files 参数都是为了保证收集到的轨迹数据是"干净的"(不含个人身份信息)。


十四、优缺点分析

优点

1. 真正的自进化机制Background Review + Curator 是实实在在的代码,不是宣传语。每次对话后 Agent 评估自己,技能库会持续演化。这是目前开源 Agent 中最完整的学习闭环实现之一。

2. 传输层抽象彻底4 种 API 传输模式 + 自动检测,200+ 模型接入。切换模型不改任何业务逻辑,hermes model 一条命令完成。对于需要多模型协同(主模型 + 压缩模型 + 辅助模型)的复杂任务,这个架构相当灵活。

3. 多凭证池与故障转移生产级的凭证管理:多账号轮询、错误码感知的冷却时间、provider 级故障自动转移。这在个人 Agent 项目里很少见。

4. 上下文引擎可插拔ContextEngine 抽象基类让第三方可以实现自己的压缩策略(如 DAG-based LCM)。内置的 ContextCompressor 在工程细节上很扎实(JSON 截断修复、图片 token 估算、摘要比例预算)。

5. LSP 集成原生 LSP 客户端让代码理解能力超越简单文件读写,达到 IDE 级别的符号分析。

6. 供应链安全意识精确锁版本、Scope 规则(只有全会话必需的包才进 dependencies)、懒加载(lazy_deps.py),体现了对供应链攻击的认真态度。

7. 多平台消息网关一套 Agent 逻辑,6 个 IM 平台接入,统一会话管理。适合需要让 AI 助手"住"在已有的通信工具里的用户。


缺点

1. 代码体量大,学习曲线陡conversation_loop.py 一个文件 3900 行,agent_init.py 60+ 参数。即便经过模块化拆分,核心流程的复杂度仍然很高。新贡献者很难快速定位"我要改哪里"。

2. 后台 Review 的质量依赖 PromptBackground Review 完全靠 prompt engineering 驱动,_SKILL_REVIEW_PROMPT 超过 80 行。如果 LLM 不严格遵循优先级规则(比如总是创建新技能而不是更新现有技能),会导致技能库膨胀甚至质量下降。项目有一定的"写技能的能力依赖写技能的技能(meta-skill)"的自举脆弱性。

3. 单进程设计,并发子 Agent 有限子 Agent 通过 ThreadPoolExecutor 运行,GIL 限制了真正的 CPU 并行。默认最大并发子 Agent 数 3(_DEFAULT_MAX_CONCURRENT_CHILDREN),复杂的并行编排场景有天花板。

4. 状态管理复杂Session ID、gateway_session_key、parent_session_id、iteration_budget 跨多个层次传递。在大量并发 gateway 会话的生产环境中,状态泄漏风险需要仔细管控。

5. 自进化的不可预期性技能自动写入是一把双刃剑。如果 Agent 从错误的操作中"学到了错误的经验",可能在未来会话中持续重现错误。Curator 的"只归档不删除"策略保守了一些,在技能库积累大量低质量条目后,清理工作会比较麻烦。

6. Windows 支持仍是 Beta尽管 v0.14.0 有原生 Windows 支持,但文档多次标注"early beta",PTY、browser dashboard 等功能依然需要 WSL2。

7. 依赖精确锁版本的维护成本精确锁版本是安全最佳实践,但意味着每个依赖升级都需要手动操作,维护负担较重。对于快速迭代的 AI 生态(openai SDK、anthropic SDK 频繁更新),这会成为一定的摩擦。


结语

Hermes Agent 是一个工程实现质量相当扎实的开源 AI Agent 框架。它不是一个"玩具"——credential pool、LSP 集成、供应链安全、多平台统一网关,这些都是生产级组件。

它的"自进化"设计思路在 AI Agent 领域也是前沿的:不满足于让模型"记住"上下文,而是让 Agent 把经验沉淀成可复用的"技能",并由后台 Curator 持续维护这个技能库的健康度。

如果你在寻找一个可以运行在云端、通过 IM 交互、能够自我学习的个人/团队 AI 助手框架,Hermes Agent 是目前开源方案中架构最完整的选择之一。


十五、工具执行管线:并行调度的规则引擎

当 LLM 一次性返回多个工具调用(batch tool calls)时,Hermes 不是简单地串行执行,而是通过 tool_dispatch_helpers.py 的规则引擎决定是否可以并行:

# 绝不并行(交互式工具)_NEVER_PARALLEL_TOOLS = frozenset({"clarify"})# 无状态只读,直接并行_PARALLEL_SAFE_TOOLS = frozenset({"read_file""web_search""web_extract","skill_view""skills_list""session_search", ...})# 路径作用域工具:目标路径不重叠则可并行_PATH_SCOPED_TOOLS = frozenset({"read_file""write_file""patch"})

_should_parallelize_tool_batch() 的决策流程:

重叠

不重叠

LLM 返回 batch\n多个工具调用
batch 中\n有 clarify?
串行执行
逐一检查每个工具
工具在\n_PATH_SCOPED_TOOLS?
提取目标路径
与已记录路径\n前缀重叠?
记录路径,继续
工具在\n_PARALLEL_SAFE_TOOLS?
是 MCP 工具且服务器\n声明 parallel_safe?
还有下一个工具?
并行执行\nThreadPoolExecutor

路径重叠检测用的是前缀匹配而非 resolve(),因为目标文件可能还不存在——这是一个很细心的边界条件处理。

工具结果的多模态包装

computer_use 等工具返回的不是字符串,而是一个特殊 envelope:

{"_multimodal"True,"content": [                      # OpenAI-style content parts        {"type""image_url""image_url": {"url""data:image/png;base64,..."}},        {"type""text""text""Screenshot taken"}    ],"text_summary""Screenshot taken"# 给不支持多模态的 provider 的纯文本回退}

_is_multimodal_tool_result() + _multimodal_text_summary() 这对函数让工具层和模型层的适配逻辑彻底解耦:工具只负责产出结构化内容,传输层决定如何把它发给具体的 provider。


十六、Prompt Caching:75% Token 成本压缩的实现

agent/prompt_caching.py 是一个纯函数模块(无类状态),实现的是 Anthropic 的 system_and_3 缓存策略:

defapply_anthropic_cache_control(    api_messages: List[Dict],    cache_ttl: str = "5m",       # "5m" 或 "1h"    native_anthropic: bool = False,) -> List[Dict]:"""    放置最多 4 个 cache_control breakpoint:      - system prompt(1 个)      - 最近的 3 条非系统消息(3 个)    所有 breakpoint 使用相同 TTL。    """

为什么是"最近 3 条"而不是"前几条"?

Anthropic 的 prompt cache 是前缀缓存——只要消息序列的前缀没变,就能命中缓存。system prompt 永远不变,天然适合缓存。而对话历史中,越靠前的消息越稳定(用户不会修改),最近 3 条反而是当前轮次刚产生的,打上 breakpoint 让下一轮可以直接命中前面所有内容。

两个 TTL 的使用场景

TTL
场景
5m
(默认)
交互式对话,用户不长时间离开
1h
background review / Curator 等长周期任务,防止 5 分钟过期重算

Background Review 的"近零成本"原理

Background Review 的 auxiliary agent 使用同一个 base_url + api_key 构建,加上同样的 system prompt(包含 SOUL.md、MEMORY.md 等)。这意味着它和主 Agent 共享前缀缓存——system prompt 那一层已经被主 Agent 缓存过,background review fork 直接命中,只需支付少量增量 token 费用。

这不是营销说法,是有代码支撑的:auxiliary_client.py 在解析 provider 配置时,Step 1 就是"用户的主 provider + 主 model",刻意和主 Agent 保持一致。


十七、错误分类器:结构化故障恢复的神经中枢

error_classifier.py 是 v0.14.0 里一个相当成熟的设计,用 FailoverReason 枚举把所有 API 错误分类,让重试循环不再靠 if-else 字符串匹配,而是查询结构化标志位:

classFailoverReason(enum.Enum):    auth = "auth"# 401/403 瞬态 → 刷新/轮换凭证    auth_permanent = "auth_permanent"# 刷新后仍失败 → 终止    billing = "billing"# 402/额度耗尽 → 立即轮换凭证    rate_limit = "rate_limit"# 429/限流 → 退避后轮换    overloaded = "overloaded"# 503/529 → 退避    server_error = "server_error"# 500/502 → 重试    timeout = "timeout"# 超时 → 重建 client + 重试    context_overflow = "context_overflow"# 上下文超限 → 压缩,不切 provider    payload_too_large = "payload_too_large"# 413 → 压缩 payload    image_too_large = "image_too_large"# 图片超限 → 缩图后重试    model_not_found = "model_not_found"# 404/模型不存在 → fallback 模型    provider_policy_blocked = "provider_policy_blocked"# OpenRouter 隐私策略 → 终止并提示    format_error = "format_error"# 400 格式错误 → 终止或清理后重试    thinking_signature = "thinking_signature"# Anthropic thinking block 签名失效    long_context_tier = "long_context_tier"# Anthropic 长上下文增量计费门槛    oauth_long_context_beta_forbidden = "..."# Anthropic OAuth 不支持 1M context    llama_cpp_grammar_pattern = "..."# llama.cpp JSON schema regex 不兼容    unknown = "unknown"# 无法分类 → 带退避重试

ClassifiedError 的恢复标志设计

@dataclassclassClassifiedError:    reason: FailoverReason    retryable: bool = True    should_compress: bool = False# True → 触发上下文压缩    should_rotate_credential: bool = False# True → 切换凭证    should_fallback: bool = False# True → 切换 provider/model

这个设计的价值在于:重试循环不需要知道"为什么失败",只需要读取 should_compressshould_rotate_credentialshould_fallback 三个标志来决定下一步动作。分类逻辑和恢复逻辑完全解耦。

auth

auth_permanent

billing

rate_limit

overloaded

server_error

timeout

context_overflow

image_too_large

model_not_found

provider_policy_blocked

format_error

unknown

API 错误
ErrorClassifier\n分类错误
FailoverReason
rotate_credential\n5分钟冷却后重试
终止会话
rotate_credential\n立即切换
退避等待\n1小时冷却
退避等待\n503/529
直接重试\n500/502
重建 HTTP client\n+ 重试
压缩上下文\nContextEngine.compress\n不切换 provider
缩小图片\n+ 重试
fallback model\n切换备用模型
终止并提示\n修改 OpenRouter 隐私设置
清理 tool schema\n如剥离 pattern 字段\n+ 重试
带退避重试
重试 LLM 调用

几个有趣的分类细节

billing vs rate_limit 的模糊地带

_USAGE_LIMIT_PATTERNS = ["usage limit""quota""limit exceeded"]_USAGE_LIMIT_TRANSIENT_SIGNALS = ["try again""retry""resets at""window"]

"usage limit exceeded" 可能是账单问题(永久)或速率限制(临时)。分类器先匹配 _USAGE_LIMIT_PATTERNS,再检查错误消息里是否有 "try again" / "resets at" 等瞬态信号——有就是 rate_limit,没有就是 billing

provider_policy_blocked

这是专门针对 OpenRouter 的一个枚举值。当用户的账户隐私设置排除了某个模型唯一可用的 endpoint 时,OpenRouter 返回 404 但消息是:

"No endpoints available matching your guardrail restrictions and data policy."

这和"模型不存在"(model_not_found)是完全不同的错误原因——切换 provider 无法解决,只能提示用户去修改 OpenRouter 账户设置。

llama_cpp_grammar_pattern

llama.cpp 的 JSON schema → grammar 转换器对 pattern / format 字段里的某些正则有兼容性问题。分类器识别出这类错误后,触发"从 tool schema 里剥离 pattern/format 字段后重试"——这是从真实兼容性 Bug 中沉淀出来的针对性处理。


十八、Auxiliary Client:背景任务的多 Provider 解析链

auxiliary_client.py 是所有"不打扰用户的后台 LLM 调用"的统一入口:上下文压缩、Session 搜索、Web 提取、Vision 分析、Background Review 都经过它。

自动解析链

文本任务(auto 模式)解析顺序:  1. 用户主 provider + 主 model(命中 prompt cache 关键)  2. OpenRouter(OPENROUTER_API_KEY 环境变量)  3. Nous Portal(~/.hermes/auth.json)  4. 自定义端点(config.yaml model.base_url)  5. 原生 Anthropic  6. 直连 API-key provider(z.ai/GLM、Kimi、MiniMax 等)视觉/多模态任务:额外检查主 provider 是否支持视觉,再走上面的链

注意"Codex OAuth(ChatGPT 账号 auth)不在备用链里"——注释明确解释了原因:OpenAI 对这个端点有个不公开、持续变化的模型白名单,硬编码一个模型名会自行腐烂。

OpenAI SDK 的懒加载代理

class_OpenAIProxy:"""模块级代理,模拟 openai.OpenAI 类行为,SDK 在首次调用时才加载。"""def__call__(self, *args, **kwargs):return _load_openai_cls()(*args, **kwargs)OpenAI = _OpenAIProxy()  # 模块全局名称

openai SDK 的冷启动大约需要 240ms(包括 responses/*graders/* 等类型树)。用代理对象把真实 import 推迟到第一次 OpenAI(...) 调用时,避免在每次启动 Hermes 时都付出这个冷启动代价——即便当前会话根本用不到 auxiliary client。

同时,from openai import OpenAI 的测试 patch 路径(patch("agent.auxiliary_client.OpenAI", ...))通过代理对象完全透明兼容。


十九、Skill 预处理:动态注入与内联 Shell

skill_preprocessing.py 在技能内容被注入 system prompt 前做两件事:

1. 模板变量替换

_SKILL_TEMPLATE_RE = re.compile(r"\$\{(HERMES_SKILL_DIR|HERMES_SESSION_ID)\}")

SKILL.md 里可以写 ${HERMES_SKILL_DIR} 引用技能自己的目录路径,或 ${HERMES_SESSION_ID} 拿到当前会话 ID。设计原则:无法解析的 token 原样保留,不替换为空字符串——这让技能作者可以快速发现自己写错了变量名。

2. 内联 Shell 执行

_INLINE_SHELL_RE = re.compile(r"!`([^`\n]+)`")_INLINE_SHELL_MAX_OUTPUT = 4000# 输出上限,防止撑爆 context

SKILL.md 里的 !`date +%Y-%m-%d` 会在技能加载时执行,结果替换进内容:

# 每日报告技能今天是 !`date +%Y-%m-%d`,请帮我生成今日工作总结。

执行后变成:

今天是 2026-05-22,请帮我生成今日工作总结。

这个功能默认关闭skills.inline_shell: false),需要在 config.yaml 里显式开启。关闭是对的——允许 SKILL.md 执行任意 shell 命令是一个明显的安全风险,只给有意识地选择了这个选项的用户开启。

失败处理也很细致:bash 不存在返回 [inline-shell error: bash not found],超时返回 [inline-shell timeout after Xs: cmd],测试环境的"live-system guard"拦截也有专门处理——一个 snippet 失败不影响其他 snippet 或整体技能加载。


二十、StreamingThinkScrubber:推理块过滤的状态机

think_scrubber.py 和 memory_manager.py 里的 StreamingContextScrubber 是同一类设计——都是为了解决流式输出无法用正则做跨 chunk 匹配的问题,用状态机替代。

背景:MiniMax-M2.7 等模型会在流式输出中夹带 <think> 推理块:

delta1 = "<think>"delta2 = "Let me check their config"delta3 = "</think> Here is my answer"

如果每个 delta 独立做 re.sub(r"<think>.*?</think>", "", delta),delta1 被抹掉(open tag 匹配失败),delta2 作为普通文本传给用户,推理内容泄漏。

解决方案

classStreamingThinkScrubber:    _OPEN_TAG_NAMES = ("think""thinking""reasoning""thought""REASONING_SCRATCHPAD")deffeed(self, text: str) -> str:# 状态机:_in_block=True 时吞掉所有内容直到 close tag# 跨 chunk 边界的 partial tag 缓存到 _buf 等下一个 delta 再判断

Block-boundary 规则:开标签只在"行首"(流开始、换行后、当前行只有空白)才触发推理块模式。这防止了模型在行内提到 <think> 标签名时被误过滤,比如:

"use <think> tags to show reasoning"

这个设计和 StreamingContextScrubber 对比值得一提:两者都是流式状态机,但触发条件不同——Think Scrubber 有 block-boundary 规则,Context Scrubber 有更宽松的匹配(memory-context 标签通常只出现在换行处)。


本文基于 hermes-agent v0.14.0 源码,核心文件包括 agent/conversation_loop.pyagent/agent_init.pyagent/context_engine.pyagent/context_compressor.pyagent/memory_manager.pyagent/curator.pyagent/background_review.pyagent/iteration_budget.pyagent/credential_pool.pytools/delegate_tool.pytools/tool_dispatch_helpers.pyagent/prompt_caching.pyagent/error_classifier.pyagent/auxiliary_client.pyagent/skill_preprocessing.pyagent/think_scrubber.py

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-05-23 17:03:19 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/657432.html
  2. 运行时间 : 0.224735s [ 吞吐率:4.45req/s ] 内存消耗:4,748.20kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=92e74ac7b21585e556a7b0d5c827defb
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.001034s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001624s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000703s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000678s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001340s ]
  6. SELECT * FROM `set` [ RunTime:0.000668s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001868s ]
  8. SELECT * FROM `article` WHERE `id` = 657432 LIMIT 1 [ RunTime:0.001741s ]
  9. UPDATE `article` SET `lasttime` = 1779526999 WHERE `id` = 657432 [ RunTime:0.001718s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000618s ]
  11. SELECT * FROM `article` WHERE `id` < 657432 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.001304s ]
  12. SELECT * FROM `article` WHERE `id` > 657432 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.001295s ]
  13. SELECT * FROM `article` WHERE `id` < 657432 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.003742s ]
  14. SELECT * FROM `article` WHERE `id` < 657432 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.002356s ]
  15. SELECT * FROM `article` WHERE `id` < 657432 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.001691s ]
0.228499s