一、三代技术演进
┌─────────────────────────────────────────────────────────────────┐
│ 工具调用技术演进 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 2023 2024 2025+ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────┐ ┌────────┐ ┌────────────┐ │
│ │Function│ │ MCP │ │ Skills │ │
│ │Calling │ │Protocol│ │ 协议 │ │
│ └────────┘ └────────┘ └────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ 工具定义 标准化接口 能力封装 │
│ 手动管理 统一发现 工作流复用 │
│ │
└─────────────────────────────────────────────────────────────────┘二、原理对比表
| 维度 | Function Calling | MCP | Skills |
|---|---|---|---|
| 本质 | LLM 输出结构化 JSON | 标准化工具发现/调用协议 | 封装工作流的可复用模块 |
| 诞生时间 | 2023(OpenAI) | 2024(Anthropic) | 2025+(Hermes) |
| 核心作用 | 让 LLM 调用函数 | 统一工具接口 | 封装复杂操作流程 |
| 粒度 | 函数/工具级别 | 函数/工具级别 | 工作流/技能级别 |
| 复用性 | 低(每次重写) | 中(标准化接口) | 高(Markdown 持久化) |
| 上下文消耗 | 工具定义 | 工具定义 + MCP 协议 | 前言摘要 + 按需加载 |
三、Function Calling 原理
3.1 核心机制
┌─────────────────────────────────────────────────────────────────┐
│ Function Calling 原理 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. 定义工具 Schema │
│ tools = [{"type": "function", "function": {...}}] │
│ │
│ 2. 发送给 LLM │
│ client.chat.completions.create( │
│ messages=[...], │
│ tools=tools │
│ ) │
│ │
│ 3. LLM 决策输出 │
│ message.tool_calls = [ │
│ {"name": "get_weather", "arguments": {"city": "北京"}} │
│ ] │
│ │
│ 4. 外部执行 + 结果喂回 │
│ result = get_weather("北京") │
│ messages.append({"role": "tool", "content": result}) │
│ │
└─────────────────────────────────────────────────────────────────┘3.2 本质
Function Calling 的本质是 Token 预测的模式切换
- LLM 通过训练学会在特定情况下切换输出模式
- 从"生成自然语言" → 切换到"生成结构化 JSON"
python
# OpenAI Function Calling 示例
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的当前天气",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名称"}
},
"required": ["city"]
}
}
}
]
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "北京天气怎么样?"}],
tools=tools
)
# response.choices[0].message.tool_calls四、MCP 原理(Model Context Protocol)
4.1 核心机制
┌─────────────────────────────────────────────────────────────────┐
│ MCP 协议原理 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ MCP Client │
│ │ │
│ ├─→ list_tools() → 发现可用工具 │
│ ├─→ call_tool() → 调用工具 │
│ └─→ read_resource() → 读取资源 │
│ │
│ MCP Server(可远程部署) │
│ │ │
│ ├─→ 工具定义(JSON Schema) │
│ ├─→ 资源定义 │
│ └─→ 工具实现 │
│ │
│ 通信方式: │
│ ├─→ stdio(本地进程) │
│ └─→ streamable_http(远程服务) │
│ │
└─────────────────────────────────────────────────────────────────┘4.2 MCP vs Function Calling
| 对比项 | Function Calling | MCP |
|---|---|---|
| 工具定义 | 内嵌在请求中 | 独立 Server 发现 |
| 工具发现 | 每次请求传递 | list_tools() 动态发现 |
| 认证信息 | 手动传递 | 协议内置 |
| 多语言支持 | 需分别实现 | 统一协议 |
| 远程工具 | 需手动处理 | 原生支持 |
python
# MCP 方式
from langchain_mcp_adapters.client import MultiServerMCPClient
connections = {
"aliyun": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path"]
}
}
client = MultiServerMCPClient(connections)
tools = await client.get_tools() # 动态发现五、Skills 原理(Hermes)
5.1 核心机制
┌─────────────────────────────────────────────────────────────────┐
│ Skills 原理 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Skill = Markdown 文件(包含工作流 + 知识 + 触发条件) │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ## 前言(Summary) │ │
│ │ 一句话描述技能用途,用于快速匹配 │ │
│ ├─────────────────────────────────────────────────────────┤ │
│ │ ## 触发条件 │ │
│ │ 何时使用这个技能 │ │
│ ├─────────────────────────────────────────────────────────┤ │
│ │ ## 操作步骤 │ │
│ │ 1. 步骤一... │ │
│ │ 2. 步骤二... │ │
│ ├─────────────────────────────────────────────────────────┤ │
│ │ ## 依赖工具 │ │
│ │ - tool_a │ │
│ │ - tool_b │ │
│ ├─────────────────────────────────────────────────────────┤ │
│ │ ## 注意事项 │ │
│ │ 常见坑和最佳实践 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 渐进加载机制: │
│ 1. 加载前言(匹配阶段) │
│ 2. 按需加载完整内容(执行阶段) │
│ │
└─────────────────────────────────────────────────────────────────┘5.2 Skills vs Function Calling / MCP
| 对比项 | Function Calling | MCP | Skills |
|---|---|---|---|
| 定义方式 | JSON Schema | MCP Protocol | Markdown + YAML |
| 粒度 | 单个函数 | 单个函数 | 完整工作流 |
| 适用场景 | API 调用 | 工具发现 | 复杂任务 |
| 复用方式 | 代码复制 | 接口共享 | 安装复用 |
| 上下文消耗 | 固定开销 | 固定开销 | 前言轻量 + 按需 |
| 社区生态 | 无 | 建设中 | agentskills.io |
5.3 Skills 示例结构
yaml
# weather.skill.md
---
name: weather_query
version: 1.0.0
---
# 一句话描述(渐进加载的关键)
查询城市天气,返回温度、湿度、天气状况。
# 触发条件
当用户询问具体城市的天气时使用。
# 操作步骤
1. 调用 weather_tool 查询城市
2. 格式化输出结果
3. 提供出行建议
# 依赖工具
- weather_tool
# 注意事项
- 某些城市可能不支持
- 温度单位统一使用摄氏度六、与本项目 Tool 对比
6.1 本项目工具定义
python
# 文件: app/tools/ssh.py, 行 79-87
ssh_run_tool = StructuredTool.from_function(
coroutine=_run_on_server,
name="ssh_run",
description="在指定服务器上通过 SSH 执行 shell 命令...",
args_schema=SSHRunInput,
)6.2 对比分析
| 维度 | 本项目 Tool | Function Calling | MCP | Skills |
|---|---|---|---|---|
| 定义方式 | Python 代码 | JSON Schema | MCP Protocol | Markdown |
| 调用方式 | LangChain bind_tools | OpenAI SDK | MCP Client | Agent 自动匹配 |
| 执行位置 | 本地 | 外部执行 | 本地/远程 | 外部执行 |
| 发现机制 | 静态绑定 | 每次传递 | 动态发现 | 前言匹配 |
| 复用性 | 代码级别 | 需复制 JSON | 协议共享 | 安装即用 |
| 封装层次 | 单个函数 | 单个函数 | 单个函数 | 工作流 |
| 上下文消耗 | 工具 Schema | 工具 Schema | 工具 Schema | 前言轻量 |
七、本项目工具的本质
┌─────────────────────────────────────────────────────────────────┐
│ 本项目工具的本质 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 本项目采用 Function Calling 模式 │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 工具定义 │ │
│ │ StructuredTool → JSON Schema → 发送给 LLM │ │
│ ├─────────────────────────────────────────────────────────┤ │
│ │ 工具执行 │ │
│ │ LangGraph execute_tools_node → tool.ainvoke(args) │ │
│ ├─────────────────────────────────────────────────────────┤ │
│ │ 结果反馈 │ │
│ │ ToolMessage → messages 状态 → 继续 LLM 推理 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 与标准 Function Calling 的区别: │
│ ├─ 使用 LangChain/LangGraph 封装 │
│ ├─ 支持异步工具执行 │
│ ├─ 集成 Human-in-the-loop 审批 │
│ └─ 支持 MCP 云工具动态加载 │
│ │
└─────────────────────────────────────────────────────────────────┘八、架构对比图
┌─────────────────────────────────────────────────────────────────┐
│ Function Calling / MCP / Skills 架构对比 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 【Function Calling】 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ LLM │────▶│ Developer │────▶│ 执行环境 │ │
│ │ (决策) │ │ (定义+执行)│ │ (代码) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ tool_calls JSON Schema │
│ │
│ 【MCP】 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ LLM │────▶│MCP Client│────▶│MCP Server│ │
│ │ (决策) │ │ (路由) │ │ (实现) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ tool_calls list_tools() │
│ │
│ 【Skills】 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ LLM │────▶│ Skills │────▶│ 执行环境 │ │
│ │ (决策) │ │ Manager │ │ (多步骤) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ 前言匹配 SKILL.md │
│ │
│ 【本项目】 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ LLM │────▶│ LangGraph│────▶│ 执行环境 │ │
│ │ (决策) │ │ (编排+审批)│ │ (SSH/MCP)│ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ tool_calls StructuredTool │
│ + interrupt() │
│ │
└─────────────────────────────────────────────────────────────────┘九、总结
| 特性 | 本项目 | OpenAI FC | MCP | Hermes Skills |
|---|---|---|---|---|
| 粒度 | 单函数 | 单函数 | 单函数 | 工作流 |
| 定义格式 | Python | JSON | Protocol | Markdown |
| 发现机制 | 静态绑定 | 静态传递 | 动态发现 | 前言匹配 |
| 审批机制 | ✅ interrupt() | ❌ | ❌ | ❌ |
| 云工具 | ✅ MCP | ❌ | ✅ | ❌ |
| 复杂度 | 中 | 低 | 中 | 高 |
| 适用场景 | 运维自动化 | 简单 API | 多工具系统 | 复杂工作流 |
本项目核心优势:在 Function Calling 基础上集成了 Human-in-the-loop 审批机制,确保危险操作可控。