工具创建模式
函数工具
从TypeScript/JavaScript函数创建工具:工具包
将相关工具组织成可重用的工具包:快速入门
基础工具创建
创建一个简单的自定义工具:复制
import { tool } from '@ag-kit/tools';
import { z } from 'zod';
const weatherTool = tool(
async ({ city, units }) => {
try {
// 获取天气数据
const response = await fetch(
`https://api.weather.com/v1/current?city=${city}&units=${units}`
);
if (!response.ok) {
return {
success: false,
error: `Weather API error: ${response.statusText}`,
error_type: 'network'
};
}
const data = await response.json();
return {
success: true,
data: {
city,
temperature: data.temperature,
condition: data.condition,
humidity: data.humidity,
units
}
};
} catch (error) {
return {
success: false,
error: error.message,
error_type: 'execution'
};
}
},
{
name: 'get_weather',
description: '获取城市的当前天气信息',
schema: z.object({
city: z.string().describe('城市名称'),
units: z.enum(['celsius', 'fahrenheit']).default('celsius')
})
}
);
工具集成
将自定义工具与代理一起使用:复制
import { Agent } from '@ag-kit/core';
import { OpenAIProvider } from '@ag-kit/providers/openai';
const provider = new OpenAIProvider({
apiKey: process.env.OPENAI_API_KEY!,
model: 'gpt-4'
});
const agent = new Agent({
name: 'weather-agent',
model: provider,
tools: [weatherTool],
instructions: '您可以查询任何城市的天气信息。'
});
const response = await agent.run({
input: '旧金山的天气如何?'
});
工具架构
BaseTool接口
所有工具都实现了标准化接口:复制
interface BaseTool<TInput = any, TOutput = any> {
name: string;
description: string;
schema: ZodSchema<TInput>;
invoke(input: TInput): Promise<ToolResult<TOutput>>;
}
工具结果结构
所有工具的一致结果格式:复制
interface ToolResult<T = any> {
success: boolean;
data?: T;
error?: string;
error_type?: "validation" | "execution" | "permission" | "network";
executionTime?: number;
}
模式验证
使用Zod进行输入验证:复制
import { z } from 'zod';
const complexSchema = z.object({
// 必填字段
id: z.string().uuid(),
name: z.string().min(1).max(100),
// 带默认值的可选字段
priority: z.enum(['low', 'medium', 'high']).default('medium'),
tags: z.array(z.string()).default([]),
// 嵌套对象
metadata: z.object({
created: z.date(),
author: z.string()
}).optional(),
// 条件验证
config: z.union([
z.object({ type: z.literal('simple'), value: z.string() }),
z.object({ type: z.literal('complex'), settings: z.record(z.any()) })
])
});
工具包架构
自定义工具包
创建自定义工具包以组织相关工具:复制
import { BaseToolkit, tool } from '@ag-kit/tools';
import { z } from 'zod';
class WeatherToolkit extends BaseToolkit {
constructor() {
super({
name: 'weather-toolkit',
description: 'Comprehensive weather information toolkit'
});
}
protected async onInitialize(): Promise<void> {
// Add weather tools
this.addTool(this.createCurrentWeatherTool());
this.addTool(this.createForecastTool());
this.addTool(this.createHistoricalTool());
}
private createCurrentWeatherTool() {
return tool(
async ({ city, units }) => {
// Implementation
return { success: true, data: { temperature: 22, condition: 'sunny' } };
},
{
name: 'current_weather',
description: 'Get current weather conditions',
schema: z.object({
city: z.string(),
units: z.enum(['celsius', 'fahrenheit']).default('celsius')
})
}
);
}
private createForecastTool() {
return tool(
async ({ city, days }) => {
// Implementation
return { success: true, data: { forecast: [] } };
},
{
name: 'weather_forecast',
description: 'Get weather forecast',
schema: z.object({
city: z.string(),
days: z.number().min(1).max(14).default(5)
})
}
);
}
private createHistoricalTool() {
return tool(
async ({ city, date }) => {
// Implementation
return { success: true, data: { historical: [] } };
},
{
name: 'weather_historical',
description: 'Get historical weather data',
schema: z.object({
city: z.string(),
date: z.string()
})
}
);
}
}
// 使用工具包
const weatherKit = new WeatherToolkit();
await weatherKit.initialize();
const tools = weatherKit.getTools();
使用自定义工具包
初始化自定义工具包并与Agent一起使用:复制
// Create and initialize toolkit
const weatherToolkit = new WeatherToolkit();
await weatherToolkit.initialize();
// Get all tools from toolkit
const weatherTools = weatherToolkit.getTools();
工具包管理
使用工具包管理器进行集中式工具包管理:复制
import { ToolkitManager } from '@ag-kit/tools';
const toolkitManager = new ToolkitManager();
// Register toolkit
toolkitManager.register(weatherToolkit);
// Get toolkit by name
const toolkit = toolkitManager.getToolkit('weather-toolkit');
// Get all tools from all registered toolkits
const allTools = toolkitManager.getAllTools();
// Find specific tool across all toolkits
const currentWeatherTools = toolkitManager.findTool('current_weather');
// Initialize all registered toolkits
await toolkitManager.initializeAll();
// Cleanup all toolkits
await toolkitManager.destroyAll();
工具包事件
监听工具包生命周期事件:复制
weatherToolkit.addEventListener((event) => {
switch (event.type) {
case 'toolkit_initialized':
console.log(`Toolkit ${event.toolkit.name} initialized`);
break;
case 'tool_added':
console.log(`Tool ${event.tool.name} added`);
break;
case 'tool_executed':
console.log(`Tool ${event.toolName} executed`);
break;
case 'toolkit_destroyed':
console.log(`Toolkit ${event.toolkit.name} destroyed`);
break;
}
});
工具测试
单元测试
全面测试自定义工具:复制
import { describe, it, expect } from 'jest/globals';
describe('weatherTool', () => {
it('should return weather data for valid city', async () => {
const result = await weatherTool.invoke({
city: 'San Francisco',
units: 'celsius'
});
expect(result.success).toBe(true);
expect(result.data).toHaveProperty('temperature');
expect(result.data.city).toBe('San Francisco');
expect(result.data.units).toBe('celsius');
});
it('should handle invalid city gracefully', async () => {
const result = await weatherTool.invoke({
city: 'InvalidCity123',
units: 'celsius'
});
expect(result.success).toBe(false);
expect(result.error_type).toBe('network');
});
it('should validate input schema', async () => {
const result = await weatherTool.invoke({
city: '', // Invalid empty city
units: 'celsius'
});
expect(result.success).toBe(false);
expect(result.error_type).toBe('validation');
});
});
工具包测试
全面测试自定义工具包:复制
import { describe, it, expect, beforeEach, afterEach } from 'jest/globals';
describe('WeatherToolkit', () => {
let weatherToolkit: WeatherToolkit;
beforeEach(async () => {
weatherToolkit = new WeatherToolkit();
await weatherToolkit.initialize();
});
afterEach(async () => {
await weatherToolkit.destroy();
});
it('should initialize with correct tools', () => {
const toolNames = weatherToolkit.getToolNames();
expect(toolNames).toContain('current_weather');
expect(toolNames).toContain('weather_forecast');
expect(toolNames).toContain('historical_weather');
expect(weatherToolkit.getTools()).toHaveLength(3);
});
it('should execute tools correctly', async () => {
const result = await weatherToolkit.invokeTool('current_weather', {
city: 'San Francisco',
units: 'celsius'
});
expect(result.success).toBe(true);
expect(result.data).toHaveProperty('temperature');
});
it('should handle batch tool execution', async () => {
const results = await weatherToolkit.invokeTools([
{ toolName: 'current_weather', input: { city: 'Tokyo' } },
{ toolName: 'weather_forecast', input: { city: 'Tokyo', days: 3 } }
]);
expect(results).toHaveLength(2);
expect(results.every(r => r.success)).toBe(true);
});
it('should validate toolkit integrity', () => {
const validation = weatherToolkit.validate();
expect(validation.valid).toBe(true);
expect(validation.errors).toHaveLength(0);
});
it('should emit events correctly', async () => {
const events: any[] = [];
const newToolkit = new WeatherToolkit();
newToolkit.addEventListener((event) => {
events.push(event);
});
await newToolkit.initialize();
await newToolkit.invokeTool('current_weather', { city: 'London' });
await newToolkit.destroy();
expect(events.some(e => e.type === 'toolkit_initialized')).toBe(true);
expect(events.some(e => e.type === 'tool_executed')).toBe(true);
expect(events.some(e => e.type === 'toolkit_destroyed')).toBe(true);
});
});
性能优化
缓存
为昂贵的操作实现缓存:复制
const cache = new Map();
const cachedWeatherTool = tool(
async ({ city, units }) => {
const cacheKey = `${city}-${units}`;
const cached = cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < 300000) { // 5 minutes
return {
success: true,
data: { ...cached.data, cached: true }
};
}
const result = await fetchWeatherData(city, units);
if (result.success) {
cache.set(cacheKey, {
data: result.data,
timestamp: Date.now()
});
}
return result;
},
{
name: 'get_weather_cached',
description: 'Get weather with caching',
schema: z.object({
city: z.string(),
units: z.enum(['celsius', 'fahrenheit']).default('celsius')
})
}
);
连接池
重用连接以获得更好的性能:复制
class DatabaseConnectionPool {
private pool: any[] = [];
async getConnection() {
if (this.pool.length > 0) {
return this.pool.pop();
}
return await createNewConnection();
}
releaseConnection(connection: any) {
if (this.pool.length < 10) {
this.pool.push(connection);
} else {
connection.close();
}
}
}
const pool = new DatabaseConnectionPool();
const optimizedDbTool = tool(
async ({ query, parameters }) => {
const connection = await pool.getConnection();
try {
const result = await connection.query(query, parameters);
return { success: true, data: result };
} finally {
pool.releaseConnection(connection);
}
},
{
name: 'optimized_db_query',
description: 'Database query with connection pooling',
schema: z.object({
query: z.string(),
parameters: z.array(z.any()).default([])
})
}
);