log-center/repair_agent/REPAIR_FLOW_ANALYSIS.md
zyc 5611839fd8
Some checks failed
Build and Deploy Log Center / build-and-deploy (push) Failing after 1m55s
fix git pr
2026-02-25 10:55:26 +08:00

400 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Bug 自动修复流程分析与优化建议
> 分析日期: 2026-02-25
> 当前版本存在的问题和改进方案
---
## 1. 当前流程概览
### 主流程 (fix_project)
```
1. 初始化
├─ 获取项目信息(本地路径、仓库地址)
├─ 获取待修复 Bug 列表NEW/PENDING_FIX
├─ 初始化 Gitpull + 创建 fix 分支)
└─ 更新所有 Bug 状态 → FIXING
2. 多轮修复循环max 3 轮)
└─ 每轮:
├─ 调用 Claude CLI 修复代码
├─ 获取 diff 和修改文件列表
├─ 安全检查(文件数/行数/核心文件)
├─ 运行 Claude 生成的测试文件
├─ 上传修复报告
└─ 标记为 FIXED无论测试是否通过
3. 自动提交(可选)
├─ commit → push fix 分支
└─ **直接合并到 main 并推送**
```
### 重试失败流程 (retry_failed_project)
```
1. 获取所有 FIX_FAILED Bug
2. 逐个分诊triage
├─ VERDICT:CANNOT_REPRODUCE → 标记为 CANNOT_REPRODUCE
└─ VERDICT:FIX → 重置为 PENDING_FIX
3. 批量调用 fix_project 修复
```
---
## 2. 主要缺陷分析
### 🔴 **严重问题 1测试验证与重试逻辑脱节**
**问题描述:**
- 代码中有 `max_rounds=3` 的多轮重试机制
- 但在 [core.py:241-254](log_center/repair_agent/agent/core.py#L241-L254),无论测试通过与否都标记为 `FIXED``break`
- **测试失败不会触发下一轮重试**
**问题代码:**
```python
# core.py Line 230-254
test_passed = bool(test_output) and "FAILED" not in test_output
# 无论 test_passed 是 True 还是 False都标记为 FIXED
for bug in bugs:
self.task_manager.update_status(bug.id, BugStatus.FIXED)
# ...
results.append(FixResult(bug_id=bug.id, success=True, ...)) # ❌
# 然后直接 break不会进入第 2、3 轮
break # Line 271
```
**影响:**
- 多轮重试机制形同虚设
- 测试失败的 Bug 被错误标记为已修复
- 浪费了 Claude 重试优化的能力
**建议修复:**
```python
# 第 1 步:运行测试
test_output = run_repair_test_file(project_path, test_file)
test_passed = self._check_test_passed(test_output)
cleanup_repair_test_file(project_path, test_file)
# 第 2 步:根据测试结果决定下一步
if test_passed:
# 测试通过,标记为 FIXED
for bug in bugs:
self.task_manager.update_status(bug.id, BugStatus.FIXED)
self._upload_round_report(...)
break # 成功,退出循环
else:
# 测试失败,记录上下文供下一轮使用
last_diff = diff
last_test_output = test_output
logger.warning(f"第 {round_num} 轮测试失败,尝试下一轮")
if round_num == max_rounds:
# 最后一轮仍失败,标记为 FIX_FAILED
for bug in bugs:
self.task_manager.update_status(bug.id, BugStatus.FIX_FAILED)
self._upload_round_report(..., status=BugStatus.FIX_FAILED)
# 继续下一轮
```
---
### 🟡 **严重问题 2Git 分支管理混乱**
**问题描述:**
1. [git_manager.py:55-75](log_center/repair_agent/agent/git_manager.py#L55-L75) `pull()` 会切回 main/master
2. [core.py:152-154](log_center/repair_agent/agent/core.py#L152-L154) 然后又从 main 创建新分支
3. [core.py:264](log_center/repair_agent/agent/core.py#L264) `auto_commit` 时**直接合并到 main 并推送**
**问题:**
- 没有 PR 审核流程,变更直接进入主分支
- 每次修复都创建新分支,但合并后删除,无法回溯
- 不符合现代 Git 工作流(应该创建 PR 供人工审核)
**建议修复方案:**
**方案 A保留 fix 分支,推送后创建 PR**
```python
# core.py Line 256-267
if git_enabled and auto_commit and modified_files and git_manager:
bug_ids = ", ".join([f"#{b.id}" for b in bugs])
git_manager.commit(f"fix: auto repair bugs {bug_ids}")
git_manager.push()
logger.info("fix 分支已推送,请手动审核并合并")
# 可选:调用 gh CLI 创建 PR
# subprocess.run(["gh", "pr", "create", "--title", f"Auto fix {bug_ids}", ...])
```
**方案 B如果确实需要直接合并慎用**
```python
# 添加配置项控制
if settings.auto_merge_to_main: # 默认 False
if git_manager.merge_to_main_and_push():
logger.info("已合并到 main 并推送")
else:
logger.info("fix 分支已推送,需人工审核")
```
---
### 🟠 **问题 3安全检查位置不当**
**问题代码:** [core.py:209-225](log_center/repair_agent/agent/core.py#L209-L225)
```python
# Step 3: 安全检查(在修改后)
if git_manager and not self._safety_check(modified_files, diff):
failure_reason = "安全检查未通过"
git_manager.reset_hard() # ❌ 丢失所有修改
# 标记为 FIX_FAILED但不会重试
for bug in bugs:
self.task_manager.update_status(bug.id, BugStatus.FIX_FAILED)
break
```
**问题:**
- Claude 已经修改了代码,安全检查失败后 `reset_hard` 丢失所有修改
- 状态已经更新为 `FIXING`,造成不一致
- 不会重试,浪费了 Claude 的工作
**建议:**
**方案 A软性警告 + 继续测试**
```python
# 安全检查改为警告,记录但不阻断
if git_manager:
safety_passed, warnings = self._safety_check(modified_files, diff)
if not safety_passed:
logger.warning(f"安全检查警告: {warnings}")
# 将警告加入报告,但继续执行测试
# 让测试结果决定是否成功
```
**方案 B预检查机制**
```python
# 在调用 Claude 前,先用只读工具做预分析
success, analysis = self.claude_service.analyze_bug(bug, project_path)
if "core file" in analysis.lower():
logger.warning("分析发现可能涉及核心文件,跳过自动修复")
# 标记为需要人工介入
```
---
### 🟡 **问题 4测试通过判断过于简单**
**问题代码:** [core.py:231](log_center/repair_agent/agent/core.py#L231)
```python
test_passed = bool(test_output) and "FAILED" not in test_output and "Error" not in test_output.split("\n")[-5:].__repr__()
```
**问题:**
- 只检查 `"FAILED"` 字符串,不严谨
- 没有测试文件也会被判定为通过(`test_output` 为空时返回 `False`
- 但代码逻辑:没有测试文件 → `test_output = "Claude 未生成测试文件"``bool(test_output) = True` → 可能误判
**建议:**
```python
def _check_test_passed(self, test_output: str) -> bool:
"""检查测试是否通过"""
if not test_output or "Claude 未生成测试文件" in test_output:
logger.warning("没有测试输出,无法验证修复")
return False # 没有测试视为未通过
# 检查常见失败标记
fail_markers = ["FAILED", "ERROR", "AssertionError", "Exception"]
for marker in fail_markers:
if marker in test_output:
return False
# 检查是否有通过标记(更严格)
if "OK" in test_output or "passed" in test_output.lower():
return True
# 无明确通过标记,保守判断
return False
```
---
### 🟠 **问题 5代码重复**
**问题:**
- [core.py:95-290](log_center/repair_agent/agent/core.py#L95-L290) `fix_project`
- [core.py:467-562](log_center/repair_agent/agent/core.py#L467-L562) `fix_single_bug`
- 两个方法的核心逻辑完全一样,只是处理单个 vs 批量
**建议:**
```python
def fix_project(self, project_id: str, ...) -> BatchFixResult:
bugs = self.task_manager.fetch_pending_bugs(project_id)
return self._fix_bugs_batch(bugs, project_id, ...)
def fix_single_bug(self, bug_id: int, ...) -> FixResult:
bug = self.task_manager.get_bug_detail(bug_id)
result = self._fix_bugs_batch([bug], bug.project_id, ...)
return result.results[0] if result.results else FixResult(...)
def _fix_bugs_batch(self, bugs: list[Bug], project_id: str, ...) -> BatchFixResult:
"""通用的批量修复逻辑"""
# 原 fix_project 的核心逻辑
```
---
### 🟢 **问题 6retry_failed_project 分诊逻辑可优化**
**当前流程:** [core.py:292-398](log_center/repair_agent/agent/core.py#L292-L398)
```
FIX_FAILED Bug → 分诊 → CANNOT_REPRODUCE / 重置为 PENDING_FIX → fix_project
```
**问题:**
- 分诊失败会保留 `FIX_FAILED` 状态,下次仍会重复分诊
- 没有分诊次数限制,可能死循环
**建议:**
```python
# 在 Bug 模型中增加 triage_count 字段
if bug.retry_count >= settings.max_triage_count:
logger.info(f"Bug #{bug.id} 已分诊 {bug.retry_count} 次,标记为 CANNOT_REPRODUCE")
self.task_manager.update_status(bug.id, BugStatus.CANNOT_REPRODUCE)
continue
# 分诊
success, output = self.claude_service.triage_bug(bug, project_path)
if not success:
# 分诊执行失败,增加计数但保留状态
self.task_manager.increment_retry_count(bug.id)
continue
```
---
## 3. 优化后的理想流程
### 新流程设计
```
1. 初始化
├─ 获取项目信息和 Bug 列表
├─ Git pull + 创建 fix 分支
└─ 更新状态 → FIXING
2. 多轮修复循环(最多 3 轮)
└─ 每轮:
├─ 调用 Claude CLI 修复
├─ 获取 diff 和修改文件
├─ 【新增】软性安全检查(警告不阻断)
├─ 运行测试文件
├─ 【关键】严格判断测试是否通过
│ ├─ 通过 → 标记 FIXED + break
│ └─ 失败 → 记录上下文,继续下一轮
└─ 最后一轮仍失败 → 标记 FIX_FAILED
3. 提交代码
├─ commit + push fix 分支
├─ 【推荐】创建 PR 供人工审核
└─ 【慎用】auto_merge_to_main需配置开关
```
---
## 4. 实施建议
### 优先级排序
#### P0必须修复
1.**修复测试验证逻辑** - 测试失败应触发重试
2.**移除自动合并到 main** - 改为创建 PR
#### P1强烈建议
3.**优化测试通过判断** - 更严格的检测逻辑
4.**重构代码消除重复** - 提取 `_fix_bugs_batch`
#### P2建议优化
5.**改进安全检查** - 改为软性警告
6.**添加分诊次数限制** - 防止重复分诊
---
## 5. 配置建议
### 新增配置项
```python
# config/settings.py
# Git 工作流
auto_merge_to_main: bool = False # 默认不自动合并
create_pr_after_fix: bool = True # 自动创建 PR
# 测试验证
require_test_pass: bool = True # 必须测试通过才标记 FIXED
test_timeout: int = 300 # 测试超时时间(秒)
# 重试策略
max_retry_count: int = 3 # 最大重试轮数
max_triage_count: int = 2 # 最大分诊次数
# 安全检查
safety_check_mode: str = "warn" # warn / block
max_modified_files: int = 10
max_modified_lines: int = 500
```
---
## 6. 测试建议
### 需要覆盖的场景
1. **测试失败重试**
- Bug 修复后测试失败 → 第 2 轮修复 → 测试通过
- 3 轮都失败 → 标记为 FIX_FAILED
2. **Git 分支管理**
- 修复后创建 PR 而不是直接合并
- 多个 Bug 修复复用同一个 fix 分支
3. **安全检查**
- 修改超限文件 → 警告但继续
- 核心文件修改 → 警告并记录
4. **分诊流程**
- FIX_FAILED → 分诊 → CANNOT_REPRODUCE
- 分诊失败达到上限 → 标记为 CANNOT_REPRODUCE
---
## 7. 总结
### 关键改进点
| 问题 | 现状 | 改进后 |
|------|------|--------|
| 测试验证 | 无论通过与否都标记 FIXED | 测试失败触发重试,最终失败标记 FIX_FAILED |
| Git 工作流 | 直接合并到 main | 创建 PR 供人工审核 |
| 安全检查 | reset_hard 丢失修改 | 软性警告,继续测试 |
| 测试判断 | 简单字符串匹配 | 严格检测通过/失败标记 |
| 代码质量 | 逻辑重复 | 提取公共方法 |
| 分诊流程 | 可能重复分诊 | 添加次数限制 |
### 预期收益
- ✅ 多轮重试机制真正发挥作用,提高修复成功率
- ✅ Git 工作流更安全,避免直接污染主分支
- ✅ 测试验证更严格,减少假阳性
- ✅ 代码更简洁,维护成本降低
---
**建议:优先实施 P0 和 P1 的改进P2 可以逐步优化。**