Files
2026-09-04 14:58:42 +08:00

606 lines
18 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.
# Skill Agent 编译流水线
本项目将 SkillsBench 任务中的单个 Skill 依次经过静态编译、Fast 动态优化、Deep 动态迭代和 BenchFlow 评测,产出可恢复、可审计的最终 Skill。
## 安装与配置
### 配置系统环境
项目目前运行在 Windows WSL 2(Ubuntu 26.04 LTS) 系统中。
```bash
# 以管理员身份打开 ps 安装
wsl --install -d Ubuntu-26.04
```
设置账号密码,进入 wsl 后安装基础工具与 python,nodejs:
```bash
sudo apt update
sudo apt upgrade -y
sudo apt install -y ca-certificates curl git python3 python3-pip python3-venv python-is-python3
sudo apt install -y nodejs
```
项目依赖 docker, 直接运行在这个 WSL 发行版中的原生 Docker Engine(29.6.2)。
```bash
sudo apt remove -y docker.io docker-compose docker-compose-v2 docker-doc docker-buildx podman-docker containerd runc
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources >/dev/null <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
sudo usermod -aG docker "$USER"
newgrp docker
```
验证 docker:
```bash
docker version
docker run --rm hello-world
```
如果遇到permission denied相关提示,可能和docker权限问题/网络问题有关:
```
permission denied while trying to connect to the docker API at unix:///var/run/docker.sock
permission denied while trying to connect to the docker API at unix:///var/run/docker.sock
```
网络问题可配置 WSL 网络镜像,在 Windows PowerShell 里创建/修改:
```bash
notepad $env:USERPROFILE\.wslconfig
```
写入:
```bash
[wsl2]
networkingMode=mirrored
dnsTunneling=true
autoProxy=true
firewall=true
```
保存后执行:
```bash
wsl --shutdown
wsl -d Ubuntu-26.04
```
然后再跑
```bash
docker run --rm hello-world
```
如果最后看到 Hello from Docker!,就说明问题已经完全解决。
项目建议放在 ~/projects/skill-agent-proj, 项目目录:
```bash
skill-agent-proj/
├── scripts/
├── requirements.txt
├── provider_routes.json
└── data/
└── skills-bench/
├── pyproject.toml
├── uv.lock
├── tasks/
└── skillsbench_agentbeats/
......
```
### 配置项目环境依赖
#### 外部模型
在项目根目录配置 `.env`,并在 `provider_routes.json` 中维护模型路由。所有模型参数使用 `provider/model-id` 格式。
#### 项目环境
可以用 conda 创建虚拟环境, python 版本选择3.12, 在虚拟环境中配置项目依赖:
```bash
python -m pip install -r requirements.txt
```
目前使用的是Python 3.12 自带的 venv,激活虚拟环境
Linux/macOS:
```bash
source .venv/bin/activate
```
用结束后退出环境
```bash
deactivate
```
#### skills-bench 环境
完整流水线要求 SkillsBench/BenchFlow CLI,测试脚本 run-raw-task.sh 会调用它们。
- SkillsBench:官方基准仓库,提供任务规范、Python 运行环境和 skillsbench_agentbeats worker。
- BenchFlow CLI:实际执行 bench eval run --sandbox docker 的命令行工具。
```bash
sudo snap remove astral-uv
hash -r
curl -LsSf https://astral.sh/uv/0.12.6/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
hash -r
uv --version
```
```bash
cd ~/Projects/skill-agent-proj/data/skills-bench
uv sync --locked
# 这里如果执行失败可能是 目录/权限问题.
# 验证
./.venv/bin/python --version
./.venv/bin/bench --version
```
- 注意uv sync --locked是在创建skills-bench下面的虚拟环境.venv
安装好验证测试脚本是否能运行:
```bash
cd ~/Projects/skill-agent-proj
source .venv/bin/activate
smoke_root=$(mktemp -d /tmp/skillc-eval-smoke.XXXXXX)
echo "临时输出目录:$smoke_root"
PYTHONDONTWRITEBYTECODE=1 \
bash scripts/evaluate/run-raw-task.sh \
--harness opencode \
--model siliconflow/Qwen/Qwen3.5-27B \
--task data/skills-bench/tasks/citation-check \
--skill-source data/skills-bench/tasks/citation-check/environment/skills \
--output "$smoke_root" \
--require-skill \
--repeat 1 \
--max-parallel 1
```
VSCODE推荐使用Containers插件,可以可视化docker镜像情况。
这里如果执行失败可能是因为: docker 需要配置代理或镜像加速,或检查 wsl 网络问题.
如果遇到以下问题:
```bash
test-001 (1/1) [#-------------------] 5% preparing elapsed=02:57
scripts/evaluate/run-raw-task.sh: line 534: rg: command not found
scripts/evaluate/run-raw-task.sh: line 536: rg: command not found
scripts/evaluate/run-raw-task.sh: line 538: rg: command not found
scripts/evaluate/run-raw-task.sh: line 540: rg: command not found
scripts/evaluate/run-raw-task.sh: line 542: rg: command not found
scripts/evaluate/run-raw-task.sh: line 544: rg: command not found
```
这是因为 WSL 系统里没有安装 rg(ripgrep),请新开一个wsl终端,安装ripgrep:
```bash
sudo apt update
sudo apt install -y ripgrep
```
验证:
```bash
rg --version
```
##### WSL mirrored 模式下配置 SkillsBench 容器代理 (补充章节)
SkillsBench/BenchFlow 会在 Docker 容器中运行 agent 和 verifier。仅配置 Docker daemon
的代理只能解决镜像拉取问题,不能保证运行中的容器可以访问 `astral.sh`、PyPI 等外部服务。
当前使用的代理链路如下:
```text
SkillsBench 容器
-> HTTP_PROXY=http://172.17.0.1:18080
-> benchflow-proxy-bridge
-> 127.0.0.1:7897
-> Windows Clash Verge
-> Internet
```
端口说明:
- `7897`:Windows Clash Verge 的实际代理端口。
- `18080`:Docker 容器访问的桥接入口。
- `172.17.0.1`:Docker 默认 bridge 网络的宿主机网关。
- 桥接入口和实际代理出口应使用不同端口,避免监听冲突或转发回路。
###### 1. 配置 WSL mirrored 网络
在 Windows PowerShell 中编辑 `%USERPROFILE%\.wslconfig`:
```powershell
notepad $env:USERPROFILE\.wslconfig
```
确保 `[wsl2]` 中包含:
```ini
[wsl2]
networkingMode=mirrored
hostAddressLoopback=true
firewall=true
autoProxy=true
ignoredPorts=18080
```
`ignoredPorts=18080` 用于避免 mirrored 网络在 Windows 层保留该端口,导致 host 网络容器报错:
```text
bind 0.0.0.0:18080: Address in use
```
如果已经配置其他忽略端口,使用逗号追加,例如:
```ini
ignoredPorts=53,18080
```
保存后,在 Windows PowerShell 中重启 WSL:
```powershell
wsl --shutdown
```
###### 2. 创建持久化代理桥接容器
确保 Windows Clash Verge 正在运行,并确认 mixed proxy 端口为 `7897`。然后在 WSL 中创建桥接容器:
```bash
docker run -d \
--name benchflow-proxy-bridge \
--network host \
--restart unless-stopped \
alpine/socat \
TCP-LISTEN:18080,fork,reuseaddr \
TCP:127.0.0.1:7897
```
检查容器状态和配置:
```bash
docker ps -a --filter name=benchflow-proxy-bridge
docker inspect benchflow-proxy-bridge \
--format 'RestartPolicy={{.HostConfig.RestartPolicy.Name}} NetworkMode={{.HostConfig.NetworkMode}}'
docker inspect benchflow-proxy-bridge \
--format '{{json .Config.Cmd}}'
```
预期结果包含:
```text
RestartPolicy=unless-stopped NetworkMode=host
["TCP-LISTEN:18080,fork,reuseaddr","TCP:127.0.0.1:7897"]
```
`unless-stopped` 表示 Docker daemon 启动或容器异常退出后会自动恢复该容器。显式执行
`docker stop benchflow-proxy-bridge` 后,容器会保持停止,直到再次手动启动。
###### 3. 给运行容器注入代理
编辑 Docker 客户端配置:
```bash
mkdir -p ~/.docker
nano ~/.docker/config.json
```
写入:
```json
{
"proxies": {
"default": {
"httpProxy": "http://172.17.0.1:18080",
"httpsProxy": "http://172.17.0.1:18080",
"noProxy": "localhost,127.0.0.1,::1"
}
}
}
```
该配置会把大小写形式的 `HTTP_PROXY`、`HTTPS_PROXY` 和 `NO_PROXY` 注入新创建的
Docker 容器,包括 SkillsBench 的 agent/verifier 容器。JSON 中必须使用纯 URL,不能写成
Markdown 链接形式。
###### 4. 验证完整代理链路
确认桥接容器正在运行并监听 `18080`:
```bash
docker ps --filter name=benchflow-proxy-bridge
sudo ss -lntp | grep ':18080'
```
确认新容器获得代理变量:
```bash
docker run --rm ubuntu:24.04 env | grep -i proxy
```
预期包含:
```text
HTTP_PROXY=http://172.17.0.1:18080
HTTPS_PROXY=http://172.17.0.1:18080
```
测试 verifier 所需的 `uv` 下载链路:
```bash
docker run --rm ubuntu:24.04 \
bash -c 'apt-get update >/dev/null &&
apt-get install -y curl >/dev/null &&
curl --connect-timeout 10 --max-time 30 -fsSIL https://astral.sh/uv/0.9.7/install.sh'
```
最终返回 `HTTP/2 200` 表示链路正常,可以重新运行 SkillsBench 测试。
###### 5. 常见问题
桥接容器反复显示 `Restarting` 时,先查看日志:
```bash
docker logs --tail 100 benchflow-proxy-bridge
```
如果日志包含:
```text
bind 0.0.0.0:18080: Address in use
```
检查 Windows `.wslconfig` 是否包含 `ignoredPorts=18080`,修改后执行 `wsl --shutdown`。
如果普通容器访问 `172.17.0.1:18080` 时出现 `Connection refused`,依次检查:
```bash
docker ps --filter name=benchflow-proxy-bridge
sudo ss -lntp | grep ':18080'
docker logs --tail 100 benchflow-proxy-bridge
```
同时确认 Windows Clash Verge 正在运行,且 mixed proxy 端口仍为 `7897`。
##### Docker daemon 代理与运行容器代理的区别
Docker daemon 代理负责拉取镜像;`~/.docker/config.json` 中的代理负责运行中容器的网络请求,
两者用途不同。Docker daemon 可以继续使用宿主侧可直接访问的地址,例如:
```text
HTTP_PROXY=http://127.0.0.1:7897
HTTPS_PROXY=http://127.0.0.1:7897
```
不要让 Docker daemon 依赖 `benchflow-proxy-bridge`,否则可能形成“Docker daemon 需要桥接
容器联网,而桥接容器又必须等待 Docker daemon 启动”的循环依赖。
#### 两个环境说明
项目核心运行环境是 conda 创建的虚拟环境, `data/skills-bench/.venv` 是 SkillsBench/BenchFlow 的独立运行环境,负责执行评测。评测脚本会显式调用 `data/skills-bench/.venv/bin/python` 和其中的 `bench`;仅这些子进程使用该 uv 创建的虚拟环境,不会切换或改变当前 Conda 环境。
#### agentrm 启动
(可以使用codex协助启动, 目前无法自动化流程,因为autodl服务器没法一直占用,且成本较高)
动态优化中,还需要启动远程 AgentRM服务,假设模型部署在远端服务器 8000 端口运行,本地 28080端口接收:
服务器端:
- https://www.autodl.com/console/instance/list
复制SSH登录指令
```bash
PS C:\Users\xfd024> ssh -p 33706 root@connect.weste.seetacloud.com
```
随后输入密码
```bash
# 进入部署目录并激活 Conda 环境:
cd root/autodl-tmp/agentrm-deployment
source /root/miniconda3/etc/profile.d/conda.sh
conda activate agentrm
chmod +x run_agentrm_server.sh
# 启动服务:
RM_HOST=127.0.0.1 ./run_agentrm_server.sh
# 查看加载日志:
tail -f outputs/agentrm_server.log
# 看到以下内容表示模型加载完成:
# [ready] AgentRM loaded on cuda
# 远端健康检查:
curl -fsS http://127.0.0.1:8000/health
# 正常返回:
# {
# "status": "ok",
# "device": "cuda",
# "max_length": 8192
# }
```
本地建立 SSH 隧道:
Windows PowerShell 执行后保持窗口开启:
```bash
ssh -o ExitOnForwardFailure=yes
-o ServerAliveInterval=30
-o ServerAliveCountMax=3
-N
-L 127.0.0.1:28080:127.0.0.1:8000
-p <SSH端口> <用户>@<服务器地址>
```
## 推荐用法:完整流水线
```bash
python -m scripts.compile_pipeline \
--harness opencode \
--model provider/target-model \
--external-model provider/compiler-model \
--task <data/skills-bench/tasks 下的任务名>
```
使用原运行目录恢复中断任务:
```bash
python -m scripts.compile_pipeline \
--harness opencode \
--model provider/target-model \
--external-model provider/compiler-model \
--task <任务名> \
--run-dir results/compile-pipeline/<run-id>
```
任务必须位于 `data/skills-bench/tasks`,且 `environment/skills` 下仅有一个 `SKILL.md`。`--run-dir` 必须位于 `results/compile-pipeline`;同一目录不能并发运行。
## 执行顺序与产物
```text
原始 Skill
→ 原始评测
→ 模型画像与静态编译
→ 静态产物评测
→ Fast 优化与评测
→ Deep 局部迭代
→ 最终评测
→ artifacts/deep/S_final
```
完整运行目录为 `results/compile-pipeline/<run-id>/`:
- `manifest.json`:输入身份、阶段状态和错误;原子写入,可用于恢复。
- `artifacts/static`、`artifacts/fast`、`artifacts/deep`:各编译阶段产物与缓存。
- `traces/<task>/`:原始、静态、Fast、最终评测结果;Deep 最后一轮可复用 rollout 也会复制到此处的 `final_skill/`。
- `artifacts/deep/S_final`:最终可交付 Skill。
评测仅复用完整的 `test-*` 产物(摘要、Skill 调用校验、结构化结果和 ACP 轨迹均有效)。不完整目录会移入同级 `.incomplete/`,不会被当作缓存。Deep 仅在最终 `SKILL.md` 哈希与最后一批有效 rollout 一致时复用其结果。
## 参考命令
以下示例使用现有的 `111-offer-letter-generator` 产物路径。静态编译使用 `--model` 指定待适配的目标模型,使用 `--external-model` 指定混合模式的语义规划模型。
### 静态编译
```bash
python -m scripts.static_compile \
--model siliconflow/Qwen/Qwen3.5-27B \
--external-model ali/deepseek-v4-pro-0813 \
--input data/skills-bench/tasks/111-offer-letter-generator/environment/skills \
--out-root results/static-opimization/ \
--mode hybrid
```
### 快速优化
```bash
python -m scripts.dynamic_compile.fast \
--traces results/dynamic-optimization/traces/raw_agent_trace/opencode/siliconflow-qwen-qwen3-5-27b/111-offer-letter-generator/model_skill \
--skill results/static-opimization/siliconflow-qwen-qwen3-5-27b/skills/docx \
--model ali/deepseek-v4-pro-0813 \
--max-parallel 3
```
### 深度迭代
```bash
python -m scripts.dynamic_compile.deep run \
--skill results/dynamic-optimization/compiled-skills/opencode/siliconflow-qwen-qwen3-5-27b/111-offer-letter-generator/model_compile/candidate-skill/docx \
--traces results/benchflow/opencode-siliconflow-qwen-qwen3-5-27b/111-offer-letter-generator/custom_skill \
--output results/dynamic-optimization-v1-5/deep-compiled-skills/opencode/siliconflow-qwen-qwen3-5-27b/111-offer-letter-generator \
--model ali/deepseek-v4-pro-0813
```
### 完整流水线
```bash
python -m scripts.compile_pipeline \
--harness opencode \
--model siliconflow/Qwen/Qwen3.5-27B \
--external-model ali/deepseek-v4-pro-0813 \
--task citation-check
```
## 独立模块
### 静态编译
根据模型画像对 Skill 做确定性或混合改写;保留 frontmatter、代码块和受保护字面量,语义保护失败时回滚原文。
```bash
python -m scripts.static_compile \
--model provider/model-id \
--input <Skill 目录或包目录> \
--out-root results/static-compiled-skills \
--mode deterministic
```
`hybrid` 模式允许一次受源文本约束的语义规划;`--dry-run` 不写产物也不调用规划模型。
实际执行 `hybrid` 模式时必须通过 `--external-model provider/model-id` 单独指定语义规划模型;`--model` 始终表示待适配的目标模型。
### Fast 动态优化
基于至少 6 条同任务、同编译类型的 BenchFlow 轨迹,依次执行预评分、AgentRM 评分、Top/Bottom 分组、Map/Reduce 与局部补丁生成;候选包原子发布。
```bash
python -m scripts.dynamic_compile.fast \
--traces <BenchFlow 轨迹目录> \
--skill <Skill 包目录> \
--model provider/model-id
```
可选 `--score-output`、`--output`、`--max-parallel`、`--rm-api-url` 与 `--force`。缓存只有在输入内容、配置、版本、哈希和产物均匹配时才复用。
### Deep 动态迭代
对 Fast 产物按章节、必要时按段落进行五维评分,生成并验证局部编辑,再用候选运行时轨迹比较;只有目标分数提升且没有运行时回归才提交。编辑始终校验章节边界、代码围栏、缓存和原子替换。
```bash
python -m scripts.dynamic_compile.deep run \
--skill <Skill 包目录> \
--traces <BenchFlow 轨迹目录> \
--output <Deep 输出目录> \
--model provider/model-id
python -m scripts.dynamic_compile.deep resume --run <Deep 输出目录>
```
## BenchFlow 评测
```bash
bash scripts/evaluate/run-raw-task.sh \
--harness opencode \
--model provider/model-id \
--task <SkillsBench 任务目录> \
--skill-source <Skill 目录或 skills 根目录> \
--output <结果目录> \
--require-skill --repeat 3 --max-parallel 3
```
该脚本为官方 BenchFlow runner 的兼容包装:每次尝试在 `<结果目录>/test-NNN/` 写入结果;`--require-skill` 会校验至少成功调用一次 Skill。可用 `--image <本地镜像>` 复用镜像;否则按任务创建或复用本地镜像。
## 失败处理
参数、任务范围、Skill 结构、模型路由、缓存、轨迹和产物均会校验。编译或评测阶段失败会记录到 manifest 并返回错误;可在修复配置后使用相同 `--run-dir` 恢复。执行实际编译或评测会调用外部模型、BenchFlow 和 Docker;`--help` 与模块导入不会。