第3课:工具系统与通信协议

核心机制⭐⭐⭐⭐ 高频↔ Hermes 源码对照MCPA2A

← 上一章:第2课下一章 → 第4课

一、概述:为什么工具系统是 Agent 的"手脚"

Agent 的能力边界 = 工具系统的能力边界。

LLM 知道万事万物的知识(预训练),但无法直接行动:它不能查数据库、发邮件、写硬盘、调用 API。工具系统给 LLM 装上了"手脚"。

工具系统有 3 个关键层次:

  1. Function Calling(协议层)— LLM 如何表达"我想调用一个工具"
  2. Tool Registry(实现层)— 工具如何定义、注册、分发
  3. MCP(标准化层)— 工具如何跨框架、跨语言被发现和调用

本节课从底向上拆解每一层。

二、Function Calling:LLM 的"工具语言"

2.1 核心流程(第2课 Agent Loop 里面的关键一步)

// 用户请求 User: "帮我查一下上海的天气" // Step 1: 系统把工具定义传给 LLM LLM.input = messages + [tool_definition_1, tool_definition_2, ...] // 工具定义长什么样? // 每个工具 = name + description + parameters(JSON Schema) // Step 2: LLM 输出(不是自然语言,是结构化 JSON) { "tool_calls": [{ "id": "call_abc123", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\": \"上海\"}" } }] } // Step 3: Agent 框架解析这个 JSON → 调用实际函数 result = get_weather(city="上海") // Step 4: 把结果拼回对话 messages.append({ "role": "tool", "tool_call_id": "call_abc123", "content": '{"temp": 28, "humidity": 65}' }) // Step 5: LLM 看到工具结果 → 生成自然语言回复 LLM: "上海现在 28°C,湿度 65%。"

2.2 工具定义:JSON Schema 是核心

每个工具都需要一个严格的 JSON Schema 描述,LLM 根据这个描述决定是否调用。

Hermes 中的真实例子(web_search 工具):

// 来自 /usr/local/lib/hermes-agent/tools/web_tools.py // Hermes 真实代码,我亲自从源码读来的 WEB_SEARCH_SCHEMA = { "name": "web_search", "description": "Search the web for information. Returns up to 5 results...", "parameters": { "type": "object", "properties": { "query": { "type": "string", "description": "The search query to look up on the web." }, "limit": { "type": "integer", "description": "Maximum number of results.", "minimum": 1, "maximum": 100, "default": 5 } }, "required": ["query"] } }

关键原则:

2.3 OpenAPI Specification vs JSON Schema 的区别

面试常问:"工具定义和 REST API 有什么区别?"

REST API 工具描述 ───────────────── POST /weather Headers: { "Authorization": "Bearer xxx" } Body: { "city": "string" } → 需要人理解 API 文档 → 自己编码调用 LLM Function Calling ──────────────────── { "name": "get_weather", "description": "...", "parameters": { ... } } → LLM 直接理解描述 → LLM 自己决定参数 → 框架执行

核心区别:LLM 不是通过代码调用 API,而是通过语义理解调用。工具的 name 和 description 对 LLM 的重要性,远大于对传统程序的重要性。

2.4 Hermes 的 Tool Registry 架构

从 Hermes 源码我读到的注册机制:

// 每个工具文件在模块加载时自动注册 // 例如 tools/web_tools.py 的底部: from tools.registry import registry registry.register( name="web_search", toolset="web", schema=WEB_SEARCH_SCHEMA, // ↑ 上面的 schema dict handler=handle_web_search, // 实际执行函数 check_fn=check_network, // 可用性检查 requires_env=["OPENAI_API_KEY"], ) // ToolRegistry 内部结构: class ToolEntry: name: str // 工具名 toolset: str // 属于哪个工具集(web, terminal, file...) schema: dict // JSON Schema handler: Callable // 实际处理函数 check_fn: Callable // 检查是否可用 is_async: bool // 一个 ToolRegistry 单例持有所有工具: ToolRegistry._tools: Dict[str, ToolEntry]

设计亮点:

三、MCP:工具标准的"HTTP 时刻"

MCP = Model Context Protocol(Anthropic 主导,2024年底推出)

3.1 为什么需要 MCP?

在 MCP 之前,每个 Agent 框架的工具有自己的注册方式:

它们本质上都是把 name + description + schema 告诉 LLM,但格式各不相同。每次换框架,工具就要重写一次。

MCP 要解决的问题:

MCP = 工具世界的 HTTP 协议

HTTP 之前:每个应用自己实现通信协议 → 各自为政
HTTP 之后:一套标准,万维网互联

MCP 之前:每个框架自己定义工具协议 → 生态割裂
MCP 之后:一套标准,工具一次开发到处可用

3.2 MCP 架构

┌──────────────┐ MCP Protocol ┌──────────────┐ │ │ ◄══════════════════════► │ │ │ MCP Client │ JSON-RPC 2.0 over │ MCP Server │ │ (Agent框架) │ stdio / SSE / Streamable │ (工具提供方) │ │ │ HTTP │ │ └──────────────┘ └──────────────┘ │ ▼ ┌──────────┐ │ API │ │ Database │ │ Files │ └──────────┘ // 核心操作 // 1. tools/list → Server 返回所有可用工具的定义(name + schema) // 2. tools/call → Client 调用指定工具,传参数 // 3. resources/list → Server 返回可读取的资源列表 // 4. resources/read → Client 读取资源内容 // 5. prompts/list → Server 返回预设的 prompt 模板

3.3 MCP 的 3 种传输方式

传输方式场景示例
stdio本地子进程,低延迟一个 Python 脚本作为 MCP Server,被 Hermes 启动
SSE (Server-Sent Events)远程服务,单向推送远程的文件系统 MCP 服务
Streamable HTTP远程服务,双向流企业内部的数据库 MCP 服务

3.4 Hermes 的 MCP 支持

Hermes 本身内置了 MCP Server(hermes_tools_mcp_server.py),如果你运行:

hermes mcp-serve # 启动一个 MCP 服务器,把 Hermes 的所有工具 # 以 MCP 协议暴露给其他 Agent 框架

这意味着:你可以用 Claude Desktop 连接 Hermes 的 MCP 服务器,使用 Hermes 的工具——工具一次开发,到处可用

四、A2A:Agent 之间的"HTTP 协议"

A2A = Agent-to-Agent Protocol(Google 主导,2025年4月推出)

4.1 和 MCP 的区别

🔧 MCP
Agent ↔ 工具
让 Agent 能调用外部工具

类比:USB 接口
连接设备和外设
🤝 A2A
Agent ↔ Agent
让 Agent 之间直接通信

类比:HTTP 协议
连接服务器和服务器
📞 Function Calling
LLM ↔ 框架
LLM 表达"我想调一个工具"

类比:指令集
CPU 告诉主板要做什么

4.2 A2A 核心概念

// A2A 工作流程 Agent A (编排器) Agent B (数据库Agent) │ │ │── Agent Card (描述自己能做什么) ──► │ │ │ │◄── Agent Card (返回B的能力描述) ── │ │ │ │── Task: "查公司2024年营收数据" ──► │ │ │── SELECT ... FROM finance │◄── Status: "working" (持续推送) ── │ │ │ │◄── Result: {data: [...], status: done}│

4.3 标准化的意义

MCP + A2A 合在一起,补全了 Agent 生态的通信标准:

┌─────────────────────────────────────────┐ │ 🧠 Agent System │ │ │ │ ┌──────────┐ A2A ┌──────────┐ │ │ │ Agent A │◄══════►│ Agent B │ │ │ │ (编排器) │ │ (专家) │ │ │ └────┬─────┘ └──────────┘ │ │ │ MCP │ │ ▼ │ │ ┌──────────┐ ┌──────────┐ │ │ │ MCP Svr1 │ │ MCP Svr2 │ │ │ │ (数据库) │ │ (文件系统)│ │ │ └──────────┘ └──────────┘ │ └─────────────────────────────────────────┘ MCP: Agent ↔ 工具(竖线) A2A: Agent ↔ Agent(横线)

五、对比与适用场景

复杂度 ▲ │ 自研 Function Calling │ 低复杂度,实现简单 + JSON Schema │ 适合单一框架、小规模 │ ─────────────────────────── │ MCP 标准化工具接口 │ 中复杂度,一次开发到处用 │ 适合多框架共存、工具共享 │ ─────────────────────────── │ A2A + MCP 全栈 │ 高复杂度,大规模 标准体系 │ 适合企业级多Agent系统 │ └────────────────────► 适用规模

六、面试问答

🎯 Q1:"请设计一个工具系统,Agent 怎么知道该调用哪个工具?"

框架:
1. 工具定义:每个工具用 JSON Schema 描述 name + description + parameters
2. 工具注册:集中式 Registry,按工具集分组(file/web/terminal...)
3. LLM 理解:工具定义随每次 LLM 调用一起传入,LLM 根据 description 决定调哪个
4. 参数填充:LLM 输出 JSON 格式的 arguments,框架解析并校验
5. 执行与反馈:框架执行工具,结果拼回对话供 LLM 继续推理

加分点:提到可用性检查(check_fn)、动态 schema(dynamic_schema_overrides)、工具集隔离。
🎯 Q2:"Function Calling 和 MCP 有什么区别?什么时候用哪个?"

框架:
Function Calling 是 LLM API 层的协议——定义 LLM 如何输出工具调用请求。精度低,但实现简单。
MCP 是工具层的协议——定义工具如何被发现和调用。精度高,但需要额外基础设施。

选型:
- 内部小工具(< 10 个)→ 直接 Function Calling
- 跨框架共享工具、或第三方工具 → MCP
- 完全云原生企业 → MCP + A2A
🎯 Q3:"工具调用失败了怎么办?怎么设计容错?"

5 层容错:
1. Retry:网络/临时错误 → 退避重试(exponential backoff + jitter)
2. Fallback:主工具挂了 → 切备用工具(如 web_search 切 bing_search)
3. Graceful Degradation:工具不可用 → 告诉 LLM"这个工具现在不可用"让 LLM 决定替代方案
4. Idempotency 幂等:工具支持幂等(如查询、读文件天然幂等;下单需要去重)
5. Timeout:每个工具有独立超时,超时后 LLM 决定继续等待还是放弃

七、课后行动

  1. ✅ 理解 JSON Schema 格式——这是任何 Agent 框架的基石
  2. ✅ 想一个你自己的工具需求(比如"查公司内部 Wiki"),用 JSON Schema 写出它的定义
  3. ✅ 梳理 MCP vs A2A vs Function Calling 的区别(面试高频对比题)
  4. ⏭ 下节课:记忆与上下文管理——Token 预算、滑动窗口、RAG

📁 0003-tools-protocols.html
📁 源码参考:/usr/local/lib/hermes-agent/tools/registry.py (589行)
📁 源码参考:/usr/local/lib/hermes-agent/tools/web_tools.py → WEB_SEARCH_SCHEMA 等
📝 有问题随时问。

← 上一章:第2课下一章 → 第4课