首页 > 基础资料 博客日记

从跑通到放弃:我的 Cloud Agent V1开发历程

2026-05-30 00:30:02基础资料围观4

本篇文章分享从跑通到放弃:我的 Cloud Agent V1开发历程,对你有帮助的话记得收藏一下,看极客资料网收获更多编程知识

从跑通到放弃:我的 Cloud Agent V1 开发历程

Vibe Coding,启动

2026年1月,我在各种SNS上看到越来越多的关于Vibe Coding的经验分享。上家公司我曾对接过一些AIGC的场景,也了解过cursor、copliot这些工具,起初并未在意。但当我看到有人说“并发开10个Agent——5个写代码、3个测试、1个工作汇总、1个写文档,下班回家睡一觉,第二天来公司代码就写好测完可上线”时,还是有点震惊,AI Coding的能力已经进化到这种地步了吗?处于尝鲜,我安装了Trae,让它接手了我业余时间编写的一个小应用,效果还不错,耳目一新。

等到年后开工,我尝试用Trae处理新分配的需求并编写代码。不过项目还没开始,公司就安排了一个调研任务——一个财务领域的 AI 助手要怎么实现?我也紧跟潮流安装了Claude Code,接入glm-5模型,开始编写代码。

Vibe Coding初体验

如何通过Vibe Coding从零构建一个Agent?对于LLM和Agent,我之前只是粗浅地了解过,没有相关的技术背景,但是既然SNS上把Vibe Coding吹的神乎其神,叠加此时的养龙虾热,我自然是信心满满。

开发流程很简单:

  • 打开对标的产品,先体验其交互,然后告诉Claude Code:“我要有XXX功能,这个功能需要XXX”/“页面布局为XXXXX”等等等等。

  • 等Claude Code写代码

  • 我启动服务器,进行测试,发现有bug就让Claude Code继续改

  • 如此循环。

不出意外,遇到了很多问题:

  • 前端交互改起来很费时间,我毕竟是后端出身,对于前端没有那么了解

  • 同一个bug,反复改很久才改好。有时还会出现:bug1修了1天修好了,开始修bug2,bug2修好了bug1又重现了。

  • 大模型限流。虽然是公司提供的coding plan,但是用的太狠还是限流。

但说来也怪,尽管各种不顺,Vibe Coding 会让人上瘾。一旦开始写代码完全停不下来,有点像刚毕业那会儿大展拳脚的感觉——把想法丢给 AI,看着代码在面前长出来,那种即时反馈让人沉迷,甚至游戏都不香了。

V1:跑通了,跑不动了

经过一点一点探索和尝试,还真的把 Agent 写出来了,也就是 Cloud Agent V1。它用 Python FastAPI 搭建,6 周时间、170 次提交、约 1.7 万行代码,纯 Vibe Coding,没有手写一行代码。V1 的核心是 LLM 输出带 XML 标签的 Python 脚本,正则解析后在沙箱环境执行。能对话、能操作文件、能执行脚本、能加载 Skill、能调用 MCP,跑通了完整链路。3 月份的各种产品演示都靠它撑了下来,但每次演示前心里都在打鼓——怕 LLM 输出跑偏,怕对话突然卡死。

能跑,但没有任何优势。CherryStudio、Openclaw 这类开箱即用的 Agent 同样能对话、能操作文件、能接 MCP,V1 没有差异化。更要命的是,V1 已经改不动了,继续加功能只会让它更不可控。下面说致命的部分。

V1 的致命伤

致命伤 一句话 直接后果
XML 当协议 LLM 生成任意 Python 脚本,正则提取执行 不可靠、不可调试、无法区分错误类型
上下文混乱 按轮数硬裁 + 提示词失控 + 优化全治错地方 失忆、token 烧光、越优化越慢
God 类膨胀 无初始架构,Vibe Coding 堆功能越堆越大 改不动、测不了、牵一发动全身

致命伤一:XML 标签当协议

这是 V1 最根本的架构问题。系统不是通过 API 原生的 tool_use / function calling 机制执行操作,而是让 LLM 用 XML 标签包裹生成的Python代码,用正则匹配提取后在python沙箱执行。流程可以简化为两阶段:

用户输入
  │
  ▼
┌─────────────┐
│ Judge 阶段   │  轻量 LLM 调用 → 决定加载哪些 Skill、文件
└──────┬──────┘
       ▼
┌─────────────┐
│ 处理阶段     │
│             │
│  ◄── 循环 ──┤  LLM 生成 <script> → 正则提取
│             │    → 沙箱执行 → 结果回传 → 下一轮
│             │    最多 50 轮
└─────────────┘
       ▼
    返回结果

这带来了一连串问题:

  • 自由代码无约束。 LLM 生成的是任意 Python 脚本,不是带 schema 的函数调用。参数是凭空捏的,函数名是幻觉出来的,文件路径是猜的。代码语法错误、import 不存在、变量未定义,全靠沙箱报错才知道。
  • 一个脚本干所有事。 LLM 倾向于把多个操作塞进一个 <script> 块:先读文件、再算逻辑、最后写结果。中间任何一步崩了,整个脚本失败,而且不知道崩在哪一步。
  • 代码错误 vs 业务失败无法区分。 沙箱返回一个 traceback 或一个 None,系统分不清是"脚本写错了"还是"查询的数据确实为空"。两种场景下游处理完全不同,但 V1 都当成"再试一次"。
  • 正则解析脆弱。 LLM 输出的 <script> 标签稍有偏差——少个闭合、think 块里混入了类似标签,代码里碰巧包含 </script> 字符串,解析就断了。唯一的恢复手段是让 LLM 再试一次,但它不知道哪错了,只能反复生成代码、反复失败,直到运气好成功、轮数耗尽或用户放弃。
  • 沙箱文件复制的开销。 每次执行脚本前,先把相关文件复制到隔离沙箱,安全但每轮多一次 I/O。多轮任务跑下来,大量时间耗在文件搬运上,实际计算反而占比不高。

致命伤二:上下文管理混乱

粗暴的轮数裁剪

历史消息不做 token 精算,唯一的措施是只保留最近 N 轮,更早的直接丢弃。简单粗暴,但结果是两个方向都崩:保留太少,聊几轮 LLM 就忘了开头说过什么,反复追问用户已经回答过的问题;保留太多,一轮交互轻松破 10 万 token。模型也就 200K 的上下文窗口,几轮就烧完了。要么触发 API 400 直接拒绝,要么 LLM 静默丢弃早期上下文,同样是失忆。根本不存在一个稳得住的平衡点。

核心循环最多跑 50 步,每步无条件追加 assistant 响应和脚本执行结果反馈到消息列表。加上聊天历史,全部按轮数硬裁,没有优先级、没有摘要压缩、没有关键信息标记。前面讨论的业务背景、确认过的文件路径,几轮之后就跟从来没出现过一样。

提示词失控

系统提示词约 200 行,硬编码在 Python 源码里。每次 LLM 调用动态拼接:基础提示词 + MCP 工具描述(含完整 JSON Schema)+ 项目文件预览(Excel 表名、列名、数据样本)+ Skill 指令全文。一次普通业务调用,提示词本身烧掉 1-2 万 token。而且每次从头构建,没有缓存复用。这意味着 Skill 指令也是跟着上下文一起膨胀:花大量时间和用户一轮轮调试优化 Skill 的触发条件和提示词,但优化完之后塞进已经臃肿的上下文里,LLM 到底有没有按指令走、触发是否准确,完全不可知。优化了一整天,效果全凭感觉。

治错地方的优化:两个失败的 token 节省策略

Judge Phase

开发和测试中,我意识到了上下文问题,设计了一个 Judge 阶段来解决它,这也是 V1 里我的原创设计。想法不复杂:每次执行任务前,先做一次轻量级 LLM 调用,判断用户要处理哪些文件、需要加载哪些 Skill,然后只把筛选后的内容注入完整上下文。

想法没问题,但忽略了一个基本账本:多一次 LLM 调用,用户就多等一轮。每次操作都要先等 Judge 返回,再等执行结果,响应速度直接被拖慢。如果能用轻量模型来做,消耗倒不至于太大。但当时根本没往这想。

而且 Judge Phase虽然削减的是文件预览和 Skill 内容,但上下文真正的大头是历史对话。前几轮生成的大段 Python 脚本、沙箱返回的几千字节执行结果、反复重试的失败记录。省掉的提示词跟历史对话这个黑洞比完全是杯水车薪。

File Preview

类似的还有文件预览机制。我观察到一个规律:LLM 处理文件时总是先瞄一眼:Excel 读第一个 Sheet 的前几行,PDF 看前几页文本,从不会一上来就做全量分析。于是加了一套文件预览:上传时解析一次,Excel 提取表名和样本数据,PDF 提取文本,Word 提取段落和表格,结果存为 preview_data。Judge 阶段只发精简版(文件名 + 维度),处理阶段发完整版(含样本行和文本摘录)。思路和 Judge 一样:用空间换 token。但问题也一样:根本没做缓存复用。同一份 Excel 预览数据,循环 50 步就在 50 次 LLM 调用里原样发了 50 遍,每次都是从头拼系统提示词。V1 的"优化"始终停在"传什么"层面,从没触及"怎么不反复传"。后者要等 V2 的 prompt caching 才真正解决。

致命三:God 类膨胀和架构失控

最根本的问题是,我一开始就没定架构。不是因为偷懒,而是此前从没做过类似的应用,根本不知道该长什么样。Vibe Coding 的方式是描述功能让 AI 写,不是先画蓝图再施工。结果是架构随功能有机生长,每多加一个模块,前面的设计债务就重一层。

executor.py,2000+ 行。这一个类干了多少事:判断阶段(Judge)、执行阶段(Execute)、脚本运行、MCP 过滤、重试逻辑、错误处理、上下文拼接。全部耦合在一个类里,没有清晰边界。

除了它,context.py 900+ 行,chat_service.py 600+ 行,每个都是同样的毛病。

开发过程中其实也让 AI 帮忙做过架构优化:分模块、拆文件、抽函数、建分层,这些 AI 都能执行。但有两个问题。第一,AI 只负责"当前这次修改",没人持续盯着全局结构。今天拆出去三个函数,明天为了修一个 bug 又塞回两个,后天加新功能再堆一层 if-else。第二,架构优化只在版本稳定时才能做:功能跑通了、演示没压力了,才敢动手。平时改需求、修 bug 时根本不敢大动结构,怕拆出新问题修不回来。结果优化窗口越来越窄,债越欠越多。

重写还是重构

这个决策我纠结了将近一周。不是因为看不清方向,而是沉没成本太重。

V1 毕竟是可以用的。3 月份好几场产品演示都靠它扛下来的,虽然每次演示前提心吊胆,但功能确实一项项跑通了。而且已经加了一个月的班,每天跟 AI 较劲到半夜,好不容易折腾出一个能跑起来的版本。调研项目有公司的时间节点,不是无限期探索。推倒重来意味着前面一个月的加班全部归零,新方案能不能按时跑出来,当时根本没底。

与此同时,用户提的 bug 越攒越多。修好一个冒出两个,越来越看不到头。

但继续在 V1 上修补,代价同样算得清。前文提的三个致命伤,每一个细看都不是重构能解决的。

  继续修补 V1                         推倒重写
  ────────────                       ──────────
  ✓ 能跑、演示扛住了                   ✓ 三个致命伤,重构解决不了
  ✓ 加班成果不归零                     ✓ 参考其他开源Agent源码,但不知道选哪个
  ✗ 时间节点越来越不可预期              ✗ 一个月加班归零,风险未知
  ✗ bug 越修越多,看不到头             ✗ 1.7 万行代码作废
  ✗ 架构缺陷是骨架层的问题             

XML 标签当协议是 V1 的根基。把 XML 解析换为标准 tool_use,意味着整个 agent loop 从 executor、parser、context 到 LLM 调用链路全部推倒。这不是"重构 executor.py 的一部分",而是删除它存在的理由。

即使有 Vibe Coding,重构的工作量也不会少。零测试兜底意味着每次改完只能靠人肉验证:告诉 AI "这里有问题,改成 X",跑一遍,发现崩溃了,再告诉 AI 修崩溃,再跑一遍。

还有一个语言层面的问题:V1 用 Python 只是因为当时熟悉 Python,并不意味着后端就应该用 Python。Claude Code 源码是 TypeScript 写的,要继续深入参考它的设计,用同一种语言显然比在 Python 和 TypeScript 之间做概念翻译更顺畅。继续守着 V1 的 Python 代码,意味着往后的每一轮优化都在隔着一层语言做映射。这个成本,重构省不掉。

最后一个砝码:V1 还处于内部小范围 demo 阶段,没有历史数据要兼容,没有线上用户要迁移。推倒重来最重的代价只是扔掉代码,不需要做数据迁移、协议兼容、灰度切换这些工作。V1 的价值在于验证方向、积累认知,不在于那 1.7 万行代码本身。

契机

当我在纠结要不要重写时,Claude Code 的源码泄露了。

消息出来那天我就把源码拉了下来,不过比起直接啃源码,真正帮我下定决心的是社区里陆续出现的解读文章。这些文章讨论的方向主要有几个:

  • Agent 循环设计

  • tool注册和调度

  • prompt caching 的分段策略

  • 上下文压缩的分级机制

  • 多 Agent 的协作模式

  • 权限系统的分层拦截

当时我看得似懂非懂,很多概念还没建立起完整的认知。但我知道这就是我应该参考的方向。经过一个多月高强度使用 Claude Code,再看社区的评价,感受更确定了。大家反复提的几个点和我自己的体验完全重合:对代码库的理解不像关键词搜索,更像一个读完代码再动手的工程师;多文件重构时不会拆东墙补西墙,共享逻辑自然合并;每一步操作都附带自解释的上下文,像一个不需要文档的工具。

更棒的是,Claude Code并不是一个纯粹面向coding而是面向通用工作设计的Agent,即使直接将财务领域或其他业务领域的文件丢给它处理,它也能三下五除二地搞定,这对我来说足够了。一个让我每天用都不烦的设计,一定是值得跟着走的。

再次抉择:用 SDK 还是尽可能参考源码

参考方向有了,怎么落地?组里一直有声音建议直接用 Claude Code 的 SDK。毕竟官方封装好了 agent loop、工具调度、流式处理,上手最快。但经过前面一个多月的折腾,我很清楚这次不能只图快。如果只是用 SDK 拼业务逻辑,不过是换了一套 API,V1 的架构问题一个也解决不了。

动手重写前,我做了最后一次评估。

方案 A:基于 Claude Code SDK。 @anthropic-ai/claude-agent-sdk 封装了 agent loop、工具调度、流式处理,接入即用。优点是开发周期短,缺点是架构受 SDK 约束:权限模型、缓存粒度、中断机制、SSE 事件定义,能用但不能改。

方案 B:参考 Claude Code 源码自行实现。 研究 Claude Code 的架构设计、技术栈选择、模块划分,用自己的方式重写一遍。优点是每一层都可控,缺点是工作量大。

我选了方案 B。理由四个:

控制力。 SDK 封装了核心能力,使用方只能按它的接口接入。我需要的是自定义每一个关键环节:工具执行策略怎么设计、权限模型怎么隔离、缓存粒度怎么控制、中断机制怎么触发、SSE 事件怎么命名和传递。这些在 SDK 里是封闭的,在源码里是透明的。

集群部署。 SDK 的心智模型是单机运行,fork + process 隔离。项目一开始就规划了集群部署:多实例 + 会话亲和 + 状态外置 + SSE 跨节点转发。这要求 HTTP 层和流式传输层都是自主可控的。源码方式从 Hono server 到 SSE 流全是自己的,做分布式改造时不会有"SDK 封装的东西改不了"的尴尬。

技术栈对齐。 Claude Code 本身就是 TypeScript + Bun 构建的。V2 选同样的技术栈,模块结构、类型体系可以和参考实现保持一致,降低理解成本。

技术积累。 实际的开发方式不是"读完源码再动手写",而是让 Agent 写代码,并同步整理技术文档辅助理解。遇到拿不准的地方,回到 Claude Code 源码看对应的实现,然后在Claude Code 里复现同一个场景,观察它是怎么处理的。源码不是照着抄的模板,是遇到问题随时回去查的参考答案。

V2 的技术方向

┌──────────────────────────┬──────────────────────────┬───────────────────────────┐
│ 原则一                    │ 原则二                    │ 原则三                     │
│ 技术栈靠拢 Claude Code    │ 按模块推进,不照抄          │ 预留集群扩展空间             │
├──────────────────────────┼──────────────────────────┼───────────────────────────┤
│ TS + Bun + Zod 对齐 cc   │ 提取核心设计思想            │ 会话外置 → SQLite / JSONL  │
│ Hono 做 HTTP(原生 SSE)  │ 适配需求做改写和简化         │ SSE → 预留跨节点转发接口     │
│ React + Vite(Web 前端)  │ 先确保能跑起来              │ 文件 → 抽象 storage 层      │
│ SQLite 持久化            │ 卡住时回源码查参考答案        │ 不假设单机,杜绝"以后改不了"  │
└──────────────────────────┴──────────────────────────┴───────────────────────────┘

动手之前,定了三条原则。

第一,技术栈向 Claude Code 靠拢。 理由很简单:Claude Code的源码是现成的参考答案,同一种语言翻起来最顺畅。具体选型以 Claude Code为基准,场景不同的地方做适配:

层面 Claude Code V2 说明
运行时 Bun Bun 一致
语言 TypeScript TypeScript 一致
校验 Zod Zod 一致
UI Ink + React(终端) React + Vite(浏览器) Claude Code是 CLI 工具,V2 面向 Web 用户
HTTP 层 Hono cc 无需 HTTP server,V2 需要;选 Hono 是因为轻量、原生支持 SSE 流
存储 SQLite cc 主要操作本地文件系统;V2 需要持久化会话、用户、配置数据

第二,按功能模块推进,不搞像素级拷贝。 Claude Code是通用 CLI 工具,V2 是面向业务的 Web 应用,场景不同决定了不能全抄。开发策略是:从源码提取核心设计思想,适配自己的需求做改写和简化,在和Claude Code的流程一致的前提下,先确保能跑起来。当简化版确实满足不了需求时,再回头参考源码,看 Claude Code 在同类场景下是怎么处理的。

第三,预留集群部署的扩展空间。 项目规划中就有多实例部署的需求。这意味着从第一行代码开始就要考虑:状态不能长在进程内(会话数据外置到 SQLite/JSONL),SSE 连接不能假设单机(跨节点转发预留接口),文件存储不能依赖本地磁盘(抽象 storage 层)。不一定一开始就把集群搭起来,但架构上不能有"以后改不了"的单机假设。

V1 的代码被全部丢弃,但 V1 验证的方向:Skill 系统、MCP 集成、产品形态,全部保留。

Vibe Coding 实战心得

除了V1本身的经验教训外,我还总结了一些通用的Vibe Coding经验。

善用 git 做小步提交。 每次 commit 只做一件事。commit 粒度太大,前端改版 + 后端调整 + 提示词修改全塞一起,出了 bug 根本定位不到哪次改动引入的。更常见的是 bug A 修好了,下一个改动又把它带回来,因为提交太乱,AI 理不清哪些代码是修 bug 的、哪些是新功能的。小步提交、每个 commit 可独立回滚,省掉大量排查时间。

控制上下文窗口。 不论是 Vibe Coding 还是设计 Agent,上下文管理都是 AI 时代程序员的核心能力。对话长了 AI 会忘事,前面说过的规则、约定、已经修好的 bug,一旦被压缩出去就不在了。压缩本质是丢信息,没有两全方案。所以实际开发中要刻意保持对话聚焦:一个需求通路走到底就开新会话,不要在一条里反复横跳。把 AI 的记忆当成一种需要主动管理的稀缺资源,而不是默认它什么都能记住。

自己管运行环境,别让 Agent 插手。 可能是我用的LLM能力不足,Agent 启动的服务有时候 kill 不掉,端口被占着回收不了,只能手动 lsof -ikill -9。吃过几次亏之后就定了规矩:Agent 只负责生成代码,人负责启动服务和管理端口。代码和运行时分离,省掉一堆奇怪的运维问题,也省掉一些token。


V1 的故事到此为止。下一篇开始进入 V2。


文章来源:https://www.cnblogs.com/wuyuegb2312/p/20224755
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

上一篇:Avalonia 制作复杂布局动画
下一篇:没有了

相关文章

本站推荐

标签云