← 返回博客

BYOK 现实检验:Open Design 当下会出问题的 5 件事

我们承诺把 BYOK 作为一等公民。本周来自社区的五个开放 bug 讨论——Gemini、DeepSeek、OpenCode、Windows——揭示了接缝仍然粗糙的地方,以及在每个修复落地前该用什么替代方案。

BYOK 现实检验:Open Design 当下会出问题的 5 件事

我们一直在告诉大家,Open Design 从底层就是 BYOK 的。这话现在依然成立。BYOK 设计工作流 的开篇之作走了一遍可用路径——把 daemon 指向任意兼容 OpenAI 的端点,粘贴你的密钥,就完成了。对绝大多数配置来说,这就是故事的全部,而且会一直是故事的全部。

但「BYOK」不是单一的一个功能。它是一份延伸进聊天编辑器、finalize 端点、模型选择器、CLI 启动路径和分析层的契约。其中每一处都是契约可能破裂的地方——而眼下,其中有好几处正是我们 公开 issue 跟踪器 里的开放 issue,是用户在过去 48 小时内报上来的。

我们本可以写完那篇开篇之作就此打住。但相反,这里来一次诚实的检视:本周进来的那些讨论、什么坏了、为什么坏、今天该怎么办,以及哪个 PR(或哪个路线图档位)正在修它。这些没有一个是藏着掖着的。它们都已立案、打了标签、链接在下面——比起让你在某个周五做 deck 做到一半才撞见它们,我们宁愿你从我们这里读到它们。

承诺 vs bug 清单

这个定调很重要,因为很容易误读成「BYOK 半生不熟」。它不是。下面这五个里没有一个是「BYOK 不工作」的 bug。它们每一个都活在边界上——一边是我们自己拥有的 adapter(兼容 OpenAI 的那一层、模型选择器、finalize 路径),另一边是我们不拥有的:上游服务商的 CLI、他们的打包选择,或宿主平台的进程模型。

那条边界,是任何开源 CLI 编排器里「现实」所在的地方。我们不运行推理,我们不为每个服务商交付一个 fork 出来的 CLI,我们也不把一切包进一个把棱角抹平(同时悄悄给你的 token 征税)的代理里。这种姿态的代价就是:当某个服务商的 CLI 改了形态,或者 Windows 强加了一条 macOS 没有的限制时,接缝就会显出来。这一周,五道这样的接缝同时显了出来。

下面是全部五个,按它们进来的先后顺序排列。

Gemini 在通往「Finish Design」的路上迷了路

Issue #1619 —— bug,开放中

症状

为 Gemini 配置好了 BYOK。Settings 里的连接测试成功了。模型选择器返回了 Gemini 模型。常规聊天能用——你能用自己的 Gemini 密钥毫无障碍地撑起一整段对话。但用户一点 Finish Design,daemon 就抛出一个 Anthropic 形态的错误,仿佛它突然忘了自己在跟哪个服务商说话。

为什么会这样

该讨论里维护者的回复证实了这一点:常规 API 模式聊天从头到尾都遵循选中的 Gemini BYOK 服务商,但 Finish Design 还没有被推广到 Anthropic 兼容的 finalize 路径之外。其余一切都走那个识得服务商的代理,它知道怎么讲每个上游各自的方言。而 Finish Design 仍然走一个遗留自更早版本的、硬编码的 Anthropic finalize 端点——所以一个以非 Anthropic 形态到达的 Gemini 响应就把解析器绊倒了。

变通办法

把 Gemini 经由 OpenRouter、放在 Anthropic 兼容的服务商槽位下来路由。这样 Finish Design 路径看到的就是一个从 OpenRouter 垫片回来的 Anthropic 形态响应,于是能正确地 finalize。这多了一跳,而且你付的是 OpenRouter 的路由费、而非直接调用 Gemini,但它今天是稳定的,并且只覆盖那条坏掉的路径,而不碰那条已经能用的聊天路径。

谁在修它

Finish Design 的推广现在以 P1 列在 BYOK 路线图上。目前还没有 PR——这是 daemon 团队接下来要拿起的事,而且它是这五个里唯一一个属于我们完全拥有的代码里的缺陷,而非边界不匹配。

Gemini 3 Flash 在 Windows 上还没等 prompt 落地就死了

Issue #1611 —— bug,开放中

症状

Gemini 3 Flash Preview 在 Windows 上的 Open Design 里失败,大约 1.5 秒后报 stdin: write EOF——还没等 prompt 抵达模型。同一套安装里 Gemini 3 Pro 工作正常。而直接的 Gemini CLI(gemini --model gemini-3-flash-preview ...)在设了 GEMINI_CLI_TRUST_WORKSPACE=true 时是成功的。所以问题不在密钥、不在账户,单独看也不在 CLI。

为什么会这样

这次诊断花了两轮,值得展示一下,因为它是这类问题如何被理清的一个好例子。对报告者截图的第一遍解读看起来像是一个上游的 429 RESOURCE_EXHAUSTED 配额错误。在一次干净的 PowerShell 复现把 OD_GEMINI_3_FLASH_OK 写到 stdout 之后,画面变了:模型是可达的,CLI 是健康的,失败恰恰发生在 Open Design → Gemini CLI 的启动路径上,并且专门针对 Windows 上的 Flash 变体。Pro 走的是同一条启动路径却活下来了;Flash 没有。

变通办法

在模型选择器里选 Gemini 3 Pro Preview。它走同样的启动路径并且能用。另外——这一点比 bug 本身还耗时间——检查一下 ~/.gemini/hooks/。在这位用户的情况里,一个慢吞吞的 gsd-check-update.js hook(Hook execution error: Hook timed out after 60000ms)给每次运行平添了大约 104 秒的开销,这跟 Flash 的失败完全无关。无论如何都把你的 Gemini hook 清理干净;一个卡住的更新检查 hook 会让任何 agent 感觉像是坏了。

谁在修它

已标记为 Flash 专属、且属 OD 侧。对 daemon 的 stdin 写入路径的调查正在进行中——write EOF 意味着子进程的 stdin 在 daemon 写完 prompt 之前就关了,所以修复在于这个特定变体是如何被 spawn 出来的。

一张检查清单矩阵,有些行通过、有几行显示破裂标记,在近白色的编辑风底纹上被绿色框选中
五道诚实的接缝——每一道都活在我们拥有的 adapter 与我们不拥有的 CLI 之间的边界上。

DeepSeek TUI 在 Windows 上有一道 30 KB 的 prompt 上限

Issue #1610 —— bug,开放中

症状

在一个 Windows 打包构建里的 DeepSeek wrapper v0.8.33 上,一个较长的组装 prompt 没能通过我们的预检守卫,报 81397 > 30000 bytes。用户什么都没做错——他们只是组了一个足够丰富的 prompt(系统上下文、设计系统、参考资料),结果越过了 30 KB。

为什么会这样

那道守卫是刻意设的,它正在保护你免于一个更糟的错误。DeepSeek TUI adapter 目前把 prompt 作为一个位置式命令行参数发送——绑定在 argv 上——而 Windows 给整条命令行设的上限远低于 macOS 和 Linux 的。没有这道预检的话,同样的 prompt 会在更靠后、spawn 更深处的地方失败,报一个有用得多的 ENAMETOOLONG 错误都谈不上,更没有任何提示说原因是 prompt 体积。所以我们提前失败,并把那个数字报出来。这个 issue 暴露出来的不匹配在文档里:高层指引暗示 Windows 的长 prompt 回退方案广泛适用,但 DeepSeek TUI 这条路径还没有一个——它的传输仍是 argv,而不是 stdin 或一个 prompt 文件。

变通办法

如果你在 Windows 上用 DeepSeek TUI adapter,就把组装出来的 prompt 控制在 30 KB 以下,或者切到一个基于 stdin 的 adapter——Claude Code、Codex 和 OpenCode 都通过 stdin 接收 prompt,没有可比的上限。在 macOS 和 Linux 上这个 issue 根本不会咬到你;那里的 argv 上限足够高,现实世界里的 prompt 触不到它。

谁在修它

正确的修法是给 DeepSeek TUI adapter 做一个 stdin 或 prompt 文件传输,这样能彻底去掉 argv 上限,让它与那些 stdin adapter 看齐。它已在 adapter 团队的队列里跟踪。

OpenCode 本地 CLI 测试在模型热起来之前就超时了

Issue #1603 —— bugpriority:p0,开放中

症状

在 Settings → BYOK → OpenCode 里,连接测试稳定地在 45 秒处超时。奇怪的地方是:如果用户先打开 OpenCode Desktop 的终端、在那里挂上一个本地 LLM,那么同一个 Open Design 测试在下一次尝试时就会成功。

为什么会这样

「先打开 Desktop 终端」这个细节就是全部线索。Open Design 不会附着到一个正在运行的 OpenCode Desktop 会话上。为了做一次 Settings 烟雾测试,daemon 会 spawn 它自己全新的 OpenCode CLI 子进程,并等待一个 ok 回复。对一个冷的本地模型——一个还没被加载进内存的——来说,那第一个回复可能比 45 秒的预算还要久,因为模型正从磁盘里被读出来、被热起来,然后才能回答任何东西。打开 Desktop 终端、让它回答一个 prompt,会以一种 daemon 全新子进程随后能立刻受益的方式,把模型热进操作系统缓存。所以这其实不是 OpenCode 的 bug;它是一个对本地模型而言错误的冷启动时序假设。

变通办法

在 Open Design 里测试 OpenCode 之前,先打开 OpenCode Desktop,挂上你的本地 LLM,让它回答一个 prompt。然后再跑 OD 的连接测试——模型是热的,回复落在预算之内。从 v0.7.0 起,连接测试的预算也是可配置的,所以如果你的本地模型加载确实慢,你可以调高那个时间窗,而不必手动去热它。

谁在修它

daemon 侧的修复是专门为本地模型 adapter 设一个更长或可配置的热身窗口,这样一个冷的本地模型就不会被用跟托管 API 一样的钟来评判。它以 p0 跟踪——是这五个里优先级最高的,因为本地模型用户恰恰是 BYOK 想要服务的那群人。

打包好的 web 应用拒绝在纯 HTTP 上加载

Issue #1620 —— bug,开放中

症状

稍微不同的 bug,同一族。报告者在一个局域网 IP 上、通过纯 HTTP 运行打包好的 web 应用,页面在加载时就抛错——它从未到达一个可用状态。

为什么会这样

在 PR #1428 之后,分析提供器和 PDF 导出 nonce 开始直接调用 crypto.randomUUID(),绕过了 PR #900 引入的那个分级辅助函数——后者会在安全 crypto API 不可用时优雅回退。Chromium 不在非安全上下文中暴露 crypto.randomUUID——而一个裸的局域网 IP 加纯 HTTP,按 Chromium 的定义,就不是安全上下文。于是这个直接调用在加载时抛错,页面也随之倒下。它严格来说不是一个 BYOK bug,但它咬的恰恰是同一群人:那些运行自己基础设施的人,常常是气隙隔离的,常常用纯 HTTP,因为为一个内部工具立一张证书不值那个麻烦。

变通办法

通过 HTTPS 或通过 localhost 来提供这个 web 应用。两者都满足 Chromium 的安全上下文要求——localhost 即使没有证书也被视为安全——页面就能正常加载。对于一个快速的内部搭建,localhost 是零成本的路;对于局域网访问,一张通过 HTTPS 的自签名证书是更耐久的那条。

谁在修它

PR #1621 把剩下的调用点重新导回 PR #900 的那个分级 UUID 辅助函数,这样安全上下文回退就处处适用了,而不只是在它已经接好线的地方。它已开放、正在审查中。

这件事对 Open Design 里的 BYOK 究竟说明了什么

把这份清单当作一张契约地图来读,而不是一张质量判决书。这五个 issue 里有四个坐落在 adapter 边界上——Gemini 的 CLI 启动路径、DeepSeek 绑定 argv 的 CLI 传输、OpenCode 的冷启动启动模型、宿主平台的安全上下文规则。第五个,也就是 Finish Design 那个,在我们自己的 finalize 端点上——一个版本之前我们在那里硬编码了一个 Anthropic 形态的响应,至今还没把它推广开。那一个怪我们;另外四个是你为尊重那些不是你造的工具而付的税。

而这正是结构性的要点。每一个不是换了马甲的代理的 BYOK 系统,最终都会走到这里。你要么自己拥有推理——然后失去 BYOK,因为现在是你在买 token 并给它们加价——要么尊重上游工具、并继承它们的棱角:它们的 CLI、它们的打包怪癖、它们各自处理方式不同的平台限制。我们 刻意选了第二种姿态,而且我们还会再选一次。代价就是像这样的一些星期:daemon 和 adapter 团队在两天里横跨五个面立了案。

这笔交换依然是对的。一套跑在 Claude Code、Codex、Cursor、macOS 上的 Gemini Pro 以及 Linux 上的 DeepSeek 之上的配置——这个矩阵覆盖了我们大约 90% 的真实用户——今天就干净地运行着,没有代理税,也没有在你的 token 上加价。上面那五个讨论就是这个矩阵的另外 10% 在 2026 年 5 月中旬的样子:被点了名、立了案,且每一个都有修复在路上。诚实的接缝胜过一张把账单去向藏起来的光滑表面。

今天该用什么(矩阵)

这是上一节的实用版——同样的五道接缝,对照到此刻可以放心去用的东西。一个 ✓ 表示这条路径原样可用;一个 ✗ 链接到阻塞它的那个 issue,变通办法在对应的小节里。

服务商macOSLinuxWindowsFinish Design 路径
Claude Code(Sonnet / Opus)原生
Codex原生
Cursor(BYOK)原生
Gemini 3 Pro PreviewOpenRouter 垫片(#1619
Gemini 3 Flash Preview✗(#1611OpenRouter 垫片(#1619
DeepSeek(API)OpenRouter 垫片
DeepSeek TUI(长 prompt)✗(#1610OpenRouter 垫片
OpenCode(本地模型)✓(先热起来,#1603不适用

这张表有两种读法。如果你的技术栈在全 ✓ 的那一块里——Claude Code、Codex、Cursor 或 Gemini Pro——你就在干净的路上,上面这些没有一条会改变你的日常。如果你在某一个 ✗ 的行上,对应的小节里有让你今天就跑起来的变通办法,同时所链接的修复也在落地途中。无论哪种情况,如果你想在某一行从 ✗ 翻成 ✓ 时收到通知,就去订阅 跟踪器上的 BYOK 标签

接下来该做什么

Open Design 的 skill 库 是这一切底下那个干活的层——一旦连接健康,BYOK adapter 就把数据喂进这些文件驱动的契约里。上面那些接缝讲的是怎么把字节从你的密钥送到模型再送回来;而 skill 才是模型拿这些字节真正去做的事。如果你想看看一个 skill 从模型那里消费什么、又对什么毫不在意——这也正是为什么这些 adapter 的棱角不改变输出、只改变你能否够到它——那个目录就是合适的起点。

浏览 skill 库

延伸阅读


← 返回博客 GitHub · 来源 ↗