en un clic
langchain-tool-calling
聊天模型如何调用工具 - 包括 bindTools、工具选择策略、并行工具调用和工具消息处理
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Menu
聊天模型如何调用工具 - 包括 bindTools、工具选择策略、并行工具调用和工具消息处理
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Basé sur la classification professionnelle SOC
| name | langchain-tool-calling |
| description | 聊天模型如何调用工具 - 包括 bindTools、工具选择策略、并行工具调用和工具消息处理 |
| language | js |
工具调用允许聊天模型请求执行外部函数。模型根据用户输入决定调用哪些工具,然后将结果传回模型以进行进一步推理。这是代理行为的基础。
核心概念:
| 场景 | 使用工具调用? | 原因 |
|---|---|---|
| 需要外部数据(API、数据库) | ✅ 是 | 模型无法直接访问外部数据 |
| 带操作的多步推理 | ✅ 是 | 模型根据结果决定下一步操作 |
| 简单问答 | ❌ 否 | 不需要工具 |
| 预定工作流 | ⚠️ 可能 | 考虑模型是否需要决定步骤 |
| 策略 | 使用时机 | 示例 |
|---|---|---|
"auto"(默认) | 模型决定是否/使用哪个工具 | 通用目的 |
"any" | 强制模型使用至少一个工具 | 提取、分类 |
"tool_name" | 强制特定工具 | 当您知道需要哪个工具时 |
"none" | 防止工具使用 | 工具执行后 |
| 模式 | 使用时机 | 示例 |
|---|---|---|
| 手动执行 | 代理外部 | 测试、自定义工作流 |
| 代理循环 | 生产使用 | createAgent 自动处理 |
| 并行执行 | 多个独立工具 | 天气 + 新闻查询 |
import { ChatOpenAI } from "@langchain/openai";
import { tool } from "langchain";
import { z } from "zod";
// 定义工具
const getWeather = tool(
async ({ location }: { location: string }) => {
return `${location}的天气:晴天,72°F`;
},
{
name: "get_weather",
description: "获取位置的当前天气",
schema: z.object({
location: z.string().describe("城市名称"),
}),
}
);
// 将工具绑定到模型
const model = new ChatOpenAI({ model: "gpt-4.1" });
const modelWithTools = model.bindTools([getWeather]);
// 模型将决定调用工具
const response = await modelWithTools.invoke(
"旧金山的天气怎么样?"
);
// 检查模型是否调用了工具
console.log(response.tool_calls);
// [{
// name: "get_weather",
// args: { location: "San Francisco" },
// id: "call_abc123"
// }]
import { ChatOpenAI } from "@langchain/openai";
import { tool } from "langchain";
import { ToolMessage } from "langchain";
const getTool = tool(
async ({ location }) => `${location}的天气:晴天`,
{
name: "get_weather",
description: "获取天气",
schema: z.object({ location: z.string() }),
}
);
const model = new ChatOpenAI({ model: "gpt-4.1" });
const modelWithTools = model.bindTools([getTool]);
// 步骤 1:模型决定调用工具
const messages = [{ role: "user", content: "纽约的天气怎么样?" }];
const response1 = await modelWithTools.invoke(messages);
// 步骤 2:执行工具
const toolResults = [];
for (const toolCall of response1.tool_calls || []) {
const result = await getTool.invoke(toolCall);
toolResults.push(result); // 这是一个 ToolMessage
}
// 步骤 3:将结果传回模型
messages.push(response1); // 添加带有工具调用的 AI 消息
messages.push(...toolResults); // 添加工具结果
const response2 = await modelWithTools.invoke(messages);
console.log(response2.content); // 使用工具结果的最终答案
import { ChatOpenAI } from "@langchain/openai";
import { tool } from "langchain";
const extractInfo = tool(
async ({ name, email }) => ({ name, email }),
{
name: "extract_info",
description: "提取姓名和邮箱",
schema: z.object({
name: z.string(),
email: z.string(),
}),
}
);
const model = new ChatOpenAI({ model: "gpt-4.1" });
// 强制模型使用此特定工具
const modelWithTools = model.bindTools([extractInfo], {
tool_choice: "extract_info", // 必须使用此工具
});
const response = await modelWithTools.invoke(
"联系人:John Doe (john@example.com)"
);
// 模型总是调用 extract_info
console.log(response.tool_calls[0].args);
// { name: "John Doe", email: "john@example.com" }
// 强制模型使用至少一个工具(任意一个)
const modelWithTools = model.bindTools(
[tool1, tool2, tool3],
{ tool_choice: "any" }
);
// 模型必须调用至少一个工具,不能仅用文本响应
const response = await modelWithTools.invoke("处理这些数据");
import { ChatOpenAI } from "@langchain/openai";
import { tool } from "langchain";
const getWeather = tool(
async ({ location }) => `${location}的天气:晴天`,
{
name: "get_weather",
description: "获取天气",
schema: z.object({ location: z.string() }),
}
);
const getNews = tool(
async ({ topic }) => `关于${topic}的最新新闻`,
{
name: "get_news",
description: "获取新闻",
schema: z.object({ topic: z.string() }),
}
);
const model = new ChatOpenAI({ model: "gpt-4.1" });
const modelWithTools = model.bindTools([getWeather, getNews]);
const response = await modelWithTools.invoke(
"获取纽约的天气和关于 AI 的新闻"
);
// 模型可能并行调用两个工具
console.log(response.tool_calls);
// [
// { name: "get_weather", args: { location: "NYC" }, id: "call_1" },
// { name: "get_news", args: { topic: "AI" }, id: "call_2" }
// ]
import { ToolMessage } from "langchain";
// 工具消息链接回请求它们的工具调用
const toolMessage = new ToolMessage({
content: "巴黎的天气:晴天,72°F",
tool_call_id: "call_abc123", // 必须匹配 AIMessage tool_call id
name: "get_weather", // 工具名称
});
// 或通过 tool.invoke() 自动创建
const result = await getTool.invoke({
name: "get_weather",
args: { location: "Paris" },
id: "call_abc123",
});
// result 是具有正确结构的 ToolMessage
import { ChatOpenAI } from "@langchain/openai";
import { tool } from "langchain";
import { ToolMessage } from "langchain";
const riskyTool = tool(
async ({ data }) => {
if (!data) throw new Error("缺少数据");
return "成功";
},
{
name: "risky_tool",
description: "可能失败的工具",
schema: z.object({ data: z.string().optional() }),
}
);
const model = new ChatOpenAI({ model: "gpt-4.1" });
const modelWithTools = model.bindTools([riskyTool]);
const response = await modelWithTools.invoke("处理这个");
// 带错误处理执行工具
const toolResults = [];
for (const toolCall of response.tool_calls || []) {
try {
const result = await riskyTool.invoke(toolCall);
toolResults.push(result);
} catch (error) {
// 将错误作为工具消息返回
toolResults.push(
new ToolMessage({
content: `错误:${error.message}`,
tool_call_id: toolCall.id,
name: toolCall.name,
})
);
}
}
import { ChatOpenAI } from "@langchain/openai";
// OpenAI 有内置工具
const model = new ChatOpenAI({
model: "gpt-4.1",
// 启用代码解释器
tools: [{ type: "code_interpreter" }],
});
// Anthropic 有内置工具
import { ChatAnthropic } from "@langchain/anthropic";
const claude = new ChatAnthropic({
model: "claude-sonnet-4-5-20250929",
// 这些是提供商参数,不是 bindTools()
});
import { ChatOpenAI } from "@langchain/openai";
const model = new ChatOpenAI({ model: "gpt-4.1" });
function getModelWithTools(userRole: string) {
const tools = [publicTool];
if (userRole === "admin") {
tools.push(adminTool);
}
return model.bindTools(tools);
}
// 不同用户获得不同的工具
const adminModel = getModelWithTools("admin");
const userModel = getModelWithTools("user");
import { ChatOpenAI } from "@langchain/openai";
import { tool } from "langchain";
const searchTool = tool(
async ({ query }) => `${query}的搜索结果`,
{
name: "search",
description: "搜索网络",
schema: z.object({ query: z.string() }),
}
);
const model = new ChatOpenAI({ model: "gpt-4.1" });
const modelWithTools = model.bindTools([searchTool]);
const messages = [
{ role: "user", content: "搜索 LangChain" },
];
// 第一次调用:模型决定使用工具
const response1 = await modelWithTools.invoke(messages);
messages.push(response1);
// 执行工具
for (const toolCall of response1.tool_calls || []) {
const result = await searchTool.invoke(toolCall);
messages.push(result);
}
// 第二次调用:模型使用工具结果
const response2 = await modelWithTools.invoke(messages);
console.log(response2.content); // 基于搜索结果的答案
// 继续对话
messages.push(response2);
messages.push({ role: "user", content: "告诉我更多" });
const response3 = await modelWithTools.invoke(messages);
// 如果需要,模型可以再次调用工具
✅ 哪些工具可用:bindTools([tool1, tool2]) ✅ 工具选择策略:auto、any、特定工具、none ✅ 工具执行逻辑:自定义错误处理、重试 ✅ 工具参数:通过工具模式 ✅ 多个工具调用:模型可以调用多个工具
❌ 强制模型推理:无法控制模型如何决定 ❌ 工具调用顺序:模型决定(可以并行调用) ❌ 阻止所有工具调用:使用 tool_choice 或不绑定工具 ❌ 在模型生成后修改工具调用:工具调用是不可变的
// ❌ 问题:没有将工具结果传回模型
const response1 = await modelWithTools.invoke(messages);
const toolResult = await tool.invoke(response1.tool_calls[0]);
// 缺少:将结果传回模型!
// ✅ 解决方案:始终传回结果
messages.push(response1); // 带有工具调用的 AI 消息
messages.push(toolResult); // 工具结果
const response2 = await modelWithTools.invoke(messages);
// ❌ 问题:错误的 tool_call_id
const response = await modelWithTools.invoke("获取天气");
const toolMessage = new ToolMessage({
content: "晴天",
tool_call_id: "wrong_id", // 不匹配!
name: "get_weather",
});
// ✅ 解决方案:使用工具调用中的正确 ID
const toolMessage = new ToolMessage({
content: "晴天",
tool_call_id: response.tool_calls[0].id, // 正确的 ID
name: "get_weather",
});
// 或使用自动处理此问题的 tool.invoke()
const toolMessage = await getTool.invoke(response.tool_calls[0]);
// ❌ 问题:假设模型总是调用工具
const response = await modelWithTools.invoke("你好");
await tool.invoke(response.tool_calls[0]); // 如果没有工具调用会出错!
// ✅ 解决方案:检查工具调用是否存在
if (response.tool_calls && response.tool_calls.length > 0) {
for (const toolCall of response.tool_calls) {
await tool.invoke(toolCall);
}
} else {
// 模型在不调用工具的情况下响应
console.log(response.content);
}
// ❌ 问题:绑定工具会覆盖之前的绑定
const model = new ChatOpenAI({ model: "gpt-4.1" });
const withTool1 = model.bindTools([tool1]);
const withTool2 = withTool1.bindTools([tool2]); // 只有 tool2!
// ✅ 解决方案:一次性绑定所有工具
const withBothTools = model.bindTools([tool1, tool2]);
// ❌ 问题:未等待异步工具
const toolResults = response.tool_calls.map(async (tc) => {
return await tool.invoke(tc); // 返回 Promise!
});
messages.push(...toolResults); // 推送的是 Promise,不是结果!
// ✅ 解决方案:使用 Promise.all 或 for...of
const toolResults = await Promise.all(
response.tool_calls.map(tc => tool.invoke(tc))
);
messages.push(...toolResults);
// 或使用 for...of
const toolResults = [];
for (const toolCall of response.tool_calls) {
const result = await tool.invoke(toolCall);
toolResults.push(result);
}
// ❌ 问题:使用错误的工具选择语法
const model = new ChatOpenAI({ model: "gpt-4.1" });
model.bindTools([tool], "required"); // 错误!
// ✅ 解决方案:使用正确的选项格式
model.bindTools([tool], { tool_choice: "any" }); // 强制任意工具
model.bindTools([tool], { tool_choice: "tool_name" }); // 强制特定工具
model.bindTools([tool]); // tool_choice: "auto"(默认)
Mac 系统深度清理和优化工具。使用 Mole (mo 命令) 执行系统清理、磁盘分析、应用卸载、系统优化等任务。 触发场景(当用户提到以下任一内容时使用此 skill): - 清理 Mac、清理磁盘、释放空间、清理缓存、清理系统 - 卸载应用、删除应用、移除应用及其残留 - 磁盘分析、查看磁盘占用、大文件查找、空间分析 - 系统优化、系统维护、刷新系统、重建缓存 - 系统状态、系统监控、CPU/内存/磁盘监控 - 清理 node_modules、清理构建产物、清理项目依赖 - 清理安装包、删除 dmg/pkg 文件 - Mac 清理工具、类似 CleanMyMac 的功能 - "我的 Mac 太慢了"、"磁盘空间不足"、"电脑卡顿" - 即使没有明确说 "Mole",只要涉及上述场景就应使用
快速搭建和配置 pnpm monorepo 项目结构,包含 TypeScript、tsup 构建、私有 npm registry 配置。当用户需要"创建 monorepo"、"初始化 monorepo 项目"、"配置 pnpm workspace"、"设置 monorepo 构建"、"monorepo setup"时使用。特别适合需要统一管理多个包、配置构建工具、处理 TypeScript 路径问题的场景。即使用户只是说"帮我搭建项目结构"或"配置构建",如果涉及多包管理也应该使用此 skill。
智能拆分暂存区的代码变更为多个符合 Conventional Commits 规范的逻辑提交。当用户需要将大量变更按逻辑关系分组提交时使用,比如"拆分这些提交"、"把暂存区的变更分成多个 commit"、"按功能分别提交"、"split commits"等场景。特别适合处理包含多个模块、多种类型文件(配置、代码、测试、文档)的复杂变更集。
OKR 优化与质量评估专家。当用户需要:(1) 评估现有 OKR 的质量,(2) 优化模糊或不可量化的关键结果,(3) 检查 OKR 是否符合核心原则(聚焦、可量化、有挑战),(4) 将任务型 KR 转化为结果型 KR,(5) 提供具体的改进建议时使用。触发词包括"帮我优化 OKR"、"检查这个 OKR"、"这个 KR 写得好吗"、"如何量化这个目标"。
基于 git commits 自动生成 CHANGELOG.md 变更日志。支持语义化版本、分类整理、多格式输出。触发场景包括"生成变更日志"、"更新 CHANGELOG"、"版本记录"。
GitHub PR 代码审查技能。检查代码质量、安全性、性能和最佳实践,生成结构化审查报告。触发场景包括"审查 PR"、"代码检查"、"review pull request"。