在 AI 时代,我们经常听到 Agent、Skills、MCP、Function Calling 等概念,但这些概念之间的关系和使用场景往往让人困惑。本文将以一个实际的使用场景为例,深入解析这些概念。
场景介绍#
环境配置:
- 平台:Ubuntu 服务器(已安装 OpenClaw 3.2)
- Agent:OpenClaw-Vango(私人 AI 助手)
- LLM:GLM-5(智谱AI,通过 API 密钥访问)
- 权限:读写文件系统、执行 Shell 命令、访问 GitHub
- 网络:畅通,可访问公网
使用场景:
- 用户与 OpenClaw-Vango 进行多轮对话,学习英语时态
- 用户让 Agent 生成一篇英语学习笔记
- Agent 自动将笔记提交到 GitHub 仓库
核心问题:
- 远端 LLM(GLM-5)、本地 OpenClaw、Skills、MCP、Function Calling 之间是什么关系?
- Agent 如何协调这些组件完成任务?
- 在实际场景中,什么时候使用 Skills、什么时候使用 MCP、什么时候使用 Function Calling?
核心概念详解#
1. Agent(智能体)#
定义:Agent 是一个完整的 AI 助手实例,包含 LLM + 记忆 + 工具 + 配置。
比喻:Agent 就像一个智能助手公司,包含 CEO(LLM)、部门、工具。
例子:
1
2
3
4
5
6
7
| Agent: OpenClaw-Vango
├── LLM: GLM-5(决策中心)
├── Memory: 对话历史、用户偏好
├── Tools: 35+ 工具(read、write、exec、browser...)
├── Skills: 英语辅导员、天气查询、文件管理
├── Config: 工作目录、权限、密钥
└── Channels: 飞书、Telegram、CLI
|
关键:
- Agent 是最外层的容器
- 包含所有其他组件
- 是用户交互的入口
2. LLM Model(大语言模型)#
定义:AI 的"大脑",负责理解、推理、决策和生成。
比喻:LLM 是 Agent 的 CEO(首席执行官)。
例子:
- GPT-4、Claude、GLM-5、Gemini
- 负责:理解用户意图、决策调用哪个工具、生成回复
关键:
- LLM 是核心决策者
- 不直接执行操作,而是决策要做什么
- 通过 Function Calling 调用工具
3. Function Calling(函数调用)#
定义:一种协议/机制,让 LLM 能调用外部工具。
比喻:Function Calling 是内部通讯系统,让 CEO 能调用各部门。
工作原理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| 1. 发送工具定义给 LLM
{
"tools": [
{
"name": "write",
"description": "写入文件到指定路径",
"parameters": {
"path": {"type": "string"},
"content": {"type": "string"}
}
}
]
}
2. LLM 决定调用工具
{
"tool_calls": [{
"function": {
"name": "write",
"arguments": "{\"path\":\"note.md\",\"content\":\"...\"}"
}
}]
}
3. 执行工具并返回结果
{
"role": "tool",
"content": "{\"status\":\"success\"}"
}
|
关键:
- Function Calling 是协议,不是具体的工具
- 定义了 LLM 和工具之间的通信标准
- 包含:工具定义、参数 schema、返回格式
4. Skills(技能)#
定义:Agent 的专业能力模块,通过代码或配置实现。
比喻:Skills 是公司的专业部门(英语部、财务部、技术部)。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 英语辅导员 Skill
name: english-learning
description: 英语学习辅导,记录表达问题,生成学习笔记
tools:
- read
- write
- web_search
prompts:
- "你是英语辅导员,帮助学生提高英语水平..."
workflow:
1. 识别英语问题
2. 解释语法规则
3. 记录到学习笔记
4. 同步到博客
|
关键:
- Skills 是内置的专业能力
- 可以包含多个工具
- 可以有特定的提示词和工作流
5. MCP(Model Context Protocol)#
定义:标准化的工具连接协议,让 AI 能使用外部工具和服务。
比喻:MCP 是外部合作标准接口,连接其他公司的服务。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| {
"mcpServers": {
"filesystem": {
"command": "mcp-filesystem",
"args": ["/home/ubuntu/workspace"]
},
"github": {
"command": "mcp-github",
"args": ["--token", "ghp_xxx"]
},
"database": {
"command": "mcp-postgres",
"args": ["postgresql://localhost/db"]
}
}
}
|
关键:
- MCP 是协议标准
- 用于连接外部服务(数据库、API、SaaS)
- 提供统一的接口规范
架构图:组件关系#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
| ┌─────────────────────────────────────────────────────┐
│ AGENT │
│ (OpenClaw-Vango) │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ LLM Model │ │
│ │ (GLM-5 - CEO) │ │
│ │ │ │
│ │ • 理解用户意图 │ │
│ │ • 推理决策 │ │
│ │ • 生成回复 │ │
│ └──────────────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Function Calling(协议) │ │
│ │ │ │
│ │ • 工具定义(schema) │ │
│ │ • 参数传递(arguments) │ │
│ │ • 结果返回(tool result) │ │
│ └──────────────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────┬──────────────────────────┐ │
│ │ Skills │ MCP Servers │ │
│ │ (内置能力) │ (外部服务协议) │ │
│ │ │ │ │
│ │ • 英语辅导 │ • filesystem │ │
│ │ • 天气查询 │ • github │ │
│ │ • 文件管理 │ • database │ │
│ │ • 代码助手 │ • web APIs │ │
│ └──────────────────┴──────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Tools(实际执行) │ │
│ │ │ │
│ │ • read/write/edit → fs 模块 │ │
│ │ • exec → child_process │ │
│ │ • web_search → Brave API │ │
│ │ • browser → Puppeteer │ │
│ └──────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────┐
│ Ubuntu 服务器 │
│ • 文件系统 │
│ • Shell │
│ • Git │
│ • 网络访问 │
└─────────────────────────┘
|
实际使用场景详解#
场景 1:英语时态学习(多轮对话)#
用户输入:
1
| "详细解释一下 of、for、with、about 的区别"
|
完整请求流程#
步骤 1:OpenClaw 构建请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| {
"model": "glm-5",
"messages": [
{
"role": "system",
"content": "你是梵高,一个英语辅导员。你的任务是帮助用户学习英语..."
},
{
"role": "user",
"content": "详细解释一下 of、for、with、about 的区别"
}
],
"tools": [
// 35+ 工具定义(但这次可能用不上)
{ "name": "read", ... },
{ "name": "write", ... },
{ "name": "exec", ... },
// ...
]
}
|
步骤 2:GLM-5 推理
1
2
3
4
5
6
7
8
| 分析用户意图:
→ 这是一个英语学习问题
→ 需要解释介词的用法
→ 可能需要记录到学习笔记
决策:
→ 不需要调用工具(纯文本回复即可)
→ 激活英语辅导员 Skill 的上下文
|
步骤 3:GLM-5 返回
1
2
3
4
5
6
7
8
9
| {
"choices": [{
"message": {
"role": "assistant",
"content": "**Of vs For vs With vs About**\n\n核心区别:\n- **Of**:属于、...的(从属关系)\n- **For**:为了、给(目的、对象)\n- **With**:和、用(伴随、工具)\n- **About**:关于、大约(主题、围绕)\n\n详细用法...",
"tool_calls": null
}
}]
}
|
关键点:
- ✅ 纯文本回复,没有调用工具
- ✅ Skills 的作用:提供上下文(英语辅导员 persona)
- ✅ Function Calling 机制存在,但未被使用
- ✅ MCP 服务器未涉及
组件使用情况:
- ✅ Agent:协调所有组件
- ✅ LLM:生成回复
- ✅ Skills:英语辅导员提供上下文
- ❌ Function Calling:未使用(不需要工具)
- ❌ MCP:未使用(不需要外部服务)
场景 2:生成学习笔记(内容生成 + 文件写入)#
用户输入:
1
| "生成一篇英语学习笔记,包含我们刚才讨论的内容,并提交到 GitHub"
|
完整请求流程#
步骤 1:OpenClaw 构建请求(包含所有对话历史)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
| {
"model": "glm-5",
"messages": [
{ "role": "system", "content": "你是梵高..." },
// 之前的多轮对话
{ "role": "user", "content": "of vs for vs with vs about" },
{ "role": "assistant", "content": "**Of vs For vs With vs About**..." },
{ "role": "user", "content": "which vs that 的区别" },
{ "role": "assistant", "content": "**Which vs That**..." },
{ "role": "user", "content": "-ing 形式的用法" },
{ "role": "assistant", "content": "**-ing Form Usage**..." },
// 当前指令
{ "role": "user", "content": "生成一篇英语学习笔记,包含我们刚才讨论的内容,并提交到 GitHub" }
],
"tools": [
{
"type": "function",
"function": {
"name": "write",
"description": "写入文件到指定路径。如果文件不存在则创建,如果存在则覆盖",
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "文件路径(相对或绝对)"
},
"content": {
"type": "string",
"description": "要写入的内容"
}
},
"required": ["path", "content"]
}
}
},
{
"type": "function",
"function": {
"name": "exec",
"description": "执行 shell 命令",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "要执行的命令"
}
},
"required": ["command"]
}
}
}
// ... 其他 33+ 工具
]
}
|
关键:
- ✅ 所有对话历史都包含在请求中
- ✅ 这就是为什么 LLM 能"记住"之前讨论的内容
- ✅ 所有工具定义都发送给 LLM(35+ 个)
步骤 2:GLM-5 推理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| 分析用户意图:
1. 生成英语学习笔记
2. 内容:包含刚才讨论的内容(of/for, which/that, -ing)
3. 提交到 GitHub
推理过程:
1. 需要生成笔记内容(基于对话历史)
2. 需要写入文件(调用 write 工具)
3. 需要提交 GitHub(调用 exec 工具)
决策顺序:
→ 先调用 write 工具(写入文件)
→ 等待写入成功
→ 再调用 exec 工具(git commit)
|
步骤 3:GLM-5 内容生成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
| 基于对话历史,GLM-5 自动生成笔记内容:
# English Learning Notes - 2026-03-06
## 1. Of vs For vs With vs About
### Of(属于、...的)
- 核心含义:从属关系、组成部分
- 例子:
- the key **of** the door(门的钥匙)
- a cup **of** coffee(一杯咖啡)
### For(为了、给)
- 核心含义:目的、对象、用途
- 例子:
- This tool is **for** encryption.(这个工具用来加密)
- I've been working here **for** two years.(持续两年)
### With(和、用)
- 核心含义:伴随、工具、方式
- 例子:
- I work **with** Alice.(我和 Alice 一起工作)
- Encrypt the data **with** AES.(用 AES 加密)
### About(关于、大约)
- 核心含义:主题、围绕
- 例子:
- a book **about** cryptography(一本关于密码学的书)
- **about** 10 minutes(大约 10 分钟)
---
## 2. Which vs That
### That(限定性从句)
- 特点:必要信息,无逗号
- 例子:
- The server **that** crashed yesterday is back online.
(昨天崩溃的那个服务器)
### Which(非限定性从句)
- 特点:额外信息,有逗号
- 例子:
- The server, **which** runs on Linux, needs updates.
(运行在 Linux 上的服务器)
**关键**:
- **that** = essential info(必要信息)
- **which** = extra info(额外信息)
---
## 3. -ing Form Usage(9 种情况)
### 1. Continuous Tenses(进行时)
- I **am working** on the migration.
### 2. After Prepositions(介词后)
- interested **in learning** Kubernetes
- good **at debugging**
### 3. After Certain Verbs(特定动词后)
- **enjoy working** with new technologies
- **avoid making** mistakes
### 4. As Noun/Gerund(作为名词)
- **Working** remotely has many benefits.
### 5. After "go"(在 go 后)
- go **shopping** / go **swimming**
### 6. After Expressions(特定表达后)
- look forward **to meeting** you
- busy **debugging** the issue
### 7. As Adjective(作为形容词)
- an **interesting** project
- a **challenging** task
### 8. Reduced Clauses(简化从句)
- The developer **working** on the API is Alice.
### 9. After "There is/are"
- There's someone **waiting** for you.
---
## Summary
- **Of vs For vs With vs About**: of = 从属,for = 目的,with = 伴随,about = 关于
- **Which vs That**: that = 必要,which = 额外
- **-ing Form**: 9 种情况,关键是介词后、特定动词后、作为名词
*Generated by OpenClaw-Vango 🎨*
|
关键:
- ✅ GLM-5 基于对话历史自动总结内容
- ✅ 内容是完整生成的(约 3.5 KB)
- ✅ 格式化为 Markdown
步骤 4:GLM-5 路径决策
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| 推理文件路径:
1. 系统提示词提到:
- 工作目录: /home/ubuntu/.openclaw/workspace
- 博客路径: /home/ubuntu/CipherHUB-Blogs/CipherHUBBlogs/content/languages/
2. 内容类型分析:
- 这是英语学习笔记
- 用户要提交到 GitHub
- 博客目录有 git 仓库
3. 路径决策:
→ /home/ubuntu/CipherHUB-Blogs/CipherHUBBlogs/content/languages/notes/english-grammar-summary.md
4. 文件名推理:
- 内容类型: 英语语法总结
- 日期: 2026-03-06
- 描述: english-grammar-summary
- 扩展名: .md
|
步骤 5:GLM-5 返回工具调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| {
"choices": [{
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_write_abc123",
"type": "function",
"function": {
"name": "write",
"arguments": "{\"path\":\"/home/ubuntu/CipherHUB-Blogs/CipherHUBBlogs/content/languages/notes/english-grammar-summary.md\",\"content\":\"# English Learning Notes - 2026-03-06\\n\\n## 1. Of vs For vs With vs About\\n\\n### Of(属于、...的)\\n...[完整内容]...\\n\\n*Generated by OpenClaw-Vango 🎨*\"}"
}
}
]
}
}]
}
|
关键:
- ✅
arguments 包含完整的笔记内容(约 3.5 KB) - ✅
path 是 GLM-5 推理得出的 - ✅ 所有换行符转义为
\n
步骤 6:OpenClaw 执行 write 工具
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| // 1. 解析工具调用
const toolCall = response.choices[0].message.tool_calls[0];
const args = JSON.parse(toolCall.function.arguments);
// args = {
// path: "/home/ubuntu/CipherHUB-Blogs/.../english-grammar-summary.md",
// content: "# English Learning Notes...\n..."
// }
// 2. 查找 write 工具的 handler
const writeTool = toolRegistry.get("write");
// 3. 执行 handler
const result = await writeTool.handler(args);
// 4. write 工具的实际实现
import fs from 'fs';
import path from 'path';
async function handler(params) {
// 确保目录存在
const dir = path.dirname(params.path);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
// 写入文件
fs.writeFileSync(params.path, params.content, 'utf-8');
return {
status: "success",
path: params.path,
size: params.content.length, // 3542 字节
lines: params.content.split('\n').length // 128 行
};
}
// 在 Ubuntu 服务器上实际执行:
// $ mkdir -p /home/ubuntu/CipherHUB-Blogs/CipherHUBBlogs/content/languages/notes
// $ cat > /home/ubuntu/CipherHUB-Blogs/.../english-grammar-summary.md
|
步骤 7:返回结果给 GLM-5
1
2
3
4
5
6
7
8
9
10
| {
"messages": [
... 之前的对话,
{
"role": "tool",
"tool_call_id": "call_write_abc123",
"content": "{\"status\":\"success\",\"path\":\"/home/ubuntu/CipherHUB-Blogs/CipherHUBBlogs/content/languages/notes/english-grammar-summary.md\",\"size\":3542,\"lines\":128}"
}
]
}
|
关键点:
- ✅ Function Calling 被使用(write 工具调用)
- ✅ Skills 提供上下文(英语辅导员,知道要记录笔记)
- ✅ MCP 未使用(write 是内置工具,不需要外部协议)
- ✅ 对话历史在每次请求中都发送(让 LLM “记住”)
组件使用情况:
- ✅ Agent:协调所有组件
- ✅ LLM:生成内容 + 决策调用工具
- ✅ Skills:英语辅导员提供上下文和工作流
- ✅ Function Calling:调用 write 工具
- ❌ MCP:未使用(write 是内置工具)
场景 3:提交 GitHub(git 操作)#
步骤 8:GLM-5 第二次推理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| 看到 write 工具执行成功:
{
status: "success",
path: "/home/ubuntu/CipherHUB-Blogs/.../english-grammar-summary.md"
}
推理下一步:
→ 用户要求提交到 GitHub
→ 记住文件路径:/home/ubuntu/.../english-grammar-summary.md
→ 需要执行 git 命令
→ 生成 commit message
决策:
→ 调用 exec 工具
→ 执行 git add + git commit + git push
|
步骤 9:GLM-5 生成 commit message
1
2
3
4
5
6
7
8
9
10
11
12
| 基于笔记内容生成 commit message:
标题:
Add English grammar summary - 2026-03-06
正文:
Summary of today's English learning:
- Of vs For vs With vs About
- Which vs That distinction
- -ing form in 9 situations
Generated by OpenClaw-Vango 🎨
|
步骤 10:GLM-5 返回 exec 工具调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| {
"choices": [{
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_exec_def456",
"type": "function",
"function": {
"name": "exec",
"arguments": "{\"command\":\"cd /home/ubuntu/CipherHUB-Blogs && git add CipherHUBBlogs/content/languages/notes/english-grammar-summary.md && git commit -m \\\"Add English grammar summary - 2026-03-06\\n\\nSummary of today's English learning:\\n- Of vs For vs With vs About\\n- Which vs That distinction\\n- -ing form in 9 situations\\n\\nGenerated by OpenClaw-Vango 🎨\\\" && git push\"}"
}
}
]
}
}]
}
|
关键:
- ✅ GLM-5 记住了文件路径
- ✅ GLM-5 生成了合适的 commit message
- ✅ commit message 包含笔记的摘要
步骤 11:OpenClaw 执行 exec 工具
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
| // 1. 解析工具调用
const execCall = response.choices[0].message.tool_calls[0];
const args = JSON.parse(execCall.function.arguments);
// args = {
// command: "cd /home/ubuntu/CipherHUB-Blogs && git add ... && git commit ... && git push"
// }
// 2. 执行 exec 工具
const execTool = toolRegistry.get("exec");
const result = await execTool.handler(args);
// 3. exec 工具的实际实现
import { exec as execSync } from 'child_process';
async function handler(params) {
return new Promise((resolve) => {
execSync(
params.command,
{
cwd: process.cwd(),
maxBuffer: 1024 * 1024 * 10
},
(error, stdout, stderr) => {
if (error) {
resolve({
error: error.message,
stdout: stdout.toString(),
stderr: stderr.toString()
});
} else {
resolve({
stdout: stdout.toString(),
stderr: stderr.toString()
});
}
}
);
});
}
// 在 Ubuntu 服务器上实际执行:
// $ cd /home/ubuntu/CipherHUB-Blogs
// $ git add CipherHUBBlogs/content/languages/notes/english-grammar-summary.md
// $ git commit -m "Add English grammar summary - 2026-03-06
//
// Summary of today's English learning:
// - Of vs For vs With vs About
// - Which vs That distinction
// - -ing form in 9 situations
//
// Generated by OpenClaw-Vango 🎨"
// $ git push
|
步骤 12:返回 git 结果
1
2
3
4
5
6
7
8
9
10
| {
"messages": [
... 之前的对话,
{
"role": "tool",
"tool_call_id": "call_exec_def456",
"content": "{\"stdout\":\"[main abc123def] Add English grammar summary\\n 1 file changed, 128 insertions(+)\\n create mode 100644 CipherHUBBlogs/content/languages/notes/english-grammar-summary.md\\nTo github.com:bowenerchen/CipherHUB-Blogs.git\\n 123abc..abc123 CipherHUBBlogs -> CipherHUBBlogs\\n\",\"stderr\":\"\"}"
}
]
}
|
步骤 13:GLM-5 生成最终回复
1
2
3
4
5
6
7
8
9
| {
"choices": [{
"message": {
"role": "assistant",
"content": "✅ **已生成英语学习笔记并提交到 GitHub!**\n\n## 📝 笔记内容\n\n总结了我们今天讨论的内容:\n- **Of vs For vs With vs About** 的用法区别\n- **Which vs That** 在从句中的使用\n- **-ing 形式** 的 9 种情况\n\n## 📂 文件信息\n\n- **路径**: `/home/ubuntu/CipherHUB-Blogs/CipherHUBBlogs/content/languages/notes/english-grammar-summary.md`\n- **大小**: 3,542 字节\n- **行数**: 128 行\n\n## 🔗 GitHub\n\n- **Commit**: abc123def\n- **仓库**: bowenerchen/CipherHUB-Blogs\n- **分支**: CipherHUBBlogs\n\n**笔记已成功推送到 GitHub!** 🎨",
"tool_calls": null
}
}]
}
|
关键点:
- ✅ Function Calling 被使用(exec 工具调用)
- ✅ Skills 未直接参与(git 操作不需要特定 skill)
- ✅ MCP 未使用(exec 是内置工具)
- ✅ LLM 协调多个工具按顺序执行
组件使用情况:
- ✅ Agent:协调所有组件
- ✅ LLM:决策 + 生成 commit message
- ❌ Skills:未直接参与(git 操作不需要特定 skill)
- ✅ Function Calling:调用 exec 工具
- ❌ MCP:未使用(exec 是内置工具)
运行机制详解#
完整请求流程图#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
| ┌─────────────────────────────────────────────────────┐
│ 1. 用户输入(Feishu) │
│ "生成英语学习笔记并提交 GitHub" │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 2. OpenClaw Gateway 接收 │
│ • 识别 channel(Feishu) │
│ • 识别 session(你的对话) │
│ • 准备构建请求 │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 3. 构建请求(包含所有组件) │
│ { │
│ model: "glm-5", │
│ messages: [ │
│ system: "你是梵高...", │
│ ... 所有对话历史 ..., │
│ user: "生成笔记并提交 GitHub" │
│ ], │
│ tools: [ ... 所有 35+ 工具定义 ... ] │
│ } │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 4. 发送 HTTPS 请求到 GLM-5 │
│ POST https://open.bigmodel.cn/api/paas/v4/... │
│ Headers: │
│ Authorization: Bearer YOUR_API_KEY │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 5. GLM-5 处理(第一次推理) │
│ • 理解用户意图 │
│ • 分析对话历史 │
│ • 决策:调用 write 工具 │
│ • 生成笔记内容(3.5 KB) │
│ • 推理文件路径 │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 6. GLM-5 返回 Function Call │
│ tool_calls: [{ │
│ function: { │
│ name: "write", │
│ arguments: "{path:..., content:...}" │
│ } │
│ }] │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 7. OpenClaw 解析和执行 write 工具 │
│ • 解析 arguments │
│ • 查找 handler │
│ • fs.writeFileSync(path, content) │
│ • 返回结果 │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 8. 返回结果给 GLM-5 │
│ role: "tool" │
│ content: "{\"status\":\"success\"}" │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 9. GLM-5 处理(第二次推理) │
│ • 看到写入成功 │
│ • 记住文件路径 │
│ • 决策:调用 exec 工具 │
│ • 生成 commit message │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 10. GLM-5 返回 Function Call │
│ tool_calls: [{ │
│ function: { │
│ name: "exec", │
│ arguments: "{command:...}" │
│ } │
│ }] │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 11. OpenClaw 执行 exec 工具 │
│ • 解析 arguments │
│ • child_process.exec(command) │
│ • git add + git commit + git push │
│ • 返回结果 │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 12. 返回结果给 GLM-5 │
│ role: "tool" │
│ content: "{\"stdout\":\"[main abc123]...\"}" │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 13. GLM-5 生成最终回复 │
│ content: "✅ 已生成笔记并提交到 GitHub..." │
│ tool_calls: null │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 14. OpenClaw 发送回复到 Feishu │
│ • 通过飞书 API 发送消息 │
│ • 用户看到最终回复 │
└─────────────────────────────────────────────────────┘
|
工具调用机制详解#
1. 工具定义(Schema)#
每次请求都会发送所有工具的定义给 LLM:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| {
"tools": [
{
"type": "function",
"function": {
"name": "write",
"description": "写入文件到指定路径。如果文件不存在则创建,如果存在则覆盖",
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "文件路径(相对或绝对)"
},
"content": {
"type": "string",
"description": "要写入的内容"
}
},
"required": ["path", "content"]
}
}
},
{
"type": "function",
"function": {
"name": "exec",
"description": "执行 shell 命令",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "要执行的命令"
}
},
"required": ["command"]
}
}
}
// ... 其他 33+ 工具
]
}
|
关键:
- ✅ 每次请求都包含所有工具(35+ 个)
- ✅ 工具定义包含:name、description、parameters schema
- ✅ 不包含实现代码(LLM 只知道"能做什么",不知道"怎么做")
2. LLM 决策#
LLM 通过 description 理解工具用途:
1
2
3
4
5
6
7
8
9
| 用户说:"生成笔记"
LLM 看到工具列表:
- read: "读取文件内容" ❌ 不匹配
- write: "写入文件到指定路径" ✅ 匹配!
- exec: "执行 shell 命令" ⚠️ 也可以用,但不是最直接
决策:
→ 调用 write 工具
|
3. 参数生成#
LLM 根据参数 schema 生成实际参数:
1
2
3
4
5
6
7
8
9
10
11
| write 工具的参数要求:
{
"path": string, // 文件路径
"content": string // 文件内容
}
LLM 生成:
{
"path": "/home/ubuntu/.../english-grammar-summary.md",
"content": "# English Learning Notes...\n..."
}
|
4. 执行和返回#
OpenClaw 执行工具并返回结果:
1
2
3
4
5
6
7
8
9
| // 执行
const result = await tool.handler(params);
// 返回给 LLM
{
role: "tool",
tool_call_id: "call_write_abc123",
content: JSON.stringify(result)
}
|
上下文传递机制#
关键:每次请求都包含所有对话历史!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| {
"messages": [
// 第 1 轮
{ "role": "user", "content": "of vs for" },
{ "role": "assistant", "content": "..." },
// 第 2 轮
{ "role": "user", "content": "which vs that" },
{ "role": "assistant", "content": "..." },
// 第 3 轮
{ "role": "user", "content": "-ing form" },
{ "role": "assistant", "content": "..." },
// 工具调用(也算一轮)
{ "role": "assistant", "tool_calls": [...] },
{ "role": "tool", "content": "..." },
// 当前(第 N 轮)
{ "role": "user", "content": "生成笔记" }
]
}
|
关键:
- ✅ 对话历史是累加的
- ✅ 工具调用也算一轮对话
- ✅ 每次请求发送完整历史
- ✅ 对话越长 → token 消耗越多
Skills vs MCP vs Function Calling 的使用时机#
对比表#
| 组件 | 层级 | 作用 | 使用时机 | 例子 |
|---|
| Skills | Agent 级别 | 提供专业能力 | 需要特定领域知识或工作流 | 英语辅导员、天气查询、文件管理 |
| MCP | 协议级别 | 标准化工具接口 | 需要连接外部服务 | 数据库、GitHub API、外部 SaaS |
| Function Calling | 机制级别 | 调用工具的协议 | 需要执行任何工具 | read、write、exec、browser |
使用时机详解#
1. 什么时候使用 Skills?#
场景特征:
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # 英语辅导员 Skill
触发条件:
• 用户问英语问题
• 需要记录学习笔记
• 需要纠错和建议
工作流:
1. 识别英语问题
2. 解释语法规则
3. 记录到学习笔记(自动调用 write 工具)
4. 同步到博客(自动调用 git 工具)
提供的价值:
• 专业的英语知识
• 自动记录学习进度
• 个性化建议
|
使用场景:
- ✅ 英语学习(英语辅导员 Skill)
- ✅ 天气查询(天气 Skill - 知道调用哪个 API)
- ✅ 代码助手(代码 Skill - 知道如何格式化、测试)
不使用 Skills:
- ❌ 简单的文件操作(不需要特定领域知识)
- ❌ 通用的对话(纯文本回复即可)
2. 什么时候使用 MCP?#
场景特征:
例子:
1
2
3
4
5
6
7
8
9
10
11
12
| {
"mcpServers": {
"github": {
"command": "mcp-github",
"args": ["--token", "ghp_xxx"]
},
"database": {
"command": "mcp-postgres",
"args": ["postgresql://localhost/db"]
}
}
}
|
MCP 提供的工具:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| {
"tools": [
{
"name": "github_create_issue",
"description": "创建 GitHub Issue",
"parameters": { ... }
},
{
"name": "github_list_prs",
"description": "列出 Pull Requests",
"parameters": { ... }
},
{
"name": "db_query",
"description": "执行 SQL 查询",
"parameters": { ... }
}
]
}
|
使用场景:
- ✅ 连接数据库(查询数据)
- ✅ 连接 GitHub(创建 Issue、PR)
- ✅ 连接 Slack(发送消息)
- ✅ 连接外部 API(调用 SaaS 服务)
不使用 MCP:
- ❌ 内置工具(read、write、exec 不需要 MCP)
- ❌ 本地操作(文件系统、Shell 命令)
3. 什么时候使用 Function Calling?#
场景特征:
Function Calling 的作用:
- ✅ 协议:定义 LLM 和工具之间的通信标准
- ✅ 机制:让 LLM 能调用所有工具(Skills 的工具、MCP 的工具、内置工具)
例子:
1
2
3
4
5
6
7
8
9
10
| 所有工具都通过 Function Calling 调用:
1. 内置工具(write、exec):
→ 通过 Function Calling 协议调用
2. Skills 提供的工具:
→ 通过 Function Calling 协议调用
3. MCP 提供的工具:
→ 通过 Function Calling 协议调用
|
关键:
- Function Calling 是底层机制
- 所有工具都通过 Function Calling 调用
- Function Calling 不区分工具的来源(内置、Skills、MCP)
实际场景的组件使用#
场景 1:英语时态学习(纯对话)#
1
2
3
4
5
6
7
8
9
10
11
12
| 用户:"of vs for 的区别"
组件使用:
✅ Agent(协调)
✅ LLM(生成回复)
✅ Skills(英语辅导员提供上下文)
❌ Function Calling(不需要工具)
❌ MCP(不需要外部服务)
原因:
→ 纯文本回复
→ 不需要执行操作
|
场景 2:生成笔记(内容生成 + 文件写入)#
1
2
3
4
5
6
7
8
9
10
11
12
13
| 用户:"生成英语学习笔记"
组件使用:
✅ Agent(协调)
✅ LLM(生成内容 + 决策调用工具)
✅ Skills(英语辅导员 - 知道要记录笔记)
✅ Function Calling(调用 write 工具)
❌ MCP(write 是内置工具,不需要 MCP)
原因:
→ 需要写入文件(调用工具)
→ Skills 提供上下文(知道要记录笔记)
→ write 是内置工具,不需要 MCP
|
场景 3:提交 GitHub(git 操作)#
1
2
3
4
5
6
7
8
9
10
11
12
13
| 用户:"提交到 GitHub"
组件使用:
✅ Agent(协调)
✅ LLM(决策 + 生成 commit message)
❌ Skills(git 操作不需要特定 skill)
✅ Function Calling(调用 exec 工具)
❌ MCP(exec 是内置工具,不需要 MCP)
原因:
→ 需要执行命令(调用工具)
→ git 操作不需要特定领域知识
→ exec 是内置工具,不需要 MCP
|
场景 4:查询数据库(假设)#
1
2
3
4
5
6
7
8
9
10
11
12
13
| 用户:"查询所有英语学习笔记"
组件使用:
✅ Agent(协调)
✅ LLM(决策)
❌ Skills(不需要特定 skill)
✅ Function Calling(调用 MCP 提供的 db_query 工具)
✅ MCP(连接数据库)
原因:
→ 需要连接外部数据库
→ 需要标准化接口(MCP)
→ 通过 Function Calling 调用 MCP 提供的工具
|
核心关系#
1
2
3
4
5
6
7
8
| Agent(容器)
└── LLM Model(大脑)
└── Function Calling(调用机制)
├── Skills(内置专业能力)
│ └── 提供工具(通过 Function Calling)
│
└── MCP(外部工具协议)
└── 提供工具(通过 Function Calling)
|
关键要点#
- Agent 是最外层容器,包含所有组件
- LLM 是核心决策者,负责理解和决策
- Function Calling 是底层机制,所有工具都通过它调用
- Skills 提供专业能力和上下文增强
- MCP 提供标准化接口连接外部服务
使用建议#
- 需要专业领域知识 → 使用 Skills
- 需要连接外部服务 → 使用 MCP
- 需要执行任何工具 → 通过 Function Calling
- 简单对话 → 纯 LLM 生成
这就是从多轮对话到自动化工作流的完整技术实现! 🎨
通过这个实际场景,我们看到了 OpenClaw Agent 如何协调 LLM、Skills、MCP 和 Function Calling,将用户的自然语言指令转化为实际的自动化操作。