IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

套壳不丢人!我用Go+AI搓了一个Agent统一编排框架,ClaudeCode-Codex-Pi全被我包了

鸟窝 2026-06-21 18:40:38 累计浏览 16 次
本机暂存
<p>去年我还在折腾 langchain&#x2F;langgraph 开发智能体,弄了个 langgraphgo 项目,把 langgraph 往 Go 生态圈里搬。那会儿网上做智能体的,十个有八个用 langchain&#x2F;Crew AI。</p><p>一个阶段有一个阶段的玩法。</p><p>现在我看到了另一种路子:大家直接用 Claude Code、Codex、OpenCode、Pi 这些 coding agent &quot;套壳&quot;来实现智能体。</p><p>先说两个很多人搞混的点。</p><p>别觉得这些工具只能写代码。Claude Code、Codex 的架构走的是通用智能体模式,早就不止 coding 了。</p><p>也别把&quot;套壳&quot;当贬义词。Manus 刚火那阵,就有同事撇嘴说&quot;这不就是 Claude 的套壳&quot;。但你看,Claude、Codex、Antigravity 一个个都在推 SDK,巴不得你基于它们二次开发。牛顿怎么说的,站在巨人肩膀上不丢人。</p><span id="more"></span><p>百度厂内突然蹿红了一个叫 dodo 的应用比龙虾都火。就是靠&quot;套壳&quot;快速出产品原型,再慢慢长成大家离不开的工具。百度公众号和前几天的百度大会上也推了。</p><p>OpenClaw 是在 Pi coding agent 上搭起来的智能体产品,上半年火得不成样子。</p><p>这些东西免费(CC),有的还开源(Codex CLI、OpenCode、Pi),甚至设计了 harness engineering 这套东西。等于送你一个结实的产品基座,剩下的精力全押在产品和创意上。</p><p>![image-20260603075823837.png<img src="/2026/06/11/go-ai-agent-orchestration-framework/image-20260603075823837.png" class=""></p><p>去年我还在从零手搓智能体。今年,我负责的 LLM 训推故障分析产品已经改成跑在其中一个智能体上了。我只需要管诊断逻辑、知识库、对外 API——那些真正跟业务相关的事。</p><p>但问题来了:这么多智能体,到底用哪个?</p><p>小孩子才做选择题,成年人我都要。</p><p>那就自己动手。套一个壳。向上给统一调用层,向下接各种智能体。</p><p>于是 agent-wrapper 出来了。你可以拿它的命令行测试,也可以直接嵌到 Go 项目里,把精力放在你该忙的地方:扩大用户和赚钱。</p><blockquote><p>有人会说 acp 不就能干这个?我实践下来 acp 不好用,从零搓了一个。具体分析见项目 README。</p></blockquote><h2 id="你到底要套什么"><a href="#你到底要套什么" class="headerlink" title="你到底要套什么"></a>你到底要套什么</h2><p>市面上的 Coding Agent CLI,单个拎出来都很能打——Claude Code 审代码,Codex 写脚本,Pi 做任务编排,OpenCode 跑自动化。但它们各自为政。五个操不同方言的装修师傅挤在一个工地,你每次想换人干活都得重新翻译需求。</p><p>胶水代码糊了一堆:启动子进程、解析各自的输出协议(NDJSON、SSE、JSONL、JSON-RPC……)、管生命周期、处理超时和错误、做重试和上下文压缩。全跟业务没关系,但不写系统就不稳。</p><p>agent-wrapper 干的就是这一层。一行代码注册 provider,一行代码切 agent:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">registry := agentwrapper.NewRegistry()</span><br><span class="line">claude.RegisterIn(registry)</span><br><span class="line">codex.RegisterIn(registry)</span><br><span class="line">pi.RegisterIn(registry)</span><br><span class="line"></span><br><span class="line">agent, _ := registry.Get(<span class="string">&quot;codex&quot;</span>, <span class="literal">nil</span>) <span class="comment">// 切 Claude? 改成 &quot;claude-code&quot;</span></span><br><span class="line">orch := agentwrapper.NewOrchestrator(agent)</span><br><span class="line">result, _ := orch.RunSync(context.Background(), types.RunInput&#123;</span><br><span class="line"> Prompt: <span class="string">&quot;帮我重构这段代码&quot;</span>,</span><br><span class="line">&#125;)</span><br><span class="line">fmt.Println(result.Text)</span><br></pre></td></tr></table></figure><p>换 agent &#x3D; 换一个字符串。胶水代码归零。</p><p>![image-20260603080124183.png<img src="/2026/06/11/go-ai-agent-orchestration-framework/image-20260603080124183.png" class=""></p><h2 id="不只是包一层,是给-Agent-装上刹车"><a href="#不只是包一层,是给-Agent-装上刹车" class="headerlink" title="不只是包一层,是给 Agent 装上刹车"></a>不只是包一层,是给 Agent 装上刹车</h2><p>套壳没技术含量?我不认。</p><p>调一次 Agent 谁都会。管住它难得多。一个 AI Agent 在你的代码库里自由调用工具——写文件、删代码、执行命令——你敢不加约束?</p><p>![image-20260603080302277.png<img src="/2026/06/11/go-ai-agent-orchestration-framework/image-20260603080302277.png" class=""></p><p>agent-wrapper 的 Orchestrator 不是简单的 for 循环。内置了三道闸门(harness engineering 的标准做法):</p><p><strong>审批拦截。</strong> 每次 tool_call 先过你的 ApprovalHandler。读文件放行,写文件拦住。按工具名、参数、上下文做决策,拒绝时注入合成 ToolResult,Agent 收到 &quot;DENIED&quot; 继续对话,不会崩:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">orch := agentwrapper.NewOrchestrator(agent,</span><br><span class="line"> agentwrapper.WithApprovalHandler(<span class="function"><span class="keyword">func</span><span class="params">(ctx context.Context, call agentwrapper.ToolCall)</span></span> (*agentwrapper.Decision, <span class="type">error</span>) &#123;</span><br><span class="line"> <span class="keyword">switch</span> call.Name &#123;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">&quot;read&quot;</span>, <span class="string">&quot;ls&quot;</span>, <span class="string">&quot;grep&quot;</span>:</span><br><span class="line"> <span class="keyword">return</span> &amp;agentwrapper.Decision&#123;Action: agentwrapper.ActionAllow&#125;, <span class="literal">nil</span></span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> <span class="keyword">return</span> &amp;agentwrapper.Decision&#123;Action: agentwrapper.ActionDeny, Reason: <span class="string">&quot;只读模式&quot;</span>&#125;, <span class="literal">nil</span></span><br><span class="line"> &#125;</span><br><span class="line"> &#125;),</span><br><span class="line">)</span><br></pre></td></tr></table></figure><p><strong>预算控制。</strong> Agent 烧 token 跟烧钱似的。每个 turn 结束回调 BudgetHandler,超阈值直接掐断:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">agentwrapper.WithBudgetHandler(<span class="function"><span class="keyword">func</span><span class="params">(ctx context.Context, usage types.TokenUsage)</span></span> <span class="type">error</span> &#123;</span><br><span class="line"> <span class="keyword">if</span> usage.TotalTokens &gt; <span class="number">50000</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> fmt.Errorf(<span class="string">&quot;预算超支: %d tokens&quot;</span>, usage.TotalTokens)</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;),</span><br></pre></td></tr></table></figure><p><strong>上下文压缩 + 自动重试。</strong> LLM 报 &quot;context length exceeded&quot;,Orchestrator 自动压消息历史(滑动窗口→摘要→链式策略,最多重试三次),调用方完全无感。</p><p>以上这三样,哪个 Agent CLI 原生都不给你。agent-wrapper 给了。</p><h2 id="会话恢复:让-Agent-记住你的项目"><a href="#会话恢复:让-Agent-记住你的项目" class="headerlink" title="会话恢复:让 Agent 记住你的项目"></a>会话恢复:让 Agent 记住你的项目</h2><p>Coding Agent 最烦的就是每次开新聊天都失忆。</p><p>![image-20260603080456247.png<img src="/2026/06/11/go-ai-agent-orchestration-framework/image-20260603080456247.png" class=""></p><p>agent-wrapper 支持 session resume。第一次 RunSync 拿回一个 SessionID,下次传进去,Agent 就知道你上次改了哪些文件、聊了什么架构、卡在哪个 bug 上:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 第一轮</span></span><br><span class="line">r1, _ := orch.RunSync(ctx, types.RunInput&#123;Prompt: <span class="string">&quot;这个项目的目录结构是什么?&quot;</span>&#125;)</span><br><span class="line">fmt.Println(r1.SessionID) <span class="comment">// ← 存起来</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 下一轮,上下文全在</span></span><br><span class="line">r2, _ := orch.RunSync(ctx, types.RunInput&#123;</span><br><span class="line"> Prompt: <span class="string">&quot;刚才你提到有一个潜在的性能问题,展开说说&quot;</span>,</span><br><span class="line"> SessionID: r1.SessionID,</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>CI 里跑重构,下班跑了一半,明天把 SessionID 传进去接着搞。跨天、跨进程、跨机器。</p><h2 id="效果展示"><a href="#效果展示" class="headerlink" title="效果展示"></a>效果展示</h2><p>![image-20260603065821797.png<img src="/2026/06/11/go-ai-agent-orchestration-framework/image-20260603065821797.png" class=""></p><p>一行命令就能跑:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 流式输出(文本→stdout,元数据→stderr)</span></span><br><span class="line">agent-wrapper run --provider claude-code <span class="string">&quot;解释这段代码&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># JSON 聚合输出(CI/脚本友好)</span></span><br><span class="line">agent-wrapper run --provider codex <span class="string">&quot;fix the bug&quot;</span> --json</span><br><span class="line"></span><br><span class="line"><span class="comment"># 带审批+预算</span></span><br><span class="line">agent-wrapper run --provider claude-code <span class="string">&quot;重构本项目&quot;</span> --approve-all --budget-tokens 50000</span><br><span class="line"></span><br><span class="line"><span class="comment"># NDJSON 管道输出</span></span><br><span class="line">agent-wrapper run --provider claude-code <span class="string">&quot;hello&quot;</span> --json --stream | jq .</span><br><span class="line"></span><br><span class="line"><span class="comment"># 恢复会话</span></span><br><span class="line">agent-wrapper run --provider claude-code --session-id abc123 <span class="string">&quot;继续&quot;</span></span><br></pre></td></tr></table></figure><p>但更核心的用法是当 Go 库用。go get 一下,import 进去,调 orch.Run。零额外进程,零协议开销。Claude Code、Codex、Pi、OpenCode,五个 provider,一套接口。</p><h2 id="套壳的真正价值"><a href="#套壳的真正价值" class="headerlink" title="套壳的真正价值"></a>套壳的真正价值</h2><p>套壳不丢人。</p><p>丢人的是换一次工具重写一遍胶水代码。丢人的是用着 AI Agent 还得手工管子进程生命周期。丢人的是一晚上 API 烧了几十美刀第二天看账单才后悔。</p><p>agent-wrapper 就是个壳。但解决的不是&quot;怎么调一次 Agent&quot;,是&quot;怎么让 Agent 安全地、长期地、按预算地、跨 provider 为你工作&quot;。把&quot;玩一下&quot;变成&quot;能上线&quot;。</p><p>项目地址:<a href="https://github.com/smallnest/agent-wrapper">https://github.com/smallnest/agent-wrapper</a></p><h2 id="最后说几句"><a href="#最后说几句" class="headerlink" title="最后说几句"></a>最后说几句</h2><p>大多数人用 Agent 还停留在&quot;命令行输一个 prompt&quot;。这没什么不对,但不够。</p><p>十年前我们从手写 SQL 走到满世界 ORM,从手动部署走到 k8s 编排。每一轮变化里,有人站在第一层骂套壳,有人站在第二层埋头套壳,还有人站在第三层——让所有想套壳的人套得更快。</p><p>Agent 时代,把壳套好,就是最好的手艺。</p>

同分类推荐文章

  1. 00 卷首语:当 Karpathy 说他半年没写一行代码 (2026-06-21 21:20:27)
  2. LLM 究竟是如何工作的? (2026-06-21 11:09:44)
  3. Loop Engineering 实践:一次批量实现 8 个 issue,完成夔牛工具的开发 (2026-06-17 04:00:24)

查看更多 AI 文章 →

建议继续学习

  1. Go Reflect 性能 (累计阅读 14,121)
  2. 面向“接口”编程和面向“实现”编程 (累计阅读 13,886)
  3. 一种基于长连接的社交游戏服务器程序构架 (累计阅读 7,471)
  4. 从Go看,语言设计(一) (累计阅读 6,146)
  5. go-kit 入门(一) (累计阅读 4,740)
  6. 分布式存储Seaweedfs源码分析 (累计阅读 4,722)
  7. 为什么我们要使用Go语言以及如何使用它的 (累计阅读 4,561)
  8. Go 语言初步 (累计阅读 4,478)
  9. 程序员的“横向发展” (累计阅读 4,119)
  10. ZeroMQ 的模式 (累计阅读 4,041)