如何添加tools工具

本项目支持fuction call (tools call) 也支持mcp工具 当前主要介绍fuction call工具添加

AI 如何知道工具?

每次调用 AI 时,工具列表会通过 POST 请求的 tools 参数发送给模型

server-tools/*.js
    ↓
local-tool-manager.js 自动扫描
    ↓
getToolsForLLM() 转换为 OpenAI 格式
    ↓
每次 API 请求附带 tools 参数
    ↓
AI 看到工具列表并决定调用
    ↓
tool-executor.js 执行工具

关键点:工具信息是每次请求时实时传递的,不是预装在模型里的。


快速开始

  1. server-tools/ 下新建 .js 文件
  2. 复制下面的模板代码,修改工具名称和逻辑
  3. 重启程序,工具自动生效

标准模板

/**
 * 工具函数
 * @param {类型} 参数名 - 参数描述
 */
async function yourTool({param1, param2}) {
    // 参数验证
    if (!param1) {
        throw new Error('参数不能为空');
    }

    // 实现逻辑
    const result = `处理结果: ${param1}`;
    return result;
}

// 必须实现:工具定义
function getToolDefinitions() {
    return [
        {
            name: "your_tool",
            description: "工具描述,帮助 AI 理解何时使用",
            parameters: {
                type: "object",
                properties: {
                    param1: {
                        type: "string",  // string | number | boolean | array | object
                        description: "参数描述"
                    },
                    param2: {
                        type: "number",
                        description: "参数描述"
                    }
                },
                required: ["param1"]
            }
        }
    ];
}

// 必须实现:工具执行
async function executeFunction(name, parameters) {
    switch (name) {
        case 'your_tool':
            return await yourTool(parameters);
        default:
            throw new Error(`不支持的函数: ${name}`);
    }
}

// 必须导出
module.exports = {
    yourTool,
    getToolDefinitions,
    executeFunction
};

参考

示例:获取当前时间

/**
 * 获取当前时间工具
 * @param {string} format - 时间格式 ('iso' | 'locale' | 'timestamp' | 'custom')
 * @param {string} timezone - 时区(可选),例如 'Asia/Shanghai', 'America/New_York'
 * @param {string} customFormat - 自定义格式(可选),例如 'YYYY-MM-DD HH:mm:ss'
 */
async function getCurrentTime({format = 'iso', timezone, customFormat}) {
    // 参数验证
    const validFormats = ['iso', 'locale', 'timestamp', 'custom'];
    if (!validFormats.includes(format)) {
        throw new Error(`格式必须是以下之一: ${validFormats.join(', ')}`);
    }

    if (format === 'custom' && !customFormat) {
        throw new Error('使用 custom 格式时必须提供 customFormat 参数');
    }

    // 获取当前时间
    const now = new Date();

    // 处理时区
    let dateObj = now;
    if (timezone) {
        try {
            const timeString = now.toLocaleString('en-US', { timeZone: timezone });
            dateObj = new Date(timeString);
        } catch (error) {
            throw new Error(`无效的时区: ${timezone}`);
        }
    }

    // 根据格式返回结果
    let result;
    switch (format) {
        case 'iso':
            result = dateObj.toISOString();
            break;
        case 'locale':
            result = dateObj.toLocaleString('zh-CN', {
                year: 'numeric',
                month: '2-digit',
                day: '2-digit',
                hour: '2-digit',
                minute: '2-digit',
                second: '2-digit',
                hour12: false
            });
            break;
        case 'timestamp':
            result = dateObj.getTime();
            break;
        case 'custom':
            result = formatCustomDate(dateObj, customFormat);
            break;
    }

    return {
        time: result,
        format: format,
        timezone: timezone || 'local'
    };
}

/**
 * 自定义日期格式化辅助函数
 */
function formatCustomDate(date, format) {
    const map = {
        'YYYY': date.getFullYear(),
        'MM': String(date.getMonth() + 1).padStart(2, '0'),
        'DD': String(date.getDate()).padStart(2, '0'),
        'HH': String(date.getHours()).padStart(2, '0'),
        'mm': String(date.getMinutes()).padStart(2, '0'),
        'ss': String(date.getSeconds()).padStart(2, '0')
    };

    let result = format;
    for (const [key, value] of Object.entries(map)) {
        result = result.replace(key, value);
    }
    return result;
}

// 必须实现:工具定义
function getToolDefinitions() {
    return [
        {
            name: "get_current_time",
            description: "获取当前时间,支持多种格式和时区。可用于显示当前日期时间、时间戳,或按指定格式返回时间信息。",
            parameters: {
                type: "object",
                properties: {
                    format: {
                        type: "string",
                        description: "时间格式: 'iso'(ISO 8601格式), 'locale'(本地化格式), 'timestamp'(Unix时间戳), 'custom'(自定义格式)",
                        enum: ["iso", "locale", "timestamp", "custom"]
                    },
                    timezone: {
                        type: "string",
                        description: "时区标识符(可选),例如 'Asia/Shanghai', 'America/New_York', 'Europe/London'"
                    },
                    customFormat: {
                        type: "string",
                        description: "自定义时间格式(可选),仅在 format='custom' 时使用。支持: YYYY(年), MM(月), DD(日), HH(时), mm(分), ss(秒)"
                    }
                },
                required: []
            }
        }
    ];
}

// 必须实现:工具执行
async function executeFunction(name, parameters) {
    switch (name) {
        case 'get_current_time':
            return await getCurrentTime(parameters);
        default:
            throw new Error(`不支持的函数: ${name}`);
    }
}

// 必须导出
module.exports = {
    getCurrentTime,
    getToolDefinitions,
    executeFunction
};


常见问题

必须导出什么?

必须:getToolDefinitionsexecuteFunction

工具会自动加载吗?

是的,只要:
- 文件在 server-tools/ 目录
- 文件名以 .js 结尾(非 index.jsserver.js
- 导出了必需的接口

工具名称规范?

建议:小写字母 + 下划线,如 send_email


代码位置

  • 工具管理器js/ai/local-tool-manager.js
  • 工具执行器js/ai/tool-executor.js
  • API 调用js/ai/llm-client.js