调用AI模型API时,Python开发者常遇到SSLCertVerificationError,典型报错为certificate verify failed: unable to get local issuer certificate。这并非API本身故障,而是TLS握手阶段客户端无法验证服务端证书链。本文从原因到方案,梳理可落地的排查与修复路径。

一、常见原因

1. 系统证书链缺失
Python的requests默认使用certifi包提供的CA证书集,而非操作系统证书库。若certifi版本过旧,或运行环境(如精简版Docker镜像、部分Linux发行版)未安装ca-certificates,就会因缺少根证书或中间证书而验证失败。

2. 企业代理或中间人证书
国内不少企业通过代理网关审计出站流量。代理会用自己的根证书动态签发目标站点证书。Python默认不信任该企业根证书,于是报错。此时浏览器可能正常,因为浏览器已信任企业根证书。

3. 自签名证书
内部AI网关或私有化部署的模型服务使用自签名证书,客户端未将其加入信任列表。

4. 环境变量干扰
REQUESTS_CA_BUNDLE、SSL_CERT_FILE、CURL_CA_BUNDLE等环境变量若指向错误路径或过期文件,会覆盖默认证书配置。

二、工程解决方法

1. 更新certifi证书

最直接的修复是升级certifi:

pip install --upgrade certifi

验证当前使用的证书路径:

import certifi
print(certifi.where())

若输出路径不存在或文件过旧,可手动下载最新CA包替换。此方案适合开发环境快速验证,生产环境应通过依赖锁定确保版本一致。

2. 指定CA证书路径

若企业代理提供了根证书(如corp-root.crt),可将其与certifi的CA包合并,或直接指定:

import requests

resp = requests.get(
    "https://api.example.com/v1/chat/completions",  # api.example.com 为占位符
    verify="/path/to/corp-ca-bundle.pem"
)

对于openai SDK(v1.x 基于 httpx),应通过 http_client 传入配置了 verify 的 httpx.Client:

import httpx
import openai

http_client = httpx.Client(verify="/path/to/corp-ca-bundle.pem")
client = openai.OpenAI(
    base_url="https://api.example.com/v1",  # 占位符
    http_client=http_client
)

注意:openai SDK 的 http_client 参数需要 httpx.Client 或 httpx.AsyncClient,传入 requests.Session 会导致类型不匹配。

也可设置环境变量,让不同库读取对应变量:

export REQUESTS_CA_BUNDLE=/path/to/corp-ca-bundle.pem   # 仅对 requests 生效
export SSL_CERT_FILE=/path/to/corp-ca-bundle.pem        # 对 httpx、OpenSSL 等生效

REQUESTS_CA_BUNDLE 仅被 requests 识别;openai(httpx)主要读取 SSL_CERT_FILE,或通过 http_client 显式配置。SSL_CERT_FILE 影响范围更广,可能干扰其他依赖 OpenSSL 的程序,建议根据实际依赖选择。

3. 代理场景下的证书处理

若通过HTTP代理访问,需同时配置代理和证书:

proxies = {
    "https": "http://proxy.corp.com:8080"
}
resp = requests.get(url, proxies=proxies, verify="/path/to/corp-ca-bundle.pem")

若代理使用自签名证书且无法获取根证书,可临时关闭验证(仅限调试):

resp = requests.get(url, verify=False)

这会触发InsecureRequestWarning,且在生产环境等同于放弃中间人攻击防护,不应作为长期方案。

4. 合并证书链

当需要同时信任公共CA和企业CA时,可将企业根证书追加到certifi的CA包:

cat /path/to/corp-root.crt >> $(python -c "import certifi; print(certifi.where())")

但直接修改certifi包内文件会在升级时丢失,推荐复制一份合并后的bundle,通过verify或环境变量指向它。

三、方案适用性对比

方案 开发环境 生产环境 说明
升级certifi 适合 适合 需锁定版本,定期更新
verify指定路径 适合 适合 需管理证书文件生命周期
环境变量 适合 谨慎 影响全局,可能干扰其他服务
verify=False 仅调试 禁止 丧失TLS安全性
合并证书链 适合 适合 需自动化构建bundle

四、排查建议

遇到SSL错误时,按以下顺序排查:

  1. 用openssl s_client -connect api.example.com:443 -showcerts查看服务端证书链是否完整。
  2. 检查certifi.where()指向的文件是否存在、是否包含目标根证书。
  3. 检查环境变量REQUESTS_CA_BUNDLE、SSL_CERT_FILE是否被意外设置。
  4. 若使用代理,确认代理根证书已加入信任链。
  5. 在容器环境中,确认基础镜像已安装ca-certificates并更新。

生产环境应避免verify=False,而是通过配置管理将企业CA证书注入到应用信任库中。对于Kubernetes环境,可将CA证书挂载为Secret,并通过环境变量或verify参数引用。

总之,SSL证书错误的核心是信任链不完整。理解requests与openai SDK的证书加载机制,结合企业网络实际,选择可维护的证书管理方案,才能兼顾安全与可用性。