Appearance
02-tool-calling.ts
单轮工具调用示例,展示 agent 底层的 tool calling 机制(不是完整 agent)。
功能介绍
这个示例演示了单轮 tool calling 的完整闭环:模型决定调用工具 -> 执行工具拿到 ToolMessage -> 把工具结果喂回模型 -> 拿到最终答案。这是理解 agent 的前置知识--agent 内部就是把这个循环多跑几轮。
注意: 这是单轮演示,真正的 agent(多轮工具调用循环)见 03-react-agent。
使用场景
- 理解 tool calling 的底层机制
- 学习
tool_calls和ToolMessage的传递 - 不需要 agent 循环的简单工具调用场景
- 调试工具定义和绑定
学习要点
- 使用
.bindTools()将工具绑定到模型上 - 检查
response.tool_calls判断模型是否想要调用工具 - 用
tool.invoke(toolCall)执行工具,返回ToolMessage - 把
[HumanMessage, AIMessage(tool_calls), ToolMessage]喂回模型拿最终答案 - 这是单轮演示,agent 会多轮循环这个过程
源码
typescript
import "dotenv/config";
import { ChatOpenAI } from "@langchain/openai";
import { tool } from "@langchain/core/tools";
import { HumanMessage } from "@langchain/core/messages";
import { z } from "zod";
if (!process.env.ZHIPUAI_API_KEY) {
throw new Error("ZHIPUAI_API_KEY is not set in environment variables");
}
// 复用 01-tools 的天气工具定义
const weatherTool = tool(
async ({ city, unit }) => {
const weatherData: Record<string, { temp: number; condition: string }> = {
"北京": { temp: 25, condition: "晴天" },
"上海": { temp: 22, condition: "多云" },
"广州": { temp: 28, condition: "小雨" },
};
const data = weatherData[city] || { temp: 20, condition: "未知" };
const temp = unit === "fahrenheit" ? Math.round(data.temp * 9/5 + 32) : data.temp;
return `${city} 的天气: ${data.condition},${temp}°${unit === "celsius" ? "C" : "F"}`;
},
{
name: "get_current_weather",
description: "获取指定城市的当前天气",
schema: z.object({
city: z.string().describe("城市名称"),
unit: z.enum(["celsius", "fahrenheit"]).default("celsius").describe("温度单位"),
}),
}
);
async function main() {
try {
console.log("=== Tool Calling 示例(单轮)===\n");
console.log("注意:这是单轮工具调用演示,展示 agent 底层机制。");
console.log("真正的 agent(多轮工具调用循环)见 03-react-agent.ts\n");
const model = new ChatOpenAI({
model: "deepseek-v3-1",
temperature: 0,
configuration: {
baseURL: "https://ark.cn-beijing.volces.com/api/coding/v3/",
apiKey: process.env.ZHIPUAI_API_KEY,
},
}).bindTools([weatherTool]);
const question = "北京今天天气怎么样?用华氏度告诉我温度。";
console.log("问题:", question);
console.log("\n---\n");
// 第一步:调用模型,看它是否要调工具
const response1 = await model.invoke([new HumanMessage(question)]);
console.log("模型响应(含 tool_calls):", response1.content);
console.log("tool_calls:", response1.tool_calls);
console.log("\n---\n");
if (response1.tool_calls && response1.tool_calls.length > 0) {
const toolCall = response1.tool_calls[0];
console.log(`调用工具: ${toolCall.name}`);
console.log(`参数:`, toolCall.args);
console.log("\n---\n");
// 第二步:执行工具,拿到 ToolMessage
const toolResult = await weatherTool.invoke(toolCall);
console.log("工具结果:", toolResult);
console.log("\n---\n");
// 第三步:把工具结果喂回模型,拿最终答案
const response2 = await model.invoke([
new HumanMessage(question),
response1, // AIMessage with tool_calls
toolResult, // ToolMessage
]);
console.log("最终回答:", response2.content);
} else {
console.log("模型未发起工具调用,直接回答:", response1.content);
}
} catch (error) {
console.error("Error during tool calling example:", error);
process.exit(1);
}
}
main().catch(console.error);运行方式
bash
npm run dev src/05-agents/02-tool-calling.ts