数据截至 (上游 commit 9fe68b96f0a7)
Composio — Tool Router 与自定义工具
本章讲什么: 两个进阶能力。Tool Router——工具多到塞不进上下文时,怎么用「会话 + 搜工具/执行工具元工具」让 agent 按需取用。自定义工具——怎么把你自己的本地函数注册成工具,并在进程内直接执行(不走 Composio 后端)。
1. 问题:工具太多,上下文塞不下
Composio 有上千个工具。如果一股脑全 wrapTools 塞给模型,光工具 schema 就吃光上下文窗口,模型还选不准。
两种应对思路:
| 思路 | 做法 | 缺点 |
|---|---|---|
| 静态裁剪 | tools.get 只取少数 toolkit/important 工具 | 得提前知道要哪些 |
| 动态检索 | 给 agent「搜工具」能力,用到再搜 | 多一次检索往返 |
Tool Router 走的是第二条:把「全部工具」藏起来,只暴露两把「元工具」——一把搜、一把执行。
2. Tool Router 的核心点子
类比: 不把整个图书馆的书都搬到你桌上,而是给你一张「检索卡 + 取书单」。要什么书先检索,再点名取。
agent 上下文里只有两把「元工具」:
┌─────────────────────────────┐
│ search(query) ──▶ 按语义找出相关工具 + 它们的 schema/用法 │
│ execute(slug, args) ──▶ 真正执行某个被搜出来的工具 │
└─────────────────────────────┘
│ 这些都在一个「会话(session)」里
▼
Composio 后端:持有全部工具 + 这个 session 的连接/沙箱配置
agent 的典型回合:search('send a slack message') → 后端返回 SLACK_SEND_MESSAGE 及其 schema → agent 用 execute('SLACK_SEND_MESSAGE', {...}) 执行。上下文里始终只有两把元工具,不随工具总数膨胀。
3. 创建会话
composio.sessions.create(userId, config)(composio.ts 里 sessions/create 是同一个,models/ToolRouter.ts:177-290)创建一个绑定到某用户的会话:
// 示意,基于 ToolRouter.ts:158-172 的 doc 示例
const session = await composio.sessions.create('user_123', {
toolkits: ['gmail'], // 限定可搜的范围(也可不限)
manageConnections: true, // 让 session 能自己发起 OAuth 授权
});
console.log(session.sessionId);
// session.mcp.url / session.mcp.headers —— 可作为 MCP endpoint 直接给支持 MCP 的客户端
创建时 config 经过一连串 transform* 函数转成后端 wire 格式(models/ToolRouter.ts:222-255):toolkits、tools、tags、manageConnections、sandbox、multiAccount 各转一道。这一步把「用户友好的 TS 配置」翻译成「后端 API 参数」。
manageConnections 的妙处
开了 manageConnections,会话自己就能 发起授权:session.authorize(toolkit) 返回一个 connectionRequest(models/ToolRouterSession.ts:380-440),复用了第 03 章的 createConnectionRequest。于是「搜工具 → 发现没连 → 当场授权 → 继续执行」可以全在一个会话里闭环。
4. 会话里的元工具
ToolRouterSession 暴露的关键方法(models/ToolRouterSession.ts):
| 方法 | 干什么 | 行号 |
|---|---|---|
search({query, toolkits?}) | 按语义检索工具,返回 schema + 用法指引 | :504-525 |
execute(slug, args, opts?) | 执行一个工具(本地或远程) | :540-589 |
authorize(toolkit, opts?) | 在会话内发起 OAuth,返回 connectionRequest | :380-440 |
tools() | 列出会话当前暴露的工具 | :188 |
toolkits() | 查会话内各 toolkit 的连接状态 | :445 |
search 的入参其实是 { use_case: query } 的语义检索(models/ToolRouterSession.ts:514-518)——你描述「想干什么」,后端返回相关工具,而不是关键字精确匹配。