Anthropic 工程博客最新文章揭示了一个关键发现:当 AI Agent 连接了大量 MCP 工具时,传统的"直接调用"模式会导致 Token 消耗爆炸式增长。他们的解决方案——代码执行模式——在实测中把 Token 消耗从 150,000 降到了 2,000,减少了 98.7%。
问题根源:两种 Token 浪费模式
问题 1:工具定义占满上下文窗口
传统 MCP 客户端在启动时把所有工具定义都加载到上下文里:
gdrive.getDocument
描述:从 Google Drive 获取文档
参数:
documentId(必填,string):文档 ID
fields(可选,string):要返回的字段
返回:包含标题、正文、元数据、权限等的文档对象
salesforce.updateRecord
描述:更新 Salesforce 记录
参数:
objectType(必填,string):Salesforce 对象类型
recordId(必填,string):记录 ID
data(必填,object):要更新的字段
返回:更新后的记录对象
每个工具描述都占上下文空间。连接几十个 MCP 服务器、几百上千个工具时,Agent 在读取用户请求之前就要先处理数十万 Token 的工具定义。
问题 2:中间结果在上下文里来回传递
传统调用流程:
用户请求:"从 Google Drive 下载会议记录并附到 Salesforce 线索上"
Step 1:
TOOL CALL: gdrive.getDocument(documentId: "abc123")
→ 返回完整会议记录文本(流入上下文)
"讨论了 Q4 目标...[完整记录内容,2 小时的会议]"
Step 2:
TOOL CALL: salesforce.updateRecord(
objectType: "SalesMeeting",
recordId: "00Q5f000001abcXYZ",
data: { "Notes": "讨论了 Q4 目标...[完整记录内容再写一遍]" }
)
(模型需要把整个文本再写进上下文一次)
一次 2 小时的会议记录,额外消耗约 50,000 Token,还要处理两次。文档更大时甚至超过上下文窗口上限,流程直接崩溃。
解决方案:把 MCP 工具当代码 API 调用
核心思路:不要把工具暴露为直接调用的函数,而是把它们暴露为文件系统上的代码文件,让 Agent 写代码来调用。
文件树结构
servers/
├── google-drive/
│ ├── getDocument.ts
│ ├── listFiles.ts
│ ├── searchFiles.ts
│ └── index.ts
├── salesforce/
│ ├── updateRecord.ts
│ ├── queryRecords.ts
│ └── index.ts
└── slack/
├── sendMessage.ts
├── getChannelHistory.ts
└── index.ts
每个工具对应一个文件:
// ./servers/google-drive/getDocument.ts
import { callMCPTool } from "../../../client.js";
interface GetDocumentInput {
documentId: string;
fields?: string;
}
interface GetDocumentResponse {
content: string;
title: string;
metadata: Record<string, unknown>;
}
/** 从 Google Drive 读取文档 */
export async function getDocument(
input: GetDocumentInput
): Promise<GetDocumentResponse> {
return callMCPTool<GetDocumentResponse>('google_drive__get_document', input);
}代码执行模式下的同一个任务
// Agent 写的代码,在执行环境里运行
import * as gdrive from './servers/google-drive';
import * as salesforce from './servers/salesforce';
// 读取会议记录
const transcript = (await gdrive.getDocument({
documentId: 'abc123'
})).content;
// 直接传到 Salesforce,文本不经过模型上下文
await salesforce.updateRecord({
objectType: 'SalesMeeting',
recordId: '00Q5f000001abcXYZ',
data: { Notes: transcript }
});
console.log('会议记录已同步到 Salesforce');Token 消耗对比:
- 传统模式:~150,000 Token(所有工具定义 + 中间数据两次传递)
- 代码执行模式:~2,000 Token(只加载需要的两个工具文件)
- 节省:98.7%
代码执行模式的四大优势
优势 1:按需加载工具(Progressive Disclosure)
Agent 通过探索文件系统来发现工具:
# 查看有哪些服务器
ls ./servers/
→ google-drive/ salesforce/ slack/ github/
# 查看 Salesforce 有哪些工具
ls ./servers/salesforce/
→ updateRecord.ts queryRecords.ts createRecord.ts ...
# 读取需要的工具定义
cat ./servers/salesforce/updateRecord.ts
→ (只读这一个文件的定义,不加载其他几百个工具)
或者通过搜索:
// 使用 search_tools 工具,支持不同详细级别
search_tools("salesforce", detail_level="name_only")
→ ["updateRecord", "queryRecords", "createRecord", "deleteRecord"]
search_tools("salesforce lead", detail_level="full")
→ [完整的 createRecord 定义(带参数 Schema)]优势 2:在执行环境过滤数据,不污染上下文
处理大型数据集时,在代码里过滤,不把完整数据集传给模型:
// 传统模式(10,000 行都进上下文)
TOOL CALL: gdrive.getSheet(sheetId: 'abc123')
→ 返回 10,000 行数据到上下文
// 代码执行模式(只有 5 行进上下文)
const allRows = await gdrive.getSheet({ sheetId: 'abc123' });
const pendingOrders = allRows.filter(row => row["Status"] === 'pending');
console.log(`找到 ${pendingOrders.length} 条待处理订单`);
console.log(pendingOrders.slice(0, 5)); // 只显示前 5 条供检查模型看到的是 5 行,而不是 10,000 行。同样的模式适用于聚合、跨数据源 Join、字段提取——都在执行环境处理,不膨胀上下文。
优势 3:代码控制流比工具链更高效
循环、条件判断、错误处理,用代码比串联工具调用更简洁:
// 等待 Slack 中的部署完成通知
let found = false;
while (!found) {
const messages = await slack.getChannelHistory({ channel: 'C123456' });
found = messages.some(m => m.text.includes('deployment complete'));
if (!found) {
await new Promise(r => setTimeout(r, 5000));
}
}
console.log('部署完成通知已收到');对比传统模式的"工具调用→等待→工具调用→等待"往返,代码执行不需要每次都经过模型判断 if-else,直接在执行环境完成,节省"首 Token 时间"延迟。
优势 4:隐私保护——敏感数据不经过模型
中间数据默认留在执行环境,模型只看你明确 log/return 的内容。
对于更敏感的数据,MCP 客户端可以自动 tokenize PII:
// Agent 写的代码
const sheet = await gdrive.getSheet({ sheetId: 'abc123' });
for (const row of sheet.rows) {
await salesforce.updateRecord({
objectType: 'Lead',
recordId: row.salesforceId,
data: { Email: row.email, Phone: row.phone, Name: row.name }
});
}如果模型打印 sheet.rows,它看到的是:
[
{ salesforceId: '00Q...', email: '[EMAIL_1]', phone: '[PHONE_1]', name: '[NAME_1]' },
{ salesforceId: '00Q...', email: '[EMAIL_2]', phone: '[PHONE_2]', name: '[NAME_2]' },
]真实的邮箱、电话、姓名从 Google Sheets 流向 Salesforce,但从未经过模型。
状态持久化和技能积累
代码执行加上文件系统访问,Agent 可以跨运行维持状态:
// 保存中间结果
const leads = await salesforce.query({
query: 'SELECT Id, Email FROM Lead LIMIT 1000'
});
const csvData = leads.map(l => `${l.Id},${l.Email}`).join('\n');
await fs.writeFile('./workspace/leads.csv', csvData);更重要的是,Agent 可以把自己写的有效代码保存为可复用的 Skill:
// 保存为 ./skills/save-sheet-as-csv.ts
import * as gdrive from './servers/google-drive';
export async function saveSheetAsCsv(sheetId: string) {
const data = await gdrive.getSheet({ sheetId });
const csv = data.map(row => row.join(',')).join('\n');
await fs.writeFile(`./workspace/sheet-${sheetId}.csv`, csv);
return `./workspace/sheet-${sheetId}.csv`;
}
// 之后任意 Session 直接复用
import { saveSheetAsCsv } from './skills/save-sheet-as-csv';
const csvPath = await saveSheetAsCsv('abc123');结合 SKILL.md 文件,这就成了 Claude Code 技能体系的基础——Agent 不断积累自己的工具库,越用越强大。
实施注意事项
代码执行模式不是没有代价:
需要准备的基础设施:
- 安全的代码执行环境(沙箱隔离)
- 资源限制(防止无限循环消耗资源)
- 执行监控和日志
适用场景:
- 连接了大量 MCP 工具(5 个服务器以上)
- 需要处理大型数据集
- 有隐私保护需求的工作流
不适用场景:
- 工具数量少(直接调用更简单)
- 一次性简单任务(设置代码执行环境的开销不划算)
来源:Anthropic 工程博客 | Cloudflare Code Mode | 整理:ClaudeEagle