Tool-让大模型调用工具
# Tool:让大模型调用工具
大模型只能告诉你怎么做,不能帮你做。Cursor 能直接读写文件、跑命令,靠的就是 Tool。
# 环境准备
用阿里的千问模型(免费额度),通过 .env 管理 API Key:
MODEL_NAME=qwen-plus
OPENAI_API_KEY=sk-xxx
OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
pnpm install @langchain/openai @langchain/core zod dotenv
# 调用大模型
import 'dotenv/config';
import { ChatOpenAI } from '@langchain/openai';
const model = new ChatOpenAI({
modelName: process.env.MODEL_NAME || 'qwen-plus',
apiKey: process.env.OPENAI_API_KEY,
temperature: 0, // 0 = 严格按指令,不要自由发挥
configuration: {
baseURL: process.env.OPENAI_BASE_URL,
},
});
const response = await model.invoke("介绍下自己");
console.log(response.content);
# 创建 Tool
核心就三样:函数实现、名称和描述、参数格式(用 zod 定义)。
import { tool } from '@langchain/core/tools';
import { z } from 'zod';
import fs from 'node:fs/promises';
const readFileTool = tool(
async ({ filePath }) => {
const content = await fs.readFile(filePath, 'utf-8');
return `文件内容:\n${content}`;
},
{
name: 'read_file',
description: '读取文件内容,输入文件路径',
schema: z.object({
filePath: z.string().describe('文件路径'),
}),
}
);
# 绑定 Tool 到模型
const modelWithTools = model.bindTools([readFileTool]);
# 完整调用流程
import { HumanMessage, SystemMessage, ToolMessage } from '@langchain/core/messages';
const messages = [
new SystemMessage('你是一个代码助手,可以使用 read_file 工具读取文件'),
new HumanMessage('请读取 src/index.js 文件并解释'),
];
let response = await modelWithTools.invoke(messages);
messages.push(response); // 把 AI 的回复也放入历史
// 循环处理 tool calls,直到没有新的工具调用为止
while (response.tool_calls && response.tool_calls.length > 0) {
// 执行所有工具调用
const toolResults = await Promise.all(
response.tool_calls.map(async (toolCall) => {
const tool = tools.find(t => t.name === toolCall.name);
return await tool.invoke(toolCall.args);
})
);
// 把工具结果封装成 ToolMessage,用 tool_call_id 关联
response.tool_calls.forEach((toolCall, index) => {
messages.push(
new ToolMessage({
content: toolResults[index],
tool_call_id: toolCall.id, // 告诉模型这是哪个工具调用的结果
})
);
});
// 再次调用模型,让它基于工具结果继续思考
response = await modelWithTools.invoke(messages);
messages.push(response);
}
console.log(response.content);
# 流程总结
用户提问 → 大模型思考 → 返回 tool_calls
↓
执行工具,拿到结果
↓
结果作为 ToolMessage 传回大模型
↓
大模型基于结果继续回答(可能再次调用工具)
↓
直到没有新的 tool_calls,输出最终回复
# 关键点
- messages 是完整的对话历史,SystemMessage → HumanMessage → AIMessage → ToolMessage,顺序不能乱
- tool_call_id 用来关联工具调用和结果,模型靠它匹配
- temperature: 0 让模型严格按指令执行,不自由发挥
- 没有 LangChain 也能实现 Tool Calling,本质就是通过 prompt 告诉模型有哪些工具、参数格式,让它按规范返回调用信息,你自己执行后再传回去。LangChain 只是做了封装。
编辑 (opens new window)
上次更新: 2026/06/09, 01:51:57