HagiCode 是怎么把 13 个 Agent CLI 接到一套系统里的
关于 HagiCode本文分享的方案来自我们在 HagiCode 项目里摸爬滚打的实践。HagiCode 是一个 AI 代码助手整合平台目标很纯粹——用一套安装、一套配置把主流 Agent CLI 全都接进来给用户用。13 个这个数字是怎么来的先说一个被反复问到的数字——为什么是 13 个 Agent CLI。其实答案就藏在AIProviderType这个枚举里像藏在窗外的竹影里只要你肯看就能看见。原始定义长这样public enum AIProviderType{ClaudeCodeCli 0,CodexCli 1,GitHubCopilot 2,CodebuddyCli 3,OpenCodeCli 4,IFlowCli 5, // 已废弃HermesCli 6,QoderCli 7,KiroCli 8,KimiCli 9,GeminiCli 10,DeepAgentsCli 11,ReasonixCli 12,PiCli 13,}枚举一共 14 个值可是IFlowCli5这条路已经走不通了。在AIProviderFactory里它被显式挡在了门外if (providerType AIProviderType.IFlowCli){throw new NotSupportedException(IFlowCli is no longer supported);}再配合IsActivelySupportedProviderType()做一次过滤真正在系统里活着的就是13 个Claude Code、Codex、GitHub Copilot、CodeBuddy、OpenCode、Hermes、Qoder、Kiro、Kimi、Gemini、DeepAgents、Reasonix、Pi。这就是13的由来。不是个营销数字是代码里真真切切数出来的。毕竟数字是不会骗人的骗人的只是我们自己罢了。分层架构把变化关在笼子里接 13 个 CLI 的核心思路其实就一句话让业务代码不关心它调的到底是哪一个。我们把它拆成了六层从上往下看1. 身份层 ——AIProviderType枚举就是每个 CLI 的身份证号。任何地方提到一个 CLI都用这个枚举值标识字符串和枚举之间用ToStringValue()/ToAIProviderType()互转。简单却不可或缺。2. 业务契约层 ——IAIProvider/IAIProviderFactory业务侧只认IAIProvider这个接口里面定义的是发一个 prompt、拿到流式回复这种通用动作。至于底下是 Claude 还是 Codex业务不关心——就像你写信只管把信交出去至于邮差姓什么谁在乎呢3. 适配器层 ——*CliProvider每个 CLI 对应一个薄适配器比如PiCliProvider、ReasonixCliProvider、ClaudeCodeCliProvider。这些适配器要做的事情很少把通用的业务请求翻译成具体 CLI 能懂的参数再把具体 CLI 的输出翻译回来。它们故意写得很薄新加一个 CLI基本就是抄一个现成的改改而已。4. 共享运行时层 ——ICliProviderTOptions这一层在HagiCode.Libs里是真正干脏活累活的地方跨平台拉起进程、处理 stdio 传输、解析流式输出、处理超时和重试。所有适配器都复用同一套运行时所以对接一个新 CLI 时进程管理这块基本不用重写。打个比方适配器层是翻译官共享运行时层是快递公司。翻译官只管把话说清楚包裹怎么送、路上堵不堵车那是快递公司的事。各司其职世界就清净了。5. 工厂路由层 ——AIProviderFactoryCreateProvider里一个switch按AIProviderType实例化对应适配器顺带校验IsConfigured。这是唯一一处知道具体类型的地方被严格隔离在工厂里。变化只允许在一个角落里发生其余地方都干干净净。6. 目录 / UI 投影层 ——main-professions.yaml这一层有意思它不是代码是数据。主职业清单我是个前端、我是个后端、我是个全栈这种角色画像由main-professions.yaml这个预设文件驱动通过HeroPrimaryProfessionPresetProvider读出来再投影到前端 UI。新增一个主职业不需要改一行代码改 YAML 就行。数据代替代码省心。顺便说一句这块是 HagiCode 重构最大的地方。早期版本里有个叫AgentCliInstallRegistry的代码内注册表后来发现维护成本太高——代码写多了人也就累了——整套被推倒换成了数据驱动 健康监测的方案。这也是为什么 HagiCode 现在能快速扩展职业类型的原因。安装这事儿怎么解决13 个 CLI 都要装每个官方安装方式还不一样这就是另一座山了。我们的做法是Docker Compose 预装 外部管理兜底。镜像里把主流 CLIClaude Code、Codex、Copilot、CodeBuddy、OpenCode、Qoder、Kiro、Kimi、Gemini、Pi都预装好用户拉镜像就能用不用自己一条条敲命令。装好了心情自然也好。对于需要在本地环境单独装的安装命令矩阵大概是这样已核对官方文档CLI官方安装方式Claude Codenpm install -g anthropic-ai/claude-codeCodexnpm install -g openai/codexGitHub Copilotnpm install -g github/copilotCodeBuddynpm install -g tencent-ai/codebuddy-codeOpenCodenpm i -g opencode-ailatestQodernpm install -g qoder-ai/qodercliKirocurl -fsSL https://cli.kiro.dev/install | bashKimicurl -LsSf https://code.kimi.com/install.sh | bashGemininpmHermes官方脚本保留 docs-only 兜底DeepAgents / Reasonix见各自官方文档前端PrimaryProfessionCard.tsx这块也跟着变了——它现在没有安装 CLI按钮而是展示 CLI 可用性、版本探测结果以及这个 CLI 由外部管理的兜底提示。也就是说装不装得起来由系统层负责UI 只负责如实反馈状态。状态和逻辑各写一遍迟早会对不上那又何必呢加一个新 CLI 要做啥落到实操在 HagiCode 里加一个新 CLI大概也就这么几步在AIProviderType里加一个枚举值抄一个现成的*CliProvider改成新 CLI 的参数和输出解析在AIProviderFactory的switch里加一行路由如果要进主职业目录在main-professions.yaml里配一下镜像里加一条安装命令或者走外部管理兜底整套流程下来核心改动不超过两百行代码——这便是这套抽象真正的价值。每多接一个 CLI边际成本都很低业务代码一行都不用改。条条大路通罗马只是我们这条路稍微好走一点罢了。总结回头看接 13 个 CLI听着吓人可拆开看其实也就两层功夫一层是把变化隔离——通过AIProviderType枚举 IAIProvider契约 薄适配器 共享运行时让业务代码和具体 CLI 解耦另一层是把配置数据化——用main-professions.yaml这种 YAML 预设驱动目录和 UI避免每加一个东西都要动代码。这套方案是我们在 HagiCode 实际开发里踩过坑、迭代过几轮才稳定下来的。如果你正在做类似的多 Provider 整合系统希望这个分层思路能给你一点参考。毕竟Agent CLI 这两年还会继续冒出来一个能快速接入新 CLI 的架构比