环境、依赖与密钥管理

本节目标

在 Windows 11 与 PowerShell 7 中建立隔离环境,理解依赖固定与密钥边界,不把真实凭据写进代码、笔记或日志。

先用 venv + pip

$lab = Join-Path $HOME "projects\llm-api-lab"  # 选择 vault 外的练习目录,避免把环境和缓存纳入知识库。
New-Item -ItemType Directory -Path $lab -Force | Out-Null  # 若目录不存在则创建,并隐藏无关输出。
Set-Location $lab  # 切换到练习目录,让 .venv 只属于这个实验项目。
py -3.11 -m venv .venv  # 用课程基线 Python 创建隔离虚拟环境。
.\.venv\Scripts\Activate.ps1  # 激活环境,使后续 python 与 pip 指向 .venv。
python -m pip install --upgrade pip  # 升级环境内的安装器,减少旧解析器导致的依赖问题。

这里刻意把实验目录放在 vault 外,避免提交 .venv、缓存或 SDK 产物。根据供应商当前官方 Python SDK 文档安装对应包,并把实际验证版本写入锁文件。团队不应只写无上限的 openai、anthropic 或 google-genai:SDK 的方法、默认 endpoint、事件类型与重试行为都可能变化。升级前至少回归 adapter、结构化输出、流式事件、错误映射与续接 payload。熟悉 venv + pip 后可评估 uv 等工具,但它们不改变隔离、锁定和验证原则。

本库 Provider 合同项目当前固定的是以下审阅基线,不是要求所有项目永远停在这些版本:

ProviderPyPI 包常用凭据入口本库固定 SDK 基线
OpenAIopenaiOPENAI_API_KEYopenai-python 2.46.0
AnthropicanthropicANTHROPIC_API_KEYanthropic-python 0.117.0
Google Geminigoogle-genaiGEMINI_API_KEY 或 GOOGLE_API_KEYgoogle-genai 2.12.1

Google SDK 在两者都存在时优先读取 GOOGLE_API_KEY。不要同时设置两个不同值再靠隐式优先级运行;选择一个、记录来源并在启动时校验。三组 SDK 版本已于 2026-07-21 对照各自官方 release 重新核验,但安装到真实项目后仍应以该项目锁文件和回归结果为准。

密钥只从安全边界进入

当前 PowerShell 会话可使用占位值演示:

$env:LLM_API_KEY = "replace-with-a-local-secret"  # 仅为当前会话设置占位变量;真实密钥必须来自受控 secret manager。

Python 只检查变量是否存在,不打印值:

import os  # 导入标准库以读取运行环境中的密钥变量。
 
api_key = os.environ.get("LLM_API_KEY")  # 读取变量但不打印其值,避免日志泄露。
if not api_key:  # 在真正发起任何请求前确认运行时已注入凭据。
    raise RuntimeError("LLM_API_KEY is not configured")  # 缺少凭据时失败关闭,而不是继续匿名或使用错误默认值。

生产环境使用平台的 secret manager,并为开发、测试、生产使用不同凭据与最小权限。浏览器、移动端和公开桌面应用不能直接携带供应商长期密钥,应通过受控后端或短期、受限凭据访问。不要将密钥作为 URL 查询参数,不要放进 .env.example、异常文本、截图、Notebook 输出或完整 HTTP 日志。若使用本地 .env,它必须被忽略;示例文件只能写变量名和占位符。

环境变量只解决“如何传入”,不自动解决权限、轮换和泄露。密钥应限制到需要的项目/环境,设置轮换和吊销流程;发现密钥进入 Git 历史后,应停止继续使用并按组织流程轮换,不能只补 .gitignore。

认证方式也属于动态能力,不要把 API key 当成永恒唯一方案。OpenAI 官方 Python SDK 2.46.0 已支持通过 workload_identity 使用短期工作负载身份,并给出 Kubernetes service-account token、Azure managed identity 与 Google Cloud ID token provider;Anthropic 当前认证文档也同时给出 API key 与 Workload Identity Federation(WIF)。两家的参数、身份提供方配置与组织授权并不通用,必须按锁定的 SDK 和平台文档接入;在受支持的托管环境中,短期工作负载身份可减少长期密钥分发。

Google 当前正把 Gemini API 迁移到 Auth key 体系。截至 2026-07-21,新建 key 默认已是 Auth key,Gemini API 已拒绝 unrestricted Standard keys;带显式限制的 Standard keys 暂时仍可工作。但官方明确说明从 2026 年 9 月起将拒绝所有 Standard keys,因此受限 Standard keys 也必须在此前迁移为 Auth keys。上线前仍需复核控制台状态和最新迁移文档,不应把这一时间点硬编码成长期假设。

配置分层

  • 非秘密配置:供应商标识、逻辑模型别名、超时、最大尝试次数,可进入版本控制。
  • 秘密:API key、临时令牌,只来自环境或密钥服务。
  • 动态限制:价格、速率、模型可用性,从官方文档或管理 API核对,不散落在代码常量里。

启动时验证配置,日志仅报告字段是否存在和使用的非秘密配置 ID。

启动与退出也要受控

在应用启动阶段创建 client,在进程或 worker 退出时显式关闭;不要为每个请求新建一套连接池,也不要依赖解释器退出替你释放流和 socket。三家当前 Python SDK 都提供同步/异步 client 生命周期接口,但具体名字与上下文管理器用法应以锁定版本为准。测试中用 fake transport 或局部 client;生产中把 client 生命周期交给应用容器,并确保取消中的 stream 也会退出上下文。

密钥存在性检查应发生在真正需要该 Provider 的启动路径。离线单元测试、文档构建和 fixture 验证不应因为没有生产密钥而失败;live 集成测试则必须用显式开关与独立低权限凭据门控。

练习与自测

创建一个新 venv,写脚本只检查 LLM_API_KEY 是否配置并输出布尔值。关闭终端后确认会话级环境变量不再存在。自测:你的错误追踪系统会自动收集环境变量或请求头吗?若会,应如何过滤?

掌握检查

  • 虚拟环境位于 vault 外,依赖版本可复现且升级前有回归测试。
  • 密钥只来自环境或 secret manager,代码、.env.example、日志和截图中没有真实值。
  • 开发、测试和生产凭据隔离,并有最小权限、轮换与吊销流程。
  • 启动失败只报告缺少哪个配置,不回显凭据或认证头。
  • Provider client 复用连接池并在退出时关闭;取消流不会遗留连接或后台任务。
  • 离线测试不读取密钥,live 测试由显式开关和独立凭据门控。
  • 我先掌握 venv + pip,再引入 uv 等工具,并保留相同安全边界。

下一步

进入 HTTP、SDK 与请求生命周期。

参考资料