公司网络下代理与证书报错:编辑器走的不是你终端那套代理设置
在公司网络里遇到代理或证书报错,最常见的误判是:你在终端里 export 过代理变量、curl 打服务商地址也通,于是默认编辑器里那个 AI 插件同样通。这两个进程读的根本不是同一份配置。 判断”我这边网络没问题”的证据链,在这里是断的。
这篇只讲一件事:这批编辑器 / 终端 Agent 把 HTTP 层的设置放在哪里,以及你怎么确认当前生效的是哪一份。站内另外三篇管别的段落——内网代理与证书链的排查讲的是网络侧本身通不通(证书链是否被中间设备替换、代理是否拦了 TLS),DNS 与 hosts 配错讲域名解析这一层,API 超时与连接中断讲请求发出去之后的重试与断流处置。本篇站在客户端配置这一层,不重复它们。
下文提到的所有产品字段,都来自各家官方文档在 2026-08-07 的记录,字段随版本会变,最终以官方文档最新版为准。
一、终端试通的那一次,证明不了编辑器也通
先把概念摆平。这批工具接自定义模型,绝大多数走的是OpenAI 兼容端点——服务商把自己的接口做成和 OpenAI 那套请求/响应格式一致,客户端只要换个地址、换把密钥就能调,不用为每家单独写适配。这也是为什么走表单的那几家(Cline、Roo Code、Kilo Code),文档里列出来的主参数都落在”填地址、填密钥、指定模型”这三件事上。
问题出在”地址填对了,请求却发不出去”这一步。你在终端里设的代理变量,属于那个 shell 进程和它拉起来的子进程。编辑器通常是由桌面环境或启动器直接拉起的,它的环境变量集合来自那条启动路径,不一定包含你写在 shell 配置里的东西。这是操作系统的进程模型,不是哪家产品的特性——但结果就是:curl 成功和插件失败可以同时成立,而且这时候你越盯着网络排查越绕远。相关的通用坑可以看环境变量丢失那篇。
所以正确的下一步不是继续测网络,而是回到这个客户端自己的配置体系,确认三件事:HTTP 层的设置写在哪个文件、这次生效的是哪一份、密钥从哪来。这三件事各家答案完全不同。
二、HTTP 层的设置写在哪:先认清四种配置形态
把这批工具的配置形态归一下类,能省很多试错:图形界面表单一类(Cline、Roo Code、Kilo Code),YAML 配置文件一类(Continue 的 config.yaml、aider 的 .aider.model.settings.yml),JSON settings 一类(Zed 的 settings.json、Gemini CLI 的 settings.json),环境变量与 CLI 子命令一类(goose 的 GOOSE_PROVIDER 加 goose configure、Crush 的 crushrc 加 provider add)。
形态决定了你该去哪儿改。表单那类,你手上没有一份能直接打开的配置文本(存到哪里、以什么格式存,本篇依据的文档页面没有说明,以官方文档为准);文件那类,改动落在你能 git diff 出来的文本上;环境变量那类,改动跟着进程走——而”跟着进程走”恰恰是本篇开头那个误判的温床。
本篇最直接的落点在 Continue。它的模型配置写在 config.yaml 的 models 块下,必填 name(唯一标识)、provider(如 openai、ollama、mistral)、model(具体模型名);可选字段里有 apiBase(覆盖默认 API 端点)、roles、capabilities、defaultCompletionOptions、autocompleteOptions、chatOptions,以及 requestOptions(timeout、headers、proxy 等 HTTP 配置)。官方文档对这一项的记录就到这个粒度,具体子字段怎么写、取什么值,以官方文档为准。
关键在于结构:requestOptions 是挂在单个模型条目下面的可选字段,也就是说它是逐条配置的。而 Continue 的 roles 取值有 chat、autocomplete、embed、rerank、edit、apply、summarize,默认是 [chat, edit, apply, summarize]。这里的 embed 指把文本转成向量以便做相似度检索,rerank 指把检索出来的候选再按相关度重排一遍——一个稍微完整的仓库配置里,对话、补全、嵌入、重排很可能是四条独立的 models 条目。你只在对话那条上加了 HTTP 设置,其余几条并不共享同一份写法(这是配置结构决定的,未配置条目的实际行为以官方文档为准)。
官方文档给的示例长这样,可以原样参照结构:
models:
- name: GPT-4o
provider: openai
model: gpt-4o
roles:
- chat
- edit
defaultCompletionOptions:
temperature: 0.7
maxTokens: 1500
其他几家在”自定义 HTTP 头”这件事上也各有落点。Kilo Code 新建 provider 时有一项 Headers(可选,自定义 HTTP 头,键值对形式);aider 的 extra_params 可以把任意参数透传给 litellm.completion(),其中包括 extra_headers,文档示例是:
- name: provider/model-name
extra_params:
extra_headers:
Custom-Header: value
max_tokens: 8192
至于 Zed,本篇依据的那两页记录里没有出现 HTTP 代理相关的字段,这不等于 Zed 没有对应能力,只说明本篇不据此展开。
| 配置项(逐字) | 属于哪家、写在哪 | 截至 2026-08-07 官方文档记录的说明 | 来源 |
|---|---|---|---|
requestOptions | Continue,config.yaml 的 models 条目下 | 可选字段,timeout、headers、proxy 等 HTTP 配置 | docs.continue.dev/reference |
apiBase | Continue,同上 | 可选字段,覆盖默认 API 端点 | 同上 |
| Headers | Kilo Code,新建 provider 的字段 | 可选,自定义 HTTP 头,键值对形式 | kilo.ai/docs/providers/openai-compatible |
extra_params | aider,.aider.model.settings.yml | 把任意参数透传给 litellm.completion(),包括 extra_headers | aider.chat/docs/config/adv-model-settings.html |
api_url | Zed,settings.json 的 openai_compatible 下 | 自定义 base URL | zed.dev/docs/ai/use-api-access |
OPENAI_HOST | goose,环境变量 | 自建 / 企业内部的 OpenAI 兼容端点,可选配 OPENAI_BASE_PATH | goose-docs.ai/docs/getting-started/providers/ |
--base-url | Crush,provider add 命令行参数 | 自定义 provider 时指定基址 | Crush 仓库 README |
| Base URL | Cline / Roo Code / Kilo Code,界面表单 | 填服务商给的 API 端点;Cline 与 Roo Code 的文档都提示这里不会是官方 OpenAI 那个地址(https://api.openai.com/v1) | 各家文档,URL 见文末 |
这张表最实用的读法是反过来读:当你在某家的文档里搜”proxy”搜不到时,先确认你搜的是不是这家对应的那个字段名。apiBase、api_url、Base URL、OPENAI_HOST、--base-url 是五个不同的东西,串台着填就是自己给自己造 bug。
三、确认”哪一份配置真的生效”
代理和证书类报错之所以难缠,一半原因是你改的那份配置压根没被读到。几家文档里都有可复核的加载规则,值得先看这个再看报错。
Gemini CLI 把 settings.json 放在四处:系统默认 /etc/gemini-cli/system-defaults.json(Linux)、用户级 ~/.gemini/settings.json、项目级的项目根 .gemini/settings.json、系统覆盖 /etc/gemini-cli/settings.json(Linux)。优先级从低到高是:硬编码默认 → system defaults 文件 → user settings → project settings → system settings → 环境变量 → 命令行参数。注意环境变量排在项目配置之上、命令行参数最高——你在项目里改了半天没效果,很可能是被上层压住了。
它还支持在 settings.json 里做环境变量插值:写 $VAR_NAME 或 ${VAR_NAME},加载时自动解析成当前进程环境里的值。这个机制的价值在于配置文件能进版本库而密钥不进。同时它的 .env 查找顺序是:当前工作目录 → 逐级父目录(到项目根或 home 为止)→ 用户 home 的 ~/.env。这条直接解释了一个常见现象:从仓库根目录启动和从子目录启动,读到的可能是不同的 .env。
aider 的 .aider.model.settings.yml 可以放四处,按顺序加载、后加载的优先:home 目录、git 仓库根目录、启动 aider 的当前目录、--model-settings-file <filename> 指定的自定义路径。Crush 的配置文件是 crushrc(bash 风格加 Crush 内建命令,不是 JSON),文档列出的顺序是 ./.crushrc(项目级)在前、~/.config/crush/crushrc(全局,Unix 类系统)在后。goose 那边,文档记录的是环境变量 GOOSE_PROVIDER、GOOSE_MODEL 用来设默认 provider 与模型,配置则持久化在 config.yaml——两套并存,但两者冲突时谁压谁,本篇依据的文档页面没有写,别靠猜,以官方文档为准。
密钥这一路也一样要确认来源。Zed 文档原话是 “Do not put API keys in settings.json.”,凭据走两条路:provider 设置界面,或环境变量,命名规则是 <PROVIDER_NAME>_API_KEY——provider 名为 my-provider 时对应 MY_PROVIDER_API_KEY。它的 configuration 页还有一句原话:“Provider keys saved through Zed are stored in the system keychain, not in settings.json.”(keychain 指操作系统自带的凭据保管服务。)所以排查鉴权类报错时,你得先答出这次用的是界面存进 keychain 的那把,还是环境变量那把。
落到手上,“确认哪一份生效”可以按这个顺序做,每一步都有明确的通过标准:
- 把候选文件全列出来。 照上面各家的位置逐条
ls:Gemini CLI 查~/.gemini/settings.json与项目根的.gemini/settings.json(Linux 上还有/etc/gemini-cli/settings.json、/etc/gemini-cli/system-defaults.json);aider 查 home、git 仓库根、当前目录三处的.aider.model.settings.yml;Crush 查./.crushrc与~/.config/crush/crushrc。通过标准:你能说出这次一共存在几份、分别在哪。 只找到一份反而是好消息,找到两份以上就得往下走。 - 按文档的优先级排序,从最高的那一份开始看,而不是从你最熟的那份。 Gemini CLI 是命令行参数 > 环境变量 > system settings > project settings > user settings > system defaults 文件 > 硬编码默认;aider 是后加载优先,
--model-settings-file指定的那份在最后、也就是最强。通过标准:你能指着一份文件说”改这份才有用”,并说出压在它上面的还有谁。 - 查环境里有没有东西压着。 在真正启动这个工具的那个环境里(不是你另开的一个终端)跑
printenv看有没有相关变量,比如 goose 的GOOSE_PROVIDER、GOOSE_MODEL,Zed 的<PROVIDER_NAME>_API_KEY,Gemini CLI 的GEMINI_API_KEY、GEMINI_MODEL。通过标准:能列出这些变量此刻是有值还是空。 有值又和文件里写的不一致,就是第 2 步排的那条优先级在起作用。 - 确认
.env是从哪儿读的。 Gemini CLI 的查找顺序是当前工作目录 → 逐级父目录 →~/.env,所以从仓库根启动和从子目录启动可能读到不同的文件。通过标准:你能说出这次启动时的工作目录,以及从它往上第一个存在.env的目录是哪个。 - 最后才用这个工具本身发一次最小请求。 不要用
curl代验,理由见第一节。通过标准:报错文案变了(说明你改的那份确实被读到了),或者请求通了。 报错文案一字不变,多半说明前四步里有一步的结论是错的,回到第 2 步重来,而不是继续改内容。
四、边界与代价:这套做法不管什么
把 HTTP 层设置写进各家自己的配置文件,代价是可移植性。你手上同时用三四个工具,就得配三四份,字段名还都不一样;换个代理地址要改好几处,漏一处就出现”有的工具能用、有的不能”的诡异状态。愿意接受这个代价的理由是它可复现——配置是文本,能进版本库,能 diff,能给同事复制。
它明确不管的事有这么几类:
第一,网络本身通不通它不管。代理是否拦截并重签了 TLS、企业根证书有没有装进对应运行时的信任库、链路上有没有别的设备改写请求——这些都在客户端配置之外,属于内网代理与证书链排查的范围。客户端能做的只是”按你说的地址和头发出去”。
第二,超时与断流的处置策略它不管。Continue 的 requestOptions 里记录了有 timeout 这一项,但请求断在半路之后怎么重试、怎么续传,是另一个话题。
第三,模型能力它不管。Roo Code 文档写得很硬:
“Roo Code uses native tool calling exclusively. This is the only supported tool protocol — there is no XML-based fallback.”
这是官方文档的说法。原生工具调用(function calling)指的是模型按接口约定直接输出结构化的函数调用请求,而不是靠在文本里拼一段标签让客户端解析。文档建议先查服务商文档确认该模型是否支持工具调用。也就是说,代理配对了、证书装好了、地址和密钥都没错,模型不支持这套协议照样用不成——这类失败很容易被误当成网络问题。Continue 那边对应的是 capabilities 里的 tool_use,Zed 的 capabilities 对象里有 tools、parallel_tool_calls 这些开关。
第四,界面细节本篇不写。各家的面板长什么样、提示语怎么写、什么时候校验,以你实际看到的界面为准。
第五,本篇不覆盖全部产品。举个可复现的例子:2026-08-07 当天,Windsurf 的模型文档地址会跳转到 Devin Desktop 的文档页,那一页未说明是否支持自带 API key(BYOK,即用你自己申请的密钥调模型),也没给配置位置,所以本篇不写它的做法,请以官方文档为准。
五、避坑清单
拿 curl 的成功当编辑器的成功。 会踩是因为两者的进程环境不同源,你的验证根本没覆盖出问题的那个进程。避法:验证要在同一个客户端里做——改完配置后用这个工具本身发一次最小请求,别用别的通道代验。
改了一份配置,生效的是另一份。 会踩是因为几家都有多处加载:aider 四个位置后加载优先,Gemini CLI 有六级优先级且环境变量压过项目配置,Crush 有项目级和全局两份。避法:动手前先按文档把加载顺序列出来,从优先级最高的那一层往下查,而不是从你最熟的那份文件开始改。
把 A 家的字段名套到 B 家。 会踩是因为这些字段在中文语境里都被叫成”接口地址”,看着可互换。避法:认名不认义,apiBase / api_url / Base URL / OPENAI_HOST / --base-url 各归各家,照着上面那张表填。
/v1 加不加拿不准。 各家文档给的形态确实不同:Cline 文档的 v0 示例是 https://api.v0.dev/v1(含 /v1),Kilo Code 明确接受 https://api.provider.com/v1 和 https://api.provider.com/v1/chat/completions 两种形态,后者是为端点结构非标准的服务商与自建网关准备的;Zed 示例是 https://example.com/v1;Groq 官方 base URL 是 https://api.groq.com/openai/v1;goose 的 OPENAI_HOST 与 OPENAI_BASE_PATH 则是拆成两段的设计。会踩是因为公司网关常会重写路径,拼错一段返回的可能是 404 或一个网关自己的错误页,看着不像”路径拼错”。避法:以你要接的那家服务商文档给的完整端点为准,逐段比对客户端拼出来的地址。
把密钥写进 settings.json 提交上去。 会踩是因为配置文件要进版本库,密钥顺手就写在旁边了。避法:Zed 明确禁止这么做,用界面或 <PROVIDER_NAME>_API_KEY;Gemini CLI 用 $VAR_NAME 插值把值留在环境里。
上下文窗口这类需要手填的项被忽略。 有几家把它交给你填:Cline 的 Context Window size、Roo Code 的 Context Window、Zed available_models 条目里的 max_tokens、aider 用 .aider.model.metadata.json 注册的 max_input_tokens / max_output_tokens。上下文窗口指一次请求里模型能看到的 token 上限,这几项填的就是 token 数量这个量纲。官方文档没有逐条说明客户端内部拿这些数做什么,所以本篇不替它们下结论;只提醒一点:按 OpenAI 兼容协议的通用机制推理,客户端报出来的参数类错误有时会长得很像网络错误,别一上来就往代理上归因。
Azure 场景直接套通用 OpenAI 兼容 provider。 Kilo Code 文档明确提醒:Azure GPT-5 不要用通用的 OpenAI 兼容 provider,要用 Kilo 原生的 azure provider,因为 Azure 会拒绝 max_tokens 参数。会踩是因为”它也是 OpenAI 兼容的”这个直觉太强。避法:先查目标平台有没有专门的 provider 选项。同类的接入路径选择可参考编辑器接自定义 API。
数据来源与核对日期
本篇引用的产品事实全部来自下列官方文档页面,核对日期均为 2026-08-07。字段与文档结构会随版本变化,请以官方文档最新版为准。
- Continue(
config.yaml、models块、requestOptions、roles、YAML 示例):https://docs.continue.dev/reference - Kilo Code(Headers、Base URL 两种形态、Azure
max_tokens提醒):https://kilo.ai/docs/providers/openai-compatible - Cline(Base URL / API Key / Model、v0 示例、Context Window size):https://docs.cline.bot/provider-config/openai-compatible
- Roo Code(Base URL / API Key / Model、Context Window、原生工具调用原句):https://roocodeinc.github.io/Roo-Code/providers/openai-compatible
- aider(
.aider.model.settings.yml加载顺序、extra_params/extra_headers、.aider.model.metadata.json):https://aider.chat/docs/config/adv-model-settings.html - Zed(
api_url、available_models、max_tokens、capabilities、密钥与 keychain 两句原话):https://zed.dev/docs/ai/use-api-access、https://zed.dev/docs/ai/configuration - goose(
GOOSE_PROVIDER、GOOSE_MODEL、OPENAI_HOST、OPENAI_BASE_PATH、config.yaml):https://goose-docs.ai/docs/getting-started/providers/ - Crush(
crushrc两处位置、provider add --base-url):https://raw.githubusercontent.com/charmbracelet/crush/main/README.md - Gemini CLI(
settings.json四处位置、优先级链、$VAR_NAME插值、.env查找顺序):https://google-gemini.github.io/gemini-cli/docs/get-started/configuration.html - Groq(base URL
https://api.groq.com/openai/v1):https://console.groq.com/docs/api-reference - Windsurf(核对日当天模型文档发生跳转、目标页未说明 BYOK 配置):https://docs.windsurf.com/windsurf/models、https://docs.devin.ai/desktop/models
本篇没有写什么,以及为什么。 任何产品的价格、免费额度、订阅档位、限速数字、版本号、完整模型清单,本次都不写——这类信息变动频繁,且不在本次核对范围内,请直接查各产品官方文档与定价页。各家界面的菜单层级、按钮位置、报错文案也不写,因为本次核对的是配置层文档,不是界面。另外,文中凡属 OpenAI 兼容协议层面的通用机制推理(例如参数类错误容易被误认成网络错误),已在原句里标明是机制推理,不是某家文档的记载;官方文档只列了字段名而没说明客户端内部用途的项,本篇也只写”这一项由你填、填的是什么量纲”,不代产品下结论。
延伸阅读:同一组里的 编辑器里AI输出卡住不出字、编辑器请求被截断或报超上下文;接完之后照 接完自定义模型别急着干活 逐项过一遍,才算真接通。