mcpField
R
rock-agent-debug

rock-agent-debug

github.com/xdlkcAgent 工作流438 次安装15 周前更新
代码仓库

关于 rock-agent-debug

Rock Agent Debug Skill 使用 rockcli 排查 ROCK 沙箱中的 Agent Job,并保存详细报告。它支持通过远程查询或检查运行中的沙箱分析 Harbor 和 Bash Job 的日志与结果。

主要功能

  1. 01识别 Harbor 与 Bash Job 类型
  2. 02远程查询任务和文件
  3. 03检查运行中沙箱内的文件
  4. 04分析 trial 结果、日志与错误
  5. 05在本地保存结构化报告

适用场景

  1. 01调查已完成或失败的 Harbor Job
  2. 02检查 Bash Job 的退出码和产物
  3. 03排查运行中沙箱内的任务

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/xdlkc/rock-marketplace --skill rock-agent-debug

安装后在 Claude Code 中输入/rock-agent-debug确认已加载。

详细介绍

来自项目 README

Rock Agent Debug Skill

通过 rockcli 查询和排查运行在 ROCK 沙箱中的 Agent Job(Harbor Job / Bash Job),最终产出一份落盘的详细报告。

背景

ROCK 沙箱支持两种 Job 类型:

类型Config 类Trial 类识别特征
Harbor JobHarborJobConfigHarborTrial有 orchestrator、datasets、agents、jobs_dir、experiment_id 字段
Bash JobBashJobConfigBashTrial有 script 或 script_path 字段,无 harbor 相关字段

Job 类型通过 YAML 配置自动检测:先尝试 HarborJobConfig 解析,失败则回退到 BashJobConfig。

两种排查路径

根据信息来源不同,排查分为两种路径:

路径适用场景核心命令
远程查询(推荐)用户提供实验 ID + Job ID(或仅 job 名);沙箱已停止无法 execrc agent view + rc agent fs
沙箱内查询用户提供沙箱 ID 且沙箱存活;需要更灵活的排查rc sandbox <id> exec

优先使用远程查询:agent view 和 agent fs 不依赖沙箱存活状态,能直接查看 job/trial 元数据和文件,效率更高。

远程查询快速流程
# 1. 查看 job 状态和 trial 列表
rockcli agent view -e <exp_id> -j <job_name>

# 2. 列出 trial 文件
rockcli agent fs ls -e <exp_id> -j <job_name> -t <task_name>

# 3. 读取关键文件
rockcli agent fs cat result.json -e <exp_id> -j <job_name> -t <task_name>
rockcli agent fs cat agent/log.txt -e <exp_id> -j <job_name> -t <task_name>

# 4. 查看执行轨迹
rockcli agent view -e <exp_id> -j <job_name> --trajectory

# 5. 查看 artifacts
rockcli agent fs artifacts -e <exp_id> -j <job_name> -t <task_name>

重要原则

拿到足够信息就停止查询。 不要陷入"文件不在预期位置就全盘搜索"的循环。判断标准:

  • Harbor Job(/data/logs/user-defined/):.out 文件包含完整运行日志,能看到 reward 就够了
  • Harbor Job(/tmp/harbor/jobs/):result.json + trial.log + exception.txt 就够了
  • Bash Job:.out 日志 + 脚本退出码 + artifact(如有)就够了
  • 如果关键文件能说明情况,不必继续找,直接用现有信息出报告

Step 1:确认排查入口和 Job 类型

根据用户提供的信息选择排查路径:

情况 A:用户提供实验 ID + Job ID(远程查询,推荐入口)

最常见的入口是 实验 ID + Job ID 组合。agent view 和 agent fs 都要求 -e <experiment_id> 定位 job,两个参数配合逐级钻取:

# 0. (可选)只有实验 ID、不知道 job 名时,先列出实验下的 jobs
rockcli agent view -e <experiment_id>

# 1. 查看 job 详情(实验 ID + Job ID)
rockcli agent view -e <experiment_id> -j <job_name>

# 2. 列出 job 文件(从文件结构判断类型)
rockcli agent fs ls -e <experiment_id> -j <job_name>

只有 job 名、没有实验 ID 时,先用 rockcli agent view -E 列出所有实验,找到对应的 experiment_id 再继续。

情况 B:用户提供沙箱 ID(沙箱内查询)
# 查看沙箱存活状态
rockcli sandbox <id> status

# 同时检查所有可能的路径
rockcli sandbox <id> exec 'echo "=== /tmp/harbor/jobs/ ==="; ls -lt /tmp/harbor/jobs/ 2>/dev/null | head -10; echo "=== /data/logs/user-defined/ ==="; ls -lt /data/logs/user-defined/ 2>/dev/null | head -10; echo "=== /data/logs/ ==="; ls -lt /data/logs/*.out /data/logs/*.log 2>/dev/null | head -10'

判断 Job 类型:

  1. 读取 YAML 配置(优先):rockcli sandbox <id> exec 'cat /data/logs/user-defined/<job_name>.yaml'
  2. 如果配置包含 orchestrator、datasets、agents → Harbor Job
  3. 如果配置包含 script 或 script_path → Bash Job
  4. 如果没有 YAML,只有 /tmp/harbor/jobs/ 下的文件 → Harbor Job(本地 harbor run)

如果用户没给沙箱 ID 也没给实验 ID,直接问。


Step 2:定位目标 Job

用户没有指定 job 时,取最新有内容的一个(空目录跳过)。

# Harbor 路径(本地 harbor run):找最新非空的 job
rockcli sandbox <id> exec 'for d in $(ls -t /tmp/harbor/jobs/); do if [ "$(ls /tmp/harbor/jobs/$d 2>/dev/null)" ]; then echo $d; break; fi; done'

# ROCK 平台路径:列出 .yaml 配置和 .out 日志
rockcli sandbox <id> exec 'ls -lt /data/logs/user-defined/*.yaml /data/logs/user-defined/*.out 2>/dev/null | head -10'

Step 3:读取 Job 信息

远程查询方式(agent view / agent fs)

适用于有 实验 ID + Job ID 的场景,不依赖沙箱存活状态:

# 查看 job 整体状态(含 tasks 列表、进度)
rockcli agent view -e <exp_id> -j <job_name>

# 列出 job 目录结构
rockcli agent fs ls -e <exp_id> -j <job_name>

# 读取 result.json
rockcli agent fs cat result.json -e <exp_id> -j <job_name> -t <task_name>

# 读取日志文件
rockcli agent fs cat agent/log.txt -e <exp_id> -j <job_name> -t <task_name>

# 查看完整执行轨迹
rockcli agent view -e <exp_id> -j <job_name> --trajectory

# 查看 trial artifacts
rockcli agent fs artifacts -e <exp_id> -j <job_name> -t <task_name>
沙箱内查询方式
Harbor Job
/tmp/harbor/jobs/ 路径(本地 harbor run)
rockcli sandbox <id> exec 'cat /tmp/harbor/jobs/<job_name>/config.json'
rockcli sandbox <id> exec 'cat /tmp/harbor/jobs/<job_name>/result.json 2>/dev/null || echo "no result yet"'
rockcli sandbox <id> exec 'cat /tmp/harbor/jobs/<job_name>/job.log 2>/dev/null'
/data/logs/user-defined/ 路径(ROCK 平台)
# 配置(agent、model、dataset)
rockcli sandbox <id> exec 'cat /data/logs/user-defined/<job_name>.yaml'

# 完整运行日志(含进度、reward、时间线)
rockcli sandbox <id> exec 'cat /data/logs/user-defined/<job_name>.out'

# result.json(可能不存在,不要为此继续搜索)
rockcli sandbox <id> exec 'cat /data/logs/user-defined/jobs/<job_name>/result.json 2>/dev/null || echo "no result.json"'

.out 文件足以判断任务是否完成(含 reward 行、完成时间、trial 名),不要因为 result.json 不存在就全盘搜索。

Bash Job
# 配置(script / script_path)
rockcli sandbox <id> exec 'cat /data/logs/user-defined/<job_name>.yaml'

# 完整运行日志
rockcli sandbox <id> exec 'cat /data/logs/user-defined/<job_name>.out'

# 检查是否有 artifact 输出
rockcli sandbox <id> exec 'ls -lt /data/logs/artifacts/ 2>/dev/null | head -10'

Bash Job 的特点:

  • 单次脚本执行,没有 trial 概念
  • 退出码 (exit code) 是判断成功/失败的关键
  • 可能有 OSS artifact 输出到 artifacts/{namespace}/{experiment_id}/{job_name}/
  • 日志直接输出到 .out 文件

Step 4:分析结果

Harbor Job:逐 Trial 分析

Trial 文件结构(/tmp/harbor/jobs/ 路径):

<trial_name>/
├── result.json          # 完整结果(阶段时间、reward、异常)
├── trial.log            # 简短摘要(失败时有错误原因)
├── exception.txt        # 完整异常栈
├── agent/setup/stdout.txt   # Agent 安装日志
├── agent/setup/return-code.txt
├── verifier/reward.txt
├── verifier/test-stdout.txt
├── verifier/test-stderr.txt
└── agent/trajectory.json    # Agent 执行轨迹(ATIF 格式,若有)
# 列出 trials
rockcli sandbox <id> exec 'ls /tmp/harbor/jobs/<job_name>/ 2>/dev/null || ls /data/logs/user-defined/jobs/<job_name>/ 2>/dev/null'

# 批量查看所有 trial 状态(快速)
rockcli sandbox <id> exec 'for t in /tmp/harbor/jobs/<job_name>/*/; do echo "=== $(basename $t) ==="; cat "$t/result.json" 2>/dev/null | python3 -c "import json,sys; d=json.load(sys.stdin); print(\"reward:\", d.get(\"verifier_result\"), \"exception:\", bool(d.get(\"exception_info\")))" 2>/dev/null || cat "$t/trial.log" 2>/dev/null | head -3; done'

result.json 关键字段说明:

字段含义异常信号
exception_info异常类型和消息非 null 说明有未捕获异常
verifier_result.rewards各项评分全 0 或 null 说明 verifier 未运行
agent_resultAgent 执行结果null 说明 agent 未正常完成
agent_execution.duration_secAgent 运行时长极短(<5s)说明提前退出
environment_setup环境启动耗时极长说明镜像构建或启动问题
started_at / finished_at开始/结束时间finished_at 为 null 说明未完成

判断 Trial 当前阶段(从 result.json):

  • environment_setup 有值,agent_setup 为 null → 环境启动中
  • agent_setup 有值,agent_execution 为 null → Agent 安装中
  • agent_execution 有值,verifier 为 null → Agent 执行中
  • verifier 有值,finished_at 为 null → Verifier 运行中
  • finished_at 有值 → 已完成
Bash Job:单次执行分析

Bash Job 没有 trial 概念,是一次性的脚本执行:

# 查看退出码(.out 末尾通常有 exit code)
rockcli sandbox <id> exec 'tail -20 /data/logs/user-defined/<job_name>.out'

# 搜索错误
rockcli sandbox <id> exec 'grep -i "error\|exception\|failed\|traceback" /data/logs/user-defined/<job_name>.out | tail -30'

# 如果有 artifact,检查输出
rockcli sandbox <id> exec 'ls -R /data/logs/artifacts/<namespace>/<experiment_id>/<job_name>/ 2>/dev/null'

Step 5:深入调试(发现问题时)

Harbor Job 调试
读取详细日志
# 1. 如果有 exception.txt,先读它
rockcli sandbox <id> exec 'cat /tmp/harbor/jobs/<job_name>/<trial_name>/exception.txt'

# 2. Verifier 输出(测试脚本的实际运行结果)
rockcli sandbox <id> exec 'cat /tmp/harbor/jobs/<job_name>/<trial_name>/verifier/test-stdout.txt'
rockcli sandbox <id> exec 'cat /tmp/harbor/jobs/<job_name>/<trial_name>/verifier/test-stderr.txt'

# 3. Trial 主日志(先搜关键词)
rockcli sandbox <id> exec 'grep -i "error\|exception\|failed\|traceback" /tmp/harbor/jobs/<job_name>/<trial_name>/trial.log | tail -50'
检查 Docker Container 状态

Harbor Docker container 命名规则:hb__<environment_name>(小写)

# 列出所有 Harbor 相关 container
rockcli sandbox <id> exec 'docker ps -a | grep "hb__"'

# 查看 container 详情
rockcli sandbox <id> exec 'docker inspect <container_name> | python3 -c "
import json, sys
data = json.load(sys.stdin)[0]
state = data[\"State\"]
print(f\"Status: {state[chr(39)]Status{chr(39)}}\")
print(f\"ExitCode: {state[chr(39)]ExitCode{chr(39)}}\")
print(f\"OOMKilled: {state[chr(39)]OOMKilled{chr(39)}}\")
"'

# 查看 container 最近日志
rockcli sandbox <id> exec 'docker logs <container_name> --tail 100'
查看 Agent 执行轨迹(按需)

用户想了解 agent 做了什么时才查。

rockcli sandbox <id> exec 'cat /path/to/trial/agent/trajectory.json | python3 -c "
import json, sys
d = json.load(sys.stdin)
steps = d.get(\"steps\", [])
print(f\"共 {len(steps)} 步\")
for i, s in enumerate(steps[:20]):
    tool = s.get(\"tool\", \"\") or s.get(\"action\", \"\")
    summary = s.get(\"observation\", \"\") or s.get(\"result\", \"\")
    print(f\"  [{i+1}] {tool}: {str(summary)[:100]}\")
"'
Bash Job 调试
# 1. 查看完整日志
rockcli sandbox <id> exec 'cat /data/logs/user-defined/<job_name>.out'

# 2. 检查沙箱内执行环境
rockcli sandbox <id> exec 'echo "=== Python ==="; python3 --version 2>/dev/null; echo "=== Node ==="; node --version 2>/dev/null; echo "=== Disk ==="; df -h / 2>/dev/null'

# 3. 如果有 artifact,查看内容
rockcli sandbox <id> exec 'cat /data/logs/artifacts/<namespace>/<experiment_id>/<job_name>/* 2>/dev/null | head -100'

Step 6:生成报告(必须输出并保存到本地文件)

每次分析结束必须:

  1. 在对话中输出结构化报告
  2. 将报告保存到本地文件:/tmp/rock-agent-report-<sandbox_id_短>-<timestamp>.md
Harbor Job 报告格式
## Harbor Job 报告

**沙箱**: <sandbox_id>
**Job**: <job_name>
**类型**: Harbor Job
**时间**: <started_at> → <finished_at 或 "运行中">
**耗时**: <duration>

### 配置
- Agent: <agent_name> (<model_name>)
- Bench: <dataset_name> v<version>(或 Task: <task_path>)
- 并发数: <n_concurrent_trials>
- Verifier 模式: <harbor/native>

### 整体结果
- 总 Trials: <n>,成功: <n>,失败: <n>
- 平均 Reward: <mean>

### Trial 明细
| Trial | 状态 | Reward | 耗时 | 问题 |
|-------|------|--------|------|------|
| <name> | ✅/❌/🔄/⚠️ | <reward> | <duration> | <issue 或 -> |

### 执行时间线
- `<HH:MM>` 环境启动完成(耗时 Xs)
- `<HH:MM>` Agent 安装完成(耗时 Xs)
- `<HH:MM>` Agent 开始执行
- `<HH:MM>` Verifier 完成,reward=<N>

### 问题分析(如有)

**[CRITICAL] 问题标题**
- 影响 trial:`<trial_name>`
- 根本原因:...
- 证据:`exception.txt` 关键日志
- 建议:...

### 行动建议
1. **立即修复**:...
2. **下次运行前**:...
Bash Job 报告格式
## Bash Job 报告

**沙箱**: <sandbox_id>
**Job**: <job_name>
**类型**: Bash Job
**时间**: <started_at> → <finished_at>
**耗时**: <duration>
**退出码**: <exit_code>

### 配置
- Script: <script 内容或 script_path>
- Environment: <environment 配置>
- Timeout: <timeout>

### 执行结果
- 状态: ✅ 成功 / ❌ 失败
- 退出码: <0 或非零>
- 关键输出: <摘要>

### 日志摘要
<关键日志片段,特别是错误信息>

### 问题分析(如有)
- 根本原因:...
- 证据:日志关键行
- 建议:...

### 行动建议
1. ...

状态图标: ✅ 通过 | ❌ 失败 | 🔄 运行中 | ⚠️ 完成但异常


常见故障速查

Harbor Job
现象失败阶段典型原因
"Docker compose command failed" / "no such host"env_setup镜像拉取 DNS 失败
agent/setup/return-code.txt = 100agent_setupAgent 安装脚本失败
AgentTimeoutErroragent_executionAgent 超时
reward=0,无异常verifierAgent 完成但未解决问题
RewardFileNotFoundErrorverifierreward.txt 不存在
no running event loopcleanupAgent 超时后清理阶段崩溃(非主要失败原因)
reward.txt 为空或不存在verifierverifier 未运行到写 reward 步骤
agent_result 为 null,execution 时间极短agent_setupagent 安装脚本报错
所有 trial 失败,同样的 exception环境层面镜像/依赖/网络问题
Bash Job
现象典型原因
退出码非零脚本执行失败
超时退出timeout 设置过短或脚本挂起
日志截断沙箱资源不足 (OOM / 磁盘满)
无 artifact 输出脚本未写入预期路径或路径权限问题

Agent 类型参考

Agent 名描述
claude-codeClaude Code CLI
terminus / terminus-2Terminus 内部 agent
swe-agent-internal内部 SWE-Agent 实现
openhandsOpenHands agent
mini-swe-agent轻量 SWE-Agent
aiderAider coding agent
opencodeOpenCode agent
oracle参考 agent(已知解)
nop空操作(测试用)

Harbor Job 批量扫描脚本

#!/usr/bin/env python3
# 用法:python3 scan_job.py ./jobs/<job_name>
import json, sys
from pathlib import Path

job_dir = Path(sys.argv[1])
trials = sorted([d for d in job_dir.iterdir() if d.is_dir()])

print(f"Job: {job_dir.name}")
print(f"{'Trial':<40} {'Reward':<8} {'Status':<12} {'Duration':<10} {'Issue'}")
print("-" * 90)

for trial_dir in trials:
    result_path = trial_dir / "result.json"
    if not result_path.exists():
        print(f"{trial_dir.name:<40} {'N/A':<8} {'NO RESULT':<12} {'-':<10}")
        continue

    try:
        r = json.loads(result_path.read_text())
    except Exception as e:
        print(f"{trial_dir.name:<40} {'ERR':<8} {'JSON ERR':<12} {'-':<10} {e}")
        continue

    reward = "N/A"
    if r.get("verifier_result") and r["verifier_result"].get("rewards"):
        rewards = r["verifier_result"]["rewards"]
        if isinstance(rewards, dict):
            reward = str(list(rewards.values())[0])
        elif isinstance(rewards, list) and rewards:
            reward = str(rewards[0])
    elif (trial_dir / "verifier" / "reward.txt").exists():
        reward = (trial_dir / "verifier" / "reward.txt").read_text().strip()

    exc = r.get("exception_info")
    status = "EXCEPTION" if exc else ("OK" if reward != "N/A" else "NO REWARD")

    duration = "-"
    if r.get("agent_execution") and r["agent_execution"].get("duration_sec"):
        duration = f"{r['agent_execution']['duration_sec']:.1f}s"

    issue = ""
    if exc:
        issue = f"{exc.get('exception_type','?')}: {str(exc.get('exception_message',''))[:50]}"

    print(f"{trial_dir.name:<40} {reward:<8} {status:<12} {duration:<10} {issue}")

评论

支持 Markdown