
Triage Loop 的五个动作:让 AI 真正「自己转起来」

这五个动作,本质上是给 AI 搭建了一个自动化的「戴明环(PDCA)」。
为了让 AI 真正「自己转起来」,而不只是「回答问题」,
每个动作都有特定的设计意图和工程落地细节。
全景图
┌─────────────────────────────────────────────────────────┐
│ Triage Loop 的五个动作 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────┐ │
│ │ 1. 发现(Discover) │ │
│ │ 自己找出这圈该做的事 │ │
│ └───────────────────┬───────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────┐ │
│ │ 2. 交付(Handoff) │ │
│ │ 把任务隔离着交给 agent │ │
│ └───────────────────┬───────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────┐ │
│ │ 3. 验证(Verify) │ │
│ │ 换个 agent 说「不」 │ │
│ └───────────────────┬───────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────┐ │
│ │ 4. 持久化(Persist) │ │
│ │ 把状态写到对话之外 │ │
│ └───────────────────┬───────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────┐ │
│ │ 5. 调度(Schedule) │ │
│ │ 让它一圈圈自动转 │ │
│ └───────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘动作与零件的关系
本章(动作篇):拆解的是「转一圈发生了什么」,即运行时的动态流程。
下一章(零件篇):拆解的是「搭一个能转的 loop,你手里得有哪几样东西」,即构建循环所需的静态组件。
两者是一体两面:
- 动作描述运转
- 零件描述材料
动作 1:发现(Discover)—— 感知信号
核心目标
让系统具备「主动性」,代替人工去监控外部变化,决定「这圈到底要干什么」。
技术实现手段
1. 轮询监控
schedule:"
- cron: "*/10 * * * *" # 每 10 分钟检查一次
steps:
- name: 检查 CI 状态
run: |
# 调用 Jenkins API 获取最近构建
BUILD_INFO=$(curl -s https://jenkins.example.com/job/ai-app/lastBuild/api/json)
echo $BUILD_INFO > build-info.json
- name: 解析失败日志
run: python parse_failures.py build-info.json2. Webhook 监听
webhooks:
- url: /api/github-events
events:
- push
- pull_request
- issues
handler:
- name: 提取事件类型
run: python classify_event.py
- name: 创建任务草稿
run: python create_task_draft.py3. 差异分析
# 对比当前代码库与上一次循环结束时的状态
last_commit = load_state("last_commit.json")
current_commit = get_current_commit()
changed_files = git_diff(last_commit, current_commit)
task_draft = {
"type": "code_change",
"files": changed_files,
"commit_sha": current_commit
}关键难点:信噪比
不是所有失败都需要介入。
需要借助 LLM 对日志进行粗筛,剔除「网络超时」「依赖下载失败」等环境噪音,只把「逻辑断言失败」提上议程。
┌─────────────────────────────────────────────────┐
│ 日志分析的挑战 │
├─────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────┐ │
│ │ 噪音(应过滤) │ │
│ │ · 网络超时 │ │
│ │ · 依赖下载失败 │ │
│ │ · 临时资源不足 │ │
│ │ · 偶发性竞态条件 │ │
│ └───────────────────┬───────────────────────┘ │
│ ↓ │
│ [LLM 日志分析过滤器] │
│ ↓ │
│ ┌───────────────────────────────────────────┐ │
│ │ 信号(需处理) │ │
│ │ · 断言失败(AssertionError) │ │
│ │ · 逻辑错误(LogicError) │ │
│ │ · 用例未覆盖(Missing Test Case) │ │
│ │ · 性能回归(Performance Regression) │ │
│ └───────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────┘产出物
一个结构化的 Task Draft(任务草稿):
{
"task_id": "task-2026-06-18-001",
"type": "bug_fix",
"source": "ci_failure",
"priority": "high",
"description": "User authentication fails when password contains special characters",
"stack_trace": "AssertionError: Expected 200, got 401 at line 42",
"files_affected": ["src/auth/login.py"],
"ci_build": "https://jenkins.example.com/job/ai-app/123/",
"created_at": "2026-06-18T14:30:00Z"
}动作 2:交付(Handoff)—— 隔离环境
核心目标
资源隔离。确保 AI 接下来的「试错」不会污染主分支,多个并发任务互不干扰。
技术实现手段
1. Git Worktree(推荐)
# 为每个任务创建独立的工作树
git worktree add ../task-001 origin/main
git worktree add ../task-002 origin/main
git worktree add ../task-003 origin/main
# 在独立工作树中工作
cd ../task-001
git checkout -b fix-auth-bug
# AI 在这里修改代码,不影响主分支
# 其他任务在其他工作树中并行进行优势:
- 相对于克隆整个仓库,Worktree 秒级创建
- 共享 .git 目录,节省磁盘空间
- 方便并行处理多个 PR
2. 容器化(Docker)
# docker-compose.yml
services:
task-001:
image: ai-agent-env:latest
volumes:
- ./task-001:/workspace
environment:
- TASK_ID=task-001
- TASK_FILE=/workspace/task-draft.json
task-002:
image: ai-agent-env:latest
volumes:
- ./task-002:/workspace
environment:
- TASK_ID=task-002
- TASK_FILE=/workspace/task-draft.json优势:
- 完全隔离的运行环境
- 避免依赖冲突
- 可以限制资源使用(CPU、内存)
3. 虚拟环境
# 为每个 Agent 分配独立的虚拟环境
python -m venv .venv-task-001
source .venv-task-001/bin/activate
pip install -r requirements-task-001.txt
# AI 在这里安装任务特定的依赖
# 不影响其他任务的依赖环境关键难点:上下文传递
必须把「发现」阶段产出的 Task Draft 注入到新 Worktree 的 Agent 系统提示词中。
┌─────────────────────────────────────────────────┐
│ 上下文传递流程 │
├─────────────────────────────────────────────────┤
│ │
│ [发现阶段] │
│ ↓ │
│ 生成 Task Draft(JSON) │
│ ↓ │
│ 写入 task-draft.json │
│ ↓ │
│ 创建新 Worktree │
│ ↓ │
│ [交付阶段] │
│ ↓ │
│ 读取 task-draft.json │
│ ↓ │
│ 注入到 Agent 系统提示词 │
│ ↓ │
│ Agent:「我知道这圈我是来修什么的」 │
│ │
└─────────────────────────────────────────────────┘系统提示词模板:
你是一个代码修复 Agent。
当前任务:
{{TASK_DESCRIPTION}}
失败堆栈:
{{STACK_TRACE}}
影响文件:
{{FILES_AFFECTED}}
CI 构建链接:
{{CI_BUILD_URL}}
请按照以下步骤修复:
1. 分析失败原因
2. 设计修复方案
3. 实施修复
4. 本地验证产出物
一个干净的、已切换好分支的独立工作目录:
../task-001/
├── .git/ # 共享 Git 仓库
├── src/ # 项目源代码
├── task-draft.json # 任务草稿
└── .venv/ # 独立虚拟环境动作 3:验证(Verify)—— 对抗性审查
核心目标
解决 AI 的「自欺欺人」问题。
写代码的 AI 容易陷入「我的代码没问题」的幻觉,必须引入「红队」(Red Team)视角。
技术实现手段
1. 双 Agent(Multi-Agent)
┌─────────────────────────────────────────────────┐
│ 双 Agent 验证流程 │
├─────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────┐ │
│ │ 主 Agent(Coder) │ │
│ │ · 读取任务草稿 │ │
│ │ · 编写修复代码 │ │
│ │ · 运行测试 │ │
│ └───────────────┬─────────────────────────────┘ │
│ ↓ │
│ 提交修复代码 │
│ ↓ │
│ ┌───────────────────────────────────────────┐ │
│ │ 子 Agent(Verifier) │ │
│ │ · 不读实现代码(blind review) │ │
│ │ · 只读测试用例和需求文档 │ │
│ │ · 检查实现是否覆盖所有 Edge Cases │ │
│ │ · 扮演「质疑者」角色 │ │
│ └───────────────┬─────────────────────────────┘ │
│ ↓ │
│ 生成审查报告 │
│ ↓ │
│ Pass / Fail + 改进建议 │
│ │
└─────────────────────────────────────────────────┘2. 静态规则检查
steps:
- name: Linter 检查
run: |
eslint src/ --fix
mypy src/
black src/
- name: 类型检查
run: |
tsc --noEmit
- name: 安全扫描
run: |
bandit -r src/
- name: LLM 审查
run: |
python llm_verify.py在 LLM 审查之前,先跑一遍静态检查,自动修复低级语法错误。
3. 「故意说不」机制
# 强制子 Agent 必须找出至少 1 个潜在问题
def verify_with_challenger(implementation, test_cases):
challenger_prompt = """
你是一个严格的代码审查员。
你的任务:找出这段代码中至少 1 个潜在问题。
如果找不出来,你必须给出非常详细的理由说明为什么这段代码是完美的。
检查维度:
1. 边界条件(Boundary Conditions)
2. 异常处理(Exception Handling)
3. 并发安全(Thread Safety)
4. 性能问题(Performance)
5. 安全漏洞(Security)
"""
issues = call_llm(challenger_prompt, implementation)
if len(issues) == 0:
# 如果找不到问题,要求详细说明
explanation = call_llm("解释为什么这段代码是完美的", implementation)
return {"status": "pass", "explanation": explanation}
else:
return {"status": "fail", "issues": issues}关键难点:误判
子 Agent 可能会过于吹毛求疵。
需要设定置信度阈值:
- 低于阈值 → 阻塞循环,必须修复
- 高于阈值 → 只添加注释,交由人工决策
if issue.severity == "critical":
block_loop()
elif issue.severity == "minor":
add_comment_to_pr()
continue_loop()产出物
审查报告:
{
"status": "pass",
"confidence": 0.85,
"issues_found": [],
"explanation": "代码覆盖了所有测试用例,异常处理完整,无明显性能问题",
"suggestions": [
"建议将魔法数字 42 提取为常量",
"可以考虑添加更多边界条件测试"
]
}或
{
"status": "fail",
"confidence": 0.92,
"issues_found": [
{
"type": "boundary_condition",
"description": "未处理空字符串输入",
"severity": "critical",
"location": "src/auth/login.py:42"
}
],
"must_fix": true
}动作 4:持久化(Persist)—— 跨对话记忆
核心目标
摆脱 LLM 有限的上下文窗口。
把结果写在「对话之外」的地方,让状态变成文件,即便当前 Chat Session 结束,状态依然留存。
技术实现手段
1. Pull Request / Merge Request
# 如果验证通过,自动提交 Commit 并创建 PR
def create_pr(task_id, fixes):
# 提交修复
git_commit(f"Fix {task_id}: {fixes.description}")
# 推送到远程
git_push()
# 创建 PR
pr = github.create_pr(
title=f"[AI Fix] {task_id}",
body=f"""
## 自动修复
- **任务 ID**: {task_id}
- **失败原因**: {fixes.original_error}
- **修复方案**: {fixes.solution}
- **测试结果**: ✅ 全部通过
## 变更文件
{fixes.files_changed}
## 审查状态
- Lint: ✅
- 类型检查: ✅
- 安全扫描: ✅
- LLM 审查: ✅
""",
base="main",
head=f"fix-{task_id}"
)
return pr2. 状态机文件(State Machine)
// .loop/state.json
{
"loop_id": "loop-2026-06-18",
"started_at": "2026-06-18T14:00:00Z",
"last_activity": "2026-06-18T14:35:00Z",
"current_task": {
"task_id": "task-001",
"status": "verifying",
"attempts": 2,
"last_error": "AssertionError: Expected 200, got 401"
},
"completed_tasks": [
{
"task_id": "task-000",
"status": "merged",
"pr_url": "https://github.com/org/repo/pull/42",
"completed_at": "2026-06-18T14:20:00Z"
}
],
"statistics": {
"total_tasks": 15,
"completed": 12,
"failed": 2,
"pending": 1
}
}3. 通知收件箱(Inbox)
# 更新团队的 Linear / Jira / Notion 数据库
def update_inbox(task_id, status):
linear.create_issue(
title=f"AI 已完成修复:{task_id}",
description="""
AI Agent 已自动完成修复,等待人工 Review。
**PR 链接**: https://github.com/org/repo/pull/43
**测试结果**: ✅ 全部通过
**置信度**: 85%
""",
status="In Review",
assignee="human_reviewer"
)
# 或发送 Slack 通知
slack.send_message(
channel="#code-review",
text=f"✅ AI 已完成修复 {task_id},等待 Review: {pr_url}"
)关键难点:冲突处理
当多个 Loop 同时产生 PR 时,极易发生文件冲突。
解决方案:
1. 锁机制
# 获取全局锁
with acquire_lock(".loop/global.lock"):
# 检查是否有其他任务在修改同一文件
conflicts = check_conflicts(my_changes)
if conflicts:
# 等待其他任务完成
wait_for_tasks(conflicts)
rebase_my_changes()
# 提交 PR
create_pr()2. 排队队列
# 任务排队,避免并发冲突
task_queue = TaskQueue()
def submit_task(task):
# 检查是否有冲突任务在运行
conflicting = task_queue.get_conflicting_tasks(task)
if conflicting:
# 加入队列,等待冲突任务完成
task_queue.enqueue(task, wait_for=conflicting)
else:
# 立即执行
task_queue.execute(task)产出物
1. 物理存在的代码变更
- Pull Request / Merge Request
- Git Commit
2. 可追溯的工单
- GitHub Issue
- Linear / Jira Ticket
- Notion Database Entry
3. 更新后的状态日志
.loop/state.json- 数据库记录
动作 5:调度(Schedule)—— 循环心脏
核心目标
解决「如何让它一圈圈自动转」的问题,即控制论中的反馈回路。
技术实现手段
1. 定时触发(Cron)
# 每天早上 6 点开始跑
schedule:
- cron: "0 6 * * *"
steps:
- name: 发现
run: python discover_tasks.py
- name: 交付
run: python handoff_tasks.py
- name: 验证
run: python verify_fixes.py
- name: 持久化
run: python persist_results.py
- name: 等待明天早上 6 点
run: sleep 864002. 事件驱动
# 当 PR 被创建后,自动触发验证
triggers:
- event: pull_request
action: created
steps:
- name: 读取 PR 信息
run: python get_pr_info.py
- name: 触发 CI
run: python trigger_ci.py
- name: 等待 CI 结果
run: python wait_for_ci.py
- name: 如果失败 → 创建修复任务
run: python create_fix_task.py
- name: 进入下一轮循环
run: python next_loop.py3. 退避策略(Backoff)
# 如果验证失败,不立即重试,而是等待指数级增长的时间
def schedule_retry(attempt_number):
wait_times = [60, 300, 1800] # 1min, 5min, 30min
if attempt_number < len(wait_times):
wait_time = wait_times[attempt_number]
else:
# 超过最大重试次数,转入人工待办
escalate_to_human()
return
print(f"等待 {wait_time} 秒后重试...")
time.sleep(wait_time)
# 下一轮循环
next_loop()避免死循环烧掉大量 Token。
4. Halt 条件
# 设定最大重试次数,防止 AI 在无解问题上无限空转
MAX_ATTEMPTS = 3
def run_loop(task):
attempts = 0
while attempts < MAX_ATTEMPTS:
attempts += 1
# 发现 → 交付 → 验证 → 持久化
result = execute_loop(task)
if result.status == "success":
print("✅ 任务完成")
return
if result.status == "failure":
print(f"❌ 第 {attempts} 次失败")
schedule_retry(attempts)
# 超过最大次数
print("⚠️ 超过最大重试次数,转入人工待办")
escalate_to_human(task)关键难点:终止判断
最难的调度是判断「什么时候算彻底完成」。
通常以「PR 被成功合并入主分支」作为本轮循环的终结信号:
def is_loop_complete(task):
pr = get_pr(task.pr_number)
if pr.merged:
return True
if pr.closed:
# PR 被关闭(未合并),任务失败
return False
# PR 还在 Review 中,继续等待
return None
def main_loop():
while True:
# 发现
tasks = discover_tasks()
for task in tasks:
# 交付 → 验证 → 持久化
execute_loop(task)
# 等待 PR 合并
while not is_loop_complete(task):
time.sleep(60)产出物
1. 持续运行的循环
- Cron Job
- Event Handler
- Orchestrator(如 Temporal、Inngest)
2. 状态监控
- 循环运行日志
- 任务执行统计
- 告警通知
五个动作的完整闭环
┌─────────────────────────────────────────────────────────┐
│ Triage Loop 完整闭环 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────┐ │
│ │ 5. 调度(Schedule) │ │
│ │ · 定时触发(Cron / Event) │ │
│ │ · 退避策略(避免死循环) │ │
│ │ · Halt 条件(最大重试次数) │ │
│ └───────────────┬───────────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────┐ │
│ │ 1. 发现(Discover) │ │
│ │ · 读取 CI 失败信息 │ │
│ │ · 追踪 Issue / Commit │ │
│ │ · LLM 日志过滤(信噪比) │ │
│ │ → 产出:Task Draft │ │
│ └───────────────┬───────────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────┐ │
│ │ 2. 交付(Handoff) │ │
│ │ · 创建 Git Worktree │ │
│ │ · 注入 Task Draft 到 Agent │ │
│ │ · 环境隔离(Docker / venv) │ │
│ │ → 产出:独立工作目录 │ │
│ └───────────────┬───────────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────┐ │
│ │ 3. 验证(Verify) │ │
│ │ · 双 Agent(Coder + Verifier) │ │
│ │ · 静态检查(Lint / Type / Security) │ │
│ │ · 「故意说不」机制 │ │
│ │ → 产出:审查报告(Pass / Fail) │ │
│ └───────────────┬───────────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────┐ │
│ │ 4. 持久化(Persist) │ │
│ │ · 创建 PR / MR │ │
│ │ · 更新状态机(state.json) │ │
│ │ · 通知收件箱(Linear / Jira / Slack) │ │
│ │ → 产出:代码变更 + 可追溯记录 │ │
│ └───────────────┬───────────────────────────────┘ │
│ ↓ │
│ 等待 PR 合并 / CI 通过 │
│ ↓ │
│ 回到调度层,触发下一轮循环 │
│ │
└─────────────────────────────────────────────────────────┘与之前内容的关联
在你之前的图片中提到的「超级 Loop(E2E Loop)」以及 Loop Engineering 分层,正是这些动作的具体应用场景。
| 动作 | 对应 E2E Loop 的环节 | 对应 Loop Engineering 分层 |
|---|---|---|
| 发现 | 读取 Plan 或失败测试 | Context Engineering(检索注入) |
| 交付 | 创建 Plan 文件或分支 | Harness Engineering(工具配置) |
| 验证 | 运行测试或审查 | Harness Engineering(终止条件) |
| 持久化 | 提交代码或更新文档 | Loop Engineering(状态管理) |
| 调度 | 自动触发新一轮循环 | Loop Engineering(循环设计) |
关键洞察
这五个动作,本质上是给 AI 搭建了一个自动化的「戴明环(PDCA)」:
Plan(计划) ← 发现(识别问题)
Do(执行) ← 交付(隔离环境)+ 验证(对抗审查)
Check(检查) ← 验证(Pass / Fail)
Act(行动) ← 持久化(创建 PR)+ 调度(下一轮循环)每个动作的设计意图:
- 发现 — 从「被动响应」到「主动感知」
- 交付 — 从「混合工作」到「隔离环境」
- 验证 — 从「自欺欺人」到「对抗审查」
- 持久化 — 从「对话记忆」到「文件记忆」
- 调度 — 从「手动触发」到「自动循环」
收尾金句:
- 发现:自己找出这圈该做的事
- 交付:把任务隔离着交给 agent
- 验证:换个 agent 说「不」
- 持久化:把状态写到对话之外
- 调度:让它一圈圈自动转
五个动作,一个循环。
从「回答问题」到「自己转起来」,这就是 AI 自动化循环的工程本质。
Triage Loop 的五个动作
让 AI 真正「自己转起来」
