一篇面向工程师的技术深度文章,带你从底层机制到上层抽象,彻底搞懂 AI Agent 的工具调用体系。


目录

  1. 为什么需要"工具调用"?
  2. Function Calling:大模型的手与脚
  3. MCP(Model Context Protocol):标准化的工具协议层
  4. Skills:可复用的能力包
  5. Plugins:Skills 的发布与分发
  6. 三层架构全景图
  7. 实战:从零构建一个 Skill
  8. 总结

1. 为什么需要"工具调用"?

大语言模型(LLM)本质上是一个文本预测器——给它一段上文,它预测下文。这让它在对话、写作、推理等方面表现出色,但也带来了三个根本性的局限:

局限表现
知识截止训练数据有固定的时间窗口,无法感知训练后发生的事件
无状态每次推理都是"无记忆"的,无法访问实时数据或外部系统
纯文本只能产出文本,无法真正执行操作:读文件、调 API、操作浏览器

解决这些问题的思路非常直接:让模型能够"调用工具"

这就是 Function Calling、MCP、Skills 三条技术线共同指向的目标。它们分别在不同的抽象层级上解决同一个问题——如何让 LLM 安全、高效、可扩展地与外部世界交互


2. Function Calling:大模型的手与脚

2.1 核心机制

Function Calling 是 LLM 与外部工具交互的底层原语。它的工作方式出奇的简单:

用户输入 + 工具定义列表 → LLM → "我要调用这个工具,参数是……" → 执行工具 → 结果返回 LLM → 最终回答

具体来说,整个流程分为以下步骤:

  1. 定义工具 Schema:用 JSON Schema 描述每个函数的名称、用途、参数类型
  2. 注入上下文:将工具定义连同用户消息一起发送给模型
  3. 模型决策:模型返回的不是工具执行结果,而是一个"调用意图"——包含函数名和参数
  4. 宿主执行:由宿主程序(而非模型)真正执行这个函数
  5. 结果回传:将执行结果作为新的上下文再次发送给模型
  6. 模型生成:模型综合所有信息,生成最终回复

2.2 一个最小示例

以 OpenAI 的 API 为例,定义一个天气查询工具:

{
  "name": "get_weather",
  "description": "获取指定城市的当前天气",
  "parameters": {
    "type": "object",
    "properties": {
      "city": {
        "type": "string",
        "description": "城市名称,如 'Beijing'"
      },
      "unit": {
        "type": "string",
        "enum": ["celsius", "fahrenheit"],
        "description": "温度单位"
      }
    },
    "required": ["city"]
  }
}

当用户问"北京现在多少度?",模型会返回:

{
  "role": "assistant",
  "tool_calls": [{
    "id": "call_abc123",
    "type": "function",
    "function": {
      "name": "get_weather",
      "arguments": "{\"city\": \"Beijing\", \"unit\": \"celsius\"}"
    }
  }]
}

注意关键点:模型不执行函数,它只是表达了"我想调用这个函数"的意图。真正调用 API 获取天气数据的是你的代码。

2.3 Function Calling 的设计哲学

理解这几个设计原则,你就能理解 Function Calling 的设计哲学:

  • 模型只管决策,不管执行——这保证了安全性:模型不可能意外删除你的文件
  • Schema 即契约——工具定义是模型与宿主之间的接口契约,双方通过 JSON Schema 对齐预期
  • 多轮对话原生支持——每次工具调用都是一轮独立的对话,结果回传后模型可以决定继续调用或给出最终答案
  • 并行调用——模型可以一次性返回多个 tool_calls,宿主可以并行执行后统一回传

2.4 主流模型的 Function Calling 实现

厂商机制名称特点
OpenAITools / Function Calling最早的标准化实现,支持并行调用、strict mode
AnthropicTool Use类似的 JSON Schema 定义方式,强调安全边界
Google GeminiFunction Calling与 OpenAI 接口高度兼容
开源模型通过 system prompt + 输出解析实现依赖 prompt engineering,稳定性不如商业方案

3. MCP(Model Context Protocol):标准化的工具协议层

3.1 Function Calling 的痛点

Function Calling 解决了"能调用"的问题,但没有解决以下问题:

  • 每个 AI 应用都要重复定义工具——如果你有三个不同的 AI 客户端,同一个"查天气"工具可能要写三遍
  • 工具实现与 AI 应用强耦合——工具的代码和 AI 应用的代码混在一起,难以独立迭代
  • 没有标准化的发现机制——模型不知道有哪些工具可用,需要开发者手动注入
  • 没有统一的传输层——工具通过 stdin/stdout、HTTP、WebSocket 还是其他方式通信?各自为政

MCP(Model Context Protocol)正是为了解决这些问题而生的。

3.2 MCP 是什么

MCP 是由 Anthropic 提出的开放协议,定义了 AI 模型与外部工具/数据源之间的标准化通信方式。它的核心思想可以概括为:用统一的协议,让任何 AI 客户端都能连接到任何工具服务器

MCP 架构包含三个角色:

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│  MCP Host    │ ←→  │ MCP Client   │ ←→  │  MCP Server  │
│ (AI 应用)    │     │ (协议客户端)  │     │ (工具服务器)  │
└──────────────┘     └──────────────┘     └──────────────┘
  • MCP Host:AI 应用本身(如 Codex、Claude Desktop)
  • MCP Client:与 Server 建立一对一连接的协议客户端
  • MCP Server:暴露特定能力的轻量服务,提供 Tools、Resources、Prompts 三类能力

3.3 MCP Server 的三种能力

每个 MCP Server 可以暴露三类能力:

Tools(工具)

模型可控的、可执行的操作。类似于 Function Calling 中的函数定义,但通过标准化协议暴露:

{
  "name": "read_file",
  "description": "读取文件内容",
  "inputSchema": {
    "type": "object",
    "properties": {
      "path": { "type": "string" }
    }
  }
}
Resources(资源)

模型可读取的上下文数据——数据库 Schema、API 文档、系统配置等。Resources 允许 Server 向模型主动暴露信息,而不需要模型先猜测有什么可用:

Resource URI: mcp://my-server/docs/api-reference
Resource URI: mcp://my-server/schemas/user-table
Prompts(提示模板)

预定义的、可复用的 prompt 模板,帮助用户快速开始特定任务。

3.4 MCP 的传输层

MCP 支持两种传输方式:

传输方式描述适用场景
stdio通过标准输入输出通信,Server 作为子进程运行本地工具、CLI 工具
HTTP + SSE通过 HTTP 请求和 Server-Sent Events 通信远程服务、云端工具

一个典型的 MCP Server 配置示例(.mcp.json):

{
  "mcpServers": {
    "cloudflare-api": {
      "type": "http",
      "url": "https://mcp.cloudflare.com/mcp"
    }
  }
}

3.5 MCP 与 Function Calling 的关系

维度Function CallingMCP
定位LLM 调用工具的机制工具服务的标准化协议
抽象层级API 级别架构级别
解决什么问题“模型如何表达调用意图”“工具如何被发现、连接和管理”
关系MCP 暴露的工具最终通过 Function Calling 被模型调用Function Calling 是 MCP 工具被调用的底层机制

简单来说:MCP 定义了工具"是什么"和"怎么连",Function Calling 定义了模型"怎么用"这些工具


4. Skills:可复用的能力包

4.1 从工具到技能——为什么需要 Skills?

MCP 解决了工具的标准化连接问题,但仍然留下了一个空白:领域知识和复杂工作流如何被复用?

举个例子:你需要让 AI 帮你处理一个复杂的 Word 文档——包含追踪修订、批注、格式保留。这不仅仅是一个"调用 docx 库"的工具调用,而是一个包含多个步骤、多种判断、大量领域知识的工作流

这就是 Skills 解决的问题:将领域知识、工作流指引、可执行脚本和资源打包成一个可复用的能力单元

4.2 Skill 的解剖结构

一个 Skill 是一个包含 SKILL.md 文件的自包含目录:

imagegen/                          # Skill 名称
├── SKILL.md                       # 核心:触发条件 + 工作流指引
│   ├── YAML frontmatter           # name + description(触发机制)
│   └── Markdown body              # 使用指引(触发后才加载)
├── agents/                        # UI 元数据(推荐)
│   └── openai.yaml                # 展示名称、描述、默认 prompt
├── scripts/                       # 可执行脚本(可选)
│   └── generate_image.py
├── references/                    # 参考文档(可选)
│   └── api_docs.md
└── assets/                        # 模板、图标等输出资源(可选)
    └── logo.png

4.3 渐进式加载:Skills 的上下文管理哲学

Skills 最精妙的设计在于三级渐进式加载机制:

第 1 级:元数据(name + description)
  ↓ 始终在上下文,约 100 词,决定是否触发

第 2 级:SKILL.md 正文
  ↓ 仅在 Skill 触发后加载,< 5000 词

第 3 级:捆綁资源(scripts/ references/ assets/)
  ↓ 按需加载,无上限

这种设计解决了 AI Agent 面临的一个核心矛盾:上下文窗口是公共资源,但我们又需要给模型足够的领域知识。通过渐进式加载,Skills 保持了下文窗口的"轻盈",同时在需要时提供深度支持。

4.4 SKILL.md 的触发机制

一个 Skill 的 SKILL.md 包含两部分的 YAML frontmatter:

---
name: imagegen
description: >
  Generate or edit raster images when the task benefits from AI-created
  bitmap visuals such as photos, illustrations, textures, sprites, mockups,
  or transparent-background cutouts. Use when Codex should create a brand-new
  image, transform an existing image, or derive visual variants from references.
---
  • name:Skill 的唯一标识
  • description:触发条件——这是 Codex 判断"什么时候该用这个 Skill"的核心依据

关键洞察:description 写得好不好,直接决定了 Skill 是否能在恰当的时机被触发。它需要同时包含"这个 Skill 做什么"和"什么时候用它"。

4.5 Skill vs Function Calling vs MCP

维度Function CallingMCPSkills
抽象层级API 原语通信协议能力包
核心价值让模型调用外部函数标准化工具连接复用领域知识和工作流
包含什么JSON Schema 定义工具、资源、提示模板指引文档、脚本、资源、资产
如何触发模型自主决策Host 发现并连接元数据匹配触发
可分发需随代码打包Server 独立部署目录即包,可 Git 分发

5. Plugins:Skills 的发布与分发

5.1 Plugin 是什么

Plugin 是 Skills 的容器和分发单元。如果说 Skill 是"功能模块",Plugin 就是"安装包"。一个 Plugin 可以包含:

my-plugin/
├── .codex-plugin/
│   └── plugin.json          # 插件元数据
├── skills/                   # 包含的 Skills
│   └── my-skill/
│       └── SKILL.md
├── .mcp.json                 # 包含的 MCP Server 配置
├── .app.json                 # 包含的应用配置
├── scripts/                  # 插件级脚本
├── hooks/                    # 生命周期钩子
└── assets/                   # 插件级资源

5.2 Plugin 的 marketplace 机制

Plugin 通过 marketplace 文件进行分发管理:

{
  "name": "personal",
  "interface": { "displayName": "Personal" },
  "plugins": [
    {
      "name": "my-plugin",
      "source": {
        "source": "local",
        "path": "./plugins/my-plugin"
      },
      "policy": {
        "installation": "AVAILABLE",
        "authentication": "ON_INSTALL"
      },
      "category": "Productivity"
    }
  ]
}
  • installation: "AVAILABLE" — 用户可选安装
  • installation: "INSTALLED_BY_DEFAULT" — 默认预装
  • authentication: "ON_INSTALL" — 安装时授权
  • authentication: "ON_USE" — 使用时授权

6. 三层架构全景图

将 Function Calling、MCP 和 Skills 放在一起看,它们构成了 AI Agent 工具调用体系的三个层次:

┌─────────────────────────────────────────────────────┐
│                    Skills / Plugins                  │  ← 能力包层
│         (可复用的领域知识、工作流、资源打包)          │     "做什么"
├─────────────────────────────────────────────────────┤
│              MCP(Model Context Protocol)           │  ← 协议层
│         (标准化的工具发现、连接、通信协议)            │     "怎么连"
├─────────────────────────────────────────────────────┤
│                Function Calling / Tool Use            │  ← 机制层
│             (LLM 调用外部工具的底层原语)              │     "怎么调"
└─────────────────────────────────────────────────────┘

一个完整的调用链路长这样:

用户请求
  →
Skill 触发(元数据匹配)→ 加载 SKILL.md 指引
  →
MCP Server 发现工具 → 建立连接
  →
Function Calling 生成调用意图 → 宿主执行 → 结果回传
  →
模型综合 Skill 指引 + 工具结果 → 生成最终回复

7. 实战:从零构建一个 Skill

让我们通过一个完整示例,理解如何创建一个 Skill。

7.1 场景定义

假设我们要创建一个 code-reviewer Skill:当用户请求代码审查时,它提供结构化的审查流程和 Checklist 指引。

7.2 初始化 Skill

使用 skill-creator 的初始化脚本:

python3 scripts/init_skill.py code-reviewer \
  --path ~/.codex/skills \
  --resources scripts,references

这会生成:

~/.codex/skills/code-reviewer/
├── SKILL.md
├── agents/
│   └── openai.yaml
├── scripts/
└── references/

7.3 编写 SKILL.md

---
name: code-reviewer
description: >
  Structured code review workflow for pull requests and code changes.
  Use when the user asks for a code review, PR review, or requests
  feedback on code changes with phrases like "review this", "code
  review", "check my code", or "look over this PR".
---

# Code Reviewer

## Review Process

Follow this structured review process for every code review:

1. **Understand the change** — Read the diff or changed files completely
   before forming opinions. Identify the primary goal of the change.

2. **Architecture & Design** — Evaluate whether the change fits the
   existing architecture. Flag unnecessary abstractions, tight coupling,
   or design decisions that work against the codebase's patterns.

3. **Correctness** — Look for off-by-one errors, null/undefined handling,
   race conditions, and edge cases.

4. **Security** — Check for injection risks, exposed secrets, missing
   auth checks, and unsafe deserialization.

5. **Performance** — Flag N+1 queries, unnecessary allocations, blocking
   operations in async contexts, and large memory footprints.

6. **Test Coverage** — Assess whether tests cover the changed behavior,
   edge cases, and regression risks.

7. **Maintainability** — Evaluate naming, comments, function length,
   and whether the code is self-explanatory.

## Output Format

Present findings ordered by severity (P0 → P3):

- **P0 (Blocker)**: Must fix before merge — security, data loss, crashes
- **P1 (High)**: Should fix — bugs, incorrect behavior
- **P2 (Medium)**: Nice to fix — code quality, minor performance
- **P3 (Low)**: Optional — style nits, alternative approaches

Use inline code comments (::code-comment{...}) when referencing specific
lines. End with a summary and risk assessment.

7.4 验证 Skill

python3 scripts/quick_validate.py ~/.codex/skills/code-reviewer

7.5 触发与使用

创建完成后,当用户说"review this PR"或"帮我审查这段代码"时,Codex 会:

  1. 在 Skill 列表中匹配 code-reviewer 的 description
  2. 加载 SKILL.md 正文获取审查流程
  3. 按照 Skill 指引执行结构化的代码审查

7.6 进阶:Skill 的复杂场景

多领域组织

当 Skill 涉及多个领域时,使用 references 按领域拆分:

bigquery-skill/
├── SKILL.md                     # 概览和各领域导航
└── references/
    ├── finance.md               # 财务相关表结构和查询
    ├── sales.md                 # 销售管道和机会数据
    └── product.md               # 产品使用和功能数据

SKILL.md 中只需要写:

## Domain-specific schemas

- **Finance metrics**: See [finance.md](references/finance.md)
- **Sales pipeline**: See [sales.md](references/sales.md)
- **Product analytics**: See [product.md](references/product.md)

这样,当用户问财务问题时,只有 finance.md 被加载到上下文。

可执行脚本

当 Skill 需要重复执行确定性的操作时,放入 scripts/

# scripts/analyze_complexity.py
"""分析代码复杂度并生成报告"""
import ast
import sys
from pathlib import Path

def analyze_file(filepath: str) -> dict:
    with open(filepath) as f:
        tree = ast.parse(f.read())
    # ... 复杂度分析逻辑 ...
    return report

脚本可以被直接执行(无需加载到上下文),极大节省 token。


8. 总结

概念一句话概括解决的核心问题
Function CallingLLM 调用外部工具的 API 原语模型如何表达"我要用工具"
MCP工具服务的标准化通信协议工具如何被发现、连接和复用
Skills领域知识+工作流的可复用能力包复杂任务的知识和流程如何传承
PluginsSkills 的容器和分发单元能力如何打包、发布和安装

三者的关系不是替代,而是逐层递进:Function Calling 提供了"调用的能力";MCP 在这个基础上添加了"标准化的连接";Skills 再往上封装了"可复用的知识"。理解这一体系,你就能更有针对性地设计 AI Agent 的工具策略:遇到新任务时,先问自己——这个问题更适合用 Function Calling 硬编码、用 MCP 暴露服务、还是封装成一个可复用的 Skill?

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐