
1. one-api 分词器缓存为什么总在重复下载如果你用 Docker Compose 部署过 one-api大概率遇到过这个场景容器起来了日志里却在反复请求openaipublic.blob.core.windows.net网络一抖就卡住接口调用报tiktoken相关错误甚至整个网关启动超时。这不是 one-api 本身的 bug而是它依赖的 tiktoken 分词器在首次使用时需要下载编码文件而默认缓存目录在容器里是临时的容器一重建缓存就没了于是又得重新下载一遍。one-api 是一个把多家大模型 API 统一成 OpenAI 兼容格式的自建网关适合想在自己服务器上聚合多个模型渠道、给团队或应用提供统一入口的开发者。它内部用 tiktoken 做 token 计数用来做额度统计和请求预估。tiktoken 在初始化某个编码比如cl100k_base时会先查本地缓存目录没有就去官方地址拉取拉完存到TIKTOKEN_CACHE_DIR指向的位置。问题就在于这个环境变量如果不显式设置缓存路径可能落在容器可写层docker-compose down再up之后就丢了。我试过最直接的解法就是把缓存目录挂到宿主机上让分词器文件持久化。这样第一次下载完之后后续无论怎么重建容器都直接读本地文件不再依赖外网。下面按「问题定位 → 前置准备 → 可复制配置 → 验证生效 → 排错」的顺序把整套落地过程写清楚你可以直接照着改自己的docker-compose.yml。2. 前置准备TaoToken 渠道与 API Keyone-api 本身只是网关要真正跑通一次对话验证分词器是否生效你还需要一个可用的上游模型渠道。这里我用 TaoToken 作为上游接入它的接口是 OpenAI 兼容的填进 one-api 的渠道配置里很顺。先去控制台拿一个 API Key地址是 https://taotoken.net/api-keys 登录后新建一个 Key复制出来备用。这个 Key 后面会填到 one-api 的「渠道」里作为调用上游模型的凭证。如果你还没注册从 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 进官网注册即可。拿到 Key 之后one-api 的渠道配置大致是这样渠道类型选 OpenAIBase URL 填https://taotoken.net/api模型可以填gpt-4o-mini这类常用名密钥就是刚才复制的 Key。保存后点「测试」能返回成功就说明上游通了。这一步通了后面验证分词器缓存才有意义否则你分不清是网络问题还是缓存问题。注意Base URL 用https://taotoken.net/api不要带多余的路径后缀one-api 会自动拼接/v1/chat/completions。3. 可复制的 docker-compose 配置与 TIKTOKEN_CACHE_DIR 骨架核心思路一句话把 one-api 容器里的/data挂到宿主机目录再把TIKTOKEN_CACHE_DIR指向/data/cache让分词器文件落在挂载卷里。下面是一份可以直接改的docker-compose.yml片段我保留了 one-api 和它常用的 mysql、redis 依赖。version: 3.8 services: one-api: image: justsong/one-api:latest container_name: one-api restart: always ports: - 3000:3000 environment: - TZAsia/Shanghai - TIKTOKEN_CACHE_DIR/data/cache volumes: - ./oneapi:/data depends_on: - mysql - redis mysql: image: mysql:8.0 container_name: one-api-mysql restart: always environment: - MYSQL_ROOT_PASSWORDoneapi123 - MYSQL_DATABASEoneapi volumes: - ./mysql:/var/lib/mysql redis: image: redis:7-alpine container_name: one-api-redis restart: always volumes: - ./redis:/data关键点有三个。第一TIKTOKEN_CACHE_DIR/data/cache写在environment里容器启动时就会带上这个变量。第二volumes把宿主机的./oneapi挂到容器的/data所以/data/cache实际就是宿主机的./oneapi/cache。第三目录要提前建好否则容器可能因为权限或路径不存在而写入失败。在宿主机上执行mkdir -p ./oneapi/cache chmod 755 ./oneapi/cache然后启动docker-compose up -d启动后进容器确认变量生效docker exec -it one-api env | grep TIKTOKEN正常应该输出TIKTOKEN_CACHE_DIR/data/cache。如果没输出说明环境变量没写进 compose 或者容器没重建先docker-compose down再up -d。4. 手动预置分词器文件彻底摆脱外网依赖即使配了缓存目录第一次启动时 one-api 还是要去外网拉一次cl100k_base.tiktoken。如果你的服务器出网不稳定这一步照样会卡。更稳的做法是手动把文件放进去让容器启动时直接命中缓存。tiktoken 的缓存文件名不是原始文件名而是对下载 URL 做 SHA1 得到的哈希值。cl100k_base对应的两个常见哈希文件名是9b5ad71b2ce5302211f9c61530b329a4922fc6a4fb374d419588a4632f3f557e76b4b70aebbca790你可以先下载原始文件cd ./oneapi/cache curl -O https://openaipublic.blob.core.windows.net/encodings/cl100k_base.tiktoken然后复制成两个哈希名cp cl100k_base.tiktoken 9b5ad71b2ce5302211f9c61530b329a4922fc6a4 cp cl100k_base.tiktoken fb374d419588a4632f3f557e76b4b70aebbca790放好之后目录结构应该是./oneapi/ ├── cache/ │ ├── 9b5ad71b2ce5302211f9c61530b329a4922fc6a4 │ ├── fb374d419588a4632f3f557e76b4b70aebbca790 │ └── cl100k_base.tiktoken └── one-api.db重启容器docker-compose down docker-compose up -d这样容器启动时tiktoken 查缓存直接命中不会再发起外网请求。如果你用的是其他编码比如o200k_base哈希名不同需要按同样方式处理但cl100k_base覆盖了 GPT-3.5/4 系列日常够用。提示哈希文件名必须完全一致多一个字符少一个字符都会导致缓存未命中tiktoken 会重新去下载。5. 验证分词器缓存是否真正生效配置完不能只看「没报错」要确认它确实读了本地缓存。有三种验证方式从简到繁。第一种看容器日志有没有下载请求。启动后执行docker logs -f one-api如果日志里没有出现openaipublic.blob.core.windows.net或Downloading字样基本说明缓存命中了。反之如果还在刷下载日志说明路径或文件名不对。第二种进容器直接跑一段 Python 验证 tiktoken 读取路径。one-api 镜像里带了 Python 环境可以这样测docker exec -it one-api python3 -c import tiktoken, os print(cache dir:, os.environ.get(TIKTOKEN_CACHE_DIR)) enc tiktoken.get_encoding(cl100k_base) print(tokens:, enc.encode(hello one-api)) 如果输出cache dir: /data/cache和一段 token 列表且执行很快没有卡顿等待下载说明缓存生效。如果卡了几秒才出结果多半还是在联网下载。第三种最贴近真实业务在 one-api 后台建好渠道后发一次对话请求看额度统计里的 token 数是否正常累加。token 计数正常说明分词器工作正常。你可以用模型对话页面直接测https://taotoken.net/api-keys 拿到的 Key 配好渠道后在 one-api 的「对话」里发一条消息观察返回和用量。curl http://localhost:3000/v1/chat/completions \ -H Authorization: Bearer sk-你的one-api令牌 \ -H Content-Type: application/json \ -d { model: gpt-4o-mini, messages: [{role: user, content: 你好}] }返回正常且后台用量有变化整条链路就通了。6. 本篇常见错误排查报错一PermissionError: [Errno 13] Permission denied: /data/cache/xxx宿主机./oneapi/cache权限不够容器内进程写不进去。执行chmod -R 777 ./oneapi/cache临时放开或者确认容器运行用户对挂载目录有写权限。生产环境建议用chown指定 uid而不是直接 777。报错二日志一直刷下载缓存目录里没文件先确认TIKTOKEN_CACHE_DIR是否真的进了容器用第 3 节的env | grep检查。再确认挂载路径对不对docker exec -it one-api ls /data/cache看目录是否存在。如果目录不存在说明宿主机./oneapi/cache没建或者挂载点写错了。报错三文件名对了但还是重新下载哈希名必须和 tiktoken 内部计算的完全一致。不同版本的 tiktoken 对同一编码的 URL 可能不同哈希也会变。最稳的办法是让容器先联网下载一次然后去/data/cache里看实际生成的文件名把它备份下来下次直接复用。这样比死记哈希名可靠。报错四docker-compose up卡在拉镜像这跟分词器无关是镜像源问题。可以分开拉docker pull justsong/one-api:latest docker pull mysql:8.0 docker pull redis:7-alpine一个个拉失败概率低拉完再docker-compose up -d。报错五渠道测试通过但对话报 token 相关错误多半是分词器编码和模型不匹配。one-api 会根据模型名选编码如果你填了非常规模型名可能选到未缓存的编码。此时要么补对应编码的缓存文件要么换成cl100k_base覆盖的模型名测试。7. 长期编码与 Agent 场景的接入建议如果你不只是拿 one-api 做临时网关而是要长期跑编码助手、Agent 工作流这类高频调用场景建议把渠道配置和额度策略一起规划好。TaoToken 的 Coding Plan 适合这种持续调用的需求地址是 https://taotoken.net/coding-plan 按套餐走比单次计费更可控。接入文档在 https://taotoken.net/doc 里面有 one-api 渠道配置的详细字段说明遇到 Base URL 或模型名不确定的时候可以直接查。回到分词器这件事核心就一句把TIKTOKEN_CACHE_DIR指到挂载卷再手动预置哈希文件之后无论怎么重建容器都不再依赖外网。这套配置我放在自己的docker-compose.yml里跑了很久docker-compose down up -d循环多次日志里再没出现过下载请求。你可以先把第 3 节的片段抄进去跑通第 5 节的验证再按第 4 节补文件顺序反了容易在排错时分不清是网络还是缓存的问题。