04 Tool Calling 与 MCP
学习目标:能把数据库、文件、搜索、浏览器、企业 API 封装成 Agent 可调用工具;能说清楚 MCP 与 A2A 的边界;能让 Agent 安全地操作浏览器/GUI。 重点度:必会(12 分) 前置要求:Ch2 LLM 应用基础(Function Calling)、Ch3 Context 工程
概述#
Agent 不能只回答,还要能调用工具、查询系统、写入数据、触发流程,甚至直接操作浏览器和桌面 GUI。
这一章把 Agent 从"会聊天"变成"能动手"。但能动手 = 能闯祸——所以工具权限、错误处理、安全边界与工具能力本身同等重要。
Part 1:Tool Calling 基础#
Tool Schema 与 Tool Selection#
Tool Schema 三要素#
{
"name": "search_jira", # 1. 名字 - 动词+对象, 避免歧义
"description": "搜索 Jira 工单。仅搜工单标题和描述,不搜评论。", # 2. 描述 - 边界要说清
"parameters": { # 3. 参数 schema
"type": "object",
"properties": {
"query": {"type": "string", "description": "搜索关键词"},
"status": {"type": "string", "enum": ["open", "closed", "all"]}
},
"required": ["query"]
}
}实战要点:
- description 是给模型看的:必须明确"做什么"和"不做什么",模糊的 description 是 Agent 选错工具的根因
- 用 enum 约束取值:不要让模型自由发挥
status字段 - required 字段必须明确:可选参数要标注清楚
- 工具数量上限:单次请求 20-30 个工具是模型决策准确率的上限,超过要 router 分流
Tool Selection(工具选择)#
模型如何在 N 个工具里选对?靠的就是 description 的语义匹配。但工具一多,重叠就多:
Bad:
search_jira: "搜索 Jira"
search_confluence: "搜索 Confluence"
search_wiki: "搜索 Wiki"
→ 模型分不清 "搜项目文档" 该用哪个
Good:
search_jira: "搜索 Jira 工单,用于查找任务/bug/需求追踪"
search_confluence: "搜索 Confluence 文档,用于查找团队协作文档"
search_wiki: "搜索 Wiki,用于查找技术规范/产品文档"工具多了之后,要做 Router:
用户请求
↓
Router Agent (轻量模型): 判断属于哪个工具域 → 选 5 个候选工具
↓
Main Agent: 在 5 个候选里决策调用参数校验与错误处理#
参数校验#
模型填的参数不能信任,必须 preflight 校验:
def call_tool(tool_name, args):
# 1. Schema 校验
validate(args, tool_schemas[tool_name])
# 2. 业务校验
if tool_name == "delete_user":
if args["user_id"] == current_user.id:
raise ToolError("不能删除自己")
if not user_has_permission("delete_user"):
raise PermissionError("无权限")
# 3. 范围/枚举校验
if "limit" in args and args["limit"] > 1000:
raise ToolError("limit 不能超过 1000")工具错误处理#
工具执行失败时,错误信息怎么回灌给模型很关键:
Bad:
Tool returns: "Error"
→ 模型不知道为什么错, 可能反复重试同一调用
Good:
Tool returns: "Error: 数据库连接超时 (timeout=5s), 请稍后重试或换用 search_web 工具"
→ 模型知道是临时错误, 会改策略错误回灌原则:
- 可读:错误信息要让模型能理解
- 可恢复:告诉模型"该怎么办"(重试/换工具/问用户)
- 不带堆栈:技术堆栈给模型没用,反而占 token
- 区分错误类型:临时错误(网络)→ 重试;业务错误(无权限)→ 不要重试
工具权限#
工具调用必须做权限控制,不能"模型想调就调":
- 白名单:每个 Agent 会话只能用预设的工具集
- 审批门禁:高风险工具(删除/转账/部署)必须人工审批(见 Ch5 Permission Mode、Ch10 安全护栏)
- 凭证最小化:工具拿到的凭证权限要 ≤ 任务所需权限(防 Confused Deputy,见 Ch10)
Part 2:MCP(Model Context Protocol)#
MCP 解决什么问题#
前 MCP 时代#
每个 Agent 平台都自己定义工具接口:
OpenAI Function Calling: 自己的 schema 格式
Anthropic Tool Use: 自己的 schema 格式
LangChain Tools: 自己的 schema 格式
Dify Tools: 自己的 schema 格式
→ 同一个工具 (如查询天气) 要为每个平台写一遍适配
→ 工具生态被平台割裂MCP 的目标#
MCP(Anthropic 2024 提出,2026 已成事实标准)解决的就是工具标准化:
- 工具开发者:写一次 MCP Server,所有支持 MCP 的 Agent 都能用
- Agent 开发者:直接接入任何 MCP Server,不用为每个工具写适配
- 协议层:统一了 Client / Server 通信、工具发现、调用、资源暴露
类比:MCP 之于 Agent 工具 = USB 之于硬件外设 = LSP 之于编辑器语言服务。
MCP 架构#
┌──────────────┐ ┌──────────────┐
│ MCP Client │ ◄────► │ MCP Server │
│ (Agent 侧) │ JSON │ (工具侧) │
│ │ RPC │ │
│ - 发起调用 │ │ - 实现 tools │
│ - 接收结果 │ │ - 暴露 resources │
│ │ │ - 暴露 prompts│
└──────────────┘ └──────────────┘
│ │
│ ├── 工具: search_web, query_db...
│ ├── 资源: file://doc.md, db://schema
│ └── 提示: code_review_template
│
└── 可同时连多个 MCP ServerTransport(传输层)#
MCP 官方只定义两种标准 transport:stdio(本地)与 Streamable HTTP(远程)。早期的 HTTP+SSE 已在 2025-03 规范中被 Streamable HTTP 取代(仅保留向后兼容);WebSocket 至今不在官方规范内。
| Transport | 适用场景 | 特点 |
|---|---|---|
| stdio | 本地工具、CLI Agent | 走 stdin/stdout 的进程间通信,最快 |
| Streamable HTTP | 远程工具、Web Agent | 2025-03 起的标准远程传输:单 HTTP 端点 + 可选 SSE 流式,可跨网 |
| 旧版远程传输 | 2024-11 老方案,2025-03 起被 Streamable HTTP 取代,仅向后兼容 |
MCP 三大组件:Resources / Prompts / Tools#
Resources(资源)#
MCP Server 暴露的只读数据源:
Resources:
file:///project/README.md ← 文件内容
db://schema/users ← 数据库 schema
git://repo/HEAD ← 仓库当前状态Agent 可以枚举、读取这些资源,但不能修改。
Prompts(提示模板)#
MCP Server 暴露的预定义提示模板:
Prompts:
code_review: 给定代码,生成 code review 报告
sql_optimize: 给定 SQL,生成优化建议让工具携带"使用建议",避免 Agent 用错。
Tools(工具)#
MCP Server 暴露的可执行函数:
Tools:
search_web(query: str, max_results: int)
query_db(sql: str, db: str)
send_email(to: str, subject: str, body: str)工具是 MCP 最常用的部分。
补充(面试常考"MCP 原语有哪些"):Resources / Prompts / Tools 是 Server 端三大原语;MCP 还定义了 Client 端原语——Roots(客户端向 server 暴露可访问的文件根)、Sampling(server 反向请求客户端做 LLM 补全)、Elicitation(server 运行中向用户追加索取信息,2025-06 规范加入)。别只答 server 三件套。
MCP 实战:写一个 MCP Server#
# 用官方 Python SDK
from mcp.server import Server
from mcp.types import Tool, TextContent
server = Server("my-weather-server")
@server.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="get_weather",
description="查询指定城市的天气",
inputSchema={
"type": "object",
"properties": {
"city": {"type": "string"}
},
"required": ["city"]
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
if name == "get_weather":
weather = await fetch_weather(arguments["city"])
return [TextContent(type="text", text=f"{arguments['city']}: {weather}")]关键工程点:
- 错误处理:MCP Server 异常不能崩,要返回结构化错误
- 限流:Server 侧自己做限流,不能让 Agent 一通乱调
- 审计日志:每次调用记录 who/when/what/result
- 凭证隔离:Server 持有的凭证不能泄露给 Agent(见 Ch10 Confused Deputy)
MCP 的 Confused Deputy 风险(★2026 头号威胁)#
什么是 Confused Deputy#
Confused Deputy(混淆代理人)攻击:MCP Server 持有高权限凭证,Agent 用低权限身份请求,但 Server 用自己的高权限执行了请求。
场景:
MCP Server 持有: 公司全员数据库读权限 (server 凭证)
Agent 用户: 实习生 A (低权限)
Agent 请求: "查询员工薪资表"
错误做法:
Server 用自己凭证执行 → 实习生看到全员薪资 ← 越权!
正确做法:
Server 按"请求者身份"校验权限 → 实习生无权 → 拒绝防护要点#
- 凭证最小化委托:不给 agent 超出任务所需的权限
- 按请求者身份校验:不是按 server 身份校验
- 审计每条调用:who/what/result 都要记
- 敏感操作二次确认:高风险操作人工审批
OWASP 2026 把 Confused Deputy 列为 MCP 头号威胁,详见 Ch10 安全护栏与权限治理。
Part 3:A2A(Agent ↔ Agent)#
A2A 与 MCP 的边界#
| MCP | A2A | |
|---|---|---|
| 通信方 | agent ↔ 工具/上下文 | agent ↔ agent |
| 解决问题 | 标准化工具调用 | 标准化 agent 协作 |
| 类比 | 人 ↔ 工具 | 人 ↔ 人 |
| 提出方 | Anthropic | |
| 状态 | 事实标准 | 补齐多 Agent 协作 |
关键判断:你调用的是"工具"(无自主决策)用 MCP;你调用的是"另一个 Agent"(有自主决策、自己的上下文)用 A2A。
治理(2026 现状,易踩反):2025-12 Linux Foundation 成立 Agentic AI Foundation(AAIF),MCP 与 Block 的 goose、OpenAI 的 AGENTS.md 一并作为首批项目并入 AAIF;A2A 则是更早(2025-06)由 Google 单独捐给 Linux Foundation 的独立项目(Agent2Agent Protocol Project),不属于 AAIF。两者都归 Linux Foundation 做中立治理,但不是同一个 foundation——别把"A2A 属于 AAIF"答反。
何时需要 A2A#
- 多 Agent 分工:coding agent + reviewer agent + deploy agent 协作完成 PR
- 跨系统 Agent 协作:我的 Agent 调用你的 Agent 查询数据
- Agent 经济:Agent 之间互相雇佣、协商、付费
A2A 协议核心概念#
Agent Card: 描述 Agent 能力
{
"name": "code-reviewer",
"capabilities": ["code_review", "security_audit"],
"endpoint": "https://...",
"auth": "..."
}
Task: 任务生命周期
submitted → working → completed/failed
Message: Agent 间消息
role: user/agent
parts: text/file/dataPart 4:Browser / Computer Use Agent(★2026 新主线)#
为什么 Browser Use 提级#
2026 最重要的趋势:Agent 不再满足于"调 API",要直接操作浏览器/GUI——很多旧系统没有 API,很多 SaaS 不开放 API,但所有应用都有 GUI。
OpenClaw(28 万+ star)内置浏览器控制;百度红手指 Operator 把 Computer Use 从浏览器扩展到整个桌面;BrowserSkill 类技能市场爆发。
浏览器接入方式#
1. CDP(Chrome DevTools Protocol)#
通过 CDP 直接控制 Chrome,不需要 Selenium:
# Playwright 风格
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await page.goto("https://example.com")
await page.click("#login-button")优势:快、稳定、能拦截网络请求;OpenClaw 内置 CDP,支持"借用已有浏览器 tab"。
2. 借用用户已登录的浏览器 tab#
用户在 Chrome 已登录 github.com
Agent 通过 CDP 接管这个 tab → 复用登录态
→ 不需要重新登录, 不需要存密码这是 OpenClaw 等个人 Agent 的关键设计——避免存用户密码、避免触发 SaaS 风控。
3. Browser Sandbox#
不让 Agent 用用户真实浏览器(风险大),用隔离的 sandbox 浏览器:
- 隔离环境:独立 profile、独立 cookies
- 网络隔离:限制可访问域名
- 截图/录像:所有操作可回放
- 资源限制:CPU/内存/时间上限
观察源:DOM / Screenshot / a11y tree#
Agent 操作浏览器前,必须先"看到"页面。三种观察方式各有取舍:
| 观察源 | 优势 | 劣势 | 适用 |
|---|---|---|---|
| DOM | 信息全、可精确选择 | 噪声多、token 大 | 已知结构页面 |
| Screenshot | 视觉直观、能看布局 | 需要 vision 模型、定位难 | 复杂视觉页面 |
| a11y tree | 结构化、token 小 | 信息有损 | 通用、推荐 |
a11y tree(无障碍树)#
浏览器为无障碍工具暴露的页面结构树:
button "登录"
input "用户名" (editable)
input "密码" (password, editable)
link "忘记密码"token 小、结构化、能直接映射到交互元素。Anthropic 的 Computer Use、OpenClaw 都优先用 a11y tree。
实战策略:多源融合#
1. 先读 a11y tree → 找到目标元素
2. 元素定位失败 → 截图给 vision 模型识别
3. 视觉识别仍失败 → 读 DOM 排查Action 执行#
常见的 Action:
click(element_id)— 点击type(element_id, text)— 输入scroll(direction)— 滚动navigate(url)— 跳转wait(seconds)— 等待screenshot()— 截图
关键工程点:
- 元素定位:不要用 xpath/css selector(页面变化就失效),用 a11y tree 的 element_id
- 异步加载:点击后页面可能要等几秒才加载完,需要
wait_for_selector或轮询 - 失败重试:selector 失效、元素被遮挡、网络抖动都要重试
- 回放:每次 Action 录制 trace,失败时能 replay 复现
登录态边界#
风险#
- 凭证泄露:Agent 持有用户密码 → 高风险
- 触发风控:自动化登录被 SaaS 检测 → 账号被锁
- 会话污染:Agent 操作污染用户当前 session
防护#
- 优先借用 tab:复用用户已登录的浏览器,不存凭证
- OAuth 授权:必须存凭证时用 OAuth,存 token 而非密码
- 隔离 session:Agent 用独立 browser profile,不污染用户主 profile
- 操作审计:所有 Browser Action 留 trace,让用户能查
Computer Use(从浏览器扩展到 GUI)#
2026 趋势:从"操作浏览器"扩展到"操作整个桌面"——打开任意应用、点击任意窗口、输入任意字符。
实现路径#
| 路径 | 代表 | 原理 |
|---|---|---|
| 操作系统级 API | Anthropic Computer Use | 截图 + 鼠标键盘模拟 |
| GUI 自动化框架 | PyAutoGUI / pywinauto | 直接调 OS API |
| 远程桌面 | VNC/RDP 控制 | 控制远程机器 GUI |
风险升级#
Browser Use 出错最多搞乱浏览器,Computer Use 出错能搞乱整个系统:
- 误删文件
- 误发邮件
- 误转账
- 误操作系统设置
→ 必须 Sandbox + 强审批 + 操作回滚,见 Ch5 Permission Mode 与 Ch10 安全护栏。
阶段产出#
完成本章后应该能:
- 设计清晰的 Tool Schema(name/description/parameters + enum/required)
- 实现 Tool Selection Router,处理多工具场景
- 实现参数校验 + 错误回灌 + 工具权限白名单
- 写一个 MCP Server(list_tools / call_tool / Resources / Prompts)
- 理解 MCP Confused Deputy 风险,能设计防护方案
- 说清楚 MCP vs A2A 的边界,知道何时用哪个
- 实现 Browser Use Agent(CDP + a11y tree + Action 执行)
- 处理登录态边界(tab 借用 / OAuth / session 隔离)
- 理解 Computer Use 的扩展场景和风险升级
下一章 Ch5 进入 Agent Runtime / Harness Engineering——这是全路线护城河:模型之外的脚手架才是产品的核心竞争力。