使用嵌入相似性进行超快速语义工具筛选,适用于MCP(模型上下文协议)服务器。将您的工具上下文从1000多个工具减少到最相关的10-20个工具,时间在10毫秒以内。
npm install @portkey-ai/mcp-tool-filter
import { MCPToolFilter } from '@portkey-ai/mcp-tool-filter';
// 1. 初始化筛选器(选择嵌入提供者)
// 选项A:本地嵌入(推荐用于低延迟<5毫秒)
const filter = new MCPToolFilter({
embedding: {
provider: 'local',
}
});
// 选项B:API嵌入(用于最高精度)
const filter = new MCPToolFilter({
embedding: {
provider: 'openai',
apiKey: process.env.OPENAI_API_KEY,
}
});
// 2. 加载您的MCP服务器(一次性设置)
await filter.initialize(mcpServers);
// 3. 根据上下文筛选工具
const result = await filter.filter(
"搜索我的邮件中关于Q4预算讨论的内容"
);
// 4. 在LLM请求中使用筛选后的工具
console.log(result.tools); // 最相关的前20个工具
console.log(result.metrics.totalTime); // 例如,本地为“2ms”,API为“500ms”
优点:
缺点:
const filter = new MCPToolFilter({
embedding: {
provider: 'local',
model: 'Xenova/all-MiniLM-L6-v2', // 可选:默认模型
quantized: true, // 可选:使用量化模型以提高速度(默认:true)
}
});
可用模型:
Xenova/all-MiniLM-L6-v2(默认)- 384维,非常快Xenova/all-MiniLM-L12-v2 - 384维,更准确Xenova/bge-small-en-v1.5 - 384维,平衡良好Xenova/bge-base-en-v1.5 - 768维,质量更高性能:
为了获得最高精度,请使用OpenAI或其他API提供者:
const filter = new MCPToolFilter({
embedding: {
provider: 'openai',
apiKey: process.env.OPENAI_API_KEY,
model: 'text-embedding-3-small', // 可选
dimensions: 384, // 可选:与本地模型匹配以进行公平比较
}
});
优点:
缺点:
性能:
| 方面 | 本地 | API | 胜者 |
|---|---|---|---|
| 速度 | 1-5毫秒 | 400-800毫秒 | 🏆 本地(快200倍) |
| 精度 | 良好(85-90%) | 最佳(100%) | 🏆 API |
| 成本 | 免费 | ~$0.02/1M令牌 | 🏆 本地 |
| 隐私 | 完全本地 | 数据发送到API | 🏆 本地 |
| 离线 | ✅ 支持离线 | ❌ 需要互联网 | 🏆 本地 |
| 设置 | 零配置 | 需要API密钥 | 🏆 本地 |
📊 查看详细分析 TRADEOFFS.md
库期望一个MCP服务器数组,具有以下结构:
[
{
"id": "gmail",
"name": "Gmail MCP服务器",
"description": "电子邮件管理工具",
"categories": ["email", "communication"],
"tools": [
{
"name": "search_gmail_messages",
"description": "在Gmail收件箱中搜索和查找电子邮件消息。当用户想要查找、搜索、查找电子邮件时使用。",
"keywords": ["email", "search", "inbox", "messages"],
"category": "email-search",
"inputSchema": {
"type": "object",
"properties": {
"q": { "type": "string" }
}
}
}
]
}
]
必填字段:
id:服务器的唯一标识符name:人类可读的服务器名称tools:工具定义数组
name:唯一的工具名称description:工具做什么以及何时使用的丰富描述可选但推荐:
description:服务器级别的描述categories:用于分层过滤的类别标签数组keywords:用于更好匹配的同义词/相关术语数组category:工具级别的类别inputSchema:参数的JSON模式(参数名称用于匹配)丰富的描述:编写带有用例的详细描述
"description": "在Gmail中搜索电子邮件。当用户想要查找、查找或检索消息、通信或邮件时使用。"
添加关键词:包括同义词和变体
"keywords": ["email", "mail", "inbox", "messages", "correspondence"]
提及用例:明确说明何时使用该工具
"description": "... 当用户想要起草、撰写、编写或将来的邮件时使用。"
MCPToolFilter工具筛选的主要类。
new MCPToolFilter(config: MCPToolFilterConfig)
配置选项:
{
embedding: {
// 本地嵌入(推荐)
provider: 'local',
model?: string, // 默认:'Xenova/all-MiniLM-L6-v2'
quantized?: boolean, // 默认:true
// 或API嵌入
provider: 'openai' | 'voyage' | 'cohere',
apiKey: string,
model?: string, // 默认:'text-embedding-3-small'
dimensions?: number, // 默认:1536(或本地的384)
baseURL?: string, // 用于自定义端点
},
defaultOptions?: {
topK?: number, // 默认:20
minScore?: number, // 默认:0.3
contextMessages?: number, // 默认:3
alwaysInclude?: string[], // 始终包含这些工具
exclude?: string[], // 从不包含这些工具
maxContextTokens?: number, // 默认:500
},
includeServerDescription?: boolean, // 默认:false(见下文)
debug?: boolean // 启用调试日志
}
关于includeServerDescription:
启用此选项将在工具嵌入中包含MCP服务器描述,提供有关工具领域/类别的附加上下文。
// 在嵌入中启用服务器描述
const filter = new MCPToolFilter({
embedding: { provider: 'local' },
includeServerDescription: true // 默认:false
});
权衡:
建议:除非您的用例主要涉及高级意图查询,否则保持禁用(默认:false)。查看examples/benchmark-server-description.ts以获取详细的基准测试。
initialize(servers: MCPServer[]): Promise<void>使用MCP服务器初始化筛选器。这会预先计算并缓存所有工具嵌入。
注意:启动时调用一次。这是一个异步操作,具体耗时取决于工具的数量。
await filter.initialize(servers);
filter(input: FilterInput, options?: FilterOptions): Promise<FilterResult>根据输入上下文筛选工具。
输入类型:
// 字符串输入
await filter.filter("搜索我关于项目的电子邮件");
// 聊天消息
await filter.filter([
{ role: 'user', content: '今天我有哪些会议?' },
{ role: 'assistant', content: '让我检查一下你的日程。' }
]);
选项(全部可选,覆盖默认值):
{
topK?: number, // 返回的最大工具数
minScore?: number, // 最小相似度分数(0-1)
contextMessages?: number, // 使用多少最近的消息
alwaysInclude?: string[], // 始终包含的工具名称
exclude?: string[], // 排除的工具名称
maxContextTokens?: number, // 上下文大小的最大值
}
返回:
{
tools: ScoredTool[], // 筛选并排名的工具
metrics: {
totalTime: number, // 总耗时(毫秒)
embeddingTime: number, // 嵌入上下文的时间
similarityTime: number, // 计算相似度的时间
toolsEvaluated: number, // 总共评估的工具数
}
}
getStats()获取筛选器状态的统计信息。
const stats = filter.getStats();
// {
// initialized: true,
// toolCount: 25,
// cacheSize: 5,
// embeddingDimensions: 1536
// }
clearCache()清除上下文嵌入缓存。
filter.clearCache();
库包括几个开箱即用的性能优化:
这些优化是自动且透明的 - 无需配置!
1000个工具的典型性能:
构建上下文: <1毫秒
嵌入API调用: 3-5毫秒 (缓存:0毫秒)
相似度计算: 1-2毫秒 (优化后6-8倍更快)
排序/筛选: <1毫秒 (混合算法)
─────────────────────────────
总计: 5-9毫秒
使用较小的嵌入:512或1024维度以加快计算
embedding: {
provider: 'openai',
model: 'text-embedding-3-small',
dimensions: 512 // 比1536更快
}
减少上下文大小:较少的消息=更快的嵌入
defaultOptions: {
contextMessages: 2, // 而不是3-5
maxContextTokens: 300
}
利用缓存:相同的上下文重用缓存的嵌入(0毫秒)
调整topK:如果您不需要20个工具,请求更少的工具
await filter.filter(input, { topK: 10 });
显示优化改进的微基准测试:
点积(1536维): 0.001毫秒 vs 0.006毫秒(6倍更快)
向量归一化: 0.003毫秒 vs 0.006毫秒(2倍更快)
Top-K选择(<500工具): 使用优化的内置排序
Top-K选择(500+工具): O(n log k)基于堆的选择
LRU缓存访问: 真实的访问顺序跟踪
查看现有的基准测试示例以进行端到端性能测试:
npx ts-node examples/benchmark.ts
import Portkey from 'portkey-ai';
import { MCPToolFilter } from '@portkey-ai/mcp-tool-filter';
const portkey = new Portkey({ apiKey: '...' });
const filter = new MCPToolFilter({ /* ... */ });
await filter.initialize(mcpServers);
// 根据对话筛选工具
const { tools } = await filter.filter(messages);
// 转换为OpenAI工具格式
const openaiTools = tools.map(t => ({
type: 'function',
function: {
name: t.toolName,
description: t.tool.description,
parameters: t.tool.inputSchema,
}
}));
// 使用筛选后的工具进行LLM请求
const completion = await portkey.chat.completions.create({
model: 'gpt-4',
messages: messages,
tools: openaiTools,
});
import { ChatOpenAI } from 'langchain/chat_models/openai';
import { MCPToolFilter } from '@portkey-ai/mcp-tool-filter';
const filter = new MCPToolFilter({ /* ... */ });
await filter.initialize(mcpServers);
// 创建自定义工具选择器
async function selectTools(messages) {
const { tools } = await filter.filter(messages);
return tools.map(t => convertToLangChainTool(t));
}
// 在您的代理中使用
const model = new ChatOpenAI();
const tools = await selectTools(messages);
const response = await model.invoke(messages, { tools });
// 推荐:启动时初始化一次
let filterInstance: MCPToolFilter;
async function getFilter() {
if (!filterInstance) {
filterInstance = new MCPToolFilter({ /* ... */ });
await filterInstance.initialize(mcpServers);
}
return filterInstance;
}
// 在请求处理器中使用
app.post('/chat', async (req, res) => {
const filter = await getFilter();
const result = await filter.filter(req.body.messages);
// ... 使用筛选后的工具
});
不同工具数量下的性能(M1 Max):
本地嵌入(Xenova/all-MiniLM-L6-v2):
| 工具 | 初始化 | 筛选(冷) | 筛选(缓存) |
|---|---|---|---|
| 10 | ~100毫秒 | 2毫秒 | <1毫秒 |
| 100 | ~500毫秒 | 3毫秒 | <1毫秒 |
| 500 | ~2秒 | 4毫秒 | 1毫秒 |
| 1000 | ~4秒 | 5毫秒 | 1毫秒 |
| 5000 | ~20秒 | 8毫秒 | 2毫秒 |
API嵌入(OpenAI text-embedding-3-small):
| 工具 | 初始化 | 筛选(冷) | 筛选(缓存) |
|---|---|---|---|
| 10 | ~200毫秒 | 500毫秒 | 1毫秒 |
| 100 | ~1.5秒 | 5 |