Open ai接口协议
https://mp.weixin.qq.com/s/smt8VjtHI53-MWGuijagwQ
虽然这个库的名字叫 openai,但在 AI Agent 开发圈子里,它更像是一个 “万能遥控器”。因为 DeepSeek、Moonshot(Kimi)、阿里通义千问等大多数模型厂商,都主动适配了这个库的格式。
核心概念:Client(客户端)
使用这个库的第一步,永远是实例化一个 Client。这就好比你拿起电话,准备拨号。
from openai import OpenAI
# 初始化客户端
client = OpenAI(
# 1. api_key: 你的身份通行证
api_key="sk-...",
# 2. base_url: AI LLM服务器地址
# 如果不填,默认发送给 OpenAI 美国官网
# 如果填了 DeepSeek 的地址,就发送给 DeepSeek
base_url="https://api.deepseek.com"
)
核心方法:chat.completions.create
这是 Agent 开发中最常用的方法。它的字面意思是:“基于对话历史,创建一个补全(回复)”。
- 基础代码结构:
response = client.chat.completions.create(
model="deepseek-chat", # 用哪颗大脑
messages=[...], # 对话上下文
temperature=0.7, # 创造力调节
max_tokens=1000, # 字数限制
response_format={"type": "text"} # 输出格式;也可以是 "json_object"
)
print(response.choices[0].message.content)
- 参数解析 (Parameters)
System prompt和user prompt
理解 System Prompt(系统提示词)和 User Prompt(用户提示词)的区别,就像理解 “人设”和“台词” 的区别一样重要。
在 OpenAI/DeepSeek 的 API 调用中,它们是 messages 列表里两个不同的角色 (role)。
System Prompt (系统提示词):上帝视角/出厂设置。它定义了 AI “是谁”、“怎么说话”、“必须遵守什么规则”。它是静态的,通常由 开发者(你) 写死在代码里。
User Prompt (用户提示词):具体任务/外界输入。它告诉 AI “现在要做什么”。它是动态的,通常来自最终用户的输入。(变量)
核心对象:messages (对话列表)
这是大模型的“短期记忆”。你传给它什么,它就记得什么。
messages = [
# 第一条通常是 System,定基调
{"role": "system", "content": "你是一个严肃的数学老师。"},
# 历史对话(可选):如果你想让它记得刚才说过的话,要把历史记录手动塞进来
{"role": "user", "content": "1+1等于几?"},
{"role": "assistant", "content": "等于2。"},
# 当前问题
{"role": "user", "content": "那2+2呢?"}
]
这里不展开,后面的章节会详细讲述这个字段,它太核心了。
tools调用
tool定义
# 定义一个简单的“查天气”工具描述
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "获取指定城市的当前天气情况",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "城市名,例如:北京, 上海",
},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["location"],
},
},
}
]
询问大模型
第一次调用:提供tools并获取tools调用决定
from openai import OpenAI
import json
client = OpenAI(api_key="your-api-key")
messages = [{"role": "user", "content": "帮我看看上海现在的天气怎么样?"}]
# 第一次请求
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=tools,
tool_choice="auto" # 自动决定是否使用工具
)
response_message = response.choices[0].message
tool_calls = response_message.tool_calls
# 检查模型是否想调用工具
if tool_calls:
print(f"模型想要调用工具: {tool_calls[0].function.name}")
第二次调用:回传执行结果
这是 Agent 逻辑中最容易出错的地方:你必须把模型返回的 response_message 原样放回上下文,再追加一条 role: tool 的消息。
if tool_calls:
# 1. 把模型刚才生成的那个包含 tool_calls 的消息加入历史(非常重要!)
messages.append(response_message)
# 2. 模拟本地执行函数(在 Java 中可能是调一个 Service 或 DAO)
for tool_call in tool_calls:
function_args = json.loads(tool_call.function.arguments)
# 假设我们执行了本地逻辑
observation = {"location": "上海", "temperature": "22", "unit": "celsius", "description": "多云"}
# 3. 把执行结果放入消息列表
messages.append({
"tool_call_id": tool_call.id, # 必须对应上面的 ID
"role": "tool",
"name": "get_current_weather",
"content": json.dumps(observation),
})
# 4. 发起第二次请求,让模型总结结果
second_response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
)
print(second_response.choices[0].message.content)
格式化输出
底层约束 (response_format)
这一层能保证是 JSON,但不保证字段。
这是 API 服务端的一个**“强力开关”**。
以 deepseek 为例,你可以查看文档:https://api-docs.deepseek.com/zh-cn/guides/json_mode。

只要在请求API服务时给出限制参数:
response_format={"type": "json_object"}
-
• 它的作用:它在模型生成的底层(概率分布层面)强行干预。它像一个严苛的**“语法警察”**,按住了 AI 的手。
-
• 效果:开启后,模型吐出的第一个字符必须是 {,最后一个字符必须是 }。它物理上杜绝了 AI 说“好的,结果如下...”这类废话的可能性。
-
• 局限性:它只保证输出的是合法的 JSON 语法(括号配对、逗号正确),但不保证里面的字段是你想要的。它可能输出 {"hello": "world"},而你想要的是 {"price": 10}
json schema(字段、类型定义)--pydantic
核心返回值:Response Object
{
"id": "chatcmpl-123", // 此次请求的唯一标识符
"object": "chat.completion", // 对象类型,始终为 chat.completion
"created": 1677652288, // Unix 时间戳(秒)
"model": "gpt-4o-2024-05-13", // 实际使用的模型版本
"system_fingerprint": "fp_44706d4fc2", // 模型运行的后端配置指纹(用于排查复现问题)
"choices": [ // 核心内容数组(通常只有一个元素)
{
"index": 0,
"message": { // 模型生成的对话消息
"role": "assistant",
"content": "你好!有什么我可以帮你的?",
"tool_calls": null // 如果触发了函数调用,这里会有具体参数
},
"logprobs": null, // 词元生成的对数概率(需在请求中开启)
"finish_reason": "stop" // 中止原因:stop(自然结束), length(达到最大token), tool_calls(触发工具)
}
],
"usage": { // Token 消耗统计
"prompt_tokens": 9, // 输入提示词占用的 token
"completion_tokens": 12, // 模型生成的 token
"total_tokens": 21, // 总计(计费依据)
"completion_tokens_details": { // 详细消耗(如推理模型会有 reasoning_tokens)
"reasoning_tokens": 0
}
}
}