[LangChain] 20. Tools配置
在实际开发中,经常还有如下的需求:
- 禁止模型调用某个工具
- 强制调用某个工具
- 注册多个函数工具
禁止模型调用工具
默认情况下,模型会自行决定是否使用 tool。但有时你希望它只能用自己的知识回答,怎么办?
你可以通过 tool_choice: "none" 禁用工具调用。
const result = await openai.chat.completions.create({
model: "gpt-3.5-turbo-1106",
messages: [{ role: "user", content: "北京天气如何?" }],
tools, // 工具注册了,但不会被调用
tool_choice: "none", // 显式禁止调用工具
});
强制调用工具
有时候你希望无论用户说什么,模型都必须调用某个函数。
思考🤔什么场景有这样的需求?
- 系统内部函数(写日志、上报埋点):比如用户输入“哈哈哈”,你并不在乎他问了啥,但系统强制调用
logUserInteraction(),确保每次对话都会记录到数据库里。 - 必须走翻译函数:如果你做一个“统一英文客服”,无论用户输入中英文,都必须调用
translateToEnglish(),再交给后续处理。 - 结构化场景
- 提取表单信息:无论用户说“我的名字是张三”还是“我来自北京”,你都强制调用
extractUserProfile(),把内容整理成{name: "张三", city: "北京"}。 - 生成 SQL:即使用户说“hi”,也要求模型调用
toSQL(),这样就能保持统一的 SQL 输出。
- 提取表单信息:无论用户说“我的名字是张三”还是“我来自北京”,你都强制调用
const res = await openai.chat.completions.create({
model: "gpt-3.5-turbo-1106",
messages,
tools,
tool_choice: {
type: "function",
function: {
name: "getCurrentWeather", // 强制调用该函数
},
},
});
注册多个工具
很多实际场景中,我们的机器人不仅能查天气,还可能支持查时间、查汇率、订机票……
tools 支持同时注册多个函数。模型会根据用户提问智能选择对应函数,无需额外配置。
额外需注意字段
parallel_tool_calls
是否允许模型在一次回复里并行提出多个 tool 调用。默认是开启的。
注意,parallel_tool_calls 只决定“能不能一次要多个工具”;用哪个工具仍由 tool_choice(或模型自动选择)决定。还有就是,parallel_tool_calls: false 只是禁止并行提出多个调用,也就是模型通常会只给一个 tool_call。它不保证“一轮就结束”。模型仍可能在下一轮继续提别的工具。
description
在 tools.function 中,description 字段能显著影响模型选择工具的行为。如果你注册多个工具,要写清楚每个工具的用途和限制,否则模型可能误选。
import OpenAI from "openai";
import { tools, getCurrentWeather, getCurrentTime } from "./tools.js";
import dotenv from "dotenv";
dotenv.config();
const openai = new OpenAI({
apiKey: process.env.API_KEY,
});
// 1. 用户提的问题
const messages = [
{
role: "user",
content: "北京今天的天气怎么样?另外,现在几点了?",
},
];
// 2. 将问题 + 工具箱一起给模型,模型判断是否使用工具
const res = await openai.chat.completions.create({
model: "gpt-3.5-turbo-1106",
messages,
tools,
parallel_tool_calls: false,
});
console.dir(res.choices[0], { depth: null });
const assistanMsg = res.choices[0].message;
// 不需要调用工具的情况
if (!assistanMsg.tool_calls?.length) {
console.log("模型未调用任何工具,直接回复的内容:", assistanMsg.content);
process.exit(0);
}
// 下面是需要调用工具的流程
messages.push(assistanMsg);
// 构建一个本地的工具箱
const funcs = {
getCurrentWeather,
getCurrentTime,
};
for (const call of assistanMsg.tool_calls) {
const {
id: tool_call_id,
function: { name, arguments: args },
} = call;
const fn = funcs[name];
if (!fn) {
messages.push({
role: "tool",
tool_call_id,
name,
content: JSON.stringify({
error: `${name}的工具不存在`,
}),
});
continue;
}
const toolResult = await fn(args);
// 针对工具调用返回的结果做一个简单的日志
const content =
typeof toolResult === "string" ? toolResult : JSON.stringify(toolResult);
console.log(`已执行 ${name}(${JSON.stringify(args)}), 返回: ${content}`);
// 将工具调用结果和之前的会话组装起来,再给大模型
messages.push({
role: "tool",
tool_call_id,
name,
content,
});
}
const finalRes = await openai.chat.completions.create({
model: "gpt-3.5-turbo-1106",
messages,
tools,
});
// console.log("最终回答:", finalRes.choices[0].message.content);
console.log(finalRes.choices[0].message.tool_calls);
// 外部工具
export function getCurrentWeather({ location, unit = "celsius" }) {
const weather_info = {
location, // 查询的城市名称
temperature: "22",
unit, // 温度的单位("celsius" 或 "fahrenheit")
forecast: ["晴朗 ☀️", "微风 🌬️"], // 天气简单的描述
};
return JSON.stringify(weather_info);
}
// 工具:获取当前时间
export function getCurrentTime({ format = "locale" }) {
switch (format) {
case "iso":
return new Date().toISOString(); // ISO 格式:2025-06-24T09:00:00.000Z
case "locale":
return new Date().toLocaleString(); // 本地格式:2025/6/24 17:00:00
case "string":
return new Date().toString(); // 英文字符串格式:Tue Jun 24 2025 17:00:00 GMT+0800
default:
return "不支持的 format 类型,请传入 iso / locale / string";
}
}
// 工具箱
export const tools = [
{
type: "function",
function: {
name: "getCurrentWeather",
description: "获取指定城市当前的天气情况",
parameters: {
type: "object",
properties: {
location: {
type: "string",
description: "城市名称,例如:北京、上海、成都",
},
unit: {
type: "string",
enum: ["celsius", "fahrenheit"],
description: "温度单位,可选:摄氏度或者华氏度",
},
},
required: ["location"],
},
},
},
{
type: "function",
function: {
name: "getCurrentTime",
description: "获取当前时间(可选格式)",
parameters: {
type: "object",
properties: {
format: {
type: "string",
enum: ["iso", "locale", "string"],
},
},
required: ["format"],
},
},
},
];
-EOF-

浙公网安备 33010602011771号