三周前,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 | ~600 | HTTP 服务器(含硬编码模型映射表) |
dashboard.ts | 1,557 | Web Dashboard(内嵌 HTML/CSS/JS) |
stats.ts | 278 | 统计追踪 |
cache.ts | 192 | 响应缓存 |
queue.ts | 187 | 请求队列 |
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.lmAPI 自己就有并发控制 - Stats(278 行)→ 统计数据喂给 Dashboard,但 Dashboard 我不看
这 2,214 行代码,没有一行在解决真正的问题。
它们存在的唯一理由是:写的时候觉得"这个功能很酷"。
🔪 手术刀式重构
认清了问题,重构方案就很清晰了:
删什么
❌ dashboard.ts (1,557 行) → 删
❌ cache.ts (192 行) → 删
❌ queue.ts (187 行) → 删
❌ stats.ts (278 行) → 删
四个文件,一刀切。不是"先注释掉,以后可能用到",是 git rm。
修什么
server.ts 的问题最多:
- JSON 解析没有 try/catch → 一个畸形请求就能让服务器 500
- 模型参数被默默丢弃 →
temperature、max_tokens传了但没传给model.sendRequest() - Anthropic 模型映射硬编码 → 写死了 5 个模型名的映射表,新模型出来就不认
- 到处是 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.2 | v1.0.0 (v2) | 变化 |
|---|---|---|---|
| 源文件数 | 8 | 5 | -37% |
| 总代码行数 | ~3,200 | 1,726 | -46% |
| 最大单文件 | 1,557 行 (dashboard) | 687 行 (server) | -56% |
| 运行时依赖 | 0 | 0 | — |
| API 格式 | OpenAI + Anthropic | OpenAI + 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 系列现在有三篇了:
- ⚡ GateX:我如何用一天时间干掉 Agent Maestro — 诞生
- 🚀 GateX 上架记:从打包到 Marketplace 的踩坑之旅 — 发布
- ✂️ 本文:删掉 2000 行代码后,它反而更强了 — 回归
以及一篇姐妹项目的文章:
- 🚀 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 调用。那个文件本身就是一个完美的反面教材:技术上没有错误,但完全不应该存在。
有时候,最好的代码就是被你删掉的那些。
