📌 定义
Tool Composition(工具组合)是指AI Agent将多个独立工具按照特定逻辑链式组合使用,使前一个工具的输出成为后一个工具的输入,从而完成单个工具无法实现的复杂任务。它是Agent从"能用工具"到"善用工具"的关键能力跃迁。
🎭 为什么工具组合如此重要?
单工具 vs 组合工具
| 维度 | 单工具调用 | 工具组合 |
|---|---|---|
| 能力边界 | 单一功能 | 跨功能协作 |
| 输入输出 | 固定格式 | 动态适配 |
| 错误处理 | 重试即可 | 需考虑链路回滚 |
| 可维护性 | 简单直接 | 需要编排逻辑 |
| 典型场景 | 查天气 | 查天气→规划行程→订票 |
📐 五大工具组合模式
1. 串行管道(Sequential Pipeline)
最基础的组合模式,工具A的输出直接作为工具B的输入,像流水线一样。
// 串行管道:搜索 → 提取 → 翻译
async function sequentialPipeline(query) {
// Step 1: 搜索
const searchResults = await web_search({ query });
// Step 2: 提取内容
const content = await web_fetch({
url: searchResults[0].url
});
// Step 3: 翻译
const translated = await translate({
text: content.text,
target: 'zh-CN'
});
return translated;
}
2. 并行扇出(Parallel Fan-out)
同时调用多个工具,聚合结果。适合需要从多个源获取信息的场景。
// 并行扇出:同时搜索多个源
async function parallelFanout(topic) {
const [github, twitter, news] = await Promise.all([
github_search({ q: topic }),
twitter_search({ q: topic }),
news_search({ q: topic })
]);
// 聚合去重
return deduplicate([...github, ...twitter, ...news]);
}
3. 条件分支(Conditional Branching)
根据中间结果决定下一步调用哪个工具,实现动态决策。
// 条件分支:根据内容类型选择不同处理
async function conditionalBranch(url) {
const content = await web_fetch({ url });
if (content.type === 'pdf') {
return await pdf_extract({ content });
} else if (content.type === 'video') {
return await video_transcribe({ content });
} else {
return await text_analyze({ content });
}
}
4. 循环迭代(Iterative Loop)
工具组合结果不满足条件时循环调用,直到达到目标。
// 循环迭代:搜索直到找到满意结果
async function iterativeSearch(query, minResults = 5) {
let results = [];
let page = 1;
while (results.length < minResults && page <= 10) {
const batch = await web_search({
query,
page
});
results.push(...batch);
page++;
}
return results.slice(0, minResults);
}
5. Map-Reduce模式
先并行处理多个数据项(Map),再汇总结果(Reduce),适合批量处理场景。
// Map-Reduce:批量分析多个URL
async function mapReduce(urls) {
// Map: 并行提取所有页面
const contents = await Promise.all(
urls.map(url => web_fetch({ url }))
);
// Reduce: 汇总分析
const summary = await llm.complete(`
综合分析以下${contents.length}个页面的核心观点:
${contents.map(c => c.text).join('\n---\n')}
`);
return summary;
}
🔧 OpenClaw实战:工具组合编排
使用OpenClaw Skills实现工具组合
# SKILL.md - 定义一个内容研究Skill
# 触发条件:用户需要研究某个话题
## 研究工作流
1. 使用 web_search 搜索话题关键词
2. 使用 web_fetch 获取前3个结果页面
3. 使用 write 生成研究报告
4. 使用 message 通知用户完成
## 参数
- topic: 研究话题
- depth: 研究深度 (quick | standard | deep)
- format: 输出格式 (md | html | pdf)
OpenClaw Agent工具组合示例
// 竞品分析工具组合链
async function competitorAnalysis(competitor) {
// 1. 搜索竞品信息
const info = await web_search({
query: `${competitor} product features pricing`
});
// 2. 获取官网数据
const siteData = await Promise.all([
web_fetch({ url: `https://${competitor}.com` }),
web_fetch({ url: `https://${competitor}.com/pricing` })
]);
// 3. 生成对比报告
const report = await llm.complete(`
基于以下信息生成竞品分析报告:
官网内容:${siteData[0].text}
定价信息:${siteData[1].text}
搜索结果:${JSON.stringify(info)}
`);
// 4. 保存报告
await write({
path: `/reports/${competitor}-analysis.md`,
content: report
});
}
⚠️ 常见踩坑与最佳实践
踩坑一:输出格式不匹配
工具A输出JSON,工具B期望CSV——格式不匹配是工具组合最常见的问题。建议在每个工具之间添加数据转换层,使用TypeScript接口定义明确的数据契约。
工具A输出JSON,工具B期望CSV——格式不匹配是工具组合最常见的问题。建议在每个工具之间添加数据转换层,使用TypeScript接口定义明确的数据契约。
踩坑二:错误传播与链路断裂
工具链中任何一个环节失败,整条链路就断了。必须实现优雅降级:搜索失败→尝试缓存→返回部分结果,而不是直接报错。
工具链中任何一个环节失败,整条链路就断了。必须实现优雅降级:搜索失败→尝试缓存→返回部分结果,而不是直接报错。
踩坑三:无限循环
迭代模式下如果不设退出条件,Agent可能在工具间无限循环。必须设置最大迭代次数(建议3-5次)和超时机制。
迭代模式下如果不设退出条件,Agent可能在工具间无限循环。必须设置最大迭代次数(建议3-5次)和超时机制。
最佳实践:
- 每个工具的输入输出格式预先定义并测试
- 实现断路器模式(Circuit Breaker)防止错误扩散
- 添加日志记录每个工具的输入输出用于调试
- 组合链不宜过长,3-5个工具为宜
- 关键节点添加人工确认(HITL)