1. 什么是 OpenAI? #

OpenAI Python库是官方提供的 Python 工具包,用于与 OpenAI 的各种 AI 服务进行交互。通过这个库,你可以轻松地在 Python 程序中使用 ChatGPT、图像生成、语音识别等强大的 AI 功能。

2. 调用Completions #

本节你将学到:

调用时序概览:

sequenceDiagram actor User as 用户 participant App as main.py participant SDK as OpenAI SDK participant API as DeepSeek API User->>App: 运行 python main.py App->>App: 读取环境变量<br/>OPENAI_API_KEY / BASE_URL / MODEL App->>SDK: OpenAI(api_key, base_url) SDK-->>App: 返回 client 实例 App->>SDK: chat.completions.create(<br/>model, messages) SDK->>API: POST /v1/chat/completions<br/>Authorization: Bearer {api_key} Note over SDK,API: 请求体包含 model 与 messages 数组 API->>API: 模型推理生成回复 API-->>SDK: 200 OK + JSON 响应<br/>choices[0].message.content SDK-->>App: ChatCompletion 对象 App->>User: print(回复内容)

2.1 安装 #

uv add openai

2.2 main.py #

# 导入操作系统相关的os模块
import os

# 从openai模块中导入OpenAI类
from openai import OpenAI

# 创建OpenAI客户端对象,并设置API密钥和基础URL(支持从环境变量读取,否则使用默认值)
client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY", "sk-6dac9405d2c74a8f9a5b921b80ebb0f2"),
    base_url=os.getenv("OPENAI_BASE_URL", "https://api.deepseek.com/v1"),
)

# 使用OpenAI客户端创建一次聊天补全请求,指定模型和用户消息内容
result = client.chat.completions.create(
    model=os.getenv("OPENAI_MODEL", "deepseek-v4-pro"),
    messages=[{"role": "user", "content": "你是谁?"}],
)

# 打印聊天补全结果的第一条回复的消息内容
print(result.choices[0].message.content)

2.3 ChatCompletion #

2.3.1 ChatCompletion #

# 调用ChatCompletion对象
ChatCompletion(
    # 指定唯一标识符
    id='ae232a31-d7f9-44fc-ab3c-c8dd8b33e0a2',
    # 指定choices参数,为一个列表,包含Choice对象
    choices=[
        # 创建一个Choice对象
        Choice(
            # 生成结束的原因是‘stop’
            finish_reason='stop',
            # 当前choice的索引为0
            index=0,
            # 没有提供logprobs
            logprobs=None,
            # message为ChatCompletionMessage对象
            message=ChatCompletionMessage(
                # 回答内容是“The answer is 2.”
                content='The answer is 2.',
                # 没有拒答内容
                refusal=None,
                # 角色是‘assistant’
                role='assistant',
                # 没有注释
                annotations=None,
                # 没有音频内容
                audio=None,
                # 没有函数调用
                function_call=None,
                # 没有工具调用
                tool_calls=None,
                # 推理过程的详细内容
                reasoning_content='We are asked: "1+1=?" This is a simple arithmetic question. The answer is 2. But we need to provide the response as the AI assistant. The user likely expects just "2". But we should output it in a proper format. The instruction: "You are an AI assistant. Help the user with their query." So I\'ll answer concisely.'
            )
        )
    ],
    # 创建时间的时间戳
    created=1781092901,
    # 模型名称
    model='deepseek-v4-pro',
    # 对象类型
    object='chat.completion',
    # 没有内容监管信息
    moderation=None,
    # 没有指定服务等级
    service_tier=None,
    # 系统指纹
    system_fingerprint='fp_9954b31ca7_prod0820_fp8_kvcache_20260402',
    # usage参数,描述本次调用的token用量
    usage=CompletionUsage(
        # 完成回答消耗的token数
        completion_tokens=85,
        # 提示语占用的token数
        prompt_tokens=8,
        # 总token数
        total_tokens=93,
        # 完成token的详细信息
        completion_tokens_details=CompletionTokensDetails(
            # 被接受的预测token数量
            accepted_prediction_tokens=None,
            # 音频相关token数量
            audio_tokens=None,
            # 推理过程所用的token数
            reasoning_tokens=78,
            # 被拒绝的预测token数量
            rejected_prediction_tokens=None
        ),
        # 提示token的详细信息
        prompt_tokens_details=PromptTokensDetails(
            # 音频相关token
            audio_tokens=None,
            # 缓存的token数量
            cached_tokens=0
        ),
        # 提示缓存命中token数量
        prompt_cache_hit_tokens=0,
        # 提示缓存未命中token数量
        prompt_cache_miss_tokens=8
    )
)

2.3.2 ChatCompletion #

字段 类型 示例值 详细说明
id str ae232a31-d7f9-... 本次聊天补全请求的唯一 ID,用于日志追踪、问题排查、对账;每次调用都会不同。
choices list[Choice] [Choice(...)] 模型生成的候选回复列表。n=1 时通常只有 1 条;n>1 时会返回多个不同回复。日常取 choices[0] 即可。
created int 1781092901 响应创建的 Unix 时间戳(秒)。可用 datetime.fromtimestamp(created) 转成可读时间。
model str deepseek-v4-pro 实际处理请求的模型名称,可能与请求参数一致,也可能是服务端解析后的具体版本。
object str chat.completion 对象类型标识,聊天补全固定为 chat.completion,用于区分 embeddings、images 等其他 API 响应。
moderation object None None 内容审核相关信息。部分平台返回违规检测结果;无审核时为 None。
service_tier str None None 服务等级(如 default、scale)。影响优先级和计费,OpenAI 部分场景可见,DeepSeek 常为 None。
system_fingerprint str fp_9954b31ca7_... 系统指纹,标识后端模型/基础设施版本。同样输入可能因指纹变化产生细微差异,可用于复现与调试。
usage CompletionUsage 见下文 本次请求的 Token 用量统计,与计费直接相关。

2.3.3 Choice #

字段 类型 示例值 详细说明
index int 0 当前候选在 choices 列表中的下标,与列表位置一致。
finish_reason str stop 模型停止生成的原因,常见取值见下表。
logprobs object None None 对数概率信息。请求时设 logprobs=True 才会返回每个 token 的概率,用于分析置信度;默认 None。
message ChatCompletionMessage 见下文 模型返回的消息体,包含角色、正文及扩展信息(函数调用、推理内容等)。

2.3.4 finish_reason #

值 含义
stop 模型自然结束,或遇到停止词,正常完成。
length 达到 max_tokens 上限被截断,回复可能不完整。
content_filter 触发内容安全策略,部分内容被过滤。
tool_calls 模型选择调用工具/函数,需解析 tool_calls 继续处理。

2.3.5 ChatCompletionMessage #

字段 类型 示例值 详细说明
role str assistant 消息角色。补全响应中固定为 assistant(对应请求里的 user / system)。
content str The answer is 2. 最终回复正文,即展示给用户的主要内容;多轮对话时将此条追加到 messages。
refusal str None None 拒答说明。模型因安全策略拒绝回答时,可能在此说明原因;正常回复为 None。
annotations list None None 引用注释(如联网搜索、文件引用的来源标注)。未启用相关能力时为 None 或 []。
audio object None None 音频输出(语音模型)。文本对话中为 None。
function_call object None None 旧版函数调用(已弃用),由 tool_calls 取代;未启用时为 None。
tool_calls list None None 工具/函数调用列表。启用 Function Calling 时,模型可能不填 content,而在此返回要调用的函数及参数。
reasoning_content str We are asked: "1+1=?"... 推理过程内容(DeepSeek 等推理模型扩展)。模型「思考链」,不一定展示给用户;计费可能计入 reasoning_tokens。

2.3.6 CompletionUsage #

字段 类型 示例值 详细说明
prompt_tokens int 8 输入侧消耗的 token 数,包括 system + user 等全部历史消息。
completion_tokens int 85 输出侧消耗的 token 数,包括 content 和推理内容等生成部分。
total_tokens int 93 总 token 数,通常满足 prompt_tokens + completion_tokens(部分平台统计方式略有差异)。
completion_tokens_details object 见下文 输出 token 的细分统计。
prompt_tokens_details object 见下文 输入 token 的细分统计。
prompt_cache_hit_tokens int 0 缓存命中的 prompt token 数(DeepSeek 等扩展)。命中缓存可降本提速。
prompt_cache_miss_tokens int 8 缓存未命中的 prompt token 数,需完整计算。

2.3.7 CompletionTokensDetails #

字段 类型 示例值 详细说明
reasoning_tokens int 78 推理 token 数(推理模型)。思考过程占用,不一定出现在 content 中,但可能计费。
accepted_prediction_tokens int None None 预测 token 被接受的数量(预测性输出优化相关),一般场景为 None。
rejected_prediction_tokens int None None 预测 token 被拒绝的数量,一般场景为 None。
audio_tokens int None None 输出中音频部分的 token 数;纯文本对话为 None。

2.3.8 PromptTokensDetails #

字段 类型 示例值 详细说明
cached_tokens int 0 输入中走缓存的 token 数,命中后通常更便宜。
audio_tokens int None None 输入中音频部分的 token 数;纯文本为 None。

2.3.9 字段层级关系 #

ChatCompletion
├── id
├── created
├── model
├── object
├── moderation
├── service_tier
├── system_fingerprint
├── choices[]
│   └── Choice
│       ├── index
│       ├── finish_reason
│       ├── logprobs
│       └── message
│           ├── role
│           ├── content          ← 最常用:最终回复
│           ├── refusal
│           ├── annotations
│           ├── audio
│           ├── function_call
│           ├── tool_calls
│           └── reasoning_content ← 推理模型扩展
└── usage
    ├── prompt_tokens
    ├── completion_tokens
    ├── total_tokens
    ├── prompt_cache_hit_tokens
    ├── prompt_cache_miss_tokens
    ├── completion_tokens_details
    │   ├── reasoning_tokens
    │   ├── accepted_prediction_tokens
    │   ├── rejected_prediction_tokens
    │   └── audio_tokens
    └── prompt_tokens_details
        ├── cached_tokens
        └── audio_tokens

3. 实现Completions #

本节你将学到:

模块结构:

openai_lite/
├── __init__.py          # 对外导出 OpenAI
├── _constants.py        # 默认配置、URL/Header 构建
├── client.py            # HTTP 客户端核心
├── resources/chat/      # Chat Completions 资源层
│   ├── __init__.py      # Chat 类
│   └── completions.py   # create() 方法
└── types/               # 响应数据模型
    ├── __init__.py
    └── chat.py          # ChatCompletion / Choice / Message

调用时序概览:

sequenceDiagram actor User as 用户 participant App as main.py participant Client as OpenAI<br/>(client.py) participant Comp as Completions<br/>(completions.py) participant HTTP as httpx participant API as DeepSeek API User->>App: 运行 python main.py App->>Client: OpenAI(api_key, base_url) Client->>Client: 初始化 Chat 资源<br/>self.chat = Chat(self) Client-->>App: 返回 client 实例 App->>Comp: client.chat.completions.create(<br/>model, messages) Comp->>Comp: 构造 payload<br/>{model, messages, ...} Comp->>Client: post("/chat/completions", json=payload) Client->>Client: build_url + build_headers Client->>HTTP: httpx.request(POST, url, headers, json) HTTP->>API: POST /v1/chat/completions API-->>HTTP: JSON 响应 HTTP-->>Client: Response 对象 Client-->>Comp: Response 对象 Comp->>Comp: ChatCompletion.model_validate(<br/>response.json()) Comp-->>App: ChatCompletion 对象 App->>User: print(choices[0].message.content)

3.1 init.py #

openai_lite/init.py

from .client import OpenAI
__all__ = [
    "OpenAI"
]

3.2 _constants.py #

openai_lite/_constants.py

# 默认的OpenAI API基地址
DEFAULT_BASE_URL = "https://api.openai.com/v1"
# 默认超时时间为60秒
DEFAULT_TIMEOUT = 60.0
# 聊天补全接口的路径
CHAT_COMPLETIONS_PATH = "/chat/completions"
# 构建HTTP请求头的函数,传入API密钥,返回字典
def build_headers(api_key: str) -> dict[str, str]:
    # 返回一个包含授权和内容类型的请求头字典
    return {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    }


# 构建完整的请求URL的函数,传入基地址和路径
def build_url(base_url: str, path: str) -> str:
    # 如果路径没以斜杠开头,则补上斜杠
    if not path.startswith("/"):
        path = f"/{path}"
    # 返回拼接后的完整URL
    return f"{base_url}{path}"

3.3 client.py #

openai_lite/client.py

# 导入httpx库,用于发起HTTP请求
import httpx
# 从._constants模块中导入默认基础URL、默认超时时间、请求头和URL构建方法
from ._constants import DEFAULT_BASE_URL,DEFAULT_TIMEOUT,build_headers,build_url
# 从resources目录的chat模块导入Chat类
from .resources.chat import Chat

# 定义OpenAI类
class OpenAI:
    # 初始化方法,设置API key、基础URL、超时时间
    def __init__(
        self,
        *,
        api_key: str,
        base_url: str = DEFAULT_BASE_URL,
        timeout: float = DEFAULT_TIMEOUT,
    ):
        # 保存API Key
        self.api_key = api_key
        # 移除基础URL右侧的斜杠并保存
        self.base_url = base_url.rstrip("/")
        # 保存超时时间
        self.timeout = timeout
        # 创建Chat类实例并保存
        self.chat = Chat(self)
    # 内部请求方法
    def _request(self, method: str, path: str, *, json: dict | None = None):
        # 使用httpx发起HTTP请求
        response = httpx.request(
            method,
            # 构造完整的请求URL
            build_url(self.base_url, path),
            # 构造请求头
            headers=build_headers(self.api_key),
            # 请求体(JSON格式)
            json=json,
            # 请求超时时间
            timeout=self.timeout,
        )
        # 返回HTTP响应
        return response    
    # POST请求方法
    def post(self, path: str, *, json: dict | None = None):
        # 调用_request方法发起POST请求
        return self._request("POST", path, json=json)

3.4 init.py #

openai_lite/resources/chat/init.py

# 从当前文件夹导入Completions类
from .completions import Completions

# 定义一个Chat类
class Chat:
    # 定义构造函数,接收一个client参数
    def __init__(self, client):
        # 创建Completions实例并赋值给self.completions属性
        self.completions = Completions(client)

3.5 completions.py #

openai_lite/resources/chat/completions.py

# 从项目的_constants模块导入CHAT_COMPLETIONS_PATH常量
from ..._constants import CHAT_COMPLETIONS_PATH
# 从openai.types.chat模块导入ChatCompletion类
from openai.types.chat import ChatCompletion
# 定义Completions类
class Completions():
    # 初始化方法,接收client对象
    def __init__(self, client):
        # 从client对象中获取post方法并赋值给实例变量_post
        self._post = client.post
    # 定义create方法,用于创建聊天补全
    def create(
        self,
        *,
        model,
        messages,
        **kwargs,
    ):
        # 构造请求负载,包括模型名、消息列表及其它可选参数
        payload = {"model": model, "messages": messages, **kwargs}
        # 发送POST请求到CHAT_COMPLETIONS_PATH,并传递payload作为json参数
        response = self._post(CHAT_COMPLETIONS_PATH, json=payload)
        # 对响应的json数据进行模型验证,并返回ChatCompletion对象
        return ChatCompletion.model_validate(response.json())

3.6 init.py #

openai_lite/types/init.py

from openai.types.chat import (
    ChatCompletion,
)

__all__ = [
    "ChatCompletion"
]

3.7 chat.py #

openai_lite/types/chat.py

# 导入Pydantic的BaseModel用于数据模型的定义
from pydantic import BaseModel
# 定义消息(Message)类,继承自BaseModel
class Message(BaseModel):
    # role字段,表示消息的角色(如user、assistant)
    role: str
    # content字段,表示消息内容,可以为None
    content: str | None = None

# 定义选择(Choice)类,继承自BaseModel
class Choice(BaseModel):
    # index字段,表示选择的索引
    index: int
    # message字段,表示对应的Message对象
    message: Message
    # finish_reason字段,表示完成的原因,可以为None
    finish_reason: str | None = None

# 定义聊天完成(ChatCompletion)类,继承自BaseModel
class ChatCompletion(BaseModel):
    # id字段,表示聊天完成对象的唯一标识符
    id: str
    # model字段,表示使用的模型
    model: str
    # choices字段,表示Choice对象的列表
    choices: list[Choice]

3.8 main.py #

main.py

# 导入操作系统相关的os模块
import os

# 从openai_lite模块中导入OpenAI类
+from openai_lite import OpenAI

# 创建OpenAI客户端对象,并设置API密钥和基础URL(支持从环境变量读取,否则使用默认值)
client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY", "sk-6dac9405d2c74a8f9a5b921b80ebb0f2"),
    base_url=os.getenv("OPENAI_BASE_URL", "https://api.deepseek.com/v1"),
)

# 使用OpenAI客户端创建一次聊天补全请求,指定模型和用户消息内容
result = client.chat.completions.create(
    model=os.getenv("OPENAI_MODEL", "deepseek-v4-pro"),
    messages=[{"role": "user", "content": "你是谁?"}],
)

# 打印聊天补全结果的第一条回复的消息内容
print(result.choices[0].message.content)

4. 流式响应 #

本节你将学到:

SSE 数据格式示例:

data: {"id":"...","choices":[{"index":0,"delta":{"content":"你"}}]}

data: {"id":"...","choices":[{"index":0,"delta":{"content":"好"}}]}

data: [DONE]

调用时序概览:

sequenceDiagram actor User as 用户 participant App as main.py participant Comp as Completions<br/>(completions.py) participant Client as OpenAI<br/>(client.py) participant HTTP as httpx.stream participant API as DeepSeek API User->>App: 运行 python main.py App->>Comp: create(model, messages, stream=True) Comp->>Comp: payload 追加 stream: true Comp->>Client: post_stream("/chat/completions", body) Client->>HTTP: httpx.stream(POST, url, json=body) HTTP->>API: POST /v1/chat/completions<br/>stream=true loop 逐行读取 SSE API-->>HTTP: data: {"choices":[{"delta":{"content":"..."}}]} HTTP-->>Client: iter_lines() 返回一行 Client->>Client: _parse_sse_line(line)<br/>去除 "data: " 前缀 alt 非 data 行 Client->>Client: 跳过 else data: [DONE] Client->>Client: break 结束流 else 有效 JSON 块 Client->>Client: ChatCompletionChunk.model_validate() Client-->>App: yield chunk App->>App: 提取 choices[0].delta.content App->>User: print(content, end="", flush=True) end end

4.1 main.py #

main.py

# 导入操作系统相关的os模块
import os

# 从openai_lite模块中导入OpenAI类
from openai_lite import OpenAI

# 创建OpenAI客户端对象,并设置API密钥和基础URL(支持从环境变量读取,否则使用默认值)
client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY", "sk-6dac9405d2c74a8f9a5b921b80ebb0f2"),
    base_url=os.getenv("OPENAI_BASE_URL", "https://api.deepseek.com/v1"),
)

# 使用OpenAI客户端创建一次聊天补全请求,指定模型和用户消息内容
+stream  = client.chat.completions.create(
    model=os.getenv("OPENAI_MODEL", "deepseek-v4-pro"),
    messages=[{"role": "user", "content": "你是谁?"}],
+   stream=True,
)

# 遍历流式返回的每一个chunk
+for chunk in stream:
   # 如果chunk中没有choices则跳过本次循环
+  if not chunk.choices:
+      continue
   # 获取第一个choice中的delta的content内容
+  content = chunk.choices[0].delta.content
   # 如果content有内容,则打印,不换行,立即输出
+  if content:
+      print(content, end="", flush=True)

4.2 client.py #

openai_lite/client.py

# 导入httpx库,用于发起HTTP请求
import httpx
# 导入json库,用于解析JSON数据
+import json
# 从._constants模块中导入默认基础URL、默认超时时间、请求头和URL构建方法
from ._constants import DEFAULT_BASE_URL,DEFAULT_TIMEOUT,build_headers,build_url
# 从resources目录的chat模块导入Chat类
from .resources.chat import Chat
# 从.types.chat模块导入ChatCompletionChunk类
+from .types.chat import ChatCompletionChunk
# 定义SSE前缀为"data: "
+_SSE_PREFIX = "data: "
# 定义解析SSE行的函数
+def _parse_sse_line(line):
    # 如果行为空或不是以_SSE_PREFIX开头
+   if not line or not line.startswith(_SSE_PREFIX):
        # 返回None
+       return None
    # 去除前缀后获取数据,并去除首尾空白符
+   data = line[len(_SSE_PREFIX) :].strip()
    # 如果数据等于"[DONE]",返回空字符串,否则返回数据本身
+   return "" if data == "[DONE]" else data
# 定义OpenAI类
class OpenAI:
    # 初始化方法,设置API key、基础URL、超时时间
    def __init__(
        self,
        *,
        api_key: str,
        base_url: str = DEFAULT_BASE_URL,
        timeout: float = DEFAULT_TIMEOUT,
    ):
        # 保存API Key
        self.api_key = api_key
        # 移除基础URL右侧的斜杠并保存
        self.base_url = base_url.rstrip("/")
        # 保存超时时间
        self.timeout = timeout
        # 创建Chat类实例并保存
        self.chat = Chat(self)
    # 内部请求方法
    def _request(self, method: str, path: str, *, json: dict | None = None):
        # 使用httpx发起HTTP请求
        response = httpx.request(
            method,
            # 构造完整的请求URL
            build_url(self.base_url, path),
            # 构造请求头
            headers=build_headers(self.api_key),
            # 请求体(JSON格式)
            json=json,
            # 请求超时时间
            timeout=self.timeout,
        )
        # 返回HTTP响应
        return response    
    # POST请求方法
    def post(self, path: str, *, json: dict | None = None):
        # 调用_request方法发起POST请求
        return self._request("POST", path, json=json)
    # 定义post_stream方法,用于以流式方式发送POST请求
+   def post_stream(self, path, *, body=None):
        # 定义内部生成器函数iter_chunks,用于逐块处理响应数据
+       def iter_chunks():
            # 使用httpx.stream方法以流式发送POST请求
+           with httpx.stream(
+               "POST",  # 请求方法为POST
+               build_url(self.base_url, path),  # 构造完整的请求URL
+               headers=build_headers(self.api_key),  # 设置请求头部,包括API KEY等信息
+               json=body,  # 以JSON格式发送请求体
+               timeout=self.timeout,  # 超时时间配置
+           ) as response:  # 使用with自动关闭响应资源
                # 迭代响应体的每一行数据
+               for line in response.iter_lines():
                    # 解析每一行的SSE(Server Sent Event)数据
+                   data = _parse_sse_line(line)
                    # 如果解析结果为None,说明该行不是以指定前缀开头,跳过
+                   if data is None:
+                       continue
                    # 如果解析结果为空字符串,说明是流的结束标记,退出循环
+                   if data == "":
+                       break
                    # 将解析出的json字符串转对象,并验证其格式,作为块数据产出
+                   yield ChatCompletionChunk.model_validate(json.loads(data))
        # 返回迭代器对象,实现流式数据处理
+       return iter_chunks()

4.3 completions.py #

openai_lite/resources/chat/completions.py

# 从项目的_constants模块导入CHAT_COMPLETIONS_PATH常量
from ..._constants import CHAT_COMPLETIONS_PATH
# 从openai.types.chat模块导入ChatCompletion类
from openai.types.chat import ChatCompletion
# 定义Completions类
class Completions():
    # 初始化方法,接收client对象
    def __init__(self, client):
        # 从client对象中获取post方法并赋值给实例变量_post
        self._post = client.post
        # 从client对象中获取post_stream方法并赋值给实例变量_post_stream
+       self._post_stream = client.post_stream
    # 定义create方法,用于创建聊天补全
    def create(
+       self,#self表示当前实例
+       *, # 表示可选参数
+       model,#模型名称
+       stream=False,#是否流式返回,默认不流式返回
+       messages,#消息列表,必选参数
+       **kwargs,#其他可选参数,如temperature、max_tokens等
    ):
        # 构造请求负载,包括模型名、消息列表及其它可选参数
        payload = {"model": model, "messages": messages, **kwargs}
        # 如果stream为真,说明需要以流式方式获取聊天补全
+       if stream:
            # 调用_post_stream方法,向CHAT_COMPLETIONS_PATH发送包含stream=True的payload,实现流式响应
+           return self._post_stream(CHAT_COMPLETIONS_PATH, body={**payload, "stream": True})
        # 发送POST请求到CHAT_COMPLETIONS_PATH,并传递payload作为json参数
        response = self._post(CHAT_COMPLETIONS_PATH, json=payload)
        # 对响应的json数据进行模型验证,并返回ChatCompletion对象
        return ChatCompletion.model_validate(response.json())

4.4 chat.py #

openai_lite/types/chat.py

# 导入Pydantic的BaseModel用于数据模型的定义
from pydantic import BaseModel

# 定义消息(Message)类,继承自BaseModel
class Message(BaseModel):
    # role字段,表示消息的角色(如user、assistant)
    role: str
    # content字段,表示消息内容,可以为None
    content: str | None = None

# 定义选择(Choice)类,继承自BaseModel
class Choice(BaseModel):
    # index字段,表示选择的索引
    index: int
    # message字段,表示对应的Message对象
    message: Message
    # finish_reason字段,表示完成的原因,可以为None
    finish_reason: str | None = None

# 定义聊天完成(ChatCompletion)类,继承自BaseModel
class ChatCompletion(BaseModel):
    # id字段,表示聊天完成对象的唯一标识符
    id: str
    # model字段,表示使用的模型
    model: str
    # choices字段,表示Choice对象的列表
    choices: list[Choice]

# 定义ChoiceDelta类,继承自BaseModel,用于描述消息变更(delta)的结构
+class ChoiceDelta(BaseModel):
    # role字段,表示当前delta的角色信息,可以为None
+   role: str | None = None
    # content字段,表示当前delta的内容,可以为None
+   content: str | None = None

# 定义ChunkChoice类,继承自BaseModel,用于描述stream时每个选择的内容
+class ChunkChoice(BaseModel):
    # index字段,表示当前选择的索引
+   index: int
    # delta字段,类型为ChoiceDelta,表示此选择的增量内容
+   delta: ChoiceDelta
    # finish_reason字段,表示结束的原因,可以为None
+   finish_reason: str | None = None

# 定义ChatCompletionChunk类,继承自BaseModel,表示拆分的聊天完成片段
+class ChatCompletionChunk(BaseModel):
    # id字段,表示本次请求的唯一ID,可以为None
+   id: str | None = None
    # model字段,表示使用的模型名称,可以为None
+   model: str | None = None
    # choices字段,包含ChunkChoice对象的列表,默认是空列表
+   choices: list[ChunkChoice] = []  

5. 推理模式 #

本节你将学到:

delta 双字段示例:

# 思考阶段
data: {"choices":[{"delta":{"reasoning_content":"先比较整数部分...","content":null}}]}

# 回答阶段
data: {"choices":[{"delta":{"reasoning_content":null,"content":"9.11 更大"}}]}

调用时序概览:

sequenceDiagram actor User as 用户 participant App as main.py participant Comp as Completions participant Client as OpenAI<br/>(client.py) participant API as DeepSeek API User->>App: 运行 python main.py App->>Comp: create(model, messages, stream=True) Comp->>Client: post_stream("/chat/completions") Client->>API: POST /v1/chat/completions Note over App: phase = None loop 思考阶段 (reasoning) API-->>App: chunk.delta.reasoning_content = "..." App->>App: phase != "reasoning"<br/>→ 打印【思考过程】<br/>→ phase = "reasoning" App->>User: print(reasoning, end="", flush=True) end App->>App: phase 切换:reasoning → content<br/>打印换行 loop 回答阶段 (content) API-->>App: chunk.delta.content = "..." App->>App: phase != "content"<br/>→ 打印【回答】<br/>→ phase = "content" App->>User: print(content, end="", flush=True) end App->>User: print() 换行结束

5.1 main.py #

main.py

# 导入操作系统相关的os模块
import os

# 从openai_lite模块中导入OpenAI类
from openai_lite import OpenAI

# 创建OpenAI客户端对象,并设置API密钥和基础URL(支持从环境变量读取,否则使用默认值)
client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY", "sk-6dac9405d2c74a8f9a5b921b80ebb0f2"),
    base_url=os.getenv("OPENAI_BASE_URL", "https://api.deepseek.com/v1"),
)

# 使用OpenAI客户端创建一次聊天补全请求,指定模型和用户消息内容
stream  = client.chat.completions.create(
    model=os.getenv("OPENAI_MODEL", "deepseek-v4-pro"),
+   messages=[{"role": "user", "content": "9.11 和 9.8 哪个更大?请简要说明。"}],
    stream=True,
)
+phase = None  # "reasoning" | "content"
for chunk in stream:
+   delta = getattr(chunk.choices[0], 'delta', None) if getattr(chunk, 'choices', None) else None
+   if not delta:
+       continue
+   reasoning = getattr(delta, 'reasoning_content', None)
+   content = getattr(delta, 'content', None)
+   if reasoning:
+       if phase != "reasoning":
+           print("【思考过程】", end="", flush=True)
+           phase = "reasoning"
+       print(reasoning, end="", flush=True)
+   elif content:
+       if phase != "content":
+           if phase is not None:
+               print()
+           print("【回答】", end="", flush=True)
+           phase = "content"
+       print(content, end="", flush=True)
+print()

5.2 chat.py #

openai_lite/types/chat.py

# 导入Pydantic的BaseModel用于数据模型的定义
from pydantic import BaseModel

# 定义消息(Message)类,继承自BaseModel
class Message(BaseModel):
    # role字段,表示消息的角色(如user、assistant)
    role: str
    # content字段,表示消息内容,可以为None
    content: str | None = None

# 定义选择(Choice)类,继承自BaseModel
class Choice(BaseModel):
    # index字段,表示选择的索引
    index: int
    # message字段,表示对应的Message对象
    message: Message
    # finish_reason字段,表示完成的原因,可以为None
    finish_reason: str | None = None

# 定义聊天完成(ChatCompletion)类,继承自BaseModel
class ChatCompletion(BaseModel):
    # id字段,表示聊天完成对象的唯一标识符
    id: str
    # model字段,表示使用的模型
    model: str
    # choices字段,表示Choice对象的列表
    choices: list[Choice]

# 定义ChoiceDelta类,继承自BaseModel,用于描述消息变更(delta)的结构
class ChoiceDelta(BaseModel):
    # role字段,表示当前delta的角色信息,可以为None
    role: str | None = None
    # content字段,表示当前delta的内容,可以为None
    content: str | None = None
    # reasoning_content字段,表示推理相关内容,可以为None
+   reasoning_content: str | None = None

# 定义ChunkChoice类,继承自BaseModel,用于描述stream时每个选择的内容
class ChunkChoice(BaseModel):
    # index字段,表示当前选择的索引
    index: int
    # delta字段,类型为ChoiceDelta,表示此选择的增量内容
    delta: ChoiceDelta
    # finish_reason字段,表示结束的原因,可以为None
    finish_reason: str | None = None

# 定义ChatCompletionChunk类,继承自BaseModel,表示拆分的聊天完成片段
class ChatCompletionChunk(BaseModel):
    # id字段,表示本次请求的唯一ID,可以为None
    id: str | None = None
    # model字段,表示使用的模型名称,可以为None
    model: str | None = None
    # choices字段,包含ChunkChoice对象的列表,默认是空列表
    choices: list[ChunkChoice] = []  

6. 工具调用 #

本节你将学到:

消息链示例:

[
  {"role": "user", "content": "北京今天天气怎么样?"},
  {"role": "assistant", "tool_calls": [{"id": "call_xxx", "type": "function", "function": {"name": "get_weather", "arguments": "{\"city\": \"北京\"}"}}]},
  {"role": "tool", "tool_call_id": "call_xxx", "content": "北京:晴,25°C,微风"}
]

调用时序概览:

sequenceDiagram actor User as 用户 participant App as main.py participant Comp as Completions participant Handler as TOOL_HANDLERS<br/>(get_weather) participant API as DeepSeek API User->>App: 运行 python main.py App->>Comp: create(messages, tools=TOOLS)<br/>第一次请求 Comp->>API: POST /v1/chat/completions<br/>{messages, tools} API-->>Comp: assistant + tool_calls<br/>finish_reason: tool_calls Comp-->>App: ChatCompletion App->>App: messages.append(assistant_message) loop 遍历 tool_calls App->>App: json.loads(arguments)<br/>解析 func_name / func_args App->>Handler: get_weather(city="北京") Handler-->>App: "北京:晴,25°C,微风" App->>App: messages.append(<br/>role=tool, tool_call_id, content) App->>User: 打印【工具调用】【工具结果】 end App->>Comp: create(messages, tools=TOOLS)<br/>第二次请求 Comp->>API: POST /v1/chat/completions<br/>完整消息链 API-->>Comp: assistant + content Comp-->>App: ChatCompletion App->>User: 打印【助手】最终回复

6.1 main.py #

main.py

# 导入json模块,用于处理JSON数据
+import json
# 导入os模块,用于与操作系统交互
import os
# 导入sys模块,用于访问系统特定的参数和函数
+import sys
# 从openai模块导入OpenAI类
from openai_lite import OpenAI

# 定义TOOLS工具列表
+TOOLS = [
+   {
        # 工具类型为函数
+       "type": "function",
        # 工具的详细信息
+       "function": {
            # 函数名称为get_weather
+           "name": "get_weather",
            # 函数功能描述
+           "description": "获取指定城市的当前天气",
            # 函数接受的参数定义
+           "parameters": {
                # 参数类型是对象
+               "type": "object",
                # 对象的属性定义
+               "properties": {
                    # 属性city,表示城市名称
+                   "city": {
                        # city的数据类型为字符串
+                       "type": "string",
                        # city的描述
+                       "description": "城市名称,如北京、上海",
+                   },
+               },
                # city字段为必需字段
+               "required": ["city"],
+           },
+       },
+   }
+]

# 定义获取天气的函数,输入城市名称,返回天气信息字符串
+def get_weather(city: str) -> str:
    # 返回格式化后的天气信息
+   return f"{city}:晴,25°C,微风"

# 定义工具处理器映射,将工具名映射到对应的实现函数
+TOOL_HANDLERS = {"get_weather": get_weather}

# 创建OpenAI客户端对象,设置API密钥和基础URL,支持从环境变量读取,否则使用默认值
client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY", "sk-6dac9405d2c74a8f9a5b921b80ebb0f2"),
    base_url=os.getenv("OPENAI_BASE_URL", "https://api.deepseek.com/v1"),
)

# 构造对话消息列表,初始只有用户的提问
+messages = [
    # 用户的提问内容
+   {"role": "user", "content": "北京今天天气怎么样?"},
+]
# 打印用户的提问内容到控制台
+print(f"【用户】{messages[0]['content']}")

# 向OpenAI API发起第一次聊天请求,模型会决定是否调用函数工具
+response = client.chat.completions.create(
    model=os.getenv("OPENAI_MODEL", "deepseek-v4-pro"),
+   messages=messages,
+   tools=TOOLS,
)
# 获取助手生成的回复消息
+assistant_message = response.choices[0].message

# 如果助手消息中tool_calls字段存在,说明模型请求调用工具
+if assistant_message.tool_calls:
    # 将助手消息转换为字典并添加到消息列表
+   messages.append(assistant_message.model_dump())
    # 遍历所有要调用的工具
+   for tool_call in assistant_message.tool_calls:
        # 获取函数名称
+       func_name = tool_call.function.name
        # 获取函数调用的参数,解析为Python字典
+       func_args = json.loads(tool_call.function.arguments)
        # 打印调用的工具名和参数
+       print(f"【工具调用】{func_name}({func_args})")

        # 根据函数名从TOOL_HANDLERS中获取实际处理函数
+       handler = TOOL_HANDLERS[func_name]
        # 调用实现函数并获得结果
+       result = handler(**func_args)
        # 打印工具调用结果
+       print(f"【工具结果】{result}")

        # 将工具调用结果以工具角色的消息追加到消息队列
+       messages.append(
+           {
                # 角色为tool
+               "role": "tool",
                # 工具调用唯一id
+               "tool_call_id": tool_call.id,
                # 工具执行的结果
+               "content": result,
+           }
+       )

    # 第二次请求OpenAI API,根据工具结果生成最终的助手回复
+   response = client.chat.completions.create(
+       model=os.getenv("OPENAI_MODEL", "deepseek-v4-pro"),
+       messages=messages,
+       tools=TOOLS,
+   )
    # 打印助手的最终回复内容
+   print(f"【助手】{response.choices[0].message.content}")
# 如果助手没有请求调用工具,直接输出助手回复内容
+else:
+   print(f"【助手】{assistant_message.content}")

6.2 completions.py #

openai_lite/resources/chat/completions.py

# 从项目的_constants模块导入CHAT_COMPLETIONS_PATH常量
from ..._constants import CHAT_COMPLETIONS_PATH
# 从openai.types.chat模块导入ChatCompletion类
from openai.types.chat import ChatCompletion
# 定义Completions类
class Completions():
    # 初始化方法,接收client对象
    def __init__(self, client):
        # 从client对象中获取post方法并赋值给实例变量_post
        self._post = client.post
        # 从client对象中获取post_stream方法并赋值给实例变量_post_stream
        self._post_stream = client.post_stream
    # 定义create方法,用于创建聊天补全
    def create(
        self,#self表示当前实例
        *, # 表示可选参数
        model,#模型名称
        stream=False,#是否流式返回,默认不流式返回
        messages,#消息列表,必选参数
+       tools,#工具列表,必选参数
        **kwargs,#其他可选参数,如temperature、max_tokens等
    ):
        # 构造请求负载,包括模型名、消息列表及其它可选参数
+       payload = {"model": model, "messages": messages, "tools": tools, **kwargs}
        # 如果stream为真,说明需要以流式方式获取聊天补全
        if stream:
            # 调用_post_stream方法,向CHAT_COMPLETIONS_PATH发送包含stream=True的payload,实现流式响应
            return self._post_stream(CHAT_COMPLETIONS_PATH, body={**payload, "stream": True})
        # 发送POST请求到CHAT_COMPLETIONS_PATH,并传递payload作为json参数
        response = self._post(CHAT_COMPLETIONS_PATH, json=payload)
        # 对响应的json数据进行模型验证,并返回ChatCompletion对象
        return ChatCompletion.model_validate(response.json())

6.3 chat.py #

openai_lite/types/chat.py

# 导入Pydantic的BaseModel用于数据模型的定义
from pydantic import BaseModel

# 定义函数(Function)类,继承自BaseModel
+class Function(BaseModel):
    # name字段,表示函数名称
+   name: str
    # arguments字段,表示函数参数
+   arguments: str
# 定义工具调用(ToolCall)类,继承自BaseModel
+class ToolCall(BaseModel):
    # id字段,表示工具调用的唯一标识符
+   id: str
    # type字段,表示工具类型
+   type: str = "function"
    # function字段,表示工具函数
+   function: Function
# 定义消息(Message)类,继承自BaseModel
class Message(BaseModel):
    # role字段,表示消息的角色(如user、assistant)
    role: str
    # content字段,表示消息内容,可以为None
    content: str | None = None
    # tool_calls字段,表示工具调用列表,可以为None
+   tool_calls: list[ToolCall] | None = None
    # tool_call_id字段,表示工具调用的唯一标识符
+   tool_call_id: str | None = None

# 定义选择(Choice)类,继承自BaseModel
class Choice(BaseModel):
    # index字段,表示选择的索引
    index: int
    # message字段,表示对应的Message对象
    message: Message
    # finish_reason字段,表示完成的原因,可以为None
    finish_reason: str | None = None

# 定义聊天完成(ChatCompletion)类,继承自BaseModel
class ChatCompletion(BaseModel):
    # id字段,表示聊天完成对象的唯一标识符
    id: str
    # model字段,表示使用的模型
    model: str
    # choices字段,表示Choice对象的列表
    choices: list[Choice]

# 定义ChoiceDelta类,继承自BaseModel,用于描述消息变更(delta)的结构
class ChoiceDelta(BaseModel):
    # role字段,表示当前delta的角色信息,可以为None
    role: str | None = None
    # content字段,表示当前delta的内容,可以为None
    content: str | None = None
    # reasoning_content字段,表示推理相关内容,可以为None
    reasoning_content: str | None = None

# 定义ChunkChoice类,继承自BaseModel,用于描述stream时每个选择的内容
class ChunkChoice(BaseModel):
    # index字段,表示当前选择的索引
    index: int
    # delta字段,类型为ChoiceDelta,表示此选择的增量内容
    delta: ChoiceDelta
    # finish_reason字段,表示结束的原因,可以为None
    finish_reason: str | None = None

# 定义ChatCompletionChunk类,继承自BaseModel,表示拆分的聊天完成片段
class ChatCompletionChunk(BaseModel):
    # id字段,表示本次请求的唯一ID,可以为None
    id: str | None = None
    # model字段,表示使用的模型名称,可以为None
    model: str | None = None
    # choices字段,包含ChunkChoice对象的列表,默认是空列表
    choices: list[ChunkChoice] = []