我宣布, CC 目前最佳使用方式是 Spec+Agents+TDD - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
sampeng
V2EX    程序员

我宣布, CC 目前最佳使用方式是 Spec+Agents+TDD

  •  
  •   sampeng 147 天前 2410 次点击
    这是一个创建于 147 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这一周都在自己的 mcp 上尝试各种开发方法。

    最终结论是 Spec 先定义好需求,实现计划,然后进行 TDD 是最舒服,成功率最高的方式。

    之前我实现了一个 gitlab 的 Spec 的 mcp ,但是还是不得劲,单元测试瞎写,纯炼丹。就是属于那种他过不去就自己改单元测试,或者单元测试写一大堆但是重复的不少。最主要的问题是上下文问题。claude code 在使用 Spec 的开发模式进行开发的时候非常容易触发压缩。尤其是对于大一点的 Spec 。压缩带来的问题更严重,随机的丢失上下文。这是一件非常麻烦的事。

    这周发布的 agents ,让我眼前一亮,因为上下文隔离就可以很好的避免上下文污染。

    我测试了 3 天,完全是可行的。QA 的 agents 只负责单元测试的修改。Developer 的 agents 只负责代码的编写保证单元测试通过。最后的重构和优化阶段非常重要,我调试了很多次才搞定。也就是形成 Red-Green-Refactor 的完整流程。一开始我没觉得最后的阶段有用,真的实现和跑了一些复杂接口实现的时候这玩意就有用了。不会一直拉屎拉到无法看懂。我要求他重构的时候把不用的清理掉,大函数拆解,发现重构机会。但当然还是有点问题,10 次里有 1 次没聚焦到这次的修改范围,目前把上下文在 prompt 里补充了好像还行。

    prompt

    please think hard about, 请读取 issues $ARGUMENTS 的详情,你会得到一个任务树; 你不得实现任何业务,应该调度角色来完成 ## 名词理解 **业务实现计划** 指定的 $ARGUMENTS 是业务实现计划的 issue ID ,包含了业务实现的详细步骤和文件修改计划。 **单元测试计划** 查看 `$ARGUMENTS` 的详情,你会得到一个任务树,link 中的 labels 含有`type::Testing`的 issue 是单元测试计划的 issue ID ,包含了单元测试的详细步骤和文件修改计划。 **使用子任务尽可能的并行的分析和拆解 TDD 循环列表** 子任务中 link 的 label 为`type::TDD-interface`的 issue 是以接口为单位的 TDD 工作大纲。 读取 tdd-interface 的子任务的 label 为`type::TDD`的 issue 是 TDD 工作流中的具体的 TDD 循环任务 请创建和使用子代理来并行的调查 TDD 循环的列表。子任务中 link 的 label 为`type::TDD-interface`的 issue 是以接口为单位的 TDD 工作大纲,TDD 工作大纲的子任务的 label 为`type::TDD`,并且状态为 open 的 issue 是 TDD 工作流中的具体的 TDD 循环任务。 - 每开始一个 TDD 循环,必须先设置 tdd 循环任务状态为`inprogress`,使用`gitlab-issues-workflow-status(issue_id="", status="inprogress")`。 - 每完成一个 TDD 循环的步骤,必须设置 tdd 循环任务中的 AC 对应步骤为 checked 。 - 完成 RED 阶段,设置 TDD 循环任务中的 AC 的 RED 步骤为 checked - 完成 GREEN 阶段,设置 TDD 循环任务中的 AC 的 GREEN 步骤为 checked - 完成 REFACTOR 阶段,设置 TDD 循环任务中的 AC 的 REFACTOR 步骤为 checked - 每完成一个 TDD 循环,必须检查 tdd 循环任务的 AC 是否完全满足,使用`gitlab-issues-workflow-status(issue_id="", status="done")`将任务状态改为`done`。 - 分析和检查 AC 的步骤一步完成了哪一步没完成。 对 TDD 循环列表创建 todowriter 列表,每一项就是 TDD 的一个循环,tdd 循环来源于子任务的调查结果。 ### TDD 工作流的阶段 **角色定义**: **QA**: `tdd-qa-partner`子代理角色负责实现单元测试,只允许实现测试代码,不允许修改业务代码。 **Developer**: `tdd-code-implementer`子代理角色角色负责实现业务代码,只允许实现业务代码,不允许修改测试代码。 ### TDD 循环 **Workflow Guidance**: - **第一**让`tdd-code-implementer`基于设计文档的接口定义,实现最小的接口或者 struct 定义,要确保 make test 是能通过的。 - tdd 以接口为单位进行迭代开发,每个接口都经过严格的测试驱动开发( TDD )流程,确保每个接口都经过 Red-Green-Refactor 的完整流程。 - 要告知角色,只做一个阶段的事,不允许做任何其他阶段的工作。 - 避免一次性创建所有接口,专注于一个功能一个功能地 TDD 循环,确保每个功能都经过测试和验证。 - 严格检查每个 Phase 的 TDD 循环的 Red ,Green 和 Refactor 阶段是否都做了。不能跳过任何阶段。 - 不是 QA 和 Developer 的任何独立完成的任务,是描述的 Phase 的 TDD 循环。 - 确保都做过步骤 Red→Green→Refactor - QA 和 Developer 角色需要紧密协作,交替按照 TDD 循环进行红绿优化循环。 - 每个循环步骤都务必聚焦于设计需求和测试需求所涉及的文件和代码,**不得擅自修改和优化其他的代码文件** - QA 和 Developer 都不是一次性完成他们的工作,而是一个接口一个接口的去进行实现和测试。 - 每次 QA 和 Developer 开始的时候,你**必须把设计文档和测试文档的 issues id 以及 TDD 循环迭代到子代理角色**,并让子代理角色先自己去分析和理解上下文。 - 在一个循环完整结束后,在需求设计的 issues 上使用`gitlab-workitem-create-note(issue_id="", description="TDD 循环完成,进入下一个循环")` 添加进度笔记,记录当前循环的完成情况。 - QA 和 Developer 除了在 TDD 循环中使用绝对不会自行去实现实现计划的接口和单元测试任务。 #### Phase 0: Ready for TDD, 1. 只定义即将测试的一个方法(如 AddLabel ) 2. 创建必要的数据结构 #### Phase 1: **TDD 循环** 每次 QA 和 Developer 开始的时候,你**必须把设计文档、测试文档和 TDD 循环迭代的 issuesID 到子代理角色**,并让子代理角色先自己去分析和理解上下文。 1. Red: QA(`tdd-qa-partner`) 为接口编写失败测试 2. Green: Developer(`tdd-code-implementer`) 实现最小代码让测试通过 3. Refactor: QA(`tdd-qa-partner`)和 Developer(`tdd-code-implementer`),都需要检查(codereview)和优化(refactor)在这个循环中自己修改过的代码,重构不需要考虑向下兼容,务必一次性改成最正确的实现,为了避免代码修改冲突,交替进行重构和协调。不能并行执行 #### Phase 2: 逐步扩展 1. 添加下一个方法到接口 2. 重复 TDD 循环 #### **phase 分解的例子** 分解的任务必须严格按照 TDD 循环的步骤进行,确保每个方法都经过 Red-Green-Refactor 的完整流程。 

    Update Todos Phase 0: Ready for TDD - 创建最小接口定义,确保 make test 通过
    TDD 循环 1: ContentBlockHelper.GetAcceptanceCriteria() - Red→Green→Refactor TDD 循环 2: ContentBlockHelper.SetAcceptanceCriteria() - Red→Green→Refactor TDD 循环 3: ContentBlockHelper.GetImplementationPlan() - Red→Green→Refactor TDD 循环 4: ContentBlockHelper.SetImplementationPlan() - Red→Green→Refactor TDD 循环 5: IssuesManager.SetAcceptanceCriteria()编排逻辑 - Red→Green→Refactor TDD 循环 6: IssuesManager.AddLabel()去重逻辑 - Red→Green→Refactor

     ##### TDD 工作流的重构阶段 QA 负责: - 重构测试代码(提取测试辅助函数、优化测试数据设置) - 确保测试仍然验证正确的业务逻辑 - 检查测试覆盖率是否受影响 - 验证重构后测试仍然能发现潜在 bug - 发现的改进机会都必须在重构阶段处理,不得延后到下一个 TDD 循环 Developer 负责: - 重构实现代码(提取小函数、优化算法、改善命名) - 确保代码结构更清晰 - 优化性能(在不改变行为的前提下) - 处理代码重复和设计改进 - 发现的改进机会都必须在重构阶段处理,不得延后到下一个 TDD 循环 共同协作: - 讨论接口设计是否需要调整 - 确保测试和实现的重构方向一致 - 运行完整测试套件验证重构成功 - 代码审查确保质量 实际操作流程: 重构阶段开始: ├─ QA:重构测试代码,保持测试意图不变 ├─ Developer:重构实现代码,保持行为不变 ├─ 协作:运行测试确保全部通过 ├─ 协作:代码审查和讨论 └─ 提交重构后的代码,进入下一个 TDD 循环 
    第 2 条附言    146 天前
    补充一下效果





    29 条回复    2025-09-16 22:49:28 +08:00
    oudioppa
        1
    oudioppa  
       147 天前
    直接放到 gitgist 吧...
    sampeng
        2
    sampeng  
    OP
       147 天前 via iPhone
    @oudioppa 有道理
    hihanley
        3
    hihanley  
       147 天前
    @sampeng op 放了踢我一下
    sampeng
        4
    sampeng  
    OP
       147 天前
    @oudioppa @hihanley

    https://gist.github.com/SamPeng87/bcd420be34f84957897637596937d71d

    理论上能用,但可能会有点问题,就是我在 prompts 里面强制使用一些我自己定义的 tools 。。。因为上下文都是通过 gitlab 的 issues 来供应的,因为太多了。md 文件其实不是太好管理。。多了就乱套了

    但用了几天,确实已经能够标准的 TDD 流程运转了。。只不过。。是个 token 怪物。因为从逻辑上来说是每个函数的接口的新增,修改,都自动是干净的上下文,要重新获取上下文。但是效果确实还可以。中间有问题你停下来,也能理解继续调度正确的子任务去干活
    hihanley
        5
    hihanley  
       147 天前
    @sampeng 感谢,我试试再来回复
    mydev6666666
        6
    mydev6666666  
       147 天前
    这个要怎么使用?是不是要建 3 个 agents? 我今天建了一个,我是想让 claude code 实现 spec 然后让 augmentcode, aug 这个比较贵。
    sampeng
        7
    sampeng  
    OP
       147 天前
    @mydev6666666 两个 agents ,一个是 qa 的角色,一个是 developer 的角色。tdd.md 是一个斜杠命令。可能需要处理一下我这些任务的上下文要有地方来。。没有上下文来源是转不起来的。。全靠有个外部上下文供应
    sampeng
        8
    sampeng  
    OP
       147 天前
    @mydev6666666 补充一下。其实我试了一下。没上下文也能工作。就是在/tdd 的时候要把上下文说清楚。他这个子任务角色很有意思,会传递你的上下文进行分析后子代理。但有时候会传递错意思或者丢了意思。。要 ctrl+r 看一眼,因为我大部分重要的任务是 gitlab 来传递上下文,就没这个问题。。。可以看到 prompts 里面很多是告诉他 gitlab 的 issues 的结构
    zqguo
        9
    zqguo  
       147 天前
    很不错的思路,楼主可以说下需要安装哪些 mcp 工具吗 ?如果能给下具体的地址就更好了。
    sampeng
        10
    sampeng  
    OP
       147 天前 via iPhone
    @zqguo 只能说提供思路了,mcp 是我自己开发的基于 gitlab 进行上下文的传递。可能要找一些 spec 管理的 mcp 吧。
    Philippa
        11
    Philippa  
       147 天前
    很好的想法,感谢分享

    但 op 有没有想过如何把需求 context 关联和顺序问题?比如说:

    1. 使用 “人和动物 class” 创建一个人物
    2. 使用 “人和动物 class” 创建一只宠物
    3. 让人物去摸宠物

    1. 如果 agent 先读取 issue 时先读了 3 ,会导致奇怪的问题。
    2. 如果 agent 先读取 1 然后马上读取 3 ,可能会导致生成了不符合要求的宠物 code 。
    Philippa
        12
    Philippa  
       147 天前
    可能要给 issue 和 issue 之间加一个依赖注入,让它能够自动把复杂的需求转化成线性顺序去解决 issues 。
    sampeng
        13
    sampeng  
    OP
       146 天前   1
    @Philippa 有一点搞错了。核心并不是上下文,而是 TDD 的流程。
    在 agent 看来。1 ,2 ,3 都是上下文。这是很自然的事。如果是我做。就是一个 issues 是总需求,3 个子需求是 1 ,2 ,3 。
    这样 tdd 的流程就是

    RED 阶段:QA ,知道人和动物的 class 是怎样的,创建人应该预期是什么样,结果是如何。然后针对这个编测试代码。预期失败
    GREE 阶段:Developer ,知道人和动物的 class 是怎样的定义的,行为是什么。根据测试代码。编写实际的创建人的代码。
    重构阶段:QA 和 Developer 交替优化各自的代码,清理临时函数,拆解大函数,检查是不是真的完成了创建人这样的动作。

    这是一个 TDD 循环,再做创建人物的 TDD 循环。最后做人物去摸宠物的 TDD 循环。

    你理解的是一个 agent 干所有事,并不是这样的。agent 是把这些需求作为上下文。目的是什么在创建 context 的时候会明确的说明。

    我尝试这个流程,搞出奇怪 code 的原因基本是自己上下文没说清楚或者说没有 review 。

    AI 是工具,不是魔法。我没打算一个需求他,就自动 spec+tdd 完事了。这是不可能的,质量没法保障。我要事先 review 上下文的顺序是否合理,内容是否能够指导开发。主控的 prompt 的过程我会先 plan 模式看一眼是不是理解偏差了。

    我这只是方法论。我有个暴论,通过一个工具,一个命令,在人完全不参与的情况下就把需求完全实现并且代码质量都极其好的都是吹牛逼。
    zqguo
        14
    zqguo  
       146 天前
    结合自己项目特点改了下,效果挺好,但是 token 不太够用
    oudioppa
        15
    oudioppa  
       146 天前
    @zqguo 你这个是 claude 的 pro 吗?( 20 刀的)
    zqguo
        16
    zqguo  
       146 天前
    @oudioppa #15 是的
    sampeng
        17
    sampeng  
    OP
       146 天前
    @zqguo 都不用再改,在要求里不让他用子代理。消耗 token 就少一个数量级了。。我也在调查。。这个子代理的 token 消耗多的不能理解。。我 max 都会吃 cd 。但不用子代理。依然进行 TDD 。效果也不差,可能会不稳定。我调查 ing 。。。总的来说是一个思路。。
    Philippa
        19
    Philippa  
       146 天前
    @sampeng Thanks

    今天研究并试验了一下,我个人觉得 TDD 并没有带来什么额外的东西,只是流程上发生了变化,似乎真正带来增益的是测试来把关。其他发现比如:

    1. Tokens 用得很多,开了订阅其实没所谓,但是那个 tokens 多 = 很久,今天测试用的前端项目 5 个 cycles 今天跑了半小时+,效率不行。
    2. 检查了测试,除非人为写测试 description ,否则还是问题。
    3. 由于是写 markdown 来驱动开发,比在 IDE 里选中行,直接告诉如何实现效率要低很多,也更加不可控。
    4. 前端需要更好的测试方法,单元测试无法解决 UI 界面测试问题。
    5. 有时候 agent 会 skip 掉往 github 添加 comment 或更新 tag 的步骤。
    6. 有时候 agent 会忽略掉生成代码,只是分析了一遍,我觉得这是 markdown agent 的问题,不同于 n8n/dify/code 的 agent ,它无法确保步骤被执行。

    说实话,我挺期待能够找到更加自动化的方法。目前后端我只敢半自动,因为后端和数据相关,崩溃没关系,最怕数据结果算错了,那个很致命。另外后端设计除非 API 这种,否则无论 opus 还是 sonnet 还是经常犯傻。前端目前我能够 90% 以上生成,但前端却难在自动化测试。

    说个题外话,我觉得目前最好使的是 Claude Code 加个 mcp server 外接 gpt ,让 gpt 和 opus 同时出方案,相互比对代码性能更加,并且强制测试。
    sampeng
        20
    sampeng  
    OP
       146 天前 via iPhone   1
    @Philippa 你说的其实没错,这是降低效率的行为。但是正确率上升了。测试覆盖的还不错,逃不过自己的 review 。我认为这是不可缺少的一步,比不可控的练丹是要强很多的,哐哐哐写一堆没用代码和一次写好代码还是有区别的,我愿意接受慢一点但是整体接受率提升。

    还是有细节区别的,我昨天对比过不用 agents 和不用 tdd 。
    1.单元测试更详细了,因为有 spec ,可以先仔细 review 单元测试有没错。
    2.最后的 tdd 的最后的重构阶段效果让我眼前一亮,因为一直以来困扰我的全自动拉屎得到了缓解,可以看到代码质量在最后重构阶段会大幅度提升。
    3.green 阶段不再一口气写一大堆看起来很牛逼但是没卵用的垃圾代码,不对、不是不会,是在大幅度减少,因为 green 阶段是参考单元测试,以单元测试为目标写最小化代码。我经常看到注释里:这个实现先简化,因为单元测试要求只处理 xx 情况。
    4.整体流程可控,在 plan 阶段发现不是 tdd 就可以提前取消了,要求严格保证

    不过你说的问题是存在的,比如偶尔 skip 掉状态设置,还是提示词没约束好。我也在改进,不要让在 agent 阶段做,让主控在一个循环的前后进行操作,这个可以在 todowriter 里观察到,没有就重来。


    慢我觉得慢慢迭代 cc 会解决的,昨天我一直在 debug 观察到底啥慢。还是要官方下场解决更新。但 token 消耗确实很莫名其妙…找原因中…一个可能是 agents 的上下文处理和主控不一样。其实观察 ccusage ,每小时的 token 消耗只是大了 20-30%,但代码生成数也多了 20-30%(因为单元测试更详细,非常的规范)。问题还是出在慢上面。
    sampeng
        21
    sampeng  
    OP
       146 天前 via iPhone
    @Philippa 回车快了…你猜为什么我的提示词里

    Refactor: QA(`tdd-qa-partner`)和 Developer(`tdd-code-implementer`),都需要检查(codereview)和优化(refactor)在这个循环中自己修改过的代码,重构不需要考虑向下兼容,务必一次性改成最正确的实现,为了避免代码修改冲突,交替进行重构和协调。不能并行执行

    这里在优化和检查要用英文解释?嘿嘿,因为我还有 zen-mcp-server 。这两个字是关键词。重构和检查阶段是由外部的 gemini 和 opus 共同 review 和检查提出想法后嚷 sonnet 来解决的。效果相当可以,每次都能发现一些实现的小问题和 bug
    sampeng
        22
    sampeng  
    OP
       146 天前 via iPhone
    我在设计一个 mcp ,当前 mcp 是 spec 的一个架子。像这些约束不好处理的,我打算用外部 mcp 来逻辑强制串联来解决。比如 tdd 是标准流程,可以通过 mcp+hooms 来串联强制检查每一步的结果,自动在代码层逻辑上强制设置状态。在考虑咋做 ing…
    lthon
        23
    lthon  
       145 天前
    code 跑测试真的好耗 token
    JasperHale
        24
    JasperHale  
       123 天前
    鄙人, 改 RIPER5 -> RIP-TDD-R 效果上佳.. 唯耗时.....

    借楼请赐教, @sampeng 是怎么解决 运行时间过长问题的?
    - red-green-r 无法并行化, cc 一次仅运行一个同名的 subagent..
    - 昨天一夜上, 只完成了 3 个 red-green-r 循环....
    sampeng
        25
    sampeng  
    OP
       123 天前 via iPhone
    @JasperHale 耗时可以试试把 node 的 heap 调大点。他这个大 json 会经常拉住。会好一点,但还是卡…我打算自己写和调度坐 red-green-r 。主线程明显快很多。
    JasperHale
        26
    JasperHale  
       123 天前
    @sampeng 鄙人余暇时光尝, cc 可拉起多个同质 subagent = 并行多个 R-G-R 循环, 限制并行 3, 效果尚可.
    JasperHale
        27
    JasperHale  
       112 天前
    https://github.com/Jasper-1024/DPTR-SIGMA
    CC 多个 subagent (同一个 subagent 也可并行) 并行供参考;
    最主要的是: PARALLEL EXECUTION: For |cycles| instances, invoke Task tool |cycles| times in ONE message. Example: [Ω×|cycles|] where cycles={1,2} requires 2 Task invocations in the same message.
    要求 CC 在一个 mes 中有几个 subagent 就调用几次 task 工具
    aulaia
        28
    aulaia  
       107 天前
    @JasperHale 兄台妙啊,仓库我看了,如何运行起来呢?没太看懂你的设计思路
    JasperHale
        29
    JasperHale  
       100 天前
    @aulaia 此仓库还在修缮中,鄙人不才,至今还有 bug.
    原理: 原楼主仓库中制定计划提示词提取为独立 subagent,要求识别无互相依赖 r-g-r 循环,编纂一个批次.
    同一批次,方执行时一次回答时 多次 invoke task, 此效果如下, 1msg 一行
    r1 r2 r3
    g1 g2 g3
    r1 r1 g3
    g1 跳过 g3
    r1 跳过 跳过
    g2 跳过 跳过
    完成
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4483 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 40ms UTC 04:00 PVG 12:00 LAX 20:00 JFK 23:00
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86