AI响应中function_calling的使用

代码参考文档:https://api-docs.deepseek.com/zh-cn/guides/function_calling

文案生成:Grok3

AI API请求中tools参数的用法全解析

在调用现代AI模型(如OpenAI或DeepSeek)的API时,tools参数是一个强大的功能,可以让模型不仅仅生成文本,还能通过外部工具完成复杂任务,比如查天气、调节情绪、搜索信息等。这篇博客将详细讲解tools参数的用法,从基本定义到多工具场景的处理。

什么是tools参数?

tools是AI API(如client.chat.completions.create)的一个可选参数,用于告诉模型有哪些外部工具可以用。它本质上是一个JSON数组,每个元素定义一个工具的功能、参数和描述。模型会根据用户输入和对话上下文,决定是否调用这些工具,并返回调用请求(tool_calls),由开发者执行后反馈结果。

简单来说,tools像是给AI一个“工具箱”,让它在需要时“借用”你的代码能力。

基本用法:一个工具的例子

我们以一个简单的天气查询工具为例,看看tools怎么用。假设用Node.js调用DeepSeek API:

工具定义

const tools = [
    {
        type: 'function',
        function: {
            name: 'get_weather',
            description: 'Get weather of a location.',
            parameters: {
                type: 'object',
                properties: {
                    location: { type: 'string', description: 'The city, e.g., Hangzhou' }
                },
                required: ['location']
            }
        }
    }
];
  • type: 'function':表示这是一个函数工具。
  • name:工具的唯一标识,AI通过它认出要调用哪个。
  • description:描述工具功能,AI靠这个判断适用场景。
  • parameters:定义工具需要的输入,格式遵循JSON Schema。

调用API

const { OpenAI } = require('openai');
const client = new OpenAI({ apiKey: '<your api key>', baseUrl: 'https://api.deepseek.com' });

async function sendMessages(messages) {
    const response = await client.chat.completions.create({
        model: 'deepseek-chat',
        messages,
        tools
    });
    return response.choices[0].message;
}

async function main() {
    let messages = [{ role: 'user', content: 'How’s the weather in Hangzhou?' }];
    let message = await sendMessages(messages);

    if (message.tool_calls) {
        messages.push(message); // 保存tool_calls
        const toolCall = message.tool_calls[0];
        const args = JSON.parse(toolCall.function.arguments);
        const result = `Weather in ${args.location} is 24°C`; // 模拟执行

        messages.push({ role: 'tool', tool_call_id: toolCall.id, content: result });
        message = await sendMessages(messages);
        console.log(message.content); // 输出最终回答
    }
}

main();

执行流程

  1. 用户问:“杭州天气怎么样?”
  2. 模型返回tool_calls,要求调用get_weather({"location": "Hangzhou"})
  3. 代码执行工具,返回结果“24°C”。
  4. 模型根据结果生成回答:“Hangzhou的天气是24°C。”

这里的关键是:AI不直接查天气,而是通过tools告诉你要用get_weather,你负责实现具体逻辑。

AI如何选择工具?

AI选择工具的过程并不神秘,它靠的是:

  • 用户输入:比如“天气”触发get_weather。(无需代码)
  • 工具描述description越清晰,AI越容易匹配。
  • 上下文messages里的对话历史帮AI判断需求。

比如用户说“我很生气”,如果有个adjust_emotion工具(描述为“Adjust user emotion”),AI可能会调用它,而不是get_weather

多工具场景:如何处理?

tools里有很多工具时,逻辑稍微复杂,但核心不变。假设有三个工具:

const tools = [
    { type: 'function', function: { name: 'adjust_emotion', description: 'Adjust user emotion.', parameters: { ... } } },
    { type: 'function', function: { name: 'get_weather', description: 'Get weather.', parameters: { ... } } },
    { type: 'function', function: { name: 'get_time', description: 'Get time.', parameters: { ... } } }
];

const toolFunctions = {
    adjust_emotion: ({ current_emotion, context }) => ({ should_adjust: true, new_emotion: 'calm' }),
    get_weather: ({ location }) => `Weather in ${location} is 24°C`,
    get_time: ({ location }) => `Time in ${location} is ${new Date().toLocaleTimeString()}`
};

async function main() {
    let messages = [{ role: 'user', content: '我很生气,北京天气和时间呢?' }];
    let message = await sendMessages(messages);

    if (message.tool_calls) {
        messages.push(message);
        for (const toolCall of message.tool_calls) {
            const args = JSON.parse(toolCall.function.arguments);
            const result = toolFunctions[toolCall.function.name](args);
            messages.push({
                role: 'tool',
                tool_call_id: toolCall.id,
                content: JSON.stringify(result)
            });
        }
        message = await sendMessages(messages);
        console.log(message.content); // “别生气,北京天气24°C,时间14:30。”
    }
}

多工具的特点

  • **多tool_calls**:一个输入可能触发多个工具,返回数组。
  • 独立处理:每个tool_call对应一条role: "tool"消息,符合规范。
  • 结果整合:AI会根据所有工具结果生成自然回答。

Token消耗:工具的影响

tools参数和相关消息会占用token:

  • tools定义:每次请求都传,10个工具≈200-300 token。
  • **messages**:包括用户输入、tool_calls和工具结果,历史越长token越多。
  • 输出tool_calls和最终回答算输出token。

一个多工具流程(3工具)可能用100-150 token,工具越多消耗越高。优化方法:

  • 精简描述。
  • 清理不必要的messages历史。

自定义示例:调节情绪工具

来看一个有趣的例子:设计一个调节情绪的工具。

工具定义

{
    "type": "function",
    "function": {
        "name": "adjust_emotion",
        "description": "Adjust user emotion based on context.",
        "parameters": {
            "type": "object",
            "properties": {
                "current_emotion": { "type": "string", "enum": ["happy", "sad", "angry", "calm"] },
                "context": { "type": "string" }
            },
            "required": ["current_emotion", "context"]
        }
    }
}

工具响应

工具内部函数举例

toolFunctions.adjust_emotion = ({ current_emotion, context }) => {
    if (current_emotion === 'angry' && context.includes('生气')) {
        return { should_adjust: true, new_emotion: 'calm' };
    }
    return { should_adjust: false, new_emotion: null };
};

用户说“我很生气”,AI调用adjust_emotion,返回calm,然后生成安抚性回复。

(这里grok简化了,我的实际想法是获取该情绪下的对话模板并更改提示词)
(另外,这里的解释可能有歧义,实际过程是AI仅返回json格式的输出,要本地主动地检查json文件并调用方法——工具调用方法前面有讲述——然后把工具方法返回内容添加到message里传给AI)

注意事项与优化

  1. 描述要精准:避免功能重叠,AI才能选对工具。
  2. 多工具管理:用对象映射(如toolFunctions)保持代码清晰。
  3. 测试验证:多试几种输入,确保AI选择合理。
  4. token控制:工具太多时,动态传必要的tools,减少开销。
    (辅助AI正愁没有用武之地,用在这里正合适)

结语

tools参数让AI从单纯的“说话机器”变成了“智能助手”,能通过外部工具解决实际问题。无论是单个工具还是多工具场景,只要定义清晰、逻辑合理,就能轻松集成到你的应用中。

我说两句

function_calling能很好地简化流程,过去我的设想一直是辅助AI动态修改提示词来达到这一效果,虽然想想效果不差,但到底太臃肿了,不正式。

在利用tools情况下,可以将需要的tools方法和参数封装起来,放在同级目录的两个文件tools.jsontool_functions.js里,使用如下方法调用,结构清晰,一目了然。

// 从当前文件夹路径导入
const tools = require('./tools.json');// 需要添加后缀否则会作为模块导入
const toolFunctions = require('./tool_functions');// js文件可以不用

当然AI也提到了,如果使用过多的tools,可能会导致token消耗过多,因此辅助AI可以动态识别判断需要传输的tool方法,可以说依旧在岗。

tools的用法当然不仅限于AI说的,那就是我之前AI本地提权的设想,对AI响应流程合理规划后完全适用。

AI调用方法会是未来很核心的功能,本身工具使用就是大模型性能参考标准之一。


当前deepseek-chat工具使用会导致空回复,我尝试多次没有成功,官方说下一版本会修复。


此方悬停
相册 小说 Ai
/*音乐播放器插件*/ /*
*/