1. 为什么要把 Copilot CLI 的 endpoint 从云端改到本地或统一网关
GitHub Copilot CLI 现在支持 BYOK(自带密钥)和本地模型,这件事对经常在终端里写代码的人意义不小。以前它只能走云端通道,模型固定、额度受限、网络抖动时补全直接卡住;现在你可以把COPILOT_API_URL指向本地 Ollama、vLLM,或者指向一个统一管理的 API 网关,让补全请求走你自己的链路。核心检索词就是 GitHub Copilot CLI 连接本地 Ollama/vLLM 模型配置,本质上是把 CLI 的模型调用出口从默认云端换成你指定的 OpenAI 兼容 endpoint。
适合谁?三类人最直接受益。第一类是本机已经跑着 Ollama、手里有 14B 甚至 32B 代码模型的开发者,想让 Copilot CLI 直接吃本地算力,省掉云端往返延迟。第二类是用 vLLM 在局域网或内网服务器上部署了推理服务,团队想共用一套模型端点。第三类是模型来源比较杂,既有本地模型又有云端模型,希望用一个统一 Key 和统一通道管理所有调用,避免每个工具配一遍密钥。
我自己的场景是:笔记本上跑 Ollama 做日常补全,服务器上跑 vLLM 做重活,但 CLI 工具一多,密钥和地址就散落在各个配置文件里。后来把 endpoint 统一收口到一个兼容 OpenAI 协议的网关,CLI 只认一个 Base URL 和一个 Key,切换模型只改 Model ID。这篇就按这个思路,从本地 Ollama 讲起,再到 vLLM,最后讲怎么把 endpoint 改到 TaoToken 复用统一通道,每一步都给可复制的配置和验证命令。
需要先明确一个前提:Copilot CLI 走的是 OpenAI 兼容协议,所以你的目标服务必须暴露/v1/chat/completions这类接口,并且支持 Tool Calling 和 Streaming。上下文窗口建议不低于 128K token,否则长文件补全会截断。这三点不满足,配置写得再对也连不上。
2. 前置准备:Ollama 与 vLLM 服务怎么起、TaoToken 通道怎么开
先说 Ollama。它是本地模型里最省事的,装完直接ollama serve就能起一个 OpenAI 兼容服务,默认监听http://localhost:11434。但要注意,Ollama 原生 API 是/api/chat,而 Copilot CLI 需要的是/v1路径,所以地址要写成http://localhost:11434/v1。模型方面,代码补全推荐qwen2.5-coder:14b或qwen2.5-coder:7b,前者质量更好但吃显存,后者在 8G 显存的机器上也能跑。
# 启动 Ollama 服务(后台常驻) ollama serve # 另开一个终端,拉取代码模型 ollama pull qwen2.5-coder:14b # 确认模型已就位 ollama listvLLM 稍微复杂一点,它是给生产环境用的高吞吐推理框架。启动时必须加--enable-auto-tool-choice,否则 Tool Calling 不生效,Copilot CLI 的子代理会报错。还要指定--tool-call-parser,不同模型用不同的解析器,比如 Qwen 系列用hermes。
# vLLM 启动示例,监听 8000 端口 python -m vllm.entrypoints.openai.api_server \ --model Qwen/Qwen2.5-Coder-14B-Instruct \ --served-model-name qwen2.5-coder-14b \ --host 0.0.0.0 \ --port 8000 \ --enable-auto-tool-choice \ --tool-call-parser hermes启动后用curl http://localhost:8000/v1/models确认服务活着,返回 JSON 里有你的模型名就对了。
再说 TaoToken 这条统一通道。它的作用是让你不用在本地和云端之间反复改配置:CLI 的 Base URL 固定指向 TaoToken 的 API 地址,Key 用同一个,想切模型只改 Model ID。官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 根地址是 https://taotoken.net/api 。你需要先去控制台建一个 API Key,路径是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,Key 管理页在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。建完 Key 先别急着配 CLI,用模型对话页 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 发一条消息,确认 Key 和通道本身是通的,再往下走能省很多排查时间。
这里有个容易踩的坑:本地 Ollama 和 TaoToken 通道的 Base URL 格式不一样。Ollama 是http://localhost:11434/v1,TaoToken 是https://taotoken.net/api,后者通常不需要你再手动补/v1,具体以接入文档为准,文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。配置前先确认路径,能避免一半的 404。
3. 可复制配置:环境变量、settings 片段与三件套写法
Copilot CLI 的配置主要靠环境变量,少量靠配置文件。最直接的方式是在 shell 里 export,但这样每次开新终端都要重来,所以更推荐写进~/.zshrc或~/.bashrc,或者用 CLI 自己的 settings 文件。下面按三种场景给可复制片段。
场景一,连本地 Ollama。这是最简配置,Key 随便填一个非空字符串即可,Ollama 不校验。
# 写入 ~/.zshrc 或 ~/.bashrc export COPILOT_MODEL="ollama/qwen2.5-coder:14b" export COPILOT_API_URL="http://localhost:11434/v1" export COPILOT_API_KEY="ollama" export COPILOT_OFFLINE="true"场景二,连 vLLM。注意 Model ID 要和你--served-model-name一致,地址带/v1。
export COPILOT_MODEL="qwen2.5-coder-14b" export COPILOT_API_URL="http://192.168.1.50:8000/v1" export COPILOT_API_KEY="your-vllm-key" export COPILOT_OFFLINE="true"场景三,把 endpoint 改到 TaoToken 复用统一通道。这里三件套必须写全:Base URL、Key、Model ID。Base URL 用https://taotoken.net/api,Key 用控制台建的那串,Model ID 填你要用的模型标识。
export COPILOT_MODEL="qwen2.5-coder-14b" export COPILOT_API_URL="https://taotoken.net/api" export COPILOT_API_KEY="sk-你的TaoToken密钥" export COPILOT_OFFLINE="true"如果你用的是 CLI 的 settings 文件而不是环境变量,可以写成 JSON。路径通常在~/.config/github-copilot/settings.json,具体以你安装版本为准。下面这个片段把 provider 指向 TaoToken,字段名和官方 settings 保持一致。
{ "model": "qwen2.5-coder-14b", "provider": { "type": "openai", "baseUrl": "https://taotoken.net/api", "apiKey": "sk-你的TaoToken密钥" }, "offline": true }如果你更习惯 TOML,等价写法如下,适合放在项目级配置里做覆盖。
model = "qwen2.5-coder-14b" offline = true [provider] type = "openai" baseUrl = "https://taotoken.net/api" apiKey = "sk-你的TaoToken密钥"关于COPILOT_OFFLINE="true",它的作用是禁用遥测,所有请求只发给你配置的 provider。本地模型场景建议开,统一通道场景也建议开,避免 CLI 偷偷往默认云端发请求导致行为不一致。子代理方面,explore、task、code-review 这些会自动继承你配的 provider,不用单独设置,这点实测下来是省心的。
配置写完记得source ~/.zshrc让环境变量生效,然后echo $COPILOT_API_URL确认值没写错。这一步看着傻,但地址拼错、Key 带空格这类问题,靠肉眼检查很容易漏。
4. 验证请求:从 providers 检查到一次真实补全
配置完不能只看变量,要发真实请求确认链路通。第一步用 CLI 自带的 providers 检查命令,看它认到的 provider 和地址对不对。
copilot help providers输出里应该能看到你配置的 baseUrl 和 model。如果这里显示的还是默认云端地址,说明环境变量没生效,回去检查 shell 配置有没有 source。
第二步,直接用 curl 打目标 endpoint,排除 CLI 本身的干扰。先测 Ollama:
curl http://localhost:11434/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ollama" \ -d '{ "model": "qwen2.5-coder:14b", "messages": [{"role": "user", "content": "写一个 Python 快排"}], "stream": false }'再测 TaoToken 通道:
curl https://taotoken.net/api/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-你的TaoToken密钥" \ -d '{ "model": "qwen2.5-coder-14b", "messages": [{"role": "user", "content": "写一个 Python 快排"}], "stream": false }'返回 JSON 里有choices[0].message.content就说明通道通了。如果返回 401,是 Key 问题;返回 404,是路径问题,重点看/v1有没有漏或多。
第三步,在真实项目里跑一次补全。进一个代码仓库,敲copilot进入交互模式,输入一句注释让它补全,比如# 读取 config.yaml 并返回 dict。观察两点:一是响应是否流式吐字,二是补全内容是否符合你的模型水平。如果卡住不动,多半是 Streaming 没开或网络不通;如果补全内容明显是云端模型风格,说明请求没走到你配的 endpoint。
我试过在同一个终端里先配 Ollama 再切 TaoToken,只改COPILOT_API_URL和COPILOT_API_KEY两个变量,COPILOT_MODEL保持不变,补全立刻从本地切到统一通道,验证成本很低。这也是统一通道的价值:切换只动地址和 Key,模型标识可以复用。
5. 常见报错排查:401、local proxy failed、reading choices、OAuth
配置过程中最容易撞上的几类报错,下面按真实错误信息对照排查。
401 Unauthorized。这是 Key 问题。本地 Ollama 场景下,Key 填任意非空值即可,但如果你填了空字符串,有些版本会直接判 401。TaoToken 场景下,检查 Key 有没有复制完整、有没有多余空格、有没有过期。去 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 重新生成一个再试。
local proxy failed 或 connection refused。这是地址或服务没起。先curl目标地址确认服务活着,Ollama 用ollama list看服务状态,vLLM 看启动日志有没有报错。如果地址是localhost但服务在另一台机器,改成实际 IP。防火墙和端口占用也要查,vLLM 默认 8000,Ollama 默认 11434。
reading choices 相关报错,通常是响应体不是标准 OpenAI 格式。常见原因是路径少了/v1,请求打到了非兼容接口上,返回了 HTML 或错误页,CLI 解析choices字段时失败。检查COPILOT_API_URL是否以/v1结尾(TaoToken 通道以文档为准),以及目标服务是否真的暴露了 chat completions 接口。
OAuth 相关报错,多出现在 CLI 尝试走默认登录流程时。如果你已经配了 BYOK,但仍然弹出 OAuth 登录,说明 provider 没被正确识别。检查 settings 文件里的 provider 字段拼写,以及环境变量有没有被其他配置覆盖。必要时先unset掉冲突的变量再重配。
还有一类不报错但行为异常:补全能出字,但 Tool Calling 不工作,子代理报工具调用失败。这基本是模型或服务不支持 Tool Calling。Ollama 要确认模型本身支持,vLLM 要确认启动时带了--enable-auto-tool-choice和正确的--tool-call-parser。上下文窗口不够 128K 也会导致长文件补全被截断,表现为补全内容突然断掉。
排查顺序建议固定成:服务是否在跑 → 地址是否含正确路径 → Key 是否有效 → 模型是否支持 Tool Calling 和 Streaming。按这个顺序走,大部分问题能在五分钟内定位。
6. 把统一通道用起来:长期编码与 Agent 场景的接入选择
配置跑通之后,真正省事的是长期使用。如果你只是偶尔补全,本地 Ollama 足够;但如果你每天在终端里跑 coding agent、做多轮重构、让子代理自动 explore 和 code-review,那统一通道的价值就出来了:一个 Key 管所有模型,切换只改 Model ID,不用在本地和云端之间反复改环境变量。
具体操作上,把COPILOT_API_URL固定成https://taotoken.net/api,COPILOT_API_KEY固定成你的 TaoToken Key,COPILOT_MODEL按任务换。日常补全用轻量模型,重活换大模型,CLI 侧不用动其他配置。如果你同时用 Claude Code 这类工具,也可以走同一套通道,接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,里面有各工具的 Base URL 和 Model ID 对照。
长期编码和 Agent 场景,建议直接看 Coding Plan,路径是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,它更适合高频调用和子代理自动化的用法。如果你还在选模型阶段,想先对比不同模型的实际输出,可以去模型对话页 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 手动试几条 prompt,确认风格和 Tool Calling 表现再写进 CLI 配置。Key 不够用或者要分项目隔离时,回 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 新建即可。
最后给一个实用技巧:把三套配置写成 shell 函数,切换时一条命令搞定,比手动 export 可靠得多。
# 写入 ~/.zshrc copilot_local() { export COPILOT_MODEL="ollama/qwen2.5-coder:14b" export COPILOT_API_URL="http://localhost:11434/v1" export COPILOT_API_KEY="ollama" export COPILOT_OFFLINE="true" echo "已切到本地 Ollama" } copilot_tao() { export COPILOT_MODEL="qwen2.5-coder-14b" export COPILOT_API_URL="https://taotoken.net/api" export COPILOT_API_KEY="sk-你的TaoToken密钥" export COPILOT_OFFLINE="true" echo "已切到 TaoToken 统一通道" }之后copilot_local和copilot_tao随时切换,配合copilot help providers确认当前 provider,整个链路就闭环了。