2776 字
约 9 分钟
16
S24-X10 · 把稳定工作流变成自动化

"让它检查一下 lint"、"让它把 import 排一下"、"让它把这份 changelog 补上"——这些话每周说五遍,就是自动化该介入的信号。判据不是"这事麻烦",而是它每次都一样。

这篇给一条从"手敲提示词"到"事件触发、无人值守"的升级路径,以及每一步会在哪里翻车。


1. 三个判据:什么值得自动化

判断一个任务该不该写成自动流程,只看三条,三条全中才动手。

判据 具体问法 不满足时的后果
高频 一周内会重复三次以上吗 写脚本的时间永远收不回来
步骤固定 每次的步骤顺序完全一致吗 每次都要改流程,脚本变成负债
验收标准明确 能否用一条机器可判定的条件说"完成" 无终止条件,跑多久都算"没完成"

第三条最容易被忽略。"代码更整洁了"不是验收标准,"eslint 零 error 且测试全绿"才是。没有可判定的验收,自动化只会把"人反复催"变成"机器反复跑"。

反过来看,这三条也在筛掉一类任务:缺陷定位、架构取舍、需求澄清。它们步骤不固定,验收靠人判断,硬做成自动流程必然产出要看第二遍的东西。


2. 三层升级:从模板到触发器

三层不是三选一,是一层一层往上加。跳层的结果通常是"脚本里塞了一段没法评审的自然语言"。

层 形态 触发方式 人在哪
第一层 提示模板 人手动粘贴 每次都在
第二层 脚本封装 人执行命令 决定跑不跑
第三层 定时/事件 cron、CI、webhook 只在告警时介入

2.1 第一层:把提示词写成模板

模板的作用是消灭变量。同一件事,每次只换仓库路径和分支名,其余一字不改。

【任务】修复 lint 与类型错误
【范围】仅改动 TARGET_DIR 下文件,不改公共接口签名
【步骤】1. 跑 QUALITY_CMD 收集错误清单
        2. 逐个修复,每修完一类就重跑 QUALITY_CMD
        3. 全绿后停下,不要顺手重构
【验收】QUALITY_CMD 退出码 0,且未修改 PUBLIC_API_FILE
【禁止】改测试断言来让测试通过;升级依赖大版本

模板里必须有"禁止"一行。没有它,模型会用自己的标准补全你的意图。

2.2 第二层:脚本化

把模板存成文件,用脚本注入变量并调用。

#!/usr/bin/env bash
# fix-lint.sh —— 幂等:可重复执行,结果收敛
set -euo pipefail

DIR="${1:?need target dir}"
BRANCH="$(git rev-parse --abbrev-ref HEAD)"
LOG="logs/fix-lint-$(date +%Y%m%d-%H%M%S).log"
mkdir -p logs

test -z "$(git status --porcelain)" || { echo "worktree dirty"; exit 2; }
git switch -c "auto/fix-lint-$RANDOM" >/dev/null

sed -e "s|TARGET_DIR|$DIR|g" \
    -e "s|QUALITY_CMD|npm run lint|g" \
    prompts/fix-lint.txt > "$LOG.prompt"

codex exec --sandbox workspace-write \
     --prompt-file "$LOG.prompt" 2>&1 | tee "$LOG"

git diff --stat | tee -a "$LOG"

两个细节决定这套能不能长期跑:工作区必须是干净的(否则 diff 分不清谁改的),以及每次在独立分支上跑(保留回滚点)。

2.3 第三层:交给触发器

cron 适合"每天该看一眼"的巡检;CI 适合"每次 push 都该验"的门禁。区别在于失败该拦谁:CI 失败拦合并,cron 失败只是发通知。


3. 检查-修复-验证:可重复的提示骨架

固定三段式,缺一段就会退化成"改完不知道对不对"。

【背景】仓库 PATH,语言与包管理器按仓库现状,质量命令 QUALITY_CMD。
        上一轮自动修复已产生提交 BASE_SHA。

【目标】让 QUALITY_CMD 通过,且不引入新的行为变更。

【约束】
- 只改 TARGET_DIR;不动 PUBLIC_API_FILE
- 不改测试断言、不加 eslint-disable、不加 ts-ignore
- 不升级依赖版本
- 每类错误单独一个提交,提交信息格式 fix(lint): <类别>

【验收】
1. QUALITY_CMD 退出码 0
2. git diff --stat 只涉及 TARGET_DIR
3. 测试命令 TEST_CMD 全绿

【失败处理】单类错误修两次仍失败 → 停止该类,写入
        logs/blocked-<类别>.md 并继续下一类,最后统一汇报。

最后那段"失败处理"是关键。没写它,模型会在同一个错误上反复试到超时,整轮白跑。

段落 缺了会怎样
背景 模型靠猜技术栈,命令全错
目标 顺手做重构,diff 不可评审
约束 用 eslint-disable 让检查"通过"
验收 无法判断是否该结束
失败处理 卡死在单点,不产出可用结果

4. 承载方式:CI 与定时任务

4.1 CI 里跑

name: auto-fix
on:
  schedule: [{ cron: "0 3 * * 1-5" }]
  workflow_dispatch:
jobs:
  fix:
    runs-on: ubuntu-latest
    permissions: { contents: write, pull-requests: write }
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - run: ./scripts/fix-lint.sh src
        env: { API_KEY: "${{ secrets.API_KEY }}" }
      - run: git push origin HEAD:auto/fix-lint
        if: always()

CI 里必须注意三点:密钥来自 secret 而不是仓库文件;产出走 PR 而不是直推主干;if: always() 保证日志被上传,否则失败时什么都看不到。

4.2 定时巡检

# crontab -e
# 每工作日 03:10 跑一次只读巡检,产出报告不产出提交
10 3 * * 1-5 cd /srv/app && ./scripts/audit.sh >> logs/audit.log 2>&1

巡检类任务优先用只读沙箱:它只要输出结论,不需要写权限。写权限留给修复类任务。


5. 幂等与失败告警

幂等 = 跑一次和跑三次结果相同。不幂等的自动化最典型症状是"第二次跑出一堆反向改动"。

不幂等的写法 幂等的写法
追加到文件末尾 按标记块整体替换
git commit 不看已有提交 先查 git log --grep=<trace_id>
每次生成新分支名 固定分支名 + force-with-lease
无条件下载依赖 校验 lockfile 哈希

告警要回答三个问题,缺一个就等于没告警:

[ALERT] auto-fix 失败
what : QUALITY_CMD 退出码 1,阻塞类别 type-error
where: 分支 auto/fix-lint-20261109,提交 abc1234
act  : 查看 logs/fix-lint-20261109-031000.log 第 40-88 行

失败静默是自动化最常见的死法。脚本 exit 0 吞掉错误、CI 步骤加了 continue-on-error、cron 输出重定向到 /dev/null——三种写法都能让一个坏掉三个月的流程继续"每天成功"。


6. 日志留存:每次运行都要能复盘

落盘内容固定为四件:输入、输出、改动、判定。

logs/
  20261109-031000/
    prompt.txt      # 实际发送的完整提示(含注入后的变量)
    stdout.log      # 模型完整输出
    diff.patch      # git diff,可直接 git apply
    verdict.json    # 退出码、耗时、验收项逐条结果
留什么 为什么
注入后的提示 变量替换错是最难复现的一类 bug
完整 stdout 失败时的推理链是唯一线索
diff.patch 能重放、能回滚、能单独评审
判定结果 区分"没跑"和"跑了但没通过"

留存周期按"下次改这段代码之前还看得到"来定,通常 30 天足够。别只留最后一轮——问题往往在第三轮才暴露。


7. 人的角色:从驱动到审查

自动化上线后,人的工作从"每次说一遍"变成"每天看一遍产出"。这项工作有具体形状:

阶段 人的动作 时间占比变化
之前 写提示、盯执行、手动改 执行占八成
之后 看 diff、判对错、改模板 审查占八成

审查时看三件事:diff 是不是只在约定范围内、有没有绕过检查的痕迹(eslint-disable、放宽的断言、skip)、失败处理是否按模板走了。

发现偏差时,改的是模板和约束,不是那一轮的产出。改产出只解决这一次,改模板解决后面每一次。


8. 什么时候自动化反而有害

场景 为什么有害 更合适的做法
判断类任务(定位根因、方案取舍) 步骤不固定,验收靠人 保留人工,只自动化"收集信息"这一段
需求高频变化 模板每周重写,维护成本高于收益 等需求稳定两周再抽象
验收标准说不清 无终止条件,跑成无限循环 先把验收写成可执行断言
一次性任务 写脚本时间 > 手做时间 手做
涉及不可逆操作(迁移、删数据) 出错无法回滚 只自动化到"生成脚本",执行留给人
需要跨团队协商 协商过程本身是产出 自动化只做材料准备

一句话边界:自动化放大的是流程的确定性,不是流程的正确性。 流程本身是错的,自动化只会让错误更快、更整齐地发生。


9. 排错:六种"跑起来了但没用"

现象 原因 处理
每天成功但 diff 为空 验收条件太松,模型立刻"通过" 收紧验收,加一条必须产出改动的断言
第二轮改动把第一轮推翻 不幂等,追加式写入 改成标记块整体替换,固定分支
失败但告警没发 错误被 exit 0 或 continue-on-error 吞掉 检查退出码传递链,去掉静默
同一错误重复修到超时 缺"失败处理"段 模板里加上"两次失败即跳过并记录"
CI 里命令全错 缺背景段,模型猜了技术栈 模板注入 QUALITY_CMD 与环境事实
评审时看不懂 diff 一次改太多类,提交没分组 按类别分组提交,一条提交一类

10. 自测

  1. 判断一个任务该不该自动化的三条判据分别是什么?
  2. 为什么"代码更整洁了"不能当验收标准?
  3. 提示骨架里"失败处理"那一段解决什么问题?
  4. 判断幂等的标准是什么,举一个不幂等的写法。
  5. 告警必须包含哪三个要素?
  6. 自动化上线后,发现产出偏差时该改模板还是改那一轮产出,为什么?
S24-X10 · 把稳定工作流变成自动化
https://www.clxhxhhr.top/posts/5702/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。