先把任务拆成能验证的小步——HelixHarness 的编排配置怎么写

文章导读
把一整个需求丢给 AI,评审时最难受的地方往往不是改动量大,而是一次改动里混着好几个变化,每个变化都没有单独的通过标准。HelixHarness 的编排文件能起作用的地方,是让每一步写清三件事:从哪读输入、往哪写产出、用什么命令判定这一步算过。编排字段的填法反而次要,真正决定结果的是拆分粒度——如果一步里还塞着“改代码 + 改测试 + 跑全量”,那配置写得再整齐,失败时也一样定位不到位置。
📋 目录
  1. A 把一个需求拆成可独立验证的步骤清单
  2. B 在编排文件里定义每一步的输入与产出
  3. C 为每一步接上可执行的验证命令
  4. D 跑一遍完整流程并定位失败停在哪一步
  5. E 根据失败点回头调整步骤粒度
A A

把一整个需求丢给 AI,评审时最难受的地方往往不是改动量大,而是一次改动里混着好几个变化,每个变化都没有单独的通过标准。HelixHarness 的编排文件能起作用的地方,是让每一步写清三件事:从哪读输入、往哪写产出、用什么命令判定这一步算过。编排字段的填法反而次要,真正决定结果的是拆分粒度——如果一步里还塞着“改代码 + 改测试 + 跑全量”,那配置写得再整齐,失败时也一样定位不到位置。

适用场景:需求横跨多文件、多阶段,一次提交后说不清是哪处引入问题。操作动作:先把需求切成带明确输入产出和验证命令的步骤,再写进 HelixHarness 编排文件,每步用退出码或可判定的输出特征作为验收点。验证方式:跑一遍编排,从日志看执行顺序和停在哪一步。风险边界:验证命令只能覆盖它真正测到的那部分,HelixHarness 的字段名与占位符语法需以本地实际版本为准,先小范围跑通再固化模板。

把一个需求拆成可独立验证的步骤清单

拆分粒度可以先按一条朴素标准判断:如果某一步失败后,你能直接说“问题出在定位、出在改代码、还是出在测试断言”,这一步就算拆到位;如果只能回答“这里整个不对”,说明还是太大。通常建议每步只做一类动作,改动的文件数量控制在自己能在评审里逐行看完的范围。

每步的验收点要落在可观察的事实上,而不是“看起来合理”。常见写法有三类:文件是否存在且非空、命令退出码是否为 0、输出里是否出现或缺少某个确定字符串。依赖关系则用显式声明表达,别靠步骤排在一起就默认先后——写上 needs 之后,编排才知道哪些步骤可以并行、哪些必须等前一步产出。

  • 步骤清单里标明输入来源:来自仓库现有文件、来自上一步产出、还是来自人工提供。
  • 每步只声明一个主产出,产出路径固定可预测,方便下游引用。
  • 依赖关系写清楚方向,避免两个步骤互相等对方的文件。

在编排文件里定义每一步的输入与产出

字段名各版本可能不同,下面是一份可直接替换成实际键名的通用骨架,重点看结构而不是键名本身。执行前先确认本机 HelixHarness 的配置 schema,再把 run 与 verify 换成你项目里真实可用的命令。

version: 1
task: add-rate-limit-header
vars:
  workdir: ./work
steps:
  - id: s1_locate
    inputs: ["src/**"]
    outputs: ["{{workdir}}/s1.hits.txt"]
    run: rg -n "rate_limit" src/ > {{workdir}}/s1.hits.txt
    verify:
      - cmd: test -s {{workdir}}/s1.hits.txt
        expect: exit0

  - id: s2_patch
    needs: [s1_locate]
    inputs: ["{{steps.s1_locate.outputs[0]}}"]
    outputs: ["src/middleware/rate_limit.py"]
    run: python tools/apply_patch.py `--plan` {{workdir}}/plan.json
    verify:
      - cmd: git diff `--name-only` | grep -q "rate_limit.py"
        expect: exit0

  - id: s3_test
    needs: [s2_patch]
    inputs: ["src/middleware/rate_limit.py"]
    outputs: ["{{workdir}}/s3.pytest.log"]
    run: python -m pytest tests/test_rate_limit.py -q | tee {{workdir}}/s3.pytest.log
    verify:
      - cmd: grep -q "failed" {{workdir}}/s3.pytest.log
        expect: exit1

字段含义逐条对照:id 是步骤的唯一名字,日志和占位符都用它定位;inputs 声明这一步允许读什么,写清楚能减少“脚本顺手改了别处”的情况;outputs 是下游唯一该依赖的东西;needs 决定执行顺序;run 只做动作,verify 只做判定,两者不要混写在一个长脚本里。

先把任务拆成能验证的小步——HelixHarness 的编排配置怎么写

占位符与上一步产出的对应方式要保守:优先引用 {{steps.<id>.outputs[0]}} 这种带步骤名的路径,而不是依赖工作目录里的相对位置。最后一个例子用了 expect: exit1,意思是“这条命令必须以非零退出”,用来表达“日志里不该出现 failed”。这类反向判定容易写反,建议写完先手动执行一次确认退出码。

为每一步接上可执行的验证命令

判定成功优先看退出码,因为退出码没有解释空间。只有在退出码说明不了问题时,才退一步看输出特征,而且特征要写成精确可判定的字符串匹配,不要写成“输出看起来正常”。

# 文件产出型:存在且非空
verify:
  - cmd: test -s {{workdir}}/s1.hits.txt
    expect: exit0

# 命令结果型:单测必须全绿
verify:
  - cmd: python -m pytest tests/test_rate_limit.py -q `--maxfail`=1
    expect: exit0

# 输出特征型:目标字符串必须出现
verify:
  - cmd: grep -q "X-RateLimit-Limit" src/middleware/rate_limit.py
    expect: exit0

添加验证命令时,有两个容易出问题的地方:一是命令的工作目录要和编排执行目录一致,否则相对路径全部失效;二是不要把带交互、需要额外凭据或依赖网络等待的命令塞进 verify,这类命令偶尔卡住不会报错,会让整条流程停在原地而看不出原因。判定标准建议不止写 expect,还写一句人能读懂的说明,失败时日志里能直接看出这条验证想证明什么。

跑一遍完整流程并定位失败停在哪一步

编排写完后先空跑一次,确认执行顺序和依赖关系符合预期。日志里应当能看清步骤边界:某一步开始、结束、哪条验证命令失败。下面是一段示例结构,字段名视实际输出格式替换,重点看边界标记。

先把任务拆成能验证的小步——HelixHarness 的编排配置怎么写
[seq 1/3] step=s1_locate start
[seq 1/3] step=s1_locate ok exit=0
[seq 2/3] step=s2_patch start
[seq 2/3] step=s2_patch ok exit=0
[seq 3/3] step=s3_test start
[seq 3/3] step=s3_test verify#1 failed cmd="pytest ... -q" exit=1
run aborted at step s3_test, 1 verify failed

看到 aborted at step 这类行,就能直接判断停在哪一步,而不是从头翻输出。常见停在原地却不像失败的原因有几种:验证命令返回非零但被当成警告继续跑;needs 漏写导致下游早于上游启动,读到旧文件后继续往下走;占位符没解析成功,命令带着字面量 {{...}} 执行却返回 0;以及某步退出码为 0 但产出文件其实是空的,直到后面某步才发现。遇到这几种,先检查该步骤的 outputs 是否真的落盘并且非空。

根据失败点回头调整步骤粒度

失败本身就是拆分粒度的反馈。如果一次失败只能定位到“s2_patch 不对”,说明这一步承担了太多动作;如果失败能定位到“s2b 的断言没覆盖新增分支”,粒度基本合适,只需要补验证命令。

调整前:s2_patch 一步里完成改中间件、补测试、跑相关用例三件事,失败时日志只报一个 exit=1。调整后拆成 s2a_patch_code(产出中间件文件,验证 diff 里有目标文件)、s2b_add_test(产出测试文件,验证新增用例名出现)、s2c_run_target_test(验证退出码为 0),三者用 needs 串起来。

调整依据是失败可定位性:拆完后任一失败都能落到具体动作上,评审时也能按步骤逐段看改动。反向调整同样成立——如果连续几个步骤的验证命令其实在同一条命令里已经覆盖,说明拆得偏细,合并成一步能减少配置维护成本。改完再跑一遍编排,确认日志里的步骤边界与新的依赖关系一致,再把这版结构作为后续需求的模板。