大模型Function Calling的函数如何调用的?
在真实开发中,大模型的 Function Calling(函数调用)不是“模型直接执行代码”,而是一套“声明-生成-解析-执行-反馈”的安全闭环机制。以下是我在项目中(如智能编程助手、自动化运维 Agent)的实际做法:
一、核心流程(生产级标准做法)
二、具体步骤
1. 注册函数
在调用 LLM 前,向模型描述有哪些函数可用(OpenAI 格式为例):
const tools = [{
type: "function",
function: {
name: "read_file",
description: "读取项目中的文件内容",
parameters: {
type: "object",
properties: {
path: { type: "string", description: "文件相对路径,如 src/main.ts" }
},
required: ["path"]
}
}
}];
关键:参数必须有明确 schema,防止模型传非法值。
2. 调用 LLM 并启用工具
const response = await openai.chat.completions.create({
model: "gpt-4o",
messages: [...],
tools, // ← 注册的函数列表
tool_choice: "auto" // 模型可自主决定是否调用
});
3. 解析模型返回
模型不会执行函数,而是返回结构化调用请求:
{
"tool_calls": [
{
"id": "call_abc123",
"function": {
"name": "read_file",
"arguments": "{"path":"src/utils.ts"}"
}
}
]
}
4. 安全执行函数
- 绝不直接 eval!而是通过白名单映射:
const toolMap = {
read_file: (args) => {
// 1. 校验路径是否在项目目录内
if (!args.path.startsWith("src/")) throw new Error("Access denied");
// 2. 读取文件(沙箱隔离)
return fs.readFileSync(args.path, "utf8");
}
};
const result = await toolMap[funcName](parsedArgs);
- 所有操作在受限环境中执行(如 Docker 沙箱、只读文件系统)。
5. 将结果反馈给模型
把函数执行结果作为“tool message”送回对话:
messages.push({
role: "tool",
tool_call_id: "call_abc123",
content: result // 文件内容
});
→ 模型基于此生成下一步(继续调用 or 最终回答)。
三、真实项目中的关键实践
| 问题 | 解决方案 |
|---|---|
| 模型传错参数(如 path: "../../../etc/passwd") | 参数校验 + 路径归一化 + 白名单目录 |
| 函数执行超时/卡死 | 设置 timeout(如 5s) + AbortController |
| 敏感操作(如删文件) | 禁止高危函数,或需用户二次确认 |
| 多次调用循环 | 限制最大 tool_calls 次数(如 5 次) |
| 调试困难 | 记录完整 trace:prompt → tool_call → result → final answer |
四、为什么不用模型直接“写代码执行”?
- 安全风险极高(任意代码执行 = RCE 漏洞);
- 不可控(无法限流、审计、降级);
- 不可靠(模型可能生成语法错误代码)。
正确做法:Function Calling 是“受控 API 调用”,不是“代码生成执行” 。
总结:
在实际项目中,大模型的 Function Calling 是一个安全代理机制:
- 我们先向模型声明可用函数及其参数 schema;
- 模型返回结构化调用请求(非执行);
- 后端严格校验参数、权限、路径,在沙箱中执行真实函数;
- 将结果反馈给模型,形成多轮推理闭环。
核心原则:模型只负责“决策”,不负责“执行” ——这是生产系统安全落地的底线。
海云前端丨前端开发丨简历面试辅导丨求职陪跑