feat: 三项框架优化 — 精准retry + ReAct首次启用 + 多文件batch

1. 精准Retry: 高通过率(差1-2个测试)时保留完整诊断不截断,
   加聚焦指令"只修这个问题不要改其他代码"(原300字符截断→800)
2. ReAct首次启用: 多文件/rename/refactor任务首次attempt就用
   ReAct循环探索,不再等retry才触发(_is_complex_task门控)
3. 多文件batch: ReactLoop增加rename专用策略指引(grep找引用→
   逐文件修改→验证), 扩展rename任务文件数限制3→8

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Val-sss
2026-05-14 08:09:05 +08:00
parent 5a6803fc30
commit 2162a9585e
3 changed files with 72 additions and 11 deletions

View File

@@ -247,12 +247,33 @@ class ReactLoop:
f"## 项目根目录: {ctx.project_root}",
f"## 目标文件: {', '.join(target_files)}",
]
# rename/refactor任务追加规则
user_lower = ctx.user_input.lower()
if any(kw in user_lower for kw in ["rename", "重命名", "refactor", "重构"]):
parts.append("")
parts.append("## 重命名/重构规则")
parts.append("- 必须用grep找到所有引用点不能只改目标文件")
parts.append("- 修改顺序:先改定义,再改所有调用点")
parts.append("- 全部改完再run_test")
return "\n".join(parts)
def _build_initial_message(self, ctx, target_files: list[str]) -> str:
"""构建初始消息,包含任务描述和当前失败信息。"""
parts = [f"## 任务\n{ctx.user_input}"]
# 检测rename/refactor任务注入多文件策略
user_lower = ctx.user_input.lower()
rename_kw = ["rename", "重命名", "refactor", "重构", "split", "拆分"]
if any(kw in user_lower for kw in rename_kw):
parts.append(
"\n## 多文件重命名策略\n"
"1. 先用 grep 搜索旧名称,找到所有包含它的文件\n"
"2. 逐个 read_file 读取每个相关文件\n"
"3. 逐个 write_file 修改每个文件中的所有引用\n"
"4. 最后 run_test 验证\n"
"不要遗漏任何文件中的引用!"
)
# 当前测试失败信息
if ctx.verifier_output:
error_detail = ctx.verifier_output.get("error_detail", "")

View File

@@ -1279,6 +1279,16 @@ class PipelineOrchestrator:
ctx._last_ver_passed = current_passed
# 高通过率聚焦: 差1-2个测试时prepend精准指令
v = ctx.verifier_output or {}
tp = v.get("tests_passed", 0)
tt = v.get("tests_total", 0)
if tt > 0 and tp >= tt - 2 and tp > 0:
hint = (
f"你已通过 {tp}/{tt} 个测试,只有 {tt - tp} 个失败。\n"
f"只修复下面指出的问题,不要改动其他代码。\n\n"
) + hint
return hint
def _should_search(self, error_type: str, retry_count: int) -> bool:

View File

@@ -228,16 +228,17 @@ class GeneratorExpert:
# 需要整文件scope的任务重构提取函数/拆分类或综合任务bug+refactor
# 判断条件:任务需要新增类/函数,或测试要求代码行数缩短/拆分
if self._needs_whole_file_scope(ctx, files, funcs):
# Retry时优先尝试ReAct循环多轮交互fallback到targeted_fix
if ctx.retry_count >= 1:
# 复杂任务(多文件/rename)首次就用ReAct; 简单任务retry时才用
use_react_first = self._is_complex_task(ctx, files, funcs)
if use_react_first or ctx.retry_count >= 1:
react_result = self._try_react_loop(ctx, files)
if react_result:
return react_result
# ReAct失败如果有best_state用targeted_fix否则再试whole_file
# ReAct失败fallback
if ctx.best_tests_passed > 0:
return self._run_targeted_fix(ctx, files)
return self._run_whole_file_refactor(ctx, files)
# 首次attempt始终用whole_file_refactor更稳定,t04靠这个PASS
# 非复杂任务首次: whole_file_refactort04靠这个PASS
return self._run_whole_file_refactor(ctx, files)
# For each file+function pair, extract original and generate modified
@@ -462,13 +463,23 @@ class GeneratorExpert:
elif test_failure:
prompt += f"\n\n## 当前测试失败详情\n{test_failure[-2000:]}\n"
# Inject retry_hint: 只传一句话总结,不传完整历史
# Inject retry_hint: 高通过率时保留完整诊断,聚焦修复
if ctx.retry_hint:
# 截断 retry_hint避免注入过多历史
hint = ctx.retry_hint
if len(hint) > 300:
hint = hint[:300] + "..."
prompt += f"\n\n## 重试提示\n{hint}"
v = ctx.verifier_output or {}
tests_passed = v.get("tests_passed", 0)
tests_total = v.get("tests_total", 0)
if tests_total > 0 and tests_passed >= tests_total - 2 and tests_passed > 0:
# 差1-2个测试: 保留完整诊断,聚焦指令
prompt += (
f"\n\n## 精准修复(已通过 {tests_passed}/{tests_total}\n"
f"只有 {tests_total - tests_passed} 个测试失败,只修这个问题,不要改其他代码。\n\n"
f"{hint}\n"
)
elif len(hint) > 800:
prompt += f"\n\n## 重试提示\n{hint[:800]}..."
else:
prompt += f"\n\n## 重试提示\n{hint}"
system = self._build_system(ctx)
@@ -1206,6 +1217,22 @@ class GeneratorExpert:
return False
def _is_complex_task(self, ctx, files: list[str], funcs: list[str]) -> bool:
"""检测需要首次就用ReAct的复杂任务多文件/rename/refactor跨文件"""
user_input = ctx.user_input.lower()
non_test_files = [f for f in files if "test" not in f.lower()]
# 多个非测试目标文件
if len(non_test_files) >= 2:
return True
# rename/refactor关键词 + 有目标文件
rename_kw = ["rename", "重命名", "split", "拆分", "move", "迁移"]
if any(kw in user_input for kw in rename_kw) and len(non_test_files) >= 1:
return True
return False
def _run_whole_file_refactor(self, ctx: TaskContext, files: list[str]) -> Optional[dict]:
"""整文件scope重构LLM看到完整文件+测试失败,输出完整修改后的文件。
与_run_whole_file不同prompt针对重构/bug修复而非存根实现。"""
@@ -2606,8 +2633,11 @@ class GeneratorExpert:
# 所有tier都允许ReAct小模型步数少一些
# 注意retry_count检查已移到调用方generator.run()中 ctx.retry_count>=1 才进入此分支)
# 过滤测试文件
target_files = [f for f in files[:3] if "test" not in f.lower()]
# 过滤测试文件rename任务扩展文件数
user_lower = ctx.user_input.lower()
is_rename = any(kw in user_lower for kw in ["rename", "重命名", "refactor", "重构"])
file_limit = 8 if is_rename else 3
target_files = [f for f in files[:file_limit] if "test" not in f.lower()]
if not target_files:
return None