手写一个 Function Call——从 API 调用来
手写一个 Function Call——从 API 调用来
上一篇讲了 Function Call 的概念,这一篇直接上手。我们用 DeepSeek 的 API 完整走一遍:定义函数 → 让 AI 决定调用 → 执行函数 → 把结果喂回给 AI。
目标:写一段代码,让 AI 能通过调用天气函数来回答"北京今天热吗?"这类问题。
2.1 准备工作
装好 Node.js(v18+),建个目录初始化项目:
mkdir function-call-demo
cd function-call-demo
npm init -y
npm install openai
DeepSeek 的 API 兼容 OpenAI 的格式,所以我们直接安装 openai 这个 npm 包,改一下 baseURL 和 apiKey 就能用openai 。
2.2 第一步:定义函数
我们先写一个假的天气函数,模拟返回数据:
// index.js
export function getWeather(city) {
const data = {
"北京": { temperature: 28, condition: "晴", humidity: 45 },
"上海": { temperature: 25, condition: "阴", humidity: 70 },
"深圳": { temperature: 30, condition: "多云", humidity: 80 },
"广州": { temperature: 32, condition: "阵雨", humidity: 85 },
};
return data[city] || { temperature: 20, condition: "未知", humidity: 50 };
}
真实场景下这里调的是天气 API,现在先用假数据跑通流程。
2.3 第二步:告诉 AI 有哪些函数可用
AI 不知道你有 getWeather 这个函数。你需要用 tools 参数告诉它——函数叫什么、干什么用、参数长什么样。
// index.js
import OpenAI from "openai";
export function getWeather(city) {
const data = {
"北京": { temperature: 28, condition: "晴", humidity: 45 },
"上海": { temperature: 25, condition: "阴", humidity: 70 },
"深圳": { temperature: 30, condition: "多云", humidity: 80 },
"广州": { temperature: 32, condition: "阵雨", humidity: 85 },
};
return data[city] || { temperature: 20, condition: "未知", humidity: 50 };
}
const openai = new OpenAI({ // DeepSeek 的 API 兼容 OpenAI 的格式
baseURL: "https://api.deepseek.com",
apiKey: "sk-your-deepseek-key", // need to update your api-key
});
// 描述函数,告诉 AI "你有这些工具可以用"
const tools = [
{
type: "function",
function: {
name: "get_weather",
description: "查询指定城市的实时天气",
parameters: {
type: "object",
properties: {
city: {
type: "string",
description: "城市名称,如 北京、上海",
},
},
required: ["city"],
},
},
},
];
这个结构就是 AI 的"菜单"——它知道有个 get_weather 函数,需要传入 city 参数。
2.4 第三步:发消息,拿指令
把用户问题 + 函数定义一起发给 AI:
const messages = [
{ role: "user", content: "北京今天热吗?" },
];
const response = await openai.chat.completions.create({
model: "deepseek-v4-flash",
messages, // 用户问题
tools, // 函数定义
});
const choice = response.choices[0];
如果 AI 认为需要调用函数,choice.finish_reason 会是 "tool_calls",然后 choice.message.tool_calls 里就是调用指令:
const toolCall = choice.message.tool_calls?.[0];
if (toolCall) {
console.log("AI 想调用:", toolCall.function.name);
console.log("参数:", toolCall.function.arguments);
// 输出: AI 想调用: get_weather
// 输出: 参数: {"city":"北京"}
}
tool_calls 是一个数组,因为 AI 可能一次想调多个函数(比如同时查北京和上海的天气)。
2.5 第四步:执行函数
拿到函数名和参数后,你自己去执行:
if (toolCall) {
const { name, arguments: argsStr } = toolCall.function;
const args = JSON.parse(argsStr);
let result;
if (name === "get_weather") {
result = getWeather(args.city);
}
console.log("执行结果:", result);
}
注意:这里是你自己的代码在执行函数。AI 只告诉你要调什么,调不调、怎么调还是你说了算。
提示:这些步骤其实已经有对应的 sdk 实现了,如可以用 Vercel 的
aisdk。
2.6 第五步:把结果送回 AI
函数执行完了,把结果作为一条新消息发给 AI,让它组织成自然语言回答:
// 把 AI 之前的回复加入对话
messages.push(choice.message);
// 把函数执行结果加入对话
messages.push({
role: "tool",
tool_call_id: toolCall.id,
content: JSON.stringify(result),
});
// 再问一次 AI
const secondResponse = await openai.chat.completions.create({
model: "deepseek-v4-flash",
messages,
});
console.log("AI:", secondResponse.choices[0].message.content);
// 输出: 北京今天 28°C,天气晴朗,有点热,建议穿短袖或薄衬衫。
2.7 完整代码
把上面几段拼起来,index.js 完整内容:
import OpenAI from "openai";
function getWeather(city) {
const data = {
北京: { temperature: 28, condition: "晴", humidity: 45 },
上海: { temperature: 25, condition: "阴", humidity: 70 },
深圳: { temperature: 30, condition: "多云", humidity: 80 },
};
return data[city] || { temperature: 20, condition: "未知", humidity: 50 };
}
const openai = new OpenAI({
baseURL: "https://api.deepseek.com",
apiKey: "sk-your-deepseek-key",
});
const tools = [
{
type: "function",
function: {
name: "get_weather",
description: "查询指定城市的实时天气",
parameters: {
type: "object",
properties: {
city: { type: "string", description: "城市名称,如 北京" },
},
required: ["city"],
},
},
},
];
async function main() {
const messages = [{ role: "user", content: "北京今天热吗?" }];
// 第一轮:AI 决定调用函数
const response = await openai.chat.completions.create({
model: "deepseek-v4-flash",
messages,
tools,
});
const choice = response.choices[0];
const toolCall = choice.message.tool_calls?.[0];
if (!toolCall) {
console.log("AI 不需要调用函数:", choice.message.content);
return;
}
console.log("→ 调用函数:", toolCall.function.name);
const args = JSON.parse(toolCall.function.arguments);
// 执行函数
const result = getWeather(args.city);
console.log("→ 执行结果:", JSON.stringify(result));
// 第二轮:把结果送回 AI
messages.push(choice.message);
messages.push({
role: "tool",
tool_call_id: toolCall.id,
content: JSON.stringify(result),
});
const secondResponse = await openai.chat.completions.create({
model: "deepseek-v4-flash",
messages,
});
// 打印 AI 最终的回答
console.log("\n🤖 AI:", secondResponse.choices[0].message.content);
}
main().catch(console.error);
2.8 跑起来
node index.js
输出:
→ 调用函数: get_weather
→ 执行结果: {"temperature":28,"condition":"晴","humidity":45}
🤖 AI: 北京今天 28°C,天气晴朗。整体来说不算特别热,但中午会有点晒,建议穿短袖或薄衬衫,注意防晒。
整个过程你写的代码只做了一件事:当中间人。用户 → AI → 你的代码 → 函数 → 你的代码 → AI → 用户。
提示:如果 整个过程 用到 loop 的话,那么这个就是一个会思考和自主干活的 Agent 了。
2.9 如果 AI 想同时调多个函数?
有时 AI 会一次请求调用多个函数。比如用户问"北京和上海的天气怎么样?"。
tool_calls 会是一个数组:
const toolCalls = choice.message.tool_calls;
// 遍历执行每个函数
const results = toolCalls.map((call) => {
const args = JSON.parse(call.function.arguments);
if (call.function.name === "get_weather") {
return getWeather(args.city);
}
// TODO ...
});
// 把每个结果都加进对话
for (let i = 0; i < toolCalls.length; i++) {
messages.push({
role: "tool",
tool_call_id: toolCalls[i].id,
content: JSON.stringify(results[i]),
});
}
核心逻辑不变:拿到指令 → 自己执行 → 送回结果,只是多了个循环。
2.10 小结
这一篇你做了这些事:
- 用 tools 参数 告诉 AI 有哪些函数可用
- AI 返回 tool_calls 告诉你"调这个函数,传这些参数"
- 你自己执行函数,控制权在你手里
- 把结果作为 role: “tool” 的消息送回 AI
- AI 结合结果生成自然语言回答
上一篇:[Function Call 是什么?——让 AI 学会"干活"
更多推荐


所有评论(0)