✂️ GateX v2:删掉 2000 行代码后,它反而更强了

三周前,GateX v0.1.0 诞生了。那篇文章记录了一个很爽的故事——发现 Agent Maestro 有 120 秒硬编码超时,于是连夜自己写一个更好的。

代码提交,Marketplace 上架,故事结束。

但故事没有结束。代码在长。


📈 一个扩展是怎么变胖的

GateX 的初始需求很简单:把 VS Code 的 vscode.lm API 暴露为 HTTP 接口。说白了就是一个协议转换器——左手接 OpenAI/Anthropic 格式的请求,右手调 VS Code 的模型 API,中间做一下格式翻译。

核心代码大概 300 行就能搞定。

然后我开始"加功能":

第 1 天:server.ts + extension.ts ✅
第 2 天:"要不加个 Dashboard 看看请求统计?"
第 3 天:"缓存相同请求能省 Token 吧?"
第 4 天:"并发请求应该排队处理……"
第 5 天:"统计数据得持久化……"

每一步都很"合理"。每一步都让代码更复杂。

到 v0.1.2 发布时,GateX 长成了这样:

文件行数功能
server.ts~600HTTP 服务器(含硬编码模型映射表)
dashboard.ts1,557Web Dashboard(内嵌 HTML/CSS/JS)
stats.ts278统计追踪
cache.ts192响应缓存
queue.ts187请求队列
extension.ts~200入口(到处是 statsManager 引用)
models.ts~120模型管理
statusBar.ts~80状态栏
合计~3,200

注意那个 dashboard.ts——1,557 行,比其他所有文件加起来还多。它在扩展内嵌了一个完整的 Web 页面,有请求量图表、成功率饼图、模型分布统计……

我大概打开过三次。其中两次是为了截图写 README。


🪞 CopilotX 带来的反思

今天还开发了 CopilotX——一个 Python 独立工具,功能和 GateX 几乎相同(把 Copilot 变成本地 API),但完全不依赖 VS Code。

写 CopilotX 的过程让我重新审视 GateX:

CopilotX 的核心代码只有 一个文件,却支持 OpenAI + Anthropic 双格式、流式输出、并发请求、智能重试。

GateX 有 8 个文件、3200 行,多出来的 2000 多行都在干什么?

答案令人汗颜:

  • Dashboard(1,557 行)→ 我从来不看
  • Cache(192 行)→ LLM 响应几乎不应该缓存(同样的 prompt 你想要不同的回答)
  • Queue(187 行)→ VS Code 的 vscode.lm API 自己就有并发控制
  • Stats(278 行)→ 统计数据喂给 Dashboard,但 Dashboard 我不看

这 2,214 行代码,没有一行在解决真正的问题。

它们存在的唯一理由是:写的时候觉得"这个功能很酷"。


🔪 手术刀式重构

认清了问题,重构方案就很清晰了:

删什么

❌ dashboard.ts  (1,557 行) → 删
❌ cache.ts      (192 行)   → 删
❌ queue.ts      (187 行)   → 删
❌ stats.ts      (278 行)   → 删

四个文件,一刀切。不是"先注释掉,以后可能用到",是 git rm。

修什么

server.ts 的问题最多:

  1. JSON 解析没有 try/catch → 一个畸形请求就能让服务器 500
  2. 模型参数被默默丢弃 → temperature、max_tokens 传了但没传给 model.sendRequest()
  3. Anthropic 模型映射硬编码 → 写死了 5 个模型名的映射表,新模型出来就不认
  4. 到处是 statsManager 引用 → 删掉 stats 后满屏报错

修复后的 server.ts 关键改进:

// 之前:空对象,温度、max_tokens 全被忽略
const response = await model.sendRequest(messages, {}, token);

// 之后:正确传递模型参数
function buildModelOptions(req: OpenAIChatRequest) {
    const opts: Record<string, unknown> = {};
    if (req.temperature !== undefined) opts['temperature'] = req.temperature;
    if (req.max_tokens !== undefined) opts['max_tokens'] = req.max_tokens;
    if (req.top_p !== undefined) opts['top_p'] = req.top_p;
    return { modelOptions: opts };
}
// 之前:硬编码映射,只认 5 个模型
const MODEL_MAP: Record<string, string> = {
    'claude-3-5-sonnet': 'copilot-claude-3.5-sonnet',
    'claude-3-opus': 'copilot-claude-3-opus',
    // ...
};

// 之后:动态模糊匹配,不怕新模型
const model = await modelManager.getModel(requestedName);
// getModel 先精确匹配,不中再模糊匹配(包含关系 + 编辑距离)

加什么

删了 2000 行,加了两个真正有用的功能:

1. Vendor Filter(模型供应商过滤)

vscode.lm.selectChatModels({}) 会返回 VS Code 里所有扩展提供的模型——不只是 Copilot,还有 AI Toolkit、Foundry Local 等。我的 VS Code 里一度列出了 215 个模型,大部分根本不能用。

解决方案:gatex.vendors 配置项,默认只暴露 copilot 模型。

// settings.json
{
    "gatex.vendors": ["copilot"]  // 215 → ~25 个有效模型
}

2. IDE 配置生成器(configGenerator.ts)

这是从 Agent Maestro 学来的灵感。与其让用户手动写配置,不如一键生成。

按 Ctrl+Shift+P → GateX: Configure for IDE,支持:

  • Claude Code → 双模型选择(main + fast),自动写入 .claude/settings.json,自动绕过 onboarding
  • Codex CLI → 生成 ~/.codex/config.toml
  • .env 文件 → OpenAI + Anthropic 环境变量
  • 剪贴板 → export 或 $env: 命令

模型选择器按家族分组(Claude / GPT / Gemini / Other),每个 IDE 有 ⭐ 推荐:

⭐ Recommended
   claude-sonnet-4
── Claude ──
   claude-sonnet-4
   claude-haiku-3.5
── GPT ──
   gpt-4o
   gpt-4o-mini
── Gemini ──
   gemini-2.0-flash

📊 数字说话

指标v0.1.2v1.0.0 (v2)变化
源文件数85-37%
总代码行数~3,2001,726-46%
最大单文件1,557 行 (dashboard)687 行 (server)-56%
运行时依赖00—
API 格式OpenAI + AnthropicOpenAI + Anthropic—
流式输出✅✅—
模型参数传递❌ (被丢弃)✅🆕 修复
JSON 错误保护❌✅🆕 修复
端口冲突处理❌ (直接崩)✅ (自动换端口)🆕 修复
Vendor 过滤❌ (215个全列出)✅ (默认仅 Copilot)🆕 功能
IDE 配置生成❌✅ (Claude/Codex/.env)🆕 功能
Web Dashboard✅ (1,557行)❌ (删了)🗑️
响应缓存✅ (192行)❌ (删了)🗑️
请求队列✅ (187行)❌ (删了)🗑️
统计追踪✅ (278行)❌ (删了)🗑️

少了 46% 的代码,多了 4 个新功能,修了 3 个 bug。

这不是什么激进的重构,只是把不该存在的东西移除了。


🔧 四个 Commit 的故事

Git log 精确记录了这次重构的四步:

682b0a2 feat: enhanced config generator (learned from Agent Maestro)
97f4803 feat: add vendor filter (gatex.vendors) - default copilot only
2da24a0 fix: fallback to next port when configured port is busy (EADDRINUSE)
3546129 v2.0: Lean rewrite — delete bloat, fix bugs, add IDE config generator

Commit 1 (3546129):大刀阔斧。删 4 个文件,重写 server.ts 和 extension.ts,新增 configGenerator.ts。编译通过,一次提交。

Commit 2 (2da24a0):装上新版后发现端口 24680 被旧进程占着,扩展直接起不来。加了 isPortAvailable() 检测和自动换端口逻辑。

Commit 3 (97f4803):发现 VS Code 里居然检测到 215 个模型——原来 AI Toolkit 等扩展也在注册模型。加了 vendor filter,默认只暴露 Copilot 的。

Commit 4 (682b0a2):研究了 Agent Maestro 的配置生成器设计,学到了双模型选择、onboarding bypass、TOML 支持、家族分组等 UX 优化。重写 configGenerator.ts。

四个 commit,从粗到细,从结构到细节。重构不是一蹴而就的,而是用了之后才知道哪里还不对。


💡 从 Agent Maestro 学到的,和没学的

v2 重构中有一个有趣的插曲:我回头仔细研究了当初"干掉"的 Agent Maestro。

三周前的我只关注它的 120 秒超时缺陷。三周后重新看它,我注意到了一些优秀的设计:

学到的:

  • ⭐ 双模型选择器(main model + fast model)→ 完美适配 Claude Code 的 ANTHROPIC_SMALL_FAST_MODEL
  • ⭐ Onboarding bypass → 自动写 ~/.claude/config.json 跳过 Anthropic 首次配置
  • ⭐ 模型按家族分组 → 比一长串列表可读性好十倍
  • ⭐ TOML 配置支持 → Codex CLI 用 TOML 而不是 JSON

没学的:

  • ❌ MCP Server 集成 → 超出了"API Gateway"的职责
  • ❌ 内置 Agent 框架 → 这是 Agent 该做的事,不是 Gateway
  • ❌ 六种 IDE 配置(Cursor、Windsurf……)→ 先做好核心的,剩下按需加

一个有趣的轮回:GateX 因为嫌 Agent Maestro 太复杂而诞生,v2 又从它身上学到了真正好的设计。不是否定它,而是有选择地吸收。


🧘 Less is More 不是功能少

重构完成后,我在想:为什么 v1 会写出 1,557 行的 Dashboard?

因为做加法太容易了。

写一个新功能、加一个新文件、多一个配置项——每次都能获得"我做了事情"的即时满足感。代码行数在涨,功能列表在长,README 里可以多写一个 bullet point。

但真正的用户体验在退化。启动慢了,配置复杂了,debug 难了,一个 JSON 畸形请求就能让服务器 500。

Less is More 不是说功能要少。v2 的功能比 v1 多(vendor filter、配置生成器、端口容错)。Less is More 说的是:

每一行代码都应该为用户解决真正的问题。

  • Dashboard 不解决任何问题 → 删
  • 缓存 LLM 响应制造问题 → 删
  • 自动配置 IDE 解决真问题 → 加
  • JSON 解析保护解决真问题 → 加

我给自己定了一个以后写代码前要问的问题:

"如果我不做这个功能,用户会怎样?"

如果答案是"完全没影响",那就不该做。


GateX 系列现在有三篇了:

  1. ⚡ GateX:我如何用一天时间干掉 Agent Maestro — 诞生
  2. 🚀 GateX 上架记:从打包到 Marketplace 的踩坑之旅 — 发布
  3. ✂️ 本文:删掉 2000 行代码后,它反而更强了 — 回归

以及一篇姐妹项目的文章:

  1. 🚀 CopilotX:一个晚上,把 GitHub Copilot 变成本地 API 服务器 — Python 独立版

GateX 是 VS Code 扩展版(零配置,开 VS Code 就能用),CopilotX 是 Python 独立版(pip install copilotx,纯终端就能跑)。两个工具互补,覆盖不同场景。


📥 获取 GateX v1.0.0

# VS Code Marketplace
ext install BaoliWang.gatex

# 或直接搜索 "GateX"

👉 GitHub: Polly2014/GateX 👉 VS Code Marketplace


写这篇文章时我又重新看了一遍 v1 的 dashboard.ts。1,557 行 TypeScript 里内嵌了完整的 HTML、CSS 和 Chart.js 调用。那个文件本身就是一个完美的反面教材:技术上没有错误,但完全不应该存在。

有时候,最好的代码就是被你删掉的那些。

Comments