为什么 MCP、Skill、RAG 能工作?从 Conversation Loop 看现代 Agent 的底层架构

149 阅读14分钟

《为什么 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 中。

本文将结合 HermesOpenClaw 的真实源码,从 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。


一、整体架构总览

先看全局,建立坐标感。

image.png

从这张图可以直接看出:所有的箭头最终都回到 Conversation Loop。消息网关是入口,工具生态是手臂,LLM 是外脑,但 Loop 才是心跳。


二、Conversation Loop:Agent 心脏

2.1 一句话讲清楚

Agent 本质上就是一个会自己循环思考的程序。每一轮都让 LLM 判断:「我是直接回答,还是调用工具?」如果调用工具,就把执行结果放回上下文,再让 LLM 思考下一步。

代码层面就是:

    while 预算没花光:
        LLM 看一遍历史消息和所有工具列表 → 决定下一步做什么
        如果 LLM 说「回答完毕」 → 退出循环,返回用户
        如果 LLM 说「调用工具 X(参数 Y)」 → 执行工具 X → 结果贴回对话 → 继续循环

这就是现代 Agent 的核心执行模型。本质上,它只是一个不断进行「决策 → 执行 → 反馈 → 再决策」的循环。

2.2 循环流程

image.png

2.3 简化版实现示意

以下是 conversation_loop.py(约 5300 行生产代码)的核心逻辑简化示意,真实实现有更多的重试、回退、压缩、安全检查等处理:

# 简化版示意 — 源自 Hermes: agent/conversation_loop.py
def run_conversation(agent, user_message):
    """一个用户 Turn 的完整处理流程"""
    
    # 1. 构建 Turn 上下文(system prompt + 历史 + 用户消息)
    messages = build_turn_context(agent, user_message)
    
    # 2. 从 Tool Registry 获取所有可用工具的定义(JSON Schema)
    tools, checks = agent.tool_registry.get_all_visible_tools()
    
    # 3. 迭代预算控制(默认最多 60 轮 tool call → API call)
    budget = IterationBudget(max_turns=agent.max_turns)
    
    while not budget.is_exhausted():
        # 4. 上下文太长就压缩
        messages = compress_if_needed(agent, messages)
        
        # 5. 调用 LLM API(带重试/fallback/provider 切换)
        response = call_llm_with_retry(agent, messages, tools, budget)
        
        # 6. 解析 LLM 返回
        if response.finish_reason == "stop" and not response.tool_calls:
            break  # 纯文本 → 完成任务
        
        if response.tool_calls:
            for tool_call in response.tool_calls:
                result = execute_tool(agent, tool_call)
                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "content": result,
                })
            continue  # ← 回到循环顶部,LLM 重新审视最新状态
    
    # 7. Turn 结束:持久化 session
    save_session(agent, messages)

# ⚠️ 以上是简化示意,不是可直接运行的源码。
# 真实文件 ~5300 行,额外包含:
#   - 多层重试(API 错误 / 限流 / 超时)
#   - Provider 自动切换(fallback)
#   - 消息压缩/截断/修复
#   - 工具参数消毒 & 安全检查
#   - 上下文长度估算 & 动态调整
#   - 异常恢复 & 审计日志

关键点

  • 每次 LLM 调用时,所有可用工具的定义都以 Function Calling JSON Schema 形式传给 API。LLM 不是「查询数据库」选工具,而是根据工具描述做语义匹配
  • 工具结果原样追加到 messages 数组。LLM 下一轮能「看到」之前的工具执行结果,这形成了情境感知链
  • 预算耗尽(60 轮)是硬上限,防止死循环烧 Token

2.4 源码中的注释印证

以下注释直接来自 agent/conversation_loop.py 文件头部(非虚构):

"""
Hermes agent/conversation_loop.py 的架构注释(真实文档字符串)

核心处理流程:
1. build_turn_context()      - 构建 System Prompt + 历史消息
2. conversation_compression   - 超长上下文压缩
3. 调用 LLM API(带重试/fallback/provider 切换)
4. 解析 response: text → 结束 / tool_calls → 执行
5. tool_executor 执行工具调用(分发到 Registry / MCP / Skill)
6. 结果追加到 messages,回到第 3 步
7. 预算耗尽或完成任务 → save + post_hooks
"""

现在你理解了心脏怎么跳。接下来看三个问题:

  1. LLM 怎么知道有哪些工具可以调? → System Prompt(第三章)
  2. 这些工具从哪来的? → Tool Registry(第四章)
  3. 外部工具和技能包怎么接进来? → MCP(第五章)和 Skill(第六章)

说得直接一点——后面介绍的所有模块(System Prompt、Tool Registry、MCP、Skill、Memory),本质上都在做同一件事:让这个 Conversation Loop 更聪明、更安全、更高效地运行。


三、System Prompt:LLM 怎么知道有哪些工具?

3.1 构建流程

Agent 并不是「知道」有什么工具,而是把所有的能力写成一个开放式菜单让 LLM 去理解。

sequenceDiagram
    participant SP as System Prompt Builder
    participant CFG as Config & 人格
    participant REG as Tool Registry
    participant MCP as MCP Manager
    participant SKILL as Skill Loader
    participant MEM as Memory Manager
    participant LLM

    SP->>CFG: 读取人格 (SOUL.md) + 行为规则 (AGENTS.md)
    SP->>REG: 获取所有内置工具的定义
    SP->>MCP: 获取已连接 MCP Server 的工具列表
    SP->>SKILL: 扫描已安装 Skill 的 name + description
    SP->>MEM: 构建记忆上下文块(RAG 检索结果)
    SP->>LLM: 组合完整的 System Prompt + 历史消息

注意:这个构建过程不是在循环内部每次都做的。

  • 静态部分(人格、工具定义、Skill 目录)在 Agent 启动时构建好,每次 API 调用时直接引用
  • 动态部分(Memory 检索结果、Skill 完整指令)在 LLM 输出对应的 function_call 后才加载并注入

3.2 Hermes:工具定义如何传给 LLM

# Hermes: agent/conversation_loop.py — 每次 API 调用前(简化版)
def _build_api_request(agent, messages, tools_entries):
    api_tools = []
    for entry in tools_entries:
        api_tools.append({
            "type": "function",
            "function": {
                "name": entry.name,
                "description": entry.description,  # ← LLM 就是靠这个字段做语义匹配
                "parameters": entry.parameters,    # JSON Schema
            }
        })

    return client.chat.completions.create(
        model=agent.model,
        messages=messages,
        tools=api_tools,  # ← 所有可用工具的菜单,一次性传给 LLM
    )

3.3 OpenClaw:Skill 目录注入

<!-- OpenClaw System Prompt 中注入的 Skill 目录 -->
<available_skills>
  <skill>
    <name>weather</name>
    <description>Current weather and forecasts with web_fetch, falling back to wttr.in...</description>
    <location>/opt/homebrew/lib/node_modules/openclaw/skills/weather/SKILL.md</location>
  </skill>
  <skill>
    <name>github</name>
    <description>GitHub CLI for issues, PRs, CI/check logs, comments, reviews, releases...</description>
    <location>/opt/homebrew/lib/node_modules/openclaw/skills/github/SKILL.md</location>
  </skill>
  <skill>
    <name>hackernews</name>
    <description>Hacker News API for stories and comments. Use when user mentions HN...</description>
    <location>~/.agents/skills/hackernews/SKILL.md</location>
  </skill>
</available_skills>

LLM 看到 hackernews 的 description 里有「Hacker News API for stories」,当用户问「HN 今天有什么热门」时,LLM 做语义匹配 → 输出 read(skills/hackernews/SKILL.md) → Agent 加载完指令后再继续循环。

核心原理:LLM 不「知道」该用什么工具,它只是看到工具的 description 字段和用户的意图相似,就决定调用。所以 description 写得越好,Agent 越「聪明」。


四、Tool Registry:工具的「货源」

4.1 工具的来源与注册

image.png

4.2 真实代码:Hermes 的 Tool Registry

# Hermes: tools/registry.py(简化版)
class ToolRegistry:
    def __init__(self):
        self._tools: Dict[str, ToolEntry] = {}
        self._toolset_checks: Dict[str, callable] = {}

    def register(self, name, func, description, parameters, toolset):
        """注册一个工具到全局注册表"""
        self._tools[name] = ToolEntry(
            name=name,
            func=func,
            description=description,  # ← LLM 做语义匹配的核心字段
            parameters=parameters,    # JSON Schema
            toolset=toolset,
        )

    def get_all_visible_tools(self):
        """
        返回当前上下文下所有可见工具。
        只返回 toolset check 通过的工具(否则不注入到 System Prompt)。
        """
        visible = []
        for name, entry in self._tools.items():
            check = self._toolset_checks.get(entry.toolset)
            if check is None or check():
                visible.append(entry)
        return visible

    def lookup(self, name: str) -> Optional[ToolEntry]:
        """按名称查找工具"""
        return self._tools.get(name)


# 工具自动发现:扫描 tools/ 目录下所有 Python 模块
def discover_builtin_tools(tools_dir: Path) -> List[str]:
    discovered = []
    for path in tools_dir.glob("*.py"):
        if _module_registers_tools(path):
            discovered.append(path.stem)
    return discovered

4.3 工具可用性检查(环境感知)

并非所有工具在所有上下文中都可用。每个 toolset 可以注册一个 check_fn

# 示例:只有当 DISCORD_BOT_TOKEN 存在时,discord 工具才可见
tool_registry.register_toolset_check(
    "discord",
    lambda: bool(os.getenv("DISCORD_BOT_TOKEN"))
)

errors.log 中的实际日志:

    WARNING tools.registry: check_fn check_discord_tool_requirements returned False
    WARNING tools.registry: check_fn _browser_cdp_check returned False

设计含义:不可用的工具不会出现在 System Prompt 的 tools 数组中,LLM 根本看不到它,也就不会调用它。这是最干净的工具屏蔽方式——不需要 LLM 知道什么「不该用」,它压根感知不到。


五、MCP(Model Context Protocol):外部工具的标准化接入

MCP 解决的核心问题:Agent 不可能为每一个业务系统单独开发 Tool,因此需要一种统一的协议来接入外部能力。

5.1 架构

image.png

5.2 配置示例

# ~/.hermes/config.yaml
mcp_servers:
  filesystem:
    command: "npx"
    args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
    timeout: 120

  github:
    command: "npx"
    args: ["-y", "@modelcontextprotocol/server-github"]
    env:
      GITHUB_PERSONAL_ACCESS_TOKEN: "ghp_..."
    supports_parallel_tool_calls: true

  remote_api:
    url: "https://my-mcp-server.example.com/mcp"
    headers:
      Authorization: "Bearer sk-..."
    timeout: 180

5.3 真实代码:Hermes 的 MCP 工具模块

# Hermes: tools/mcp_tool.py(约 5500 行的生产级实现)
"""
MCP (Model Context Protocol) Client Support

Architecture:
    A dedicated background event loop runs in a daemon thread.
    Each MCP server runs as a long-lived asyncio Task on this loop.
    Tool call coroutines are scheduled via `run_coroutine_threadsafe()`.

Transport modes:
    - Stdio:    command + args → 启动子进程,stdin/stdout 通信
    - HTTP:     url → Streamable HTTP POST
    - SSE:      url + transport: sse → Server-Sent Events

Features:
    - Auto-reconnect with exponential backoff(最多 5 次)
    - Environment variable filtering(安全过滤敏感 env)
    - Credential stripping in error messages(不把 token 泄露给 LLM)
    - Parallel tool call opt-in per server
"""

5.4 OpenClaw 的 MCP 实现

// OpenClaw: agent-bundle-mcp-runtime-BcscePMD.js
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";

function loadEmbeddedAgentMcpConfig(params) {
    const bundleMcp = loadMergedBundleMcpConfig({
        workspaceDir: params.workspaceDir,
        cfg: params.cfg,
        manifestRegistry: params.manifestRegistry,
    });
    return {
        mcpServers: bundleMcp.config.mcpServers,
        diagnostics: bundleMcp.diagnostics,
    };
}

// 启动流程:connect → listTools() → 注册到 Tool Catalog → LLM 可调用

5.5 MCP 调用完整时序

sequenceDiagram
    participant U as 用户
    participant A as Agent
    participant MC as MCP Client
    participant MS as MCP Server
    participant LLM

    Note over MC,MS: 启动阶段 — 建立连接 & 发现工具
    MC->>MS: connect(stdio / http)
    MC->>MS: listTools()
    MS-->>MC: [{name:&#34;list_files&#34;, description:&#34;List files in dir&#34;}, ...]
    MC->>A: 注册 MCP 工具到 Tool Registry

    Note over U,LLM: 运行时 — 用户提问促发调用
    U->>A: &#34;帮我读一下 /tmp/config.json&#34;
    A->>LLM: messages + tools(含 mcp__filesystem__read_file)
    LLM-->>A: function_call: mcp__filesystem__read_file(path=&#34;/tmp/config.json&#34;)
    A->>MC: callTool(&#34;filesystem&#34;, &#34;read_file&#34;, {path:&#34;/tmp/config.json&#34;})
    MC->>MS: tools/call (JSON-RPC)
    MS-->>MC: {content: [{&#34;type&#34;:&#34;text&#34;,&#34;text&#34;:&#34;{'key':'value'}&#34;}]}
    MC-->>A: 工具执行结果
    A->>LLM: 追加 tool result → 生成回答
    LLM-->>A: &#34;/tmp/config.json 的内容是...&#34;
    A-->>U: 最终回答

六、Skill 系统:可复用的工具组合指令

与 MCP(提供单个函数调用接口)不同,Skill 提供的是执行指令和上下文。它告诉 LLM「遇到某类任务时,按这个步骤组合调用多个工具」。

6.1 Skill 的两种形态

形态说明示例
目录式 SkillSKILL.md + 可执行脚本/配置文件weather — 有 wttr.in 调用逻辑的完整技能包
内联指令纯 SKILL.md 文本注入 promptbrowser-automation — 浏览器操作最佳实践指南

6.2 加载与触发流程

image.png

6.3 真实代码:Hermes 的 Skill 预处理引擎

# Hermes: agent/skill_preprocessing.py

# 模板变量替换:${HERMES_SKILL_DIR} → 实际路径
_SKILL_TEMPLATE_RE = re.compile(r"\$\{(HERMES_SKILL_DIR|HERMES_SESSION_ID)\}")

# 内联 Shell:!`date +%Y-%m-%d` → 可在 prompt 中直接执行命令并注入结果
_INLINE_SHELL_RE = re.compile(r"!`([^`\n]+)`")

def substitute_template_vars(content, skill_dir, session_id):
    """替换 SKILL.md 中的模板变量"""
    def _replace(match):
        token = match.group(1)
        if token == "HERMES_SKILL_DIR" and skill_dir:
            return str(skill_dir)
        return match.group(0)
    return _SKILL_TEMPLATE_RE.sub(_replace, content)

def run_inline_shell(command, cwd, timeout):
    """
    执行 SKILL.md 中的内联 shell 命令。
    例如 `!`date +%Y-%m-%d`` → 注入 "2026-07-14"
    失败不抛异常,返回 [inline-shell error: ...] 标记
    """
    completed = subprocess.run(
        ["bash", "-c", command],
        capture_output=True, text=True,
        timeout=max(1, int(timeout)),
    )
    return (completed.stdout or "").rstrip("\n")

6.4 Skill 安全扫描(安装前防线)

# Hermes: tools/skills_guard.py
"""
Skills Guard — 外部 Skill 的安全扫描器

Trust levels:
  - builtin:   随 Hermes 发布,永不扫描,始终信任
  - trusted:   来自 openai/skills、anthropics/skills、NVIDIA/skills
  - community: 其他来源。有发现即阻止,除非 --force
"""

TRUSTED_REPOS = {
    "openai/skills", "anthropics/skills", "NVIDIA/skills",
}

# 正则威胁检测模式
THREAT_PATTERNS = [
    ("curl.*\\|.*bash",     "remote-pipe",   "critical", "exfiltration"),
    ("crontab\\s+-",        "crontab-edit",  "high",     "persistence"),
    ("rm\\s+-rf\\s+/",      "rm-root",       "critical", "destructive"),
    ("nc\\s+.*-e",          "netcat-shell",  "critical", "network"),
]

6.5 OpenClaw 的 Skill 选择策略

<!-- OpenClaw System Prompt 中的 Skill 目录 -->
<available_skills>
  <skill>
    <name>weather</name>
    <description>Current weather and forecasts with web_fetch, falling back to wttr.in...</description>
  </skill>
</available_skills>

触发流程:用户说「今天天气怎么样」→ LLM 匹配 weather skill → Agent 执行 read(skills/weather/SKILL.md) → 按指令调用 web_fetch(wttr.in) → 返回结果


七、Memory / RAG:长期记忆与知识检索

7.1 记忆的完整生命周期

RAG 不只是「检索」,完整的记忆系统包含写入和检索两个方向

image.png

关键设计:写入和检索是解耦的——Agent 不直接在对话中「写记忆」,而是在每次 Turn 结束后通过 post_turn_hook 持久化到文件。后续对话中,LLM 通过 memory_search 工具(或自动注入 context block)检索这些记忆。

flowchart TB
    subgraph 离线索引
        DOCS[文档 / 记忆文件] --> CHUNK[文本分块]
        CHUNK --> EMBED[Embedding 向量化]
        EMBED --> STORE[(向量数据库<br/>Chroma / FAISS / local)]
    end

    subgraph 运行时检索
        Q[用户提问] --> QEMBED[问题向量化]
        QEMBED --> SEARCH[相似度检索]
        STORE --> SEARCH
        SEARCH --> RERANK[结果重排]
        RERANK --> CONTEXT[注入上下文]
        CONTEXT --> LLM
    end

7.2 知识库检索架构

flowchart TB
    subgraph 离线索引
        DOCS[文档 / 记忆文件] --> CHUNK[文本分块]
        CHUNK --> EMBED[Embedding 向量化]
        EMBED --> STORE[(向量数据库)]
    end

    subgraph 运行时检索
        Q[用户提问] --> QEMBED[Question 向量化]
        QEMBED --> SEARCH[相似度检索]
        STORE --> SEARCH
        SEARCH --> RERANK[结果重排]
        RERANK --> CONTEXT[注入上下文]
        CONTEXT --> LLM
    end

7.3 真实代码:Hermes 的 Memory Manager

# Hermes: agent/memory_manager.py
def build_memory_context_block(agent, user_message: str, max_chars=8000) -> str:
    """检索相关记忆,构建上下文块注入到对话中"""
    results = agent.memory_store.search(query=user_message, top_k=10)

    if not results:
        return ""

    context_lines = ["<memory_context>"]
    for result in results:
        if len("\n".join(context_lines)) > max_chars:
            break
        context_lines.append(
            f"<memory score={result.score:.2f}>{result.text}</memory>"
        )
    context_lines.append("</memory_context>")
    return "\n".join(context_lines)

7.4 RAG 在 Conversation Loop 中的位置

sequenceDiagram
    participant U as 用户
    participant A as Agent
    participant MEM as Memory Manager
    participant EMB as Embedding 服务
    participant STORE as 向量存储
    participant LLM as LLM

    U->>A: &#34;上次我们讨论的那个 bug 修复了吗?&#34;

    Note over A,LLM: Loop 第 1 轮:LLM 判断需要搜索记忆
    A->>LLM: messages + tools(含 memory_search)
    LLM-->>A: function_call: memory_search(query=&#34;bug 修复&#34;)

    A->>MEM: memory_search(query=&#34;bug 修复&#34;)
    MEM->>EMB: query 向量化
    EMB-->>MEM: embedding vector
    MEM->>STORE: 相似度检索
    STORE-->>MEM: top-k 相关片段
    MEM-->>A: 返回语义相关记忆

    Note over A,LLM: Loop 第 2 轮:记忆注入后继续对话
    A->>LLM: messages + 检索到的记忆片段 + 原问题
    LLM-->>A: &#34;根据之前讨论的 #42 bug,已在上周通过 PR #58 修复&#34;
    A-->>U: 最终回答

关键设计memory_search 本身也是 Tool Registry 中的一个工具!LLM 在循环中自主决定「我需要先查一下历史记忆」,然后调用它。检索结果作为上下文追加到 messages,下一轮 LLM 就能基于记忆生成回答。

7.5 OpenClaw 的 Memory Search 工具定义


八、全链路端到端:一条消息的完整旅程

以「帮我查一下 GitHub 上 openclaw 项目的最近 3 个 Issue」为例,展示完整的 Conversation Loop 流转:

flowchart LR
    U[用户提问] --> GW[Gateway]
    GW --> L1[Loop R1: 加载 github SKILL]
    L1 --> L2[Loop R2: 调用 MCP gh issue list]
    L2 --> L3[Loop R3: 格式化回答]
    L3 --> U2[返回]

代码路径对照

    1. 消息到达 → hermes_cli/tui_gateway/server.py
    2. 创建 Session + 启动 Loop → agent/conversation_loop.py::run_conversation()
    3. 构建上下文 → agent/turn_context.py + agent/memory_manager.py
    4. 调用 LLM → agent/conversation_loop.py::call_llm_with_retry()
    5. 解析 function_call → tools/registry.py::lookup()
       → Built-in: 直接执行函数
       → MCP:      tools/mcp_tool.py → 转发到 MCP Server
       → Skill:    agent/skill_utils.py → 加载 SKILL.md
    6. 追加结果 + 回到步骤 4(最多 60 轮)

九、核心速查:对比总结 + 关键洞察

9.1 Hermes vs OpenClaw

对比维度HermesOpenClaw
定位大而全的 Agent 平台(桌面 GUI + 网关 + 多平台消息)轻量 Agent 框架(命令行 + 可嵌入)
语言Python 3.11TypeScript (Node.js)
Conversation Loopagent/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 / RAGagent/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」

十、核心设计模式总结

image.png

十一、一张图看懂 Agent

image.png

核心公式

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)