让代码智能体自己编写、测试并修复代码,难点通常不在于一次模型调用,而在于如何组织多轮行动。围绕 LangChain4j 文档进行的这项实验表明,智能体框架的架构选择会直接影响调试任务的执行速度、可控性和应对异常的能力。
实验聚焦于一个能够自主完成“写代码、跑测试、定位问题、修改代码、再次验证”的编码框架。其中值得关注的是两种常见组织方式:由中央决策者协调的 Supervisor,以及预先编排步骤的 Workflow。
Supervisor:把下一步交给协调者决定
Supervisor 模式中,多个专职能力通常被拆开:代码生成、测试执行、错误分析、修复建议等。一个主管智能体读取当前状态,决定下一步该调用哪个能力,并把结果写回共享上下文。
这种方式适合调试路径不确定的任务。例如测试失败后,系统可能需要:
- 先重新读取相关实现和测试;
- 检查编译错误还是断言失败;
- 查询依赖或框架文档;
- 生成补丁后选择局部测试或完整回归。
它的优势是灵活。错误信息出现新的线索时,Supervisor 可以改变路线,而不必强行走完固定步骤。代价也很明确:每一轮决策都可能增加模型调用、上下文整理和工具编排成本;如果缺少停止条件,还可能在“分析 - 修复 - 再分析”之间循环。
Workflow:让高频路径走固定流水线
Workflow 模式将步骤提前定义,例如:生成实现、执行测试、提取失败信息、修复、复测。每一步的输入输出更稳定,执行也更快,尤其适合有明确验收条件的重复工作。
对于常规编码任务,固定工作流可以减少主管决策的开销:测试通过就结束,测试失败才进入修复分支。它也更容易监控,因为每个节点都有清晰的职责和可观测结果。
不过,工作流的边界就是它的约束。当失败原因超出预设分支,例如环境异常、依赖版本冲突或需求本身含糊时,系统往往需要补充大量分支,最终又接近一个隐式的 Supervisor。
来源中的结论不是“某一种架构总是更好”,而是两者在调试中交换了不同能力:Supervisor 换取适应性,Workflow 换取执行速度和确定性。
可以这样实践:先把路由逻辑写成可测试代码
下面的示例不依赖具体模型 SDK,用纯 Java 模拟编码智能体的两种调度方式。它可以直接运行,用来验证你对状态、停止条件和重试次数的设计;接入 LangChain4j 时,将 runTest、repair 和 analyze 替换为工具调用或 AI Service 即可。
将文件保存为 WorkflowVsSupervisor.java,然后运行 javac WorkflowVsSupervisor.java && java WorkflowVsSupervisor。
import java.util.ArrayList;
import java.util.List;
public class WorkflowVsSupervisor {
record State(String code, boolean testsPass, int attempts, List<String> log) {
State next(String code, boolean testsPass, String event) {
List<String> nextLog = new ArrayList<>(log);
nextLog.add(event);
return new State(code, testsPass, attempts + 1, nextLog);
}
}
static State runTest(State state) {
boolean pass = state.code().contains("return a + b;");
return state.next(state.code(), pass, pass ? "tests: pass" : "tests: add() returns the wrong value");
}
static State repair(State state) {
String fixed = "int add(int a, int b) { return a + b; }";
return state.next(fixed, false, "repair: replaced implementation");
}
static State workflow(State initial) {
State tested = runTest(initial);
return tested.testsPass() ? tested : runTest(repair(tested));
}
static State supervisor(State initial) {
State current = initial;
while (!current.testsPass() && current.attempts() < 4) {
current = current.log().isEmpty() ? runTest(current) : repair(current);
if (!current.testsPass() && current.code().contains("return a + b;")) {
current = runTest(current);
}
}
return current;
}
public static void main(String[] args) {
State initial = new State("int add(int a, int b) { return a - b; }", false, 0, List.of());
System.out.println("workflow = " + workflow(initial).log());
System.out.println("supervisor = " + supervisor(initial).log());
}
}
示例刻意保留了两个工程约束。attempts < 4 是硬停止条件,避免自主调试无限循环;状态中的 log 则是最小审计记录。生产环境还应保存模型输入、工具输出、补丁 diff、测试命令和退出码,才能复盘智能体为何做出某个修复决定。
LangChain4j 接入时的职责划分
接入 LangChain4j 后,可以将模型限制在它擅长的判断与生成环节,而将副作用操作交给可控工具:
readFile和searchCode提供受限的代码上下文;runTests在隔离环境中执行,并返回结构化结果;applyPatch只接受统一 diff,且限制可修改目录;- Supervisor 只返回下一个动作及理由,不能直接绕过工具修改工作区;
- Workflow 对已知的“修改后必须测试”规则做强制编排。
这类边界比提示词本身更重要。若允许模型任意执行 shell 命令、读取全部密钥或跳过测试,智能体即使短期看起来高效,也会带来明显的安全与质量风险。
选择建议
可以从 Workflow 起步:它适合格式化、生成样板代码、执行既定测试和处理常见失败。等到任务经常遇到分支不明、需要跨文件调查或必须选择不同工具时,再在工作流外层加入 Supervisor。
实际系统常常采用混合方案:Workflow 负责确定性步骤,Supervisor 只处理异常路由和复杂诊断。上线前至少检查三件事:每个循环是否有预算,工具权限是否最小化,以及每次补丁是否经过可重复执行的验证。这会比单纯增加模型能力更直接地提升代码智能体的可靠性。