外观
第 8 章 · 配置与个性化
工具用熟之后,你会开始想:默认模型能不能固定?改完文件能不能自动格式化?换台机器怎样一键带走全部习惯?这些都靠配置解决。本章讲透 OpenCode 的两套配置体系、核心配置项,以及怎样把个人习惯组织成可迁移、可共享的配置。
本章包含 5 个知识点:
- 配置文件基础:两套配置、位置与层级合并
- opencode.jsonc 核心配置项详解
- 主题与外观:把界面调成自己喜欢的样子
- Formatter:让 AI 改完的文件自动符合风格
- 网络、代理与后台服务环境
知识点 1:配置文件基础:两套配置、位置与层级合并
① 定位
配置是个性化的入口,但 OpenCode 有「两套配置文件」,放错位置是新手最常见的困惑(比如主题怎么写都不生效)。本知识点先把配置的载体、位置与合并规则讲清楚。
② 是什么(What)
OpenCode V2 有两套配置,职责不同:
| 配置文件 | 位置 | 管什么 |
|---|---|---|
opencode.jsonc(服务端配置) | 项目根目录,或 ~/.config/opencode/opencode.jsonc | 模型、Agent、权限、MCP、Formatter、Compaction 等行为 |
cli.json(终端客户端配置) | ~/.config/opencode/cli.json | 主题、键位等终端界面相关设置 |
一句话记忆:行为配置进 opencode.jsonc,外观 / 键位进 cli.json。 主题写进 opencode.jsonc 不生效,就是违反了这条分工。
opencode.jsonc 的两种放置位置(项目级):
text
my-app/opencode.jsonc # 直接放在目录里
my-app/.opencode/opencode.jsonc # 放在 .opencode 目录里格式支持 JSON 与 JSONC;JSONC 允许注释和尾逗号,适合写说明。任何一个配置文件都建议首行加 schema,获得编辑器校验与自动补全:
jsonc
{
"$schema": "https://opencode.ai/config.json",
// 默认模型
"model": "anthropic/claude-sonnet-4-5"
}③ 怎么做(How)
- 在项目根目录创建
opencode.jsonc,加上$schema; - 只写你要改的选项——没写的全部走默认值,不必抄一份全量配置;
- 不确定字段名 / 取值时,以
https://opencode.ai/config.json这个 schema 为准(编辑器会自动提示); - 也可以直接让 OpenCode 帮你改这个文件(「把默认模型改成 X」);
- 主题 / 键位去
~/.config/opencode/cli.json改,不要放错文件。
配置层级的合并规则(重要):OpenCode 从当前目录向上搜索到文件系统根,按「越远越低、就近越高」合并:
text
低 ~/.config/opencode/opencode.jsonc (全局)
/projects/acme/opencode.jsonc (仓库根)
高 /projects/acme/packages/web/opencode.jsonc(当前子包)子包配置覆盖仓库配置中的同名设置,仓库配置覆盖全局;不冲突的设置都保留。另有一条细节:所有 .opencode/opencode.jsonc 整体优先于直接放置的 opencode.jsonc。除非刻意利用该行为,一个目录树里最好统一只用一种形式。
④ 为什么这么做(Why)
- 行为与界面分属两个进程。
opencode.jsonc由后台服务读取(模型、工具),cli.json由终端客户端读取(渲染、按键)。两者生命周期不同——你可以换 TUI 客户端而保留同一套行为配置。分文件是架构分层的自然结果。 - JSONC + schema 兼顾可读性与正确性。 注释让配置能解释「为什么这么配」;schema 在你写错字段名时即时报错,避免启动后才发现配置静默失效。
- 多层合并让「全局习惯 + 项目约定 + 局部例外」共存。 全局配个人偏好,仓库根配团队基线,子包配特殊需求,三层叠加而非互相拷贝。这与 AGENTS.md 的分层思想一致(第 4 章)。
- 「只写需要的项」降低维护成本。 抄全量默认值会让配置文件充斥噪音,且升级时可能与新默认值冲突;最小配置永远最易读、最可移植。
- schema 是唯一的事实来源。 文档可能滞后,但
config.json与当前版本严格同步;养成查 schema 的习惯,就不会写出已废弃的字段。
⑤ 这样做的好处
- 放对位置,配置一次生效,不用反复怀疑语法。
- 编辑器自动校验补全,写错立刻发现。
- 配置分层清晰:个人 / 团队 / 子包互不打架。
- 最小配置可迁移:复制一个小文件就能换机器。
- 两套配置各随其主:换客户端、换服务互不影响。
⑥ 不这么做的问题 / 坏处
- 主题写进 opencode.jsonc → 怎么改都不生效,白白浪费时间。
- 不加 schema → 字段拼错、取值非法都无提示,静默走默认值。
- 抄全量默认值 → 文件臃肿,升级后新旧默认值冲突难排查。
- 一个目录树混用两种放置形式 → 忘记
.opencode整体优先,产生意外覆盖。
⑦ 举一反三:三个例子
例 1(基础):新建项目的第一份配置
📌 场景:新项目开始,你想固定默认模型并能写注释。
✅ 做法:项目根创建 opencode.jsonc:
jsonc
{
"$schema": "https://opencode.ai/config.json",
"model": "供应商/你的常用模型"
}🔍 讲解:schema + 一个最小项,就是最标准的开局。其它选项等真正需要时再加。
例 2(进阶):全局放通用项、项目放团队项
📌 场景:你希望所有项目都遵守个人偏好,但每个项目有各自的命令和权限。
✅ 分工:
text
~/.config/opencode/opencode.jsonc → update、个人 shell、通用偏好
项目 opencode.jsonc → 项目模型、permissions、mcp🔍 讲解:全局不出现项目专属路径,项目配置进版本控制共享给团队。分层放置后,配置在任何机器上都可复现。
例 3(挑战):诊断「配置为什么不生效」
📌 场景:你改了子目录的模型,但启动后仍用旧模型。
✅ 排查顺序:
- 配置放对文件了吗?(模型在 opencode.jsonc,不是 cli.json)
- 目录树里是否有
.opencode/opencode.jsonc整体覆盖了直接配置? - 该文件在当前启动目录的搜索路径上吗?(从当前目录向上找)
- JSON / JSONC 语法是否正确、schema 是否报红?
🔍 讲解:配置不生效 90% 是「放错文件 / 放错层级 / 语法错误」三类。按顺序排查,很快定位。
⑧ 练习题 ×2
练习 1(巩固型)
📝 题目:opencode.jsonc 与 cli.json 各管什么?配置层级中,就近配置与上级配置冲突时如何处理、不冲突时如何处理?
💡 思路提示:行为 vs 外观;同名覆盖、其余保留。
✅ 参考答案:
text
opencode.jsonc 管模型、Agent、权限、MCP 等行为;
cli.json 管主题、键位等终端界面设置。
多层合并:就近(高优先级)配置覆盖上级的同名设置,
不冲突的设置全部保留。🔍 讲解:两套配置的分工与合并顺序,是所有配置操作的基础坐标。
练习 2(迁移型)
📝 题目:迁移到 CSS 的样式来源:「浏览器默认样式表(全局)→ 网站样式表(项目)→ 行内样式(局部)」的层叠(cascade)规则,与 OpenCode 配置合并有何共性?为什么这样的分层让协作更方便?
💡 思路提示:逐层覆盖、各自维护、基线可共享。
✅ 参考答案(示例):
text
- 共性:都按「全局基线 → 项目约定 → 局部例外」的顺序层叠,
高优先级覆盖同名项,未冲突项保留;
- 浏览器 / 全局基线给默认,网站 / 项目层给团队统一风格,
行内 / 局部层处理特殊情况;
- 各层由不同角色维护、互不干扰:用户管全局、团队管项目、
子包管例外。OpenCode 配置合并是同一种工程模式。知识点 2:opencode.jsonc 核心配置项详解
① 定位
知道配置放哪后,要知道有哪些项可配、各自什么含义。本知识点把日常最常用的配置项系统过一遍,并区分「根级默认」与「可被 Agent / 命令覆盖」的关系。
② 是什么(What)
高频配置项速览:
| 配置项 | 作用 | 典型值 / 说明 |
|---|---|---|
model | 默认模型,供应商/模型 格式 | 根级默认当前不保留 #变体;Agent / 命令里引用模型时可指定变体 |
default_agent | 会话未显式选 Agent 时的主 Agent | 如 "build" |
shell | 终端与 shell 工具使用的 shell | 如 "/bin/zsh" |
update | 更新检查(仅全局配置生效,项目值被忽略) | "disable" / "notify"(默认)/ "auto";自动安装不会重启运行中的服务 |
permissions | 有序权限规则 | 第 7 章详解 |
mcp | MCP 服务器 | mcp.servers.<name>,第 7 章详解 |
formatter | 写 / 改 / 补丁后自动格式化 | 知识点 4 详解 |
websearch | 搜索供应商选择 / 关闭 | 如 { "provider": "random" } |
snapshots | 文件系统快照(支撑 undo / revert) | false 可关闭 |
compaction | 自动压缩与保留量 | 第 3 章详解;auto:false 只关自动、不删已有检查点 |
watcher | 文件监听忽略列表 | 如 ignore: ["dist/**","coverage/**"] |
tool_output | 工具结果保留的行数 / 字节数 | 默认 max_lines:2000、max_bytes:51200 |
media.image | 超大图片如何缩放 / 拒绝 | auto_resize、max_width/height、max_base64_bytes |
worktree.directory | 新建本地 worktree 的父目录 | 相对路径按项目规范检出目录解析,支持 ~/ |
skills / commands | 额外的 Skill 搜索路径 / 命令定义 | 第 5 章详解 |
warming | 让最近活跃的模型会话保持温热 | 默认关闭;默认 4 分钟空闲间隔、30 分钟活跃窗口 |
③ 怎么做(How)
- 按需求从上表挑项,不要一次全开;
- 根级
model/default_agent只设「默认值」,允许会话内临时切换(第 2、6 章的操作不受锁死); update只在全局配置里设;- 改完保存,留意服务是否需要重启(部分项启动时读取);
- 每项改完做一次小验证,确认行为真的变了。
④ 为什么这么做(Why)
- 根级默认与会话临时切换分离,兼顾稳定与灵活。 配置给的是「开局值」,你仍可
F2/<leader>a临时换挡;若配置强制锁死,前面学的按任务选型就无法落地。 update只认全局配置,是为了防止项目仓库劫持你的更新策略。 否则克隆一个仓库就可能让你的客户端自动升级 / 停止检查——更新策略属于本机用户,不属于项目。- 快照、监听、输出、媒体这些「工程细节项」默认值已经调好。 多数人无需改动;但当 undo 行为异常、
dist/频繁触发刷新、大输出灌爆上下文时,知道有这些开关就能精准处置。 - warming 默认关闭,因为它有真实成本。 保活靠周期性「空转请求」,会消耗 token;只有频繁复用同一会话、且对冷启动延迟敏感时才值得开。默认值指向零额外花费。
- compaction 支持本地摘要与供应商原生两种模式,模型级设置覆盖供应商级——延续第 3 章:压缩策略可按模型精细定制。
- 配置项虽多,但遵循同一哲学:默认安全 / 省成本,按需开启。 这让你可以放心地「只配需要的」。
⑤ 这样做的好处
- 默认值稳定:开局模型、Agent、更新策略一次设好。
- 临时切换不受限:默认 ≠ 锁死。
- 工程异常有开关可调:监听、输出、媒体、快照。
- 成本可控:warming 等花钱功能默认关闭。
- 配置意图清晰:每项都对应一个具体可验证的行为。
⑥ 不这么做的问题 / 坏处
- 在项目配置里设
update→ 被忽略,还以为策略已生效。 - 根级模型锁死思维 → 误以为会话内不能换挡,放弃混合策略。
- 从不了解工程细节项 → 遇到 watcher 频繁刷新、输出截断时只能忍受。
- 无脑开启 warming → 空转请求悄悄累积账单。
⑦ 举一反三:三个例子
例 1(基础):固定默认 Agent 与模型
📌 场景:你希望每个新会话默认从 build + 常用模型开始。
✅ 配置:
jsonc
{
"default_agent": "build",
"model": "供应商/常用模型"
}🔍 讲解:这两项只决定开局;会话中随时可切。固定开局让每个任务以你最熟悉的姿态启动。
例 2(进阶):让监听忽略构建产物
📌 场景:项目构建后 dist/ 频繁变动,导致界面不断刷新文件状态。
✅ 配置:
jsonc
{
"watcher": { "ignore": ["dist/**", "coverage/**"] }
}🔍 讲解:构建产物不是「源信息」,本就不该触发会话更新。把它们从监听中排除,既减少干扰也降低无谓的上下文变动。
例 3(挑战):为高频复用场景开启 warming 并评估成本
📌 场景:你一天内反复回到同一个长会话,每次冷启动都要等。
✅ 做法:先评估频率,再显式开启并可自定义保活参数:
jsonc
{
"warming": {
"prompt": "Do not perform any work. Reply with exactly: OK",
"interval": "4 minutes",
"duration": "30 minutes"
}
}观察一周用量,若保活花费 > 省下的等待时间价值,就关闭。
🔍 讲解:warming 是典型的「花小钱买顺滑」,但是否划算取决于使用频率。先量化、再开启、定期复核,与第 6 章的选型逻辑完全一致。
⑧ 练习题 ×2
练习 1(巩固型)
📝 题目:update 有哪三个取值、默认是什么?为什么它只在全局配置生效?warming 默认开启还是关闭?
💡 思路提示:disable/notify/auto;防项目劫持;默认关闭。
✅ 参考答案:
text
update:disable(不检查)、notify(默认,提示后安装)、
auto(自动安装,且不会重启运行中的服务)。
只在全局生效:更新策略属于本机用户,防止克隆的项目仓库
改变你的更新行为。
warming 默认关闭(保活有空转 token 成本)。🔍 讲解:这两项都涉及「本机控制权与成本」,是最容易被误解的全局项。
练习 2(迁移型)
📝 题目:迁移到手机的「默认应用」设置:系统给每个动作设了默认 App(打开链接、发短信),但每次使用时仍可「分享到其它 App」。这与 OpenCode「根级默认模型 / Agent + 会话内临时切换」有何共性?
💡 思路提示:默认值降成本、临时选择保灵活。
✅ 参考答案(示例):
text
- 默认 App:省去每次选择,高频操作一键启动(≈ 根级默认);
- 仍可临时分享到其它 App:特殊需求不被默认值锁死
(≈ F2 / leader+a 临时换挡);
共性:好的默认配置降低日常决策成本,同时保留场景化覆盖的
自由。OpenCode 的默认模型 / Agent 与手机默认 App 是同一种
「默认不锁死」的设计哲学。知识点 3:主题与外观:把界面调成自己喜欢的样子
① 定位
每天盯着 TUI 几小时,配色直接影响心情与可读性。本知识点讲如何选择主题、切换深浅模式,以及怎样创建自定义主题——注意主题配置属于 cli.json。
② 是什么(What)
选择方式一(TUI 内):Ctrl+P 打开命令面板 → Open settings → Theme,可视化选择。
选择方式二(直接写配置):编辑 ~/.config/opencode/cli.json:
jsonc
{
"theme": {
"name": "tokyonight",
"mode": "system"
}
}mode三个取值:system(跟随终端外观,默认)、dark、light;自定义主题只提供一种模式时,请求另一种会回退到它已有的模式。- 内置主题众多,常见的有:
opencode、tokyonight、catppuccin(含-frappe/-macchiato)、dracula、nord、gruvbox、github、solarized、rosepine、kanagawa、everforest、monokai、one-dark、synthwave84、matrix、carbonfox等(完整列表以官方 Themes 文档为准)。 - 当 OpenCode 能读取终端调色板时,还有
system主题可跟随终端配色。
③ 怎么做(How)
- 先在 TUI 设置里实时预览几个主题,挑对比度适合自己、与终端字体搭配的;
- 确定后在
cli.json固定name与mode; - 长时间夜间使用选
dark,截图 / 演示需要浅底可选light; - 想微调颜色:在
~/.config/opencode/themes/放自定义主题文件(文件名即主题名,如ocean.json),可引用色板变量(如$hue.cyan); - 不确定主题结构时,用官方 theme 工具生成一份完整文件再改。
④ 为什么这么做(Why)
- 主题属于渲染层,所以在 cli.json。 同一个后台服务可被不同终端客户端连接,每个客户端可有自己的外观;把主题放在客户端配置里,换客户端不影响行为配置。
- 提供实时预览是因为配色必须眼见为实。 名字(dracula、nord)无法告诉你在你的终端、字体、环境光下的实际对比;在设置里切换预览,选择成本极低。
system模式跟随环境,减少手动切换。 白天终端浅底、夜晚深底时,主题自动跟随,避免「黑底黑字」之类的可读性事故。- 自定义主题用 JSON + 色板变量,让一处改色、全局生效;全局目录
~/.config/opencode/themes/对所有项目可见,个人审美只需维护一次。 - 可读性优先于炫酷。 TUI 是生产工具,低对比的花哨主题长时间使用会增加疲劳;选主题时应先保证代码与状态文字清晰可辨。
⑤ 这样做的好处
- 界面耐看、长时间使用不疲劳。
- 深浅模式自动 / 手动随心。
- 选择有实时预览,不盲猜。
- 自定义一次、全局复用。
- 配置位置正确,改完立即生效。
⑥ 不这么做的问题 / 坏处
- 主题写进 opencode.jsonc → 不生效,困惑半天。
- 只看名字不预览 → 实际对比度过低,代码看不清。
- 锁定错误的 mode → 终端浅底时配深主题,文字糊成一片。
- 每个项目各配主题 → 主题是全局个人偏好,分散配置难统一。
⑦ 举一反三:三个例子
例 1(基础):跟随终端外观
📌 场景:你的终端会随时间切换深浅底色。
✅ 配置:cli.json 设 "theme": { "name": "opencode", "mode": "system" }。
🔍 讲解:system 让 TUI 与终端保持一致,任何光线下都有合适对比,无需手动来回切。
例 2(进阶):为演示固定浅色主题
📌 场景:你要录屏 / 投屏演示,浅底在投影上更清晰。
✅ 配置:开始前临时设 "mode": "light"、选 github 之类浅底主题;演示结束切回 system。
🔍 讲解:主题可按场合临时改。演示、截图、写文档配图常需要浅底,固定深色会让观众看不清。
例 3(挑战):制作个人自定义主题
📌 场景:内置主题都差一点,你想要一套专属配色。
✅ 做法:用 theme 工具生成完整文件到 ~/.config/opencode/themes/myeyes.json,先只改 accent 等关键色、用色板变量统一调整;保存后在设置中选 myeyes,真实使用一两天再微调。
🔍 讲解:从完整模板出发、小步迭代,比从零手写几十个色值可靠。先保可读、再谈个性,每次只改少数颜色并实测。
⑧ 练习题 ×2
练习 1(巩固型)
📝 题目:主题配置写在哪个文件?mode 有哪三个取值?说出至少四个内置主题名。
💡 思路提示:cli.json;system/dark/light;任选四个。
✅ 参考答案:
text
文件:~/.config/opencode/cli.json。
mode:system(跟随终端)、dark、light。
内置主题(任选四个):opencode、tokyonight、catppuccin、
dracula、nord、gruvbox、github、solarized、rosepine 等。🔍 讲解:记住「主题在 cli.json」可避免最常见的配置失效问题。
练习 2(迁移型)
📝 题目:迁移到键盘的灯效 / 手机壁纸:为什么这类「纯外观偏好」通常按「设备 / 用户」全局设置,而不是按每个项目 / 每个 App 单独设置?什么情况下值得为特定场景单独换外观?
💡 思路提示:偏好跟随人、减少重复;场景化临时切换。
✅ 参考答案(示例):
text
- 外观偏好跟随「人」而非「任务」:一套顺眼的配色适用于
所有项目,按项目重复设置纯属浪费;
- 全局设置一次、处处一致,维护成本最低;
- 值得单独换的场景:演示 / 投屏需浅底高对比、暗光环境需
护眼深色、色盲 / 低视力需要特殊配色。
共性:OpenCode 主题也应全局固定 + 场景临时切换,
而不是在项目配置里分散维护。知识点 4:Formatter:让 AI 改完的文件自动符合风格
① 定位
AI 写出的代码逻辑正确,但缩进、引号、行宽可能与项目风格不符。手动让它「按 Prettier 调整」是额外一轮;Formatter 让格式化在每次写入后自动发生。本知识点讲如何开启、内置支持哪些,以及如何自定义。
② 是什么(What)
Formatter 默认关闭,在 opencode.jsonc 开启:
jsonc
{
"$schema": "https://opencode.ai/config.json",
"formatter": true
}true:启用所有内置 formatter;OpenCode 只在对应可执行命令存在、且满足项目检测条件时才实际运行(不会因为没装工具而报错)。- 也接受对象形式:空对象
{}等价于true;对象里还能覆盖内置项或添加自定义 formatter。
内置 formatter(按扩展名自动匹配,均需相应命令可用):
| Formatter | 覆盖扩展名 | 使用条件 |
|---|---|---|
gofmt | .go | 有 gofmt 命令 |
mix | .ex .exs .eex .heex 等 | 有 mix 命令 |
oxfmt | .js .jsx .ts .tsx 等 | package.json 中有 oxfmt 依赖 |
prettier | JS/TS、HTML、CSS、Vue 等一大串前端格式 | 有 prettier(及对应解析器) |
(内置完整列表与检测规则以官方 Formatters 文档为准。)
③ 怎么做(How)
- 在项目配置设
"formatter": true; - 确保项目实际使用的格式化工具已安装(如 devDependencies 中的 prettier);
- AI 经
write/edit/patch改完文件后,格式化自动执行,无需你提醒; - 项目用非内置工具(如 biome、black)时,用对象形式添加自定义 formatter,指定命令与参数;
- 若发现格式化结果不符预期,检查项目自身的 formatter 配置(如
.prettierrc)——OpenCode 调用的是项目里的工具,风格由项目配置决定。
④ 为什么这么做(Why)
- 格式一致性应自动化,而非靠人 / 模型记忆。 缩进与引号是机械规则,让每次写入都经同一工具处理,结果 100% 一致;靠 Prompt 说「用 2 空格」既啰嗦也可能被忽略。
- 默认关闭、按需运行,尊重项目实际。 OpenCode 不自带一套风格强加给你,而是检测到项目里有对应工具才调用——格式化永远使用项目选定的工具与配置。
- 格式化紧跟写操作,避免「脏代码」进入下一步。 文件一落盘就是合规风格,后续 read 看到的是干净代码,diff 也只包含真实改动而非格式噪音,代码审查更轻松。
- 对象形式提供扩展点,覆盖所有技术栈。 内置列表有限,但任何能从命令行运行的格式化工具(black、ruff、biome、rustfmt 包装等)都能自定义接入。
- 不把格式化混进模型任务,节省一轮对话。 模型不必专门输出「格式化后的完整文件」,工具在文件系统层直接完成,更快也更省 token。
⑤ 这样做的好处
- 代码风格始终一致,无需人工提醒。
- diff 干净:只含真实逻辑改动。
- 零额外对话成本:写入即格式化。
- 自动适配项目工具链:不强行注入风格。
- 任意技术栈可扩展:自定义 formatter 兜底。
⑥ 不这么做的问题 / 坏处
- 不开 formatter → 风格时好时坏,提交前要手动整理。
- 在 Prompt 里反复要求格式 → 啰嗦、占上下文,还不一定遵守。
- 误以为 OpenCode 决定风格 → 没装 / 没配项目工具却抱怨格式化结果。
- 自定义 formatter 命令写错 → 写入后报错或文件未被处理。
⑦ 举一反三:三个例子
例 1(基础):前端项目开启自动格式化
📌 场景:项目已把 prettier 放进 devDependencies。
✅ 配置:"formatter": true。此后 AI 改任何 .ts / .vue 文件,落盘即按 .prettierrc 格式化。
🔍 讲解:工具和风格配置都由项目提供,OpenCode 只负责在写入后调用——团队每个人(及 AI)产出风格完全一致。
例 2(进阶):接入未内置的格式化工具
📌 场景:Python 项目用 ruff format,内置列表没有。
✅ 做法:用对象形式添加自定义项(具体字段以官方 Formatters 文档为准),把扩展名映射到 ruff format <file> 之类命令;安装 ruff 后验证一次写入。
🔍 讲解:自定义 formatter 让任何 CLI 格式化工具都能接入。关键是命令要能对「单个文件」原地生效,与写操作的时机配合。
例 3(挑战):排查「格式化没触发」
📌 场景:设了 formatter: true,但文件风格没变。
✅ 排查:
- 该扩展名是否有匹配的内置 formatter?
- 对应命令是否真的在 PATH / 项目依赖中可用?
- 项目检测条件是否满足(如 oxfmt 需在 package.json 中)?
- 项目 formatter 配置是否本身就与现状一致(即「看起来没变」其实已合规)?
🔍 讲解:true 只是「允许」,真正运行还需工具在场。排查重点是匹配 + 可执行 + 检测条件三关。
⑧ 练习题 ×2
练习 1(巩固型)
📝 题目:Formatter 默认开启还是关闭?formatter: true 后,决定某个文件是否被格式化的条件有哪些?
💡 思路提示:默认关;扩展名匹配 + 命令可用 + 检测条件。
✅ 参考答案:
text
默认关闭,需在 opencode.jsonc 设 "formatter": true。
文件被格式化的条件:扩展名有匹配的内置(或自定义)formatter、
对应命令可用、满足该 formatter 的项目检测条件
(如 oxfmt 需在 package.json 中声明依赖)。🔍 讲解:理解「启用 ≠ 强制运行」,就不会在没装工具时误以为功能坏了。
练习 2(迁移型)
📝 题目:迁移到工厂质检流水线:为什么在「产品下线」的固定节点自动检测,比让工人「记得检查」更可靠?当不同产品线要用不同检测标准时,系统应如何设计?这与 Formatter 有何共性?
💡 思路提示:固定节点自动化、标准跟随产品线。
✅ 参考答案(示例):
text
- 固定节点自动检测:不依赖人的记忆与自觉,一致性 100%;
- 标准跟随产品线:不同产品调用各自的检测规范,而非全厂统一;
- 可扩展:新增产品时注册新的检测程序。
共性:Formatter 在「文件落盘」这个固定节点自动运行,
风格配置跟随具体项目、未覆盖的工具可自定义接入——
本质都是「关键节点自动化 + 标准就近定义 + 可扩展」。知识点 5:网络、代理与后台服务环境
① 定位
在公司网络、自建代理、私有证书环境下,OpenCode 可能连不上模型 API。本知识点讲代理变量怎么设、后台服务的环境为何要单独持久化,以及私有 CA 的处理——这是配置章节中偏运维、但关键时刻能救命的一块。
② 是什么(What)
标准代理变量(三件套):
bash
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
export NO_PROXY=localhost,127.0.0.1,::1HTTP_PROXY处理 HTTP 目标、HTTPS_PROXY处理 HTTPS 目标;代理 URL 本身两个都可以用http://。NO_PROXY必须包含回环地址:CLI 与后台服务之间走本地 HTTP,若回环也被代理,内部通信会失败。NO_PROXY是逗号分隔的直连主机 / 地址列表。
为什么还要写入后台服务配置:shell 里 export 的变量,只对「从该 shell 启动的服务」生效。想让服务以后每次启动都用同样网络设置,要持久化:
bash
opencode service set env HTTP_PROXY http://proxy.example.com:8080
opencode service set env HTTPS_PROXY http://proxy.example.com:8080
opencode service set env NO_PROXY localhost,127.0.0.1,::1
opencode service start # 改变量会停止运行中的服务,start 用新环境拉起
opencode service unset env HTTPS_PROXY # 删除持久化变量代理认证:用户名密码直接写进 URL,特殊字符做百分号编码:
bash
export HTTPS_PROXY='http://user:p%40ssword@proxy.example.com:8080'私有证书:代理或目标站使用私有 CA 签发的证书时,设 NODE_EXTRA_CA_CERTS 指向一个 PEM 文件,进程启动时把额外 CA 加入信任库。
③ 怎么做(How)
- 先在 shell 里导出三件套(含回环排除),前台验证能否连通;
- 确认可用后用
opencode service set env持久化,再service start; - 设代理的 shell 里同样保留
NO_PROXY(服务变量只管服务进程,不管 CLI 进程); - 私有 CA 环境配
NODE_EXTRA_CA_CERTS; service get env的输出含凭证 URL,不要外发分享。
④ 为什么这么做(Why)
- 代理是环境级事实,靠标准变量表达最通用。 几乎所有网络工具(Node、curl 等)都识别
HTTP_PROXY系列;用标准变量,OpenCode 与其依赖的运行时行为一致,不需要专属配置。 - 回环必须排除,因为代理通常只服务外网。 把
127.0.0.1也发给代理,会让 CLI↔服务的内部调用被转发、甚至失败。这是代理环境最典型的坑。 - 服务环境单独持久化,源于「服务独立于终端运行」。 后台服务可能开机自启、被其它终端触发;shell export 无法覆盖这些启动方式。把环境写进受管服务配置,才能保证任何方式启动都一致。
- 改变量即重启服务,是为了让环境干净生效。 环境变量在进程启动时固化,热修改一个常驻进程的环境既不可靠也不安全;停止再启动语义明确。
- 私有 CA 走显式信任文件,而非放宽 TLS 校验。 正确做法是把企业 CA 加入信任库,既通过企业代理又保持完整的证书验证;关闭校验才是真正危险的做法。
- 凭证 URL 需谨慎,因为它同时包含网络位置与密码。 持久化值虽然存在私有配置中,但展示 / 截图时仍可能泄露。
⑤ 这样做的好处
- 任何网络环境都能连通:公司代理、认证代理、私有 CA 均有解。
- 服务行为可复现:持久化后与启动方式无关。
- 内部通信不受影响:回环排除避开经典坑。
- 保持完整 TLS 安全:用额外 CA,而非关闭校验。
- 排障路径清晰:变量、服务环境、证书三层分别检查。
⑥ 不这么做的问题 / 坏处
- 只在 shell export → 换个终端 / 重启服务后代理失效。
- 漏掉 NO_PROXY 回环 → CLI 与服务内部通信异常,表现怪异。
- 为省事关闭证书校验 → 中间人攻击敞口,安全彻底失守。
- 私有 CA 不处理 → 所有请求报 TLS 错误却找不到原因。
⑦ 举一反三:三个例子
例 1(基础):在代理网络下首次配置
📌 场景:公司网络必须走代理才能访问模型 API。
✅ 做法:导出三件套(NO_PROXY 含回环)→ 前台验证一条消息 → service set env 持久化 → service start。
🔍 讲解:「先临时验证、再持久化」避免把错误的代理地址写进服务配置。回环排除一步不能省。
例 2(进阶):代理需要账号密码
📌 场景:企业代理要求认证,密码含 @ 等特殊字符。
✅ 做法:把特殊字符百分号编码(@ → %40),写成 http://user:p%40ssword@proxy...;CLI shell 与服务环境两边都更新。
🔍 讲解:URL 里的特殊字符不编码会导致解析错位、用户名密码被截断。编码后的值才是合法的代理 URL。
例 3(挑战):TLS 错误的分层诊断
📌 场景:配好代理后仍报证书错误。
✅ 顺序:
- 是私有 CA 环境吗?→ 配
NODE_EXTRA_CA_CERTS指向企业根证书 PEM; - 代理本身是否在做 TLS 拦截?→ 同样需要信任拦截证书;
- 系统时间是否正确?→ 时间错误也会导致证书校验失败;
- 确认你没有通过关闭 TLS 校验来「绕过」问题。
🔍 讲解:证书错误优先考虑「信任链缺失」,正确解法永远是补齐信任、而非关闭验证。
⑧ 练习题 ×2
练习 1(巩固型)
📝 题目:写出三个标准代理变量,并解释为什么 NO_PROXY 必须包含回环地址。shell 导出后,为什么还要用 opencode service set env?
💡 思路提示:HTTP_PROXY/HTTPS_PROXY/NO_PROXY;内部通信;服务独立启动。
✅ 参考答案:
text
三变量:HTTP_PROXY、HTTPS_PROXY、NO_PROXY。
NO_PROXY 含 localhost,127.0.0.1,::1:CLI 与后台服务之间走
本地 HTTP,若回环也走代理,内部通信会被转发而失败。
还要持久化:shell export 只影响从该 shell 启动的服务;
服务可被其它方式启动,写入受管配置才能每次一致。🔍 讲解:这两点是代理配置中最容易被忽视、又最常导致怪问题的关键。
练习 2(迁移型)
📝 题目:迁移到办公室的邮件外发服务器(SMTP 中继):公司内网发外部邮件必须经统一中继、内部同事互发则直连、中继还需登录。这与 OpenCode 的代理三件套有何共性?面对私有证书 / 登录凭证,正确的安全姿态是什么?
💡 思路提示:外部走中继、内部直连;显式信任而非关闭校验。
✅ 参考答案(示例):
text
- 外部邮件走中继(≈ HTTP/HTTPS_PROXY),内部互发直连
(≈ NO_PROXY 排除内部地址);
- 中继需要登录(≈ 代理 URL 内嵌凭证),凭证受管存储;
- 共性:都按「目标在内部还是外部」分流,内部通信不经过
外部通道,凭证不随处散落。
安全姿态:面对私有证书,应显式加入信任(NODE_EXTRA_CA_CERTS)
而非关闭校验;凭证放进受管配置、不外发。🔍 讲解:网络分流与凭证管理是通用运维常识。把邮件中继的经验迁移过来,你就能在任何受限网络中正确配置 OpenCode,既连通又不失安全。
本章小结
| 知识点 | 一句话核心 |
|---|---|
| 1. 配置文件基础 | 行为进 opencode.jsonc、外观键位进 cli.json;就近合并、只写需要的项 |
| 2. 核心配置项 | model/default_agent 是开局默认、可临时换挡;update 仅全局;warming 默认关 |
| 3. 主题外观 | 主题在 cli.json;实时预览、mode 跟随终端、自定义放全局 themes 目录 |
| 4. Formatter | 默认关闭;写入后自动调用项目自带工具,机械风格交给工具 |
| 5. 网络与服务 | 代理三件套必排回环;环境持久化进服务;私有 CA 显式信任 |
下一章进入《AI Agent 工作流方法论》:把前面所有技能组织成完整的工作方式——任务拆解、计划先行、子代理编排、检查点与复盘,从「会用 AI」进阶到「用 AI 系统性地交付项目」。