写给想让 AI 真正帮你做事的开发者,不讲废话,直接上干货
先说一个让人抓狂的场景
你有没有遇到过这种情况:
问 AI:"帮我查一下北京今天的天气。"
AI 一本正经地回答你:"北京今天天气晴,气温大约在 15-22 度之间......"
然后你一看,完全是编的。因为它根本没有联网,它只是在用训练数据里的"印象"给你瞎猜。
或者你问它:"帮我查一下我们数据库里,上个月销售额最高的产品是哪个?"
它说:"我没有访问您数据库的权限,无法回答这个问题。"
这就是大模型的另一个"硬伤":它只会说话,不会干活。
Function Calling 就是给大模型装上了"手"。
Function Calling 到底是什么?
你告诉 AI 有哪些工具可以用,AI 自己决定什么时候用哪个工具,然后告诉你怎么调用,你去执行,把结果再喂给 AI,AI 给你最终答案。
用一个比喻:
想象你有一个超级聪明的老板(AI),但他不会用电脑。你是他的助理(你的代码)。
老板说:"去查一下今天北京的天气。"
你去查了,把结果告诉他:"北京今天晴,22 度。"
老板说:"好,那告诉客户,今天适合户外活动。"
整个过程:老板负责思考和决策,你负责执行具体操作。
工作流程
scss
① 定义函数(工具)
↓
② 用户提问 + 函数定义 → 发给 AI
↓
③ AI 判断:要不要调用函数?调用哪个?传什么参数?
↓
④ AI 返回:getWeather({"city": "北京"})
↓
⑤ 代码执行 getWeather("北京")
↓
⑥ 结果返回给 AI
↓
⑦ AI 生成最终回答
完整代码示例(JavaScript)
第一步:定义你的函数
javascript
// 这是你真正要执行的函数
function getWeather(city) {
// 实际项目里这里调用真实天气 API
const weatherData = {
'北京': { temperature: 22, condition: '晴', humidity: 40 },
'上海': { temperature: 25, condition: '多云', humidity: 65 },
'广州': { temperature: 30, condition: '阵雨', humidity: 80 },
};
return weatherData[city] || { error: '城市不存在' };
}
function getStockPrice(symbol) {
const prices = {
'AAPL': { price: 175.5, change: '+1.2%' },
'TSLA': { price: 245.0, change: '-0.8%' },
};
return prices[symbol] || { error: '股票代码不存在' };
}
第二步:告诉 AI 有哪些工具可以用
matlab
const tools = [
{
type: 'function',
function: {
name: 'getWeather',
description: '获取指定城市的实时天气信息',
parameters: {
type: 'object',
properties: {
city: {
type: 'string',
description: '城市名称,例如:北京、上海、广州',
},
},
required: ['city'],
},
},
},
{
type: 'function',
function: {
name: 'getStockPrice',
description: '获取指定股票的实时价格',
parameters: {
type: 'object',
properties: {
symbol: {
type: 'string',
description: '股票代码,例如:AAPL、TSLA',
},
},
required: ['symbol'],
},
},
},
];
第三步:处理 AI 的决策
javascript
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
async function chatWithTools(userMessage) {
const messages = [{ role: 'user', content: userMessage }];
// 第一次请求:让 AI 决定要不要调用函数
const response = await client.chat.completions.create({
model: 'gpt-4o',
messages: messages,
tools: tools,
tool_choice: 'auto',
});
const message = response.choices[0].message;
// 如果 AI 决定要调用函数
if (message.tool_calls) {
console.log(`AI 决定调用函数:${message.tool_calls[0].function.name}`);
messages.push(message);
// 执行 AI 要求的函数
for (const toolCall of message.tool_calls) {
const funcName = toolCall.function.name;
const funcArgs = JSON.parse(toolCall.function.arguments);
let result;
if (funcName === 'getWeather') {
result = getWeather(funcArgs.city);
} else if (funcName === 'getStockPrice') {
result = getStockPrice(funcArgs.symbol);
}
console.log(`函数执行结果:${JSON.stringify(result)}`);
messages.push({
role: 'tool',
tool_call_id: toolCall.id,
content: JSON.stringify(result),
});
}
// 第二次请求:让 AI 基于函数结果生成最终回答
const finalResponse = await client.chat.completions.create({
model: 'gpt-4o',
messages: messages,
});
return finalResponse.choices[0].message.content;
}
return message.content;
}
// 测试
async function main() {
console.log(await chatWithTools('北京今天天气怎么样?'));
console.log(await chatWithTools('苹果公司股票现在多少钱?'));
console.log(await chatWithTools('你好,今天几号?'));
}
main();
运行结果:
erlang
AI 决定调用函数:getWeather
函数执行结果:{"temperature":22,"condition":"晴","humidity":40}
北京今天天气晴,气温 22 度,湿度 40%,是个不错的好天气!
AI 决定调用函数:getStockPrice
函数执行结果:{"price":175.5,"change":"+1.2%"}
苹果公司(AAPL)股票目前报价 175.5 美元,今日上涨 1.2%。
今天是 2025 年 X 月 X 日。(直接回答,不调用函数)
多函数并行调用
AI 可以同时决定调用多个函数,并行执行,效率翻倍。
ini
// 并行执行所有函数调用
const results = await Promise.all(
message.tool_calls.map(async (toolCall) => {
const funcName = toolCall.function.name;
const funcArgs = JSON.parse(toolCall.function.arguments);
if (funcName === 'getWeather') return getWeather(funcArgs.city);
if (funcName === 'getStockPrice') return getStockPrice(funcArgs.symbol);
})
);
能做什么?
🔍 数据查询类
- 查数据库(订单、库存、销售数据)
- 查实时信息(天气、股价、汇率)
- 搜索内部知识库
🛠️ 操作执行类
- 发送邮件、短信
- 创建日历事件
- 操作文件
- 调用第三方 API
🤖 Agent 自动化类
- 自动化工作流
- 代码执行
- 浏览器操作
四个容易踩的坑
坑 1:函数描述写得太烂
❌ 烂描述:
json
{ "name": "query", "description": "查询数据" }
✅ 好描述:
json
{
"name": "queryOrderStatus",
"description": "根据订单号查询订单状态,包括支付、发货、物流等。当用户询问订单进度时使用。",
"parameters": {
"properties": {
"order_id": {
"type": "string",
"description": "订单号,例如:ORD202501010001"
}
},
"required": ["order_id"]
}
}
原则:函数描述是给 AI 看的说明书,越详细越好。
坑 2:没处理 AI 不调用函数的情况
代码要同时处理两种情况:tool_calls 存在 和 不存在。
坑 3:函数执行出错没处理
vbnet
try {
return getWeather(city);
} catch (error) {
return { error: error.message, message: '获取天气失败,请稍后重试' };
}
坑 4:tool_choice 设置不当
"auto"--- AI 自己决定(推荐)"required"--- 强制调用(别乱用)- 强制指定某个函数 --- 按需使用
Function Calling vs RAG
| 对比项 | Function Calling | RAG |
|---|---|---|
| 解决的问题 | 执行操作、获取实时数据 | 基于知识库回答问题 |
| 数据来源 | 实时调用外部系统 | 预先建好的向量库 |
| 适合场景 | 查天气、操作数据库、发邮件 | 文档问答、企业知识库 |
| 实时性 | 强,每次最新 | 弱,需定期更新 |
两者经常结合使用:
- RAG → 回答产品知识问题
- Function Calling → 查询订单、处理退款
进阶:构建 Agent
Function Calling 的终极形态------自主完成复杂任务的 Agent。
你说:"帮我分析上个月销售数据,找出最佳产品,然后给销售团队发邮件。"
Agent 会这样工作:
scss
1. querySalesData(month="2025-02") → 获取数据
2. analyzeData(data) → 分析最佳产品
3. getTeamEmails(team="sales") → 获取邮箱
4. sendEmail(to, subject, body) → 发送邮件
5. 返回完成结果
整个过程 AI 自主决策,你只需定义好工具。
主流框架
- LangChain.js ---
@tool装饰器 - LlamaIndex --- 专注数据操作
- AutoGen --- 微软出品,多 Agent 协作
- CrewAI --- 角色扮演式多 Agent
- OpenAI Assistants API --- 官方封装
总结
AI 负责思考和决策,代码负责执行和操作,两者分工合作,AI 才能真正"干活"。
Function Calling 是构建实用 AI 应用的必备技能。
推荐学习路径:
- 用 OpenAI API 跑通天气查询示例
- 把项目里的接口包装成 Function
- 让 AI 自主完成多步操作任务
点个赞 👍 收藏一下,后续写 Agent 构建实战、多工具协作等!