一、问题背景
最近在内网环境部署 OpenManus 项目时,遇到了一个令人头疼的问题:即使已经正确配置了 tiktoken 的离线缓存,程序仍然会尝试从网络下载编码文件,导致连接超时异常。
二、错误现象
运行以下测试代码:
python
import tiktoken
enc = tiktoken.get_encoding("cl100k_base")
print(enc.encode("Hello"))
抛出如下异常:
text
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='openaipublic.blob.core.windows.net', port=443):
Max retries exceeded with url: /encodings/cl100k_base.tiktoken
(Caused by NameResolutionError("Failed to resolve 'openaipublic.blob.core.windows.net'"))
即使在环境变量中设置了离线模式和缓存路径:
bash
set TIKTOKEN_OFFLINE=1 set TIKTOKEN_CACHE_DIR=C:\Users\admin\.cache\tiktoken
问题依然存在。
三、环境信息
| 项目 | 信息 |
|---|---|
| tiktoken 版本 | 0.9.0 |
| Python 版本 | 3.12.13 |
| 操作系统 | Windows 10 / Ubuntu 22.04 |
| 安装方式 | pip install tiktoken |
四、问题分析
4.1 根本原因
通过分析调用栈发现,tiktoken 0.9.0 版本在加载编码文件时,即使本地缓存文件存在且环境变量已设置,仍然会优先尝试从网络下载。
调用链路如下:
text
tiktoken.get_encoding()
└── load_tiktoken_bpe()
└── read_file_cached()
└── read_file() ← 这里直接发起网络请求
4.2 版本对比
| 版本 | 离线缓存行为 | 状态 |
|---|---|---|
| 0.5.0 | ✅ 正常使用本地缓存 | 可用 |
| 0.6.0-0.8.x | ⚠️ 部分版本有问题 | 不稳定 |
| 0.9.0 | ❌ 忽略本地缓存,强制联网 | 存在 Bug |
| 0.10.0+ | ❓ 尚未测试 | 未知 |
4.3 问题定位
在 tiktoken/load.py 中,read_file 函数直接使用 requests.get() 获取文件,没有优先检查本地缓存:
python
def read_file(blobpath: str) -> bytes:
# 问题代码:直接发起网络请求
resp = requests.get(blobpath)
resp.raise_for_status()
return resp.content
而 read_file_cached 函数虽然会检查缓存,但在某些条件下仍然会调用 read_file。
五、解决方案
方案一:降级到稳定版本(推荐)
最可靠的解决方法是降级到 0.5.0 版本:
bash
# 卸载当前版本 pip uninstall tiktoken -y # 安装稳定版本 pip install tiktoken==0.5.0 # 使用 conda 安装(预编译,更稳定) conda install -c conda-forge tiktoken=0.5.0 -y
方案二:使用 conda 安装最新版
conda 源中的版本通常是预编译的,可能已经修复了部分问题:
bash
conda install -c conda-forge tiktoken -y
方案三:设置离线环境变量(部分有效)
虽然不能完全解决问题,但设置以下环境变量可以减少网络请求:
bash
set TIKTOKEN_OFFLINE=1 set TIKTOKEN_CACHE_DIR=C:\Users\用户名\.cache\tiktoken set TRANSFORMERS_OFFLINE=1 set HF_HUB_OFFLINE=1
方案四:手动放置缓存文件
确保编码文件存放在正确位置:
bash
# Windows 默认路径 C:\Users\用户名\.cache\tiktoken\ # Linux/Mac 默认路径 ~/.cache/tiktoken/
需要下载的文件:
-
cl100k_base.tiktoken(GPT-4 编码器) -
p50k_base.tiktoken -
r50k_base.tiktoken -
o200k_base.tiktoken
方案五:创建假的 tiktoken 模块(终极方案)
如果只是想绕过 tiktoken 运行其他项目,可以创建假的模块:
python
# fake_tiktoken.py
import sys
class Encoding:
def __init__(self, name):
self.name = name
def encode(self, text, **kwargs):
return [ord(c) for c in text]
def decode(self, tokens):
return ''.join(chr(t) for t in tokens if t < 0x110000)
def get_encoding(name):
print(f"[离线模式] 使用假编码器: {name}")
return Encoding(name)
sys.modules['tiktoken'] = sys.modules.get('__main__')
六、验证修复
运行以下命令验证问题是否解决:
bash
python -c "import tiktoken; enc = tiktoken.get_encoding('cl100k_base'); print(enc.encode('Hello'))"
预期输出(正常):
text
[9906, 37556]
七、经验总结
-
版本选择很重要:对于离线环境,尽量选择经过验证的稳定版本,不要盲目追求最新版
-
优先使用 conda:conda 提供的预编译包通常比 pip 源码编译更可靠
-
环境变量要提前设置:必须在导入 tiktoken 之前设置
TIKTOKEN_OFFLINE环境变量 -
文件位置要正确:确保缓存文件在正确的用户目录下
421



被折叠的 条评论
为什么被折叠?



