《为什么 MCP、Skill、RAG 能工作?从 Conversation Loop 看现代 Agent 的底层架构》
作 者:吴佳浩Alben
撰稿时间:2026.7.10
更新时间:2026.7.13
前言
很多文章介绍 Agent 时,都会分别讲 MCP、Skill、Function Calling、RAG,却很少回答一个更关键的问题:
MCP、Skill、RAG 为什么能够协同工作?它们究竟是如何融入 Agent 的?
答案,其实都藏在 Agent 的执行主线——Conversation Loop 中。
本文将结合 Hermes 与 OpenClaw 的真实源码,从 Conversation Loop 出发,逐步串联 Tool Calling、Tool Registry、MCP、Skill、Memory(RAG) 等核心模块,完整解析现代 Agent 的底层架构,解释一个 Agent 为什么能够不断思考、调用工具、检索知识,并最终完成复杂任务。
MCP、Skill、Memory(RAG)并不是独立工作的能力,它们都是 Conversation Loop 中可被 LLM 调度的组成部分。
Conversation Loop 负责持续执行 「LLM 决策 → Tool 调用 → 结果反馈 → 再决策」;Tool Registry 提供工具目录;MCP 接入外部能力;Skill 封装可复用的执行流程;Memory(RAG) 提供长期记忆与知识检索。
它们共同构成了现代 Agent 的工具生态,而 Conversation Loop 则将这些能力串联起来,驱动整个 Agent 持续运行。理解了这条执行主线,也就理解了 MCP、Skill、RAG 为什么能够真正融入 Agent。
一、整体架构总览
先看全局,建立坐标感。
从这张图可以直接看出:所有的箭头最终都回到 Conversation Loop。消息网关是入口,工具生态是手臂,LLM 是外脑,但 Loop 才是心跳。
二、Conversation Loop:Agent 心脏
2.1 一句话讲清楚
Agent 本质上就是一个会自己循环思考的程序。每一轮都让 LLM 判断:「我是直接回答,还是调用工具?」如果调用工具,就把执行结果放回上下文,再让 LLM 思考下一步。
代码层面就是:
1 while 预算没花光: 2 LLM 看一遍历史消息和所有工具列表 → 决定下一步做什么 3 如果 LLM 说「回答完毕」 → 退出循环,返回用户 4 如果 LLM 说「调用工具 X(参数 Y)」 → 执行工具 X → 结果贴回对话 → 继续循环 5
这就是现代 Agent 的核心执行模型。本质上,它只是一个不断进行「决策 → 执行 → 反馈 → 再决策」的循环。
2.2 循环流程
2.3 简化版实现示意
以下是 conversation_loop.py(约 5300 行生产代码)的核心逻辑简化示意,真实实现有更多的重试、回退、压缩、安全检查等处理:
1# 简化版示意 — 源自 Hermes: agent/conversation_loop.py 2def run_conversation(agent, user_message): 3 """一个用户 Turn 的完整处理流程""" 4 5 # 1. 构建 Turn 上下文(system prompt + 历史 + 用户消息) 6 messages = build_turn_context(agent, user_message) 7 8 # 2. 从 Tool Registry 获取所有可用工具的定义(JSON Schema) 9 tools, checks = agent.tool_registry.get_all_visible_tools() 10 11 # 3. 迭代预算控制(默认最多 60 轮 tool call → API call) 12 budget = IterationBudget(max_turns=agent.max_turns) 13 14 while not budget.is_exhausted(): 15 # 4. 上下文太长就压缩 16 messages = compress_if_needed(agent, messages) 17 18 # 5. 调用 LLM API(带重试/fallback/provider 切换) 19 response = call_llm_with_retry(agent, messages, tools, budget) 20 21 # 6. 解析 LLM 返回 22 if response.finish_reason == "stop" and not response.tool_calls: 23 break # 纯文本 → 完成任务 24 25 if response.tool_calls: 26 for tool_call in response.tool_calls: 27 result = execute_tool(agent, tool_call) 28 messages.append({ 29 "role": "tool", 30 "tool_call_id": tool_call.id, 31 "content": result, 32 }) 33 continue # ← 回到循环顶部,LLM 重新审视最新状态 34 35 # 7. Turn 结束:持久化 session 36 save_session(agent, messages) 37 38# ⚠️ 以上是简化示意,不是可直接运行的源码。 39# 真实文件 ~5300 行,额外包含: 40# - 多层重试(API 错误 / 限流 / 超时) 41# - Provider 自动切换(fallback) 42# - 消息压缩/截断/修复 43# - 工具参数消毒 & 安全检查 44# - 上下文长度估算 & 动态调整 45# - 异常恢复 & 审计日志 46
关键点:
- 每次 LLM 调用时,所有可用工具的定义都以 Function Calling JSON Schema 形式传给 API。LLM 不是「查询数据库」选工具,而是根据工具描述做语义匹配
- 工具结果原样追加到 messages 数组。LLM 下一轮能「看到」之前的工具执行结果,这形成了情境感知链
- 预算耗尽(60 轮)是硬上限,防止死循环烧 Token
2.4 源码中的注释印证
以下注释直接来自 agent/conversation_loop.py 文件头部(非虚构):
1""" 2Hermes agent/conversation_loop.py 的架构注释(真实文档字符串) 3 4核心处理流程: 51. build_turn_context() - 构建 System Prompt + 历史消息 62. conversation_compression - 超长上下文压缩 73. 调用 LLM API(带重试/fallback/provider 切换) 84. 解析 response: text → 结束 / tool_calls → 执行 95. tool_executor 执行工具调用(分发到 Registry / MCP / Skill) 106. 结果追加到 messages,回到第 3 步 117. 预算耗尽或完成任务 → save + post_hooks 12""" 13
现在你理解了心脏怎么跳。接下来看三个问题:
- LLM 怎么知道有哪些工具可以调? → System Prompt(第三章)
- 这些工具从哪来的? → Tool Registry(第四章)
- 外部工具和技能包怎么接进来? → MCP(第五章)和 Skill(第六章)
说得直接一点——后面介绍的所有模块(System Prompt、Tool Registry、MCP、Skill、Memory),本质上都在做同一件事:让这个 Conversation Loop 更聪明、更安全、更高效地运行。
三、System Prompt:LLM 怎么知道有哪些工具?
3.1 构建流程
Agent 并不是「知道」有什么工具,而是把所有的能力写成一个开放式菜单让 LLM 去理解。
1sequenceDiagram 2 participant SP as System Prompt Builder 3 participant CFG as Config & 人格 4 participant REG as Tool Registry 5 participant MCP as MCP Manager 6 participant SKILL as Skill Loader 7 participant MEM as Memory Manager 8 participant LLM 9 10 SP->>CFG: 读取人格 (SOUL.md) + 行为规则 (AGENTS.md) 11 SP->>REG: 获取所有内置工具的定义 12 SP->>MCP: 获取已连接 MCP Server 的工具列表 13 SP->>SKILL: 扫描已安装 Skill 的 name + description 14 SP->>MEM: 构建记忆上下文块(RAG 检索结果) 15 SP->>LLM: 组合完整的 System Prompt + 历史消息 16
注意:这个构建过程不是在循环内部每次都做的。
- 静态部分(人格、工具定义、Skill 目录)在 Agent 启动时构建好,每次 API 调用时直接引用
- 动态部分(Memory 检索结果、Skill 完整指令)在 LLM 输出对应的 function_call 后才加载并注入
3.2 Hermes:工具定义如何传给 LLM
1# Hermes: agent/conversation_loop.py — 每次 API 调用前(简化版) 2def _build_api_request(agent, messages, tools_entries): 3 api_tools = [] 4 for entry in tools_entries: 5 api_tools.append({ 6 "type": "function", 7 "function": { 8 "name": entry.name, 9 "description": entry.description, # ← LLM 就是靠这个字段做语义匹配 10 "parameters": entry.parameters, # JSON Schema 11 } 12 }) 13 14 return client.chat.completions.create( 15 model=agent.model, 16 messages=messages, 17 tools=api_tools, # ← 所有可用工具的菜单,一次性传给 LLM 18 ) 19
3.3 OpenClaw:Skill 目录注入
1<!-- OpenClaw System Prompt 中注入的 Skill 目录 --> 2<available_skills> 3 <skill> 4 <name>weather</name> 5 <description>Current weather and forecasts with web_fetch, falling back to wttr.in...</description> 6 <location>/opt/homebrew/lib/node_modules/openclaw/skills/weather/SKILL.md</location> 7 </skill> 8 <skill> 9 <name>github</name> 10 <description>GitHub CLI for issues, PRs, CI/check logs, comments, reviews, releases...</description> 11 <location>/opt/homebrew/lib/node_modules/openclaw/skills/github/SKILL.md</location> 12 </skill> 13 <skill> 14 <name>hackernews</name> 15 <description>Hacker News API for stories and comments. Use when user mentions HN...</description> 16 <location>~/.agents/skills/hackernews/SKILL.md</location> 17 </skill> 18</available_skills> 19
LLM 看到 hackernews 的 description 里有「Hacker News API for stories」,当用户问「HN 今天有什么热门」时,LLM 做语义匹配 → 输出 read(skills/hackernews/SKILL.md) → Agent 加载完指令后再继续循环。
核心原理:LLM 不「知道」该用什么工具,它只是看到工具的 description 字段和用户的意图相似,就决定调用。所以 description 写得越好,Agent 越「聪明」。
四、Tool Registry:工具的「货源」
4.1 工具的来源与注册
4.2 真实代码:Hermes 的 Tool Registry
1# Hermes: tools/registry.py(简化版) 2class ToolRegistry: 3 def __init__(self): 4 self._tools: Dict[str, ToolEntry] = {} 5 self._toolset_checks: Dict[str, callable] = {} 6 7 def register(self, name, func, description, parameters, toolset): 8 """注册一个工具到全局注册表""" 9 self._tools[name] = ToolEntry( 10 name=name, 11 func=func, 12 description=description, # ← LLM 做语义匹配的核心字段 13 parameters=parameters, # JSON Schema 14 toolset=toolset, 15 ) 16 17 def get_all_visible_tools(self): 18 """ 19 返回当前上下文下所有可见工具。 20 只返回 toolset check 通过的工具(否则不注入到 System Prompt)。 21 """ 22 visible = [] 23 for name, entry in self._tools.items(): 24 check = self._toolset_checks.get(entry.toolset) 25 if check is None or check(): 26 visible.append(entry) 27 return visible 28 29 def lookup(self, name: str) -> Optional[ToolEntry]: 30 """按名称查找工具""" 31 return self._tools.get(name) 32 33 34# 工具自动发现:扫描 tools/ 目录下所有 Python 模块 35def discover_builtin_tools(tools_dir: Path) -> List[str]: 36 discovered = [] 37 for path in tools_dir.glob("*.py"): 38 if _module_registers_tools(path): 39 discovered.append(path.stem) 40 return discovered 41
4.3 工具可用性检查(环境感知)
并非所有工具在所有上下文中都可用。每个 toolset 可以注册一个 check_fn:
1# 示例:只有当 DISCORD_BOT_TOKEN 存在时,discord 工具才可见 2tool_registry.register_toolset_check( 3 "discord", 4 lambda: bool(os.getenv("DISCORD_BOT_TOKEN")) 5) 6
在 errors.log 中的实际日志:
1 WARNING tools.registry: check_fn check_discord_tool_requirements returned False 2 WARNING tools.registry: check_fn _browser_cdp_check returned False 3
设计含义:不可用的工具不会出现在 System Prompt 的 tools 数组中,LLM 根本看不到它,也就不会调用它。这是最干净的工具屏蔽方式——不需要 LLM 知道什么「不该用」,它压根感知不到。
五、MCP(Model Context Protocol):外部工具的标准化接入
MCP 解决的核心问题:Agent 不可能为每一个业务系统单独开发 Tool,因此需要一种统一的协议来接入外部能力。
5.1 架构
5.2 配置示例
1# ~/.hermes/config.yaml 2mcp_servers: 3 filesystem: 4 command: "npx" 5 args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"] 6 timeout: 120 7 8 github: 9 command: "npx" 10 args: ["-y", "@modelcontextprotocol/server-github"] 11 env: 12 GITHUB_PERSONAL_ACCESS_TOKEN: "ghp_..." 13 supports_parallel_tool_calls: true 14 15 remote_api: 16 url: "https://my-mcp-server.example.com/mcp" 17 headers: 18 Authorization: "Bearer sk-..." 19 timeout: 180 20
5.3 真实代码:Hermes 的 MCP 工具模块
1# Hermes: tools/mcp_tool.py(约 5500 行的生产级实现) 2""" 3MCP (Model Context Protocol) Client Support 4 5Architecture: 6 A dedicated background event loop runs in a daemon thread. 7 Each MCP server runs as a long-lived asyncio Task on this loop. 8 Tool call coroutines are scheduled via `run_coroutine_threadsafe()`. 9 10Transport modes: 11 - Stdio: command + args → 启动子进程,stdin/stdout 通信 12 - HTTP: url → Streamable HTTP POST 13 - SSE: url + transport: sse → Server-Sent Events 14 15Features: 16 - Auto-reconnect with exponential backoff(最多 5 次) 17 - Environment variable filtering(安全过滤敏感 env) 18 - Credential stripping in error messages(不把 token 泄露给 LLM) 19 - Parallel tool call opt-in per server 20""" 21
5.4 OpenClaw 的 MCP 实现
1// OpenClaw: agent-bundle-mcp-runtime-BcscePMD.js 2import { Client } from "@modelcontextprotocol/sdk/client/index.js"; 3import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; 4import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; 5 6function loadEmbeddedAgentMcpConfig(params) { 7 const bundleMcp = loadMergedBundleMcpConfig({ 8 workspaceDir: params.workspaceDir, 9 cfg: params.cfg, 10 manifestRegistry: params.manifestRegistry, 11 }); 12 return { 13 mcpServers: bundleMcp.config.mcpServers, 14 diagnostics: bundleMcp.diagnostics, 15 }; 16} 17 18// 启动流程:connect → listTools() → 注册到 Tool Catalog → LLM 可调用 19
5.5 MCP 调用完整时序
1sequenceDiagram 2 participant U as 用户 3 participant A as Agent 4 participant MC as MCP Client 5 participant MS as MCP Server 6 participant LLM 7 8 Note over MC,MS: 启动阶段 — 建立连接 & 发现工具 9 MC->>MS: connect(stdio / http) 10 MC->>MS: listTools() 11 MS-->>MC: [{name:"list_files", description:"List files in dir"}, ...] 12 MC->>A: 注册 MCP 工具到 Tool Registry 13 14 Note over U,LLM: 运行时 — 用户提问促发调用 15 U->>A: "帮我读一下 /tmp/config.json" 16 A->>LLM: messages + tools(含 mcp__filesystem__read_file) 17 LLM-->>A: function_call: mcp__filesystem__read_file(path="/tmp/config.json") 18 A->>MC: callTool("filesystem", "read_file", {path:"/tmp/config.json"}) 19 MC->>MS: tools/call (JSON-RPC) 20 MS-->>MC: {content: [{"type":"text","text":"{'key':'value'}"}]} 21 MC-->>A: 工具执行结果 22 A->>LLM: 追加 tool result → 生成回答 23 LLM-->>A: "/tmp/config.json 的内容是..." 24 A-->>U: 最终回答 25
六、Skill 系统:可复用的工具组合指令
与 MCP(提供单个函数调用接口)不同,Skill 提供的是执行指令和上下文。它告诉 LLM「遇到某类任务时,按这个步骤组合调用多个工具」。
6.1 Skill 的两种形态
| 形态 | 说明 | 示例 |
|---|---|---|
| 目录式 Skill | SKILL.md + 可执行脚本/配置文件 | weather — 有 wttr.in 调用逻辑的完整技能包 |
| 内联指令 | 纯 SKILL.md 文本注入 prompt | browser-automation — 浏览器操作最佳实践指南 |
6.2 加载与触发流程
6.3 真实代码:Hermes 的 Skill 预处理引擎
1# Hermes: agent/skill_preprocessing.py 2 3# 模板变量替换:${HERMES_SKILL_DIR} → 实际路径 4_SKILL_TEMPLATE_RE = re.compile(r"\$\{(HERMES_SKILL_DIR|HERMES_SESSION_ID)\}") 5 6# 内联 Shell: → 可在 prompt 中直接执行命令并注入结果 7_INLINE_SHELL_RE = re.compile(r"!`([^`\n]+)`") 8 9def substitute_template_vars(content, skill_dir, session_id): 10 """替换 SKILL.md 中的模板变量""" 11 def _replace(match): 12 token = match.group(1) 13 if token == "HERMES_SKILL_DIR" and skill_dir: 14 return str(skill_dir) 15 return match.group(0) 16 return _SKILL_TEMPLATE_RE.sub(_replace, content) 17 18def run_inline_shell(command, cwd, timeout): 19 """ 20 执行 SKILL.md 中的内联 shell 命令。 21 例如 `!`date +%Y-%m-%d`` → 注入 "2026-07-14" 22 失败不抛异常,返回 [inline-shell error: ...] 标记 23 """ 24 completed = subprocess.run( 25 ["bash", "-c", command], 26 capture_output=True, text=True, 27 timeout=max(1, int(timeout)), 28 ) 29 return (completed.stdout or "").rstrip("\n") 30
6.4 Skill 安全扫描(安装前防线)
1# Hermes: tools/skills_guard.py 2""" 3Skills Guard — 外部 Skill 的安全扫描器 4 5Trust levels: 6 - builtin: 随 Hermes 发布,永不扫描,始终信任 7 - trusted: 来自 openai/skills、anthropics/skills、NVIDIA/skills 8 - community: 其他来源。有发现即阻止,除非 --force 9""" 10 11TRUSTED_REPOS = { 12 "openai/skills", "anthropics/skills", "NVIDIA/skills", 13} 14 15# 正则威胁检测模式 16THREAT_PATTERNS = [ 17 ("curl.*\\|.*bash", "remote-pipe", "critical", "exfiltration"), 18 ("crontab\\s+-", "crontab-edit", "high", "persistence"), 19 ("rm\\s+-rf\\s+/", "rm-root", "critical", "destructive"), 20 ("nc\\s+.*-e", "netcat-shell", "critical", "network"), 21] 22
6.5 OpenClaw 的 Skill 选择策略
1<!-- OpenClaw System Prompt 中的 Skill 目录 --> 2<available_skills> 3 <skill> 4 <name>weather</name> 5 <description>Current weather and forecasts with web_fetch, falling back to wttr.in...</description> 6 </skill> 7</available_skills> 8
七、Memory / RAG:长期记忆与知识检索
7.1 记忆的完整生命周期
RAG 不只是「检索」,完整的记忆系统包含写入和检索两个方向:
关键设计:写入和检索是解耦的——Agent 不直接在对话中「写记忆」,而是在每次 Turn 结束后通过 post_turn_hook 持久化到文件。后续对话中,LLM 通过 memory_search 工具(或自动注入 context block)检索这些记忆。
1flowchart TB 2 subgraph 离线索引 3 DOCS[文档 / 记忆文件] --> CHUNK[文本分块] 4 CHUNK --> EMBED[Embedding 向量化] 5 EMBED --> STORE[(向量数据库<br/>Chroma / FAISS / local)] 6 end 7 8 subgraph 运行时检索 9 Q[用户提问] --> QEMBED[问题向量化] 10 QEMBED --> SEARCH[相似度检索] 11 STORE --> SEARCH 12 SEARCH --> RERANK[结果重排] 13 RERANK --> CONTEXT[注入上下文] 14 CONTEXT --> LLM 15 end 16
7.2 知识库检索架构
1flowchart TB 2 subgraph 离线索引 3 DOCS[文档 / 记忆文件] --> CHUNK[文本分块] 4 CHUNK --> EMBED[Embedding 向量化] 5 EMBED --> STORE[(向量数据库)] 6 end 7 8 subgraph 运行时检索 9 Q[用户提问] --> QEMBED[Question 向量化] 10 QEMBED --> SEARCH[相似度检索] 11 STORE --> SEARCH 12 SEARCH --> RERANK[结果重排] 13 RERANK --> CONTEXT[注入上下文] 14 CONTEXT --> LLM 15 end 16
7.3 真实代码:Hermes 的 Memory Manager
1# Hermes: agent/memory_manager.py 2def build_memory_context_block(agent, user_message: str, max_chars=8000) -> str: 3 """检索相关记忆,构建上下文块注入到对话中""" 4 results = agent.memory_store.search(query=user_message, top_k=10) 5 6 if not results: 7 return "" 8 9 context_lines = ["<memory_context>"] 10 for result in results: 11 if len("\n".join(context_lines)) > max_chars: 12 break 13 context_lines.append( 14 f"<memory score={result.score:.2f}>{result.text}</memory>" 15 ) 16 context_lines.append("</memory_context>") 17 return "\n".join(context_lines) 18
7.4 RAG 在 Conversation Loop 中的位置
1sequenceDiagram 2 participant U as 用户 3 participant A as Agent 4 participant MEM as Memory Manager 5 participant EMB as Embedding 服务 6 participant STORE as 向量存储 7 participant LLM as LLM 8 9 U->>A: "上次我们讨论的那个 bug 修复了吗?" 10 11 Note over A,LLM: Loop 第 1 轮:LLM 判断需要搜索记忆 12 A->>LLM: messages + tools(含 memory_search) 13 LLM-->>A: function_call: memory_search(query="bug 修复") 14 15 A->>MEM: memory_search(query="bug 修复") 16 MEM->>EMB: query 向量化 17 EMB-->>MEM: embedding vector 18 MEM->>STORE: 相似度检索 19 STORE-->>MEM: top-k 相关片段 20 MEM-->>A: 返回语义相关记忆 21 22 Note over A,LLM: Loop 第 2 轮:记忆注入后继续对话 23 A->>LLM: messages + 检索到的记忆片段 + 原问题 24 LLM-->>A: "根据之前讨论的 #42 bug,已在上周通过 PR #58 修复" 25 A-->>U: 最终回答 26
关键设计:memory_search 本身也是 Tool Registry 中的一个工具!LLM 在循环中自主决定「我需要先查一下历史记忆」,然后调用它。检索结果作为上下文追加到 messages,下一轮 LLM 就能基于记忆生成回答。
7.5 OpenClaw 的 Memory Search 工具定义
八、全链路端到端:一条消息的完整旅程
以「帮我查一下 GitHub 上 openclaw 项目的最近 3 个 Issue」为例,展示完整的 Conversation Loop 流转:
1flowchart LR 2 U[用户提问] --> GW[Gateway] 3 GW --> L1[Loop R1: 加载 github SKILL] 4 L1 --> L2[Loop R2: 调用 MCP gh issue list] 5 L2 --> L3[Loop R3: 格式化回答] 6 L3 --> U2[返回] 7
代码路径对照:
1 1. 消息到达 → hermes_cli/tui_gateway/server.py 2 2. 创建 Session + 启动 Loop → agent/conversation_loop.py::run_conversation() 3 3. 构建上下文 → agent/turn_context.py + agent/memory_manager.py 4 4. 调用 LLM → agent/conversation_loop.py::call_llm_with_retry() 5 5. 解析 function_call → tools/registry.py::lookup() 6 → Built-in: 直接执行函数 7 → MCP: tools/mcp_tool.py → 转发到 MCP Server 8 → Skill: agent/skill_utils.py → 加载 SKILL.md 9 6. 追加结果 + 回到步骤 4(最多 60 轮) 10
九、核心速查:对比总结 + 关键洞察
9.1 Hermes vs OpenClaw
| 对比维度 | Hermes | OpenClaw |
|---|---|---|
| 定位 | 大而全的 Agent 平台(桌面 GUI + 网关 + 多平台消息) | 轻量 Agent 框架(命令行 + 可嵌入) |
| 语言 | Python 3.11 | TypeScript (Node.js) |
| Conversation Loop | agent/conversation_loop.py (~5300 行) | embedded-agent-BgF2MOkH.js (dist 打包) |
| Tool 系统 | tools/registry.py — 类继承 + 装饰器自动注册 | agent-tools-XUrUI5bQ.js — Tool Catalog + Compaction |
| Tool 发现 | 自动扫描 tools/*.py + MCP listTools + Skill 元数据 | 显式注册 + MCP listTools + Skill 清单 |
| MCP 支持 | 原生支持(stdio / HTTP / SSE,守护线程) | 原生支持(stdio / HTTP / SSE) |
| Skill 系统 | SKILL.md + 模板变量 + 内联 Shell + 安全扫描 + 信任分级 | SKILL.md + description 注入 |
| Memory / RAG | agent/memory_manager.py — 向量检索 + 上下文注入 | memory_search Tool — 语义搜索 MEMORY.md |
| 消息平台 | 微信 / Discord / Telegram / Slack / Signal / QQ 等 | WebChat / Discord / Telegram / Signal 等 |
| 安全 | Skill 来源信任分级 + MCP 凭证脱敏 + 危险命令拦截 + 可用性检查 | Skill 可用性检查 + 命令审批 |
| 配置复杂度 | 高(~/.hermes/config.yaml 的完整生态配置) | 低(Gateway config + 工作区文件) |
| 适用场景 | 个人全能助理、多平台部署 | 嵌入式 Agent、轻量部署、API 集成 |
9.2 关键洞察速查
| 问题 | 答案 |
|---|---|
| Agent 的本质是什么? | 一个带工具的白盒 while 循环:「LLM 决策 → Tool 调用 → 结果反馈 → LLM 再决策」 |
| Agent 怎么知道该调哪个工具? | 不「知道」。LLM 做语义匹配——工具 description 和用户意图越接近,越容易被调用 |
| MCP 和 Skill 有什么区别? | MCP = 标准化外部函数接口(一个工具一件事),Skill = 指令包(多个工具如何组合) |
| RAG 什么时候触发? | 在 Conversation Loop 内部,LLM 自主决定调用 memory_search 工具 → 检索 → 结果注入上下文 → 继续循环 |
| 记忆从哪来? | 每次 Turn 结束后 Agent 自动写入 memory/YYYY-MM-DD.md,周期性提炼到 MEMORY.md,再通过 Embedding 建立向量索引 |
| 一个 Turn 最多调多少次 LLM? | Hermes 默认 max_turns=60,即最多 60 轮 tool call ↔ API call |
| 工具不可用时怎么办? | check_fn 返回 False → 工具不注入到 tools 数组 → LLM 看不到 → 根本不会调用 |
| Hermes 和 OpenClaw 最大区别? | Hermes 是「大而全的平台」(桌面 + 网关 + N 平台),OpenClaw 是「轻量可嵌入 Agent」 |
十、核心设计模式总结
十一、一张图看懂 Agent
核心公式:
Conversation Loop + Tool Calling + Memory = 现代 Agent 的全部秘密
从上往下读:用户提问进入 Loop → Loop 调用 Prompt(菜单)、Memory(记忆)、Tools(工具)→ 工具分为 Built-in / MCP / Skill → 结果回到 Loop → 完成业务目标。
整篇文章,本质上就是这张图从上到下的逐层展开。
十二、写在最后
无论是 Hermes、OpenClaw,还是 Claude Code、Codex、Gemini CLI、Cursor Agent,它们底层几乎都遵循同一种架构:
Conversation Loop + Tool Calling + Memory
不同产品真正的差异,不在于有没有 MCP,而在于——
- Loop 如何组织:单轮 vs 多轮、同步 vs 异步、预算策略是什么
- Tool 如何管理:装饰器自动注册 vs 显式注册、可用性检查粒度多细
- Memory 如何利用:文件级检索 vs 向量数据库、注入时机在哪一环
- 以及围绕这些能力构建出的工程体系:安全扫描、平台适配、会话持久化、多 Agent 协作
理解了 Conversation Loop、Tool Calling 和 Memory,就理解了现代 Agent 的核心设计;其余能力,如 Planning、多 Agent 协作、Workflow 等,大多是建立在这一基础之上的。
结语:
现代 Agent 看起来能力越来越多:MCP、Skill、Memory、Planning、Workflow……
但当真正读完源码之后会发现,它们并不是彼此独立的能力,而都是围绕 Conversation Loop 这一条执行主线构建出来的。
理解了 Conversation Loop,也就理解了 MCP、Skill、RAG 为什么能够真正融入 Agent;理解了 Tool Registry、Tool Calling 与 Memory 的协作方式,也就理解了现代 Agent 为什么能够持续思考、持续调用工具,并最终完成复杂任务。
源码会不断演进,但底层设计思想往往比代码更加稳定。
希望这篇文章,能够帮助你真正建立现代 Agent 的整体认知。
本文基于 Hermes v0.18.2 与 OpenClaw 当前版本源码分析,部分代码为简化示意,旨在说明整体设计思路。
作者:吴佳浩(Alben)
《为什么 MCP、Skill、RAG 能工作?从 Conversation Loop 看现代 Agent 的底层架构》 是转载文章,点击查看原文。
