一个模型调用示例要能被再次运行,需要同时固定 Python 版本、依赖解析结果和 API 参数。本文使用 Python 3.12、uv 项目模式和 OpenAI Python SDK,连接提供 Chat Completions 接口的服务。
创建可重复安装的项目
按 uv 安装说明安装工具后执行:
uv --version
uv init --python 3.12 learnlm
cd learnlm
uv add openai
uv sync --lockedpyproject.toml 声明依赖,uv.lock 保存解析结果,.python-version 记录解释器选择,.venv 存放本地环境。将前三个文件提交到版本管理,忽略 .venv 和凭据文件。重新取回项目后使用 uv sync --locked,可以发现声明与锁文件不一致的问题。uv 项目文档说明了这些文件及同步行为。
uv pip install 适合直接管理环境中的包;持续维护的项目用 uv add 更新依赖声明,再用锁文件同步。激活环境仅改变当前 shell 的命令查找路径,uv run 可直接使用项目环境。
从环境变量读取连接参数
设置 OPENAI_API_KEY 和 OPENAI_MODEL。自建兼容服务还需设置 OPENAI_BASE_URL,例如本机服务的 http://127.0.0.1:8000/v1。模型 ID 从服务端可用模型清单取得,不能根据 SDK 名称猜测。
在项目目录创建 demo.py:
import os
from openai import OpenAI
options = {
"api_key": os.environ["OPENAI_API_KEY"],
"timeout": 30.0,
"max_retries": 0,
}
if os.environ.get("OPENAI_BASE_URL"):
options["base_url"] = os.environ["OPENAI_BASE_URL"]
with OpenAI(**options) as client:
stream = client.chat.completions.create(
model=os.environ["OPENAI_MODEL"],
messages=[{"role": "user", "content": "用两句话解释 HTTP 缓存。"}],
stream=True,
)
with stream:
for chunk in stream:
if chunk.choices:
content = chunk.choices[0].delta.content
if content:
print(content, end="", flush=True)
print()运行 uv run demo.py。示例只显示公开返回的文本,跳过无 choices 或无文本的事件。调试时关闭自动重试,有助于识别第一次请求失败;正式应用需按接口幂等性、费用和超时预算设计重试。流式返回的事件粒度和模型 Token 数量应分别统计,详见流式响应说明。
按错误所在层排查
| 现象 | 首先检查 | 验证方式 |
|---|---|---|
| 缺少模块 | 命令使用的解释器和项目目录 | uv run python -c "import sys; print(sys.executable)" |
| 401/403 | 凭据、项目权限、目标服务 | 检查服务端响应与请求 ID,日志隐藏密钥 |
| 404 | 基础地址、接口路径、模型 ID | 对照服务端 API 文档和模型清单 |
| 超时 | 连接建立、排队、生成阶段 | 分别记录连接错误、首段等待和总耗时 |
| 第三方参数被拒绝 | 服务支持的参数集合 | 从最小请求逐项增加参数 |
兼容接口的路径相同,仍可能在模型参数、错误结构或工具调用上存在差异。将成功调用的服务版本、模型 ID 和锁文件一起记录,后续升级时复跑同一个最小请求。
← 返回文章