1. Docker 里跑 Ollama 后,为什么要把 endpoint 改到 TaoToken
很多人第一次在 Docker 里跑 Ollama,都是被“本地模型、数据不出内网”这句话吸引的。docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama一行命令下去,ollama pull qwen2.5:7b再一跑,http://localhost:11434/api/chat就能返回内容,确实很爽。但真把它接进项目里,问题就来了:本地容器只暴露了一个11434,团队里每个人的机器都要各自拉模型、各自占显存;换一台机器,模型名、量化版本、上下文长度全对不上;更麻烦的是,你项目里可能同时还在用云端模型,Key 散落在.env、settings.json、auth.json好几个地方,谁改了哪个配置根本查不清。
我试过在一个小团队里同时维护三套调用入口:本地 Ollama 给离线场景、云端 API 给线上服务、还有一个内部网关给测试环境。结果就是每次加一个新模型,都要在三个地方改 base_url 和 model 名,漏一个就报 404。后来我把思路反过来:Ollama 容器继续负责“跑模型”,但所有对外的调用 endpoint 统一收敛到一个兼容 OpenAI 协议的入口,也就是把base_url从http://localhost:11434/v1改成 TaoToken 的https://taotoken.net/api。这样本地推理链路还在,但 Key 管理、模型路由、用量统计都集中到了一处。
这里要先说清楚一个概念,避免误会:Ollama 本身是本地推理引擎,TaoToken 是统一的模型访问通道,两者不是替代关系。你可以理解为——Ollama 是厨房里的灶台,TaoToken 是统一采购和配送的窗口。灶台该开火还是开火,但食材从哪个仓库出、用什么账号结算,交给窗口统一管。对于已经有 Ollama 容器、又想让模型访问集中管理的开发者来说,这个改法最省事:不用动容器里的模型文件,只改调用方的环境变量。
适合谁看这篇?三类人最合适。第一类是本机或服务器上已经跑着 Ollama 容器,但项目里 base_url 写死成localhost:11434的;第二类是想把本地模型和云端模型用同一套 SDK 调用、不想维护两套客户端的;第三类是团队里多人共用模型、需要统一 Key 和配额,但又不想放弃本地推理的。下面我会从 Docker 配置讲到 curl 验证,再到常见报错,尽量让你照着敲就能跑通。
核心检索词先摆在这:Docker 部署 Ollama 模型后修改 endpoint 到 TaoToken 统一调用。你如果是搜“ollama docker 改 base_url”“ollama 容器 统一 api 网关”进来的,这篇就是写给你的。
2. TaoToken 前置准备:Key、Base URL 和模型 ID 三件套
在动 Docker 配置之前,先把 TaoToken 这边的三样东西准备好,不然后面改环境变量会卡住。这三样是:API Key、Base URL、Model ID。任何接入问题,九成都能归到这三件套没对齐。
先说 Base URL。TaoToken 的 API 入口是https://taotoken.net/api,注意这里不要加 UTM 参数,UTM 只用于官网跳转统计,写进代码里会导致部分客户端把 query 当成路径的一部分。官网地址是https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,你注册、看文档、进控制台都从这走。API Key 的创建入口在控制台的 API Keys 页面,路径是https://taotoken.net/console/api-keys,登录后新建一个 Key,复制出来先存到密码管理器里,因为它只完整显示一次。
Model ID 这块要特别注意。Ollama 本地用的模型名是qwen2.5:7b、llama3.1:8b这种带 tag 的格式,而 TaoToken 侧的模型 ID 通常是qwen2.5-7b、llama-3.1-8b这类不带冒号的写法。你在配置里填错一个字符,返回的就是model not found。所以建议先在模型对话页面确认一下你要用的模型 ID 到底叫什么,页面地址是https://taotoken.net/chat,选一个模型发一句话,看请求里带的 model 字段是什么,照抄就行。
如果你是要做长期编码或者 Agent 类任务,比如接 Claude Code、Cline 这类工具,那更推荐用 Coding Plan,入口在https://taotoken.net/coding-plan,它针对长上下文和连续调用做了配额优化,比按次调用划算。接入文档在https://taotoken.net/doc,里面有各语言 SDK 的示例,遇到不确定的参数先翻文档,比在群里问快。
把这三件套记成一张表,后面配置时对照着填:
| 项目 | 值 | 获取位置 |
|---|---|---|
| Base URL | https://taotoken.net/api | 固定,不加 UTM |
| API Key | sk-开头的一串 | 控制台 API Keys 页面 |
| Model ID | 如qwen2.5-7b | 模型对话页面确认 |
这里有个容易踩的坑:有人把 Base URL 写成https://taotoken.net/api/v1,结果 404。TaoToken 的 OpenAI 兼容层已经处理了/v1前缀,你在客户端里填https://taotoken.net/api即可,SDK 自己会拼/v1/chat/completions。如果你用的是原生requests直接发请求,那 URL 要写全https://taotoken.net/api/v1/chat/completions。这两种写法对应两种调用方式,别混。
还有一点,Key 不要硬编码进docker-compose.yml提交到 Git。正确做法是放在同目录的.env文件里,compose 会自动读取,.env加进.gitignore。下面第三节会给完整的 compose 片段。
3. 可复制的 docker-compose 配置:把 endpoint 指向 TaoToken
这一节是重点,直接给能跑的配置。先明确一个设计:Ollama 容器本身不需要改任何东西,它还是监听11434,负责本地推理。我们要改的是调用方的环境变量,也就是你的应用容器或者你本机的客户端。如果你希望 Ollama 容器里的某些工具也走 TaoToken,那就在 Ollama 容器的 environment 里加变量。
先看一个典型的双容器 compose,一个跑 Ollama,一个跑你的应用,应用通过环境变量决定走本地还是走 TaoToken:
services: ollama: image: ollama/ollama:latest container_name: ollama ports: - "11434:11434" volumes: - ollama_data:/root/.ollama environment: - OLLAMA_HOST=0.0.0.0:11434 - OLLAMA_KEEP_ALIVE=24h restart: unless-stopped app: build: . container_name: my-app depends_on: - ollama environment: - OPENAI_BASE_URL=https://taotoken.net/api - OPENAI_API_KEY=${TAOTOKEN_API_KEY} - OPENAI_MODEL=qwen2.5-7b - OLLAMA_LOCAL_URL=http://ollama:11434 env_file: - .env restart: unless-stopped volumes: ollama_data:配套的.env文件长这样,注意不要提交到仓库:
TAOTOKEN_API_KEY=sk-你的真实key这里的关键是OPENAI_BASE_URL指向https://taotoken.net/api,OPENAI_API_KEY从.env注入。你的应用代码里如果用 OpenAI SDK,初始化时读这两个环境变量就行,不用改代码。比如 Python 里:
import os from openai import OpenAI client = OpenAI( base_url=os.environ["OPENAI_BASE_URL"], api_key=os.environ["OPENAI_API_KEY"], ) resp = client.chat.completions.create( model=os.environ["OPENAI_MODEL"], messages=[{"role": "user", "content": "用一句话解释什么是容器"}], ) print(resp.choices[0].message.content)如果你用的是 Node.js,配置方式类似,环境变量名换成OPENAI_BASE_URL和OPENAI_API_KEY,SDK 会自动读取。这里要提醒一句:有些 SDK 默认读的是OPENAI_API_BASE而不是OPENAI_BASE_URL,版本不同名字有差异,遇到读不到就手动传参,别死磕环境变量名。
那如果你想让Ollama 容器内部的某些调用也走 TaoToken 呢?比如你在 Ollama 容器里装了个脚本,想让它调用云端模型。这时候在 ollama 服务的 environment 里加:
environment: - OLLAMA_HOST=0.0.0.0:11434 - OPENAI_BASE_URL=https://taotoken.net/api - OPENAI_API_KEY=${TAOTOKEN_API_KEY}但要注意,Ollama 自身的ollama serve不认OPENAI_BASE_URL,它只认OLLAMA_HOST。这个变量是给你容器里其他脚本用的。所以别指望改了它 Ollama 就自动转发到 TaoToken,Ollama 不做转发,它只做本地推理。转发这件事要么在你的应用层做,要么用 LiteLLM 这类代理层做。
说到 LiteLLM,如果你确实需要一个“本地 Ollama 和 TaoToken 二选一”的路由层,可以在 compose 里加一个 litellm 服务,配置config.yaml:
model_list: - model_name: local-qwen litellm_params: model: ollama/qwen2.5:7b api_base: http://ollama:11434 - model_name: cloud-qwen litellm_params: model: openai/qwen2.5-7b api_base: https://taotoken.net/api api_key: os.environ/TAOTOKEN_API_KEY这样你的应用只需要连 LiteLLM 的4000端口,用model_name切换本地还是云端。这个方案适合模型种类多、需要统一入口的团队。配置里的api_base就是https://taotoken.net/api,api_key从环境变量读,别写死。
最后强调一下路径一致性:docker-compose.yml里写的OPENAI_BASE_URL和代码里读的变量名必须完全一致,大小写敏感。我见过有人 compose 里写OPENAI_BASE_URL,代码里读OPENAI_API_BASE,结果一直连本地默认地址,排查半天。改完配置记得docker compose up -d --force-recreate,光restart不会重新读环境变量。
4. 验证请求:用 curl 确认请求真的经 TaoToken 返回
配置改完,别急着跑业务代码,先用 curl 打一发,确认链路通了。这一步能帮你把“配置问题”和“代码问题”分开。
先验证 TaoToken 本身通不通,在你本机终端直接发:
curl -s https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "qwen2.5-7b", "messages": [{"role": "user", "content": "回复两个字:通了"}], "max_tokens": 16 }'正常返回是一个 JSON,choices[0].message.content里是模型输出。如果返回401,说明 Key 不对或者没带Bearer前缀;返回404,多半是 model ID 写错或者 URL 多了/v1又重复拼了一次。这一步通了,说明 TaoToken 侧没问题。
接着进到你的应用容器里验证,确认容器内环境变量生效:
docker compose exec app env | grep OPENAI你应该看到OPENAI_BASE_URL=https://taotoken.net/api和OPENAI_API_KEY=sk-...。如果OPENAI_BASE_URL还是http://localhost:11434/v1,说明 compose 没重新创建容器,或者.env没被读到。这时候docker compose down && docker compose up -d重来一遍。
然后在容器内发请求:
docker compose exec app curl -s $OPENAI_BASE_URL/v1/chat/completions \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "'"$OPENAI_MODEL"'", "messages": [{"role": "user", "content": "ping"}], "max_tokens": 8 }'注意这里 URL 是$OPENAI_BASE_URL/v1/chat/completions,因为环境变量里存的是https://taotoken.net/api,拼上/v1/chat/completions才是完整路径。如果你在代码里用 OpenAI SDK,SDK 会自动拼/v1,所以 base_url 只写到/api就行,别自己再加。
验证成功的标志有三个:HTTP 状态码 200、返回体里有choices数组、content字段非空。如果返回体里出现error字段,把error.message复制出来对照下一节排查。
再补一个验证本地 Ollama 还在正常工作的命令,确保你没把本地链路搞坏:
docker compose exec ollama ollama list curl -s http://localhost:11434/api/tags | head -c 200本地 Ollama 该返回模型列表还是返回,说明容器没受影响。这样你就有了两条独立链路:本地11434走 Ollama,统一入口走 TaoToken,互不干扰。
如果你用的是 Claude Code 这类工具,验证方式不太一样,它读的是~/.claude/settings.json或者项目里的.claude/settings.json。配置片段长这样:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的key", "ANTHROPIC_MODEL": "claude-sonnet-4-20250514" } }注意 Claude Code 用的是ANTHROPIC_BASE_URL而不是OPENAI_BASE_URL,模型 ID 也是 Anthropic 系的命名。改完重启 Claude Code,用/status看当前连的地址对不对。这一步很多人漏掉,以为改了环境变量就生效,其实 Claude Code 读的是配置文件。
5. 本篇常见报错排查:401、local proxy failed、reading choices、OAuth
这一节把最常见的四类报错拆开讲,每个都给现象、原因、修法。
401 Unauthorized。现象是返回体里error.message是invalid api key或authentication failed。原因通常是三种:Key 复制时带了空格、Key 已经删除或过期、请求头没带Bearer前缀。修法是重新去https://taotoken.net/console/api-keys生成一个 Key,复制时注意别带首尾空格,请求头写成Authorization: Bearer sk-xxx。如果你用的是 SDK,确认api_key参数传对了,有些 SDK 要求不带Bearer,它自己加。
local proxy failed。这个报错一般出现在你本机配了某些网络工具,或者容器里设了HTTP_PROXY环境变量,导致请求发不出去。现象是连接超时或者connection refused。修法是检查容器环境变量里有没有HTTP_PROXY、HTTPS_PROXY、ALL_PROXY,有就删掉。在 compose 里显式清空:
environment: - HTTP_PROXY= - HTTPS_PROXY= - ALL_PROXY=同时确认容器能解析taotoken.net,docker compose exec app nslookup taotoken.net看有没有返回 IP。如果 DNS 不通,检查 Docker 的 DNS 配置。
reading choices 报错。完整报错通常是Error reading choices: ...或者list index out of range,出现在你解析返回体的时候。原因是返回体里没有choices字段,可能是请求失败返回了 error 对象,但你的代码直接去读resp.choices[0]。修法是先判断状态码和 error 字段:
data = resp.json() if "error" in data: raise RuntimeError(data["error"]["message"]) content = data["choices"][0]["message"]["content"]这样报错信息会清晰很多,不会掩盖真实原因。另一个可能是max_tokens设太小,模型还没输出就截断了,choices里finish_reason是length,content为空。把max_tokens调到 256 以上再试。
OAuth 相关报错。如果你用的是 Claude Code 或者某些 CLI 工具,可能会看到OAuth token expired或please login。这类工具默认走 OAuth 登录流程,但你要用 API Key 接入,就得在配置里显式指定ANTHROPIC_API_KEY和ANTHROPIC_BASE_URL,并且关掉 OAuth 自动登录。Claude Code 的配置在~/.claude/settings.json,加上前面给的 env 片段,然后claude logout再claude启动,让它读配置而不是走登录。如果还提示 OAuth,检查有没有~/.claude/.credentials.json残留,删掉再试。
再补一个 Codex 的auth.json场景。如果你用 Codex CLI,它读的是~/.codex/auth.json,格式是:
{ "OPENAI_API_KEY": "sk-你的key", "OPENAI_BASE_URL": "https://taotoken.net/api" }注意这里字段名是OPENAI_API_KEY和OPENAI_BASE_URL,和 Claude Code 的ANTHROPIC_前缀不同。改完auth.json记得重启终端,环境变量优先级高于配置文件,如果 shell 里还留着旧的OPENAI_BASE_URL,会覆盖文件里的值。用echo $OPENAI_BASE_URL确认一下。
排查顺序建议固定成:先 curl 直连 TaoToken 确认 Key 和模型 ID 对,再进容器确认环境变量生效,最后看代码解析逻辑。三步走下来,九成问题能定位。
6. 统一入口之后:本地推理和集中管理的分工
把 endpoint 改到 TaoToken 之后,你的架构其实变成了两层:Ollama 容器负责“算”,TaoToken 负责“管”。这个分工的好处是,本地模型该跑还是跑,但模型清单、Key、用量这些事不用再散落在每台机器上。团队里新人入职,只要拿到一个 Key,配好OPENAI_BASE_URL,就能用上所有已授权的模型,不用再挨个拉镜像。
如果你还在犹豫要不要改,可以先从一个小项目试起:把OPENAI_BASE_URL从http://localhost:11434/v1换成https://taotoken.net/api,跑通一次 curl,感受一下链路。确认没问题再推到团队配置里。接入文档在https://taotoken.net/doc,里面有各语言的完整示例,遇到参数不确定就翻文档。需要长期跑编码任务的,Coding Plan 在https://taotoken.net/coding-plan,配额和长上下文都更合适。Key 管理统一在https://taotoken.net/console/api-keys,建议按项目建不同 Key,方便后面看用量和吊销。
最后留一个实用技巧:在 compose 里给应用容器加一个健康检查,启动时自动 curl 一次 TaoToken,通了再让业务进程起来,这样配置错了能第一时间发现,而不是等业务请求失败才排查。
healthcheck: test: ["CMD", "curl", "-sf", "-o", "/dev/null", "-w", "%{http_code}", "https://taotoken.net/api/v1/models", "-H", "Authorization: Bearer ${TAOTOKEN_API_KEY}"] interval: 30s timeout: 10s retries: 3这个检查打的是/v1/models接口,返回 200 说明 Key 和网络都正常。把它加进 compose,以后改配置心里有底。