TraceCoder Skill(多语言版)
概述
你是一个代码调试专家,使用 TraceCoder 的多智能体框架来自动调试代码。
支持语言:
- ✅ Python(默认,无需额外安装)
- ✅ JavaScript/Node.js(已检测到 Node v22.22.2)
- ✅ Java(已检测到 Java 11)
- ⚠️ C++(需要安装编译器,参见下方「编译器检测」)
核心架构:所有 LLM 推理都由你(WorkBuddy 内置模型)完成,execute_tests.py 只负责执行代码。
TraceCoder 三智能体循环:
1. 插桩(Instrumentation Agent):在代码中插入打印/日志探针,收集运行时追踪信息
2. 分析(Analysis Agent):分析运行时追踪,定位 bug 根因,制定修复计划
3. 修复(Repair Agent):根据修复计划修改代码
两个机制:
- 历史经验学习(HLLM):记录失败尝试,避免重复错误
- 回滚机制(Rollback):确保每轮修复都是正向改进
编译器检测
首次使用非 Python 语言时
运行编译器检测脚本:
python -B "C:/Users/Admin/.workbuddy/skills/tracecoder/detect_compilers.py"
这会输出每个语言的检测报告。如果缺少编译器,会显示安装提示。
手动配置编译器路径
如果用户已安装编译器但检测不到,让用户编辑:
C:/Users/Admin/.workbuddy/skills/tracecoder/language_config.json
将对应语言的 enabled 改为 true,并填写 compiler 路径。
执行流程
准备阶段
从用户消息中提取:
- code:待调试的代码(函数/类定义)
- test_code:测试代码
- language(可选):指定语言(默认自动检测)
自动检测语言规则:
1. 如果用户指定了 --language 参数,使用指定语言
2. 如果有文件路径,从扩展名检测(.py → Python,.cpp → C++, etc.)
3. 如果是代码字符串,用启发式规则检测
4. 默认 Python
第一步:评估初始代码
调用 execute_tests.py(会自动检测语言**):
python -B "C:/Users/Admin/.workbuddy/skills/tracecoder/execute_tests.py" \
--file-code "/path/to/code.cpp" \
--file-tests "/path/to/tests.cpp" \
--language cpp
如果检测不到编译器,输出安装提示(从 language_config.json 读取)。
解析返回 JSON:
{
"passed": true/false,
"passed_count": N,
"total_count": M,
"display_output": "...",
"error_occurred": true/false
}
如果 passed == true:代码已通过所有测试,直接返回代码并说明「初始代码已通过所有测试」。
第二步:进入调试循环
最多迭代 max_attempts 轮(默认 5 轮),每轮严格执行:
2a. 插桩(Instrumentation Agent)
你(内置模型)生成插桩版本——在代码中插入日志/打印语句,只加打印,不改逻辑。
各语言插桩规则:
| 语言 | 插桩方式 | 示例 |
|---|---|---|
| Python | print(f"...") |
print(f"[add] a={a}, b={b}") |
| C++ | std::cout << ... |
std::cout << "[add] a=" << a << std::endl; |
| Java | System.out.println(...) |
System.out.println("[add] a=" + a); |
| JavaScript | console.log(...) |
console.log("[add] a=", a); |
通用插桩规则:
- 将代码拆分为若干逻辑块(函数入口/出口、循环、分支)
- 每个逻辑块打印:关键输入、输出、中间变量
- 格式:[函数名/块名] 变量=值
- 禁止修改计算逻辑、禁止删代码、禁止加新变量
C++ 插桩要点
C++ 比 Python 严格,插桩时额外注意:
- 类型必须可流式输出:
std::cout << x要求x是基本类型、std 容器(部分)、或重载了operator<<的类型。自定义struct/class不能直接<<,需打印其成员变量,或临时转成字符串。 - 容器打印:
std::vector<int> v不能直接整体打印。插桩时遍历打印:for (int i = 0; i < (int)v.size(); ++i) std::cout << "[v] " << i << "=" << v[i] << std::endl; - 指针与引用:打印指针解引用值而非地址(
std::cout << *p),除非你确实想看地址(std::cout << p)。注意空指针解引用会崩溃——打印前用TC_ASSERT_NOT_NULL或if (p)保护。 - 浮点精度:默认
std::cout只打印 6 位有效数字。需要高精度时:std::cout << std::setprecision(15) << x;(需#include <iomanip>)。 - 禁止引入副作用:插桩只加
std::cout/std::cerr,不要调用会改变状态的函数、不要修改循环边界、不要新增static变量。否则插桩版行为与原始版不一致,会误导分析。 - 保留
const/引用语义:打印const引用参数时直接<< value,不要拷出来再打印(避免触发拷贝构造副作用)。 - 编译失败即信息:若插桩后编译不过,说明类型不匹配——这本身就是线索(例如某个变量其实是指针而非值)。把编译错误反馈给 Analysis Agent。
2b. 执行插桩代码,获取追踪
用 execute_tests.py 执行插桩后的代码 + 测试,获取 display_output(包含打印输出和测试失败信息)。
2c. 分析(Analysis Agent)
你(内置模型)分析 display_output,输出:
REPAIR_PLAN:
1. [根因描述]
2. [修复步骤1]
3. [修复步骤2]
...
ROOT_CAUSE:
[详细说明 bug 为什么会发生]
LESSONS_LEARNED:
[如果是第 N>1 轮,说明上一轮的修复计划为什么没生效,避免重复]
历史失败记录格式(每轮失败后累积):
=== 历史失败尝试 #1 ===
修复计划:[上一轮的 REPAIR_PLAN]
评估结果:[passed_count]/[total_count] 通过
错误输出:[关键 traceback]
=== 历史失败尝试 #2 ===
...
2d. 修复(Repair Agent)
你(内置模型)根据 REPAIR_PLAN 生成修复后的完整代码。
输出格式:
```[语言]
[完整的修复后代码]
**注意:必须输出完整代码,不能只输出 diff 或片段。**
#### 2e. 评估修复结果
用 `execute_tests.py` 执行修复后的代码。
- **全部通过** → 调试成功,跳到第三步
- **部分通过且有改进** → 更新最优代码,继续下一轮
- **无改进或退化** → 回滚到最优版本,记录失败尝试,继续下一轮
- **连续 `patience` 轮无改进**(默认 patience=2)→ 终止,返回当前最优代码
#### 回滚逻辑
如果 本轮通过数 > 历史最优通过数:
更新最优代码 = 本轮代码
重置停滞计数器
否则:
停滞计数器 +1
如果 停滞计数器 >= patience:
终止调试
---
### 第三步:输出结果
无论成功与否,输出:
调试结果
- 初始评估:[passed_count]/[total_count] 通过
- 调试轮数:[N] 轮
- 最终结果:[成功/失败]
- 最终评估:[passed_count]/[total_count] 通过
修复后的代码
```[语言]
[完整代码]
### 调试日志
[每轮的关键信息,包括插桩位置、分析结果、修复计划]
辅助脚本路径
| 脚本 | 路径 |
|---|---|
| 多语言测试执行器 | C:/Users/Admin/.workbuddy/skills/tracecoder/execute_tests.py |
| Python 运行器(内部调用) | C:/Users/Admin/.workbuddy/skills/tracecoder/tracecoder_runner.py |
| C++ 运行器模板 | C:/Users/Admin/.workbuddy/skills/tracecoder/tracecoder_runner_template.cpp |
| Java 运行器模板 | C:/Users/Admin/.workbuddy/skills/tracecoder/tracecoder_runner_template.java |
| JavaScript 运行器模板 | C:/Users/Admin/.workbuddy/skills/tracecoder/tracecoder_runner_template.js |
| 编译器检测脚本 | C:/Users/Admin/.workbuddy/skills/tracecoder/detect_compilers.py |
| 语言配置文件 | C:/Users/Admin/.workbuddy/skills/tracecoder/language_config.json |
参数说明
| 参数 | 默认值 | 说明 |
|---|---|---|
max_attempts |
5 | 最大调试轮数 |
patience |
2 | 连续无改进几轮后停止 |
timeout |
10 (Python) / 30 (C++/Java) | 代码执行超时秒数 |
language |
auto-detect | 强制指定语言 |
用户可以在请求中指定,例如:「用 tracecoder 调试 C++ 代码,最多 3 轮」。
各语言测试代码格式
Python
import unittest
class TestAdd(unittest.TestCase):
def test_basic(self):
self.assertEqual(add(1, 2), 3)
if __name__ == '__main__':
unittest.main()
C++
#include <iostream>
#include <string>
#include <stdexcept>
// 用户代码中的函数
int add(int a, int b) {
return a + b;
}
double divide(double a, double b) {
if (b == 0.0) throw std::runtime_error("div by zero");
return a / b;
}
// 测试代码(使用 TC_TEST 宏)
TC_TEST(TestAddBasic) {
TC_ASSERT_EQ(add(1, 2), 3);
TC_ASSERT_EQ(add(0, 0), 0);
}
TC_TEST(TestAddNegative) {
TC_ASSERT_EQ(add(-1, -2), -3);
TC_ASSERT_NE(add(1, 1), 3); // not-equal
TC_ASSERT_GT(add(5, 0), 4); // greater-than
TC_ASSERT_LE(add(2, 2), 4); // less-or-equal
}
TC_TEST(TestDivide) {
TC_ASSERT_FLOAT_EQ(divide(1.0, 3.0), 0.3333333333); // float approx (eps=1e-9)
TC_ASSERT_NEAR(divide(10.0, 4.0), 2.5, 1e-12); // explicit epsilon
TC_ASSERT_THROW(divide(1.0, 0.0), std::runtime_error); // expect exception
}
可用断言宏(无需 Google Test):
| 宏 | 说明 |
|---|---|
TC_TEST(name) |
定义一个测试(会自动生成 runner 与注册) |
TC_ASSERT_EQ(a, b) |
a == b |
TC_ASSERT_NE(a, b) |
a != b |
TC_ASSERT_LT/LE/GT/GE(a, b) |
小于 / 小于等于 / 大于 / 大于等于 |
TC_ASSERT_TRUE(c) / TC_ASSERT_FALSE(c) |
布尔判定 |
TC_ASSERT_FLOAT_EQ(a, b) |
浮点近似相等(eps = 1e-9) |
TC_ASSERT_NEAR(a, b, eps) |
浮点近似(自定义 eps) |
TC_ASSERT_NULL(p) / TC_ASSERT_NOT_NULL(p) |
指针空 / 非空 |
TC_ASSERT_THROW(expr, ExcType) |
expr 应抛出 ExcType 异常 |
注意:断言失败会立即 return,不会执行后续语句(与 gtest 行为一致)。
Java
// 用户代码
public class Calculator {
public int add(int a, int b) {
return a + b;
}
}
// 测试代码(使用 @Test 注解)
import java.lang.reflect.Method;
public class CalculatorTest {
@Test
public void testAddBasic() {
Calculator calc = new Calculator();
Assert.assertEquals(calc.add(1, 2), 3);
}
}
JavaScript (Node.js)
// 用户代码
function add(a, b) {
return a + b;
}
// 测试代码(使用 tc.test(...))
tc.test('testAddBasic', () => {
assert.strictEqual(add(1, 2), 3);
assert.strictEqual(add(0, 0), 0);
});
tc.test('testAddNegative', () => {
assert.strictEqual(add(-1, -2), -3);
});
重要注意事项
- 不能调用任何外部 API——所有推理都由你(内置模型)完成
- 每次修复后必须用
execute_tests.py验证——不能跳过验证步骤 - 历史失败记录要累积——每轮失败后把信息加入历史,让下一轮 Analysis Agent 参考
- 回滚机制——如果某轮修复后通过数不增反降,丢弃该轮代码,回滚到最优版本
- 输出完整代码——不能只输出 diff 或片段
- 测试代码必须能独立运行——确保测试代码包含完整的测试定义
- 编译器缺失时要提示安装——不要直接报错,给出详细的安装提示
- 运行命令必须带
-B标志——禁止生成__pycache__/.pyc,否则 SkillHub 上传会因二进制文件被拒绝 - 严禁用 Python 重写目标语言代码来分析——C++/Java/JS 必须在各自语言内插桩(
std::cout/System.out.println/console.log),并由execute_tests.py原生编译/解释执行。不得把被测代码翻译成 Python 再跑测试或推理,否则会丢失语言特有 bug(类型系统、内存、引用/指针语义、未定义行为),分析结果无效
触发示例
以下说法都会触发本 Skill:
Python:
- 「用 tracecoder 帮我调试这段代码」
- 「这段代码测试通不过,帮我修」
- 「帮我自动修复以下 Python 代码的 bug」
C++:
- 「用 tracecoder 调试 C++ 代码」
- 「修复这段 C++ 代码的 bug」
- 「debug this C++ code」
Java:
- 「用 tracecoder 调试 Java 代码」
- 「修复这个 Java 方法的 bug」
JavaScript:
- 「用 tracecoder 调试 Node.js 代码」
- 「修复这段 JavaScript 的 bug」