当 LLM CLI 不是 API:一次真实的 Gemini Adapter 调试

当 LLM CLI 不是 API:一次真实的 Gemini Adapter 调试复盘

很多人在讨论多模型路由时,默认前提是「所有模型都是 HTTP API」。
但现实中,总会遇到 CLI-only、半官方、行为不稳定 的模型接入方式。

这是一篇关于 Google Gemini CLI 的真实适配与调试复盘。


背景:为什么要接入 Gemini CLI

在我的模型路由系统中,已经存在多个 Adapter:

  • ✅ Qwen(HTTP API)
  • ✅ CodeBuddy(CLI)
  • ✅ Google Gemini(CLI)

设计目标很简单:

Router 负责“选谁”,Adapter 负责“怎么用”

Gemini 之所以选择 CLI 而不是 SDK,是因为:

  • CLI 是 Google 官方支持路径
  • 能快速覆盖多个模型
  • 本地调试与自动化测试方便

于是我写了一个 GoogleAdapter,通过 child_process 调用 gemini


第一次失败:看起来一切都对,但就是不工作

表象

在 Adapter 中执行:

gemini --prompt "hi" --model gemini-2.5-flash --output-format json  

返回结果却是:

  • exit code ≠ 0
  • Adapter 判定 健康检查失败
  • Router 认为 Gemini 不可用

但奇怪的是:

  • gemini --version
  • gemini list-models
  • API Key 已配置 ✅

误区:以为是自己代码写错了

一开始我怀疑的是:

  • JSON 解析逻辑
  • stdout / stderr 混用
  • Node.js spawn 参数问题
  • Adapter 抽象设计有缺陷

但这些方向全部走不通。


关键转折点:直接跑 CLI,而不是“想当然”

我开始完全抛开代码,只做一件事:

像普通用户一样,用终端跑 gemini

gemini --prompt "hi" --model gemini-2.5-flash  

这时,终端给出了一个非常“温柔”的提示:

The --prompt (-p) flag has been deprecated and will be removed in a future version.  

⚠️ 重点在于

  • 这是 stderr
  • CLI 仍然输出了一些内容
  • 但 exit code = 1

也就是说:
CLI 行为已经变了,但并没有以“硬错误”的形式提醒你。


真正的原因:Gemini CLI 的接口语义变更

Gemini CLI 已经从:

gemini --prompt "hi"  

切换为:

gemini "hi"  

也就是:

  • prompt 变成了 位置参数
  • --prompt 进入废弃阶段
  • 但并未立即兼容旧行为

✅ 当我把 Adapter 改为:

gemini "hi" --model gemini-2.5-flash --output-format json  

一切立刻恢复正常。


第二个现实问题:CLI 冷启动非常慢

即便修复参数问题后,我又遇到了第二个“非代码错误”:

  • 首次调用 Gemini CLI:20–25 秒
  • 默认 timeout:30 秒
  • 在网络波动时,极易超时

解决方式很朴素:

timeout: 60_000  

这不是“性能优化”,而是尊重现实


最终结果:Gemini Adapter 稳定可用

测试命令:

yuangs router test google-gemini --prompt "hi"  

结果:

  • ✅ 健康检查通过
  • ✅ 模型响应正常
  • ✅ JSON 解析正确
  • ⏱️ 执行时间 ~23.8s(在安全范围内)

当前默认模型策略:

  • gemini-2.5-flash:通用 / 对话
  • gemini-2.5-pro:代码 / 高复杂度任务

这次调试带来的架构启示

1️⃣ CLI ≠ API

CLI 的问题在于:

  • 参数语义可能悄悄改变
  • stderr / stdout / exit code 不一致
  • 文档更新滞后

✅ 正确做法是:

把 CLI 当作“不稳定外部系统”


2️⃣ Adapter 层必须是“变化缓冲区”

这次问题如果发生在:

  • Router 层 → 架构设计失败
  • 调用方 → 使用体验灾难

而现在:

  • 变化被完全限制在 Adapter 内
  • Router / 上层 零修改

这正是 Adapter 模式存在的意义。


3️⃣ 健康检查 ≠ 功能正确

  • gemini --version 成功
  • 不代表 gemini "hi" 可用

CLI Adapter 的健康检查必须是:

最小真实调用


结语

这次 Gemini Adapter 的问题,不是“踩坑”,而是一次很好的提醒:

真实世界的 LLM 接入,从来不是一条干净的 API 路径。

当你开始接入:

  • CLI
  • 本地模型
  • 半官方工具

你面对的不是“调用问题”,而是系统演化问题

而一个好的模型路由系统,
应该 天然允许这些变化发生,而不被拖垮。


如果你正在做:

  • 多模型路由
  • LLM Infra
  • CLI / SDK 混合接入

希望这次 Gemini 的真实复盘,能帮你少走一点弯路。