with one click
langchain-tool-calling
聊天模型如何调用工具 - 包括 bindTools、工具选择策略、并行工具调用和工具消息处理
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
聊天模型如何调用工具 - 包括 bindTools、工具选择策略、并行工具调用和工具消息处理
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
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"。
| 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"(默认)