OpenAI Chat Completions 函数调用与安全接入
使用 Chat Completions 的 tools 结构,不要混用 Responses。本文说明字段布局、后续回合,以及 401 探测无法证明的能力边界。
Chat Completions 工具调用实际做了什么
模型不会替你执行代码。它只返回结构化的 tool_calls;应用需要校验参数、运行白名单函数,再回传 role: tool 消息。模型生成的参数必须按不可信输入处理。
| 步骤 | Chat Completions 字段 | 应用职责 |
|---|---|---|
| 1. 定义 | tools[].type = function 与 tools[].function | 只暴露允许调用的函数 |
| 2. 请求 | choices[0].message.tool_calls[] | 读取 id、function.name、function.arguments |
| 3. 执行 | 模型不会执行外部操作 | 鉴权、校验、执行并记录 |
| 4. 继续 | 追加 assistant 消息 + 匹配 tool_call_id 的 role: tool | 请求最终回答 |
先验证接口、Key 和模型
请求 GET /v1/models,再使用当前 Key 返回的准确模型 ID。2026 年 8 月 4 日,对 MonkeyAI 生产环境的探测结果如下:
- 未携带 Key 的
POST /v1/chat/completions(请求体含合法 tools)返回401 API_KEY_REQUIRED。 - 无效 Bearer 返回
401 INVALID_API_KEY。 - 未携带 Key 的
GET /v1/models返回401 API_KEY_REQUIRED。
这些结果只能证明路由和认证可达,不能证明某个模型支持 tools、strict 或并行调用。
curl -sS https://monkeytheme.com/v1/models \ -H "Authorization: Bearer ***"
发送最小 Chat Completions 工具定义
在 Chat Completions 中,函数字段位于 tools[].function 下。OpenAI OpenAPI 将该结构命名为 ChatCompletionTool。函数名最长 64 个字符,建议只使用字母、数字、下划线和短横线。
curl -sS https://monkeytheme.com/v1/chat/completions \
-H "Authorization: Bearer ***" \
-H "Content-Type: application/json" \
-d '{
"model": "MODEL_ID_FROM_LIST",
"messages": [
{"role": "user", "content": "What is the weather in Paris?"}
],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Return current weather for a city.",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"}
},
"required": ["city"],
"additionalProperties": false
}
}
}],
"tool_choice": "auto"
}'严格模式下,每个属性都要写入 required,且每个对象设置 additionalProperties: false。OpenAI 说明:Chat Completions 默认非 strict,需要显式设置 strict: true。
解析 tool_calls 并返回工具结果
当模型选择调用工具时,assistant 消息的 content 常常为空,finish_reason 多为 tool_calls,真正的调用在 message.tool_calls。先把该 assistant 消息追加进会话,再为每个 call ID 追加一条 tool 消息。
import json
from openai import OpenAI
client = OpenAI(
api_key="YOUR_KEY",
base_url="https://monkeytheme.com/v1",
)
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Return current weather for a city.",
"strict": True,
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
"additionalProperties": False,
},
},
}]
messages = [{"role": "user", "content": "What is the weather in Paris?"}]
first = client.chat.completions.create(
model="MODEL_ID_FROM_LIST",
messages=messages,
tools=tools,
tool_choice="auto",
)
assistant = first.choices[0].message
messages.append(assistant)
for call in assistant.tool_calls or []:
args = json.loads(call.function.arguments)
result = dispatch_approved_function(call.function.name, args)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result),
})
final = client.chat.completions.create(
model="MODEL_ID_FROM_LIST",
messages=messages,
tools=tools,
)
print(final.choices[0].message.content)dispatch_approved_function 是应用代码,不是 SDK 自带函数。OpenAI 也提醒:function.arguments 是 JSON 字符串,可能非法或编造 schema 外字段,执行前必须校验。
tool_choice 与 parallel_tool_calls
| 控制项 | Chat Completions 取值 | 效果 |
|---|---|---|
| 自动 | "tool_choice": "auto" | 有 tools 时的默认值:可调用零个、一个或多个 |
| 必须调用 | "tool_choice": "required" | 必须调用一个或多个工具 |
| 禁用 | "tool_choice": "none" | 不调用工具,只返回文本 |
| 指定函数 | {"type":"function","function":{"name":"get_weather"}} | 强制调用该函数 |
| 关闭并行 | "parallel_tool_calls": false | 本轮最多一个工具调用 |
不要把 Responses 的指定函数写法 {"type":"function","name":"..."} 直接用于 Chat Completions。Chat Completions 的名称必须嵌套在 function 下。
不要混用 Chat Completions 与 Responses 结构
| 项目 | Chat Completions | Responses |
|---|---|---|
| 接口 | /v1/chat/completions | /v1/responses |
| 函数定义 | tools[].function.{name,description,parameters,strict} | 函数字段直接位于 tools 项内 |
| 返回调用 | choices[0].message.tool_calls[] | output[] 中类型为 function_call 的项 |
| 关联字段 | tool 消息使用 tool_call_id | function_call_output 使用 call_id |
| 结果消息 | {"role":"tool", ...} | function_call_output 输入项 |
如果示例来自 Responses,先改 schema,再把 Base URL 指到 /v1/chat/completions。
给执行器加上安全边界
- 使用函数名白名单,禁止把模型给出的名称映射到任意代码。
- 解析 JSON 后再次执行服务端校验,并拒绝未知字段。
- 对每个资源 ID 检查当前用户权限。
- 破坏性操作或对外可见操作必须要求确认。
- 写操作使用幂等键,并按 tool call ID 保留审计记录。
- 返回内容应限制大小并移除敏感数据,不能把密钥送回模型上下文。
资料与相关教程
常见问题
模型会直接执行函数吗?
不会。模型只返回结构化 tool_calls。应用决定是否执行,并把 role: tool 结果传回模型。
收到 401 能证明工具调用可用吗?
不能。401 只能证明请求到达认证层。应使用真实 Key 和准确模型 ID 测试 tools。
Chat Completions 的函数字段写在哪里?
写在 tools[].function 下。不要像 Responses 那样把 name/description/parameters 直接放在 tools 项根级。
如何关联工具结果?
把 message.tool_calls[].id 复制到下一条 role: tool 消息的 tool_call_id。ID 缺失或不匹配会打断后续回合。
一条 assistant 消息会包含多个 tool_calls 吗?
会。除非把 parallel_tool_calls 设为 false,否则应按零个、一个或多个调用处理,并遍历每一个 call。