|
| 1 | +# 基于 Skill 的代码审查 Agent |
| 2 | + |
| 3 | +本示例提供自动代码审查 Agent 的最小框架:Workflow 只负责输入、调用、校验、落库和报告等确定性步骤;Agent 负责判断是否需要 Skill 和沙箱检查。`code-review` Skill 提供规则和脚本,结果通过可替换存储层持久化,并生成 JSON 与 Markdown 报告。 |
| 4 | + |
| 5 | +## 目录结构 |
| 6 | + |
| 7 | +```text |
| 8 | +skills_code_review_agent/ |
| 9 | +├── run_agent.py # 主要入口 |
| 10 | +├── workflow.py # 审查流程编排 |
| 11 | +├── docs/design.md # 方案设计说明 |
| 12 | +├── agent/ |
| 13 | +│ ├── agent.py # LlmAgent 构建 |
| 14 | +│ ├── config.py # 模型配置 |
| 15 | +│ ├── fake.py # 确定性 fake model |
| 16 | +│ ├── normalization.py # 去重、降噪和脱敏 |
| 17 | +│ ├── prompts.py # 审查 Prompt |
| 18 | +│ └── tools.py # SkillToolSet 与沙箱连接 |
| 19 | +├── inputs/ # diff、file list、worktree、fixture 输入 |
| 20 | +├── filters/ # 命令策略和 SDK Tool Filter |
| 21 | +├── skills/code-review/ |
| 22 | +│ ├── SKILL.md # Skill 入口 |
| 23 | +│ ├── agents/openai.yaml # Skill UI 元数据 |
| 24 | +│ ├── references/RULES.md # 审查规则 |
| 25 | +│ └── scripts/ # 输入解析、受控读取及分类审查脚本 |
| 26 | +├── sandbox/ |
| 27 | +│ ├── base.py # 可替换沙箱接口 |
| 28 | +│ ├── factory.py # 环境变量驱动的实现选择 |
| 29 | +│ ├── docker.py # Docker 实现 |
| 30 | +│ ├── lazy.py # 按工具调用惰性创建 runtime |
| 31 | +│ ├── fake.py # 不执行代码的测试模拟器 |
| 32 | +│ ├── .dockerignore # 最小化镜像构建上下文 |
| 33 | +│ └── Dockerfile # 最小审查镜像 |
| 34 | +├── storage/ |
| 35 | +│ ├── base.py # BaseReviewStore 抽象基类 |
| 36 | +│ ├── factory.py # 环境变量驱动的实现选择 |
| 37 | +│ ├── schema.sql # 显式 SQLite schema |
| 38 | +│ └── sqlite.py # SQLite 实现 |
| 39 | +├── reports/ |
| 40 | +│ ├── models.py # 结构化审查模型 |
| 41 | +│ └── writers.py # JSON/Markdown 输出 |
| 42 | +├── tests/fixtures/ # 8 条要求样本及超时补充样本 |
| 43 | +├── tests/run_tests.py # 非 Docker 验收测试入口 |
| 44 | +├── tests/run_docker_tests.py # tRPC Container runtime 集成测试 |
| 45 | +├── tests/evaluate_fixtures.py # 公开 fixture 指标评测 |
| 46 | +└── examples/review_report.* # 示例报告 |
| 47 | +``` |
| 48 | + |
| 49 | +## 运行要求 |
| 50 | + |
| 51 | +- Python 3.10+ |
| 52 | +- 已按仓库根目录说明安装 `trpc-agent-python` 及其现有依赖 |
| 53 | +- fake/dry-run 不需要 Docker 或模型 API Key |
| 54 | +- 真实模式需要 Docker daemon,以及模型环境变量 |
| 55 | + |
| 56 | +远程模型地址必须使用 HTTPS;仅 `localhost`、`127.0.0.1` 和 `::1` |
| 57 | +允许使用 HTTP,便于连接本地开发模型服务。 |
| 58 | +生产环境建议设置 `TRPC_AGENT_ALLOWED_MODEL_HOSTS`,限制可接收 API Key |
| 59 | +和审查证据的模型服务域名。 |
| 60 | + |
| 61 | +本示例不额外依赖 `.env` 解析库。入口只读取示例目录下权限为 `0600`、 |
| 62 | +键名前缀为 `TRPC_AGENT_` 或 `CODE_REVIEW_` 的普通文件;同名进程变量优先: |
| 63 | + |
| 64 | +```bash |
| 65 | +cp examples/skills_code_review_agent/.env.example \ |
| 66 | + examples/skills_code_review_agent/.env |
| 67 | +chmod 600 examples/skills_code_review_agent/.env |
| 68 | +``` |
| 69 | + |
| 70 | +## 输入与运行方式 |
| 71 | + |
| 72 | +所有命令从仓库根目录执行。默认审查 Git 工作区变更: |
| 73 | + |
| 74 | +```bash |
| 75 | +uv run --project examples/skills_code_review_agent --with-editable . \ |
| 76 | + python examples/skills_code_review_agent/run_agent.py \ |
| 77 | + --repo-path /path/to/repository |
| 78 | +``` |
| 79 | + |
| 80 | +其他输入: |
| 81 | + |
| 82 | +```bash |
| 83 | +# unified diff / PR patch |
| 84 | +uv run --project examples/skills_code_review_agent --with-editable . \ |
| 85 | + python examples/skills_code_review_agent/run_agent.py --diff-file change.patch |
| 86 | + |
| 87 | +# 文件路径列表;真实模式同时提供列表所属仓库 |
| 88 | +uv run --project examples/skills_code_review_agent --with-editable . \ |
| 89 | + python examples/skills_code_review_agent/run_agent.py \ |
| 90 | + --repo-path /path/to/repository --file-list /path/to/repository/files.txt |
| 91 | + |
| 92 | +# 内置 fixture,无模型、无 Docker |
| 93 | +uv run --project examples/skills_code_review_agent --with-editable . \ |
| 94 | + python examples/skills_code_review_agent/run_agent.py \ |
| 95 | + --fixture security --fake-model |
| 96 | +``` |
| 97 | + |
| 98 | +`--dry-run` 同样走确定性 fake 链路,仍执行解析、Filter、sandbox 模拟、落库和报告生成,但不执行任何宿主或容器命令。省略输入时从当前工作目录向上查找最近的 Git worktree,并仅审查其变更;全仓库审查必须显式添加 `--full`。 |
| 99 | + |
| 100 | +unified diff 解析结果保留每个 hunk 的 added、removed、unchanged context |
| 101 | +行、old/new 双侧行号和候选变更行号,生命周期规则可利用未修改上下文降噪。 |
| 102 | + |
| 103 | +## 输出和持久化 |
| 104 | + |
| 105 | +默认输出位置: |
| 106 | + |
| 107 | +- SQLite:`storage/reviews.sqlite3` |
| 108 | +- JSON:`reports/output/<task-id>/review_report.json` |
| 109 | +- Markdown:`reports/output/<task-id>/review_report.md` |
| 110 | + |
| 111 | +持久化默认由以下环境变量选择: |
| 112 | + |
| 113 | +```bash |
| 114 | +CODE_REVIEW_STORAGE_BACKEND=sqlite |
| 115 | +CODE_REVIEW_SQLITE_PATH=storage/reviews.sqlite3 |
| 116 | +CODE_REVIEW_SQLITE_SCHEMA_PATH=storage/schema.sql |
| 117 | +``` |
| 118 | + |
| 119 | +当前只实现 `sqlite`;新增后端应继承 `BaseReviewStore` 并在 `storage/factory.py` 注册。`--database` 的优先级高于 `CODE_REVIEW_SQLITE_PATH`。 |
| 120 | +`CODE_REVIEW_SQLITE_SCHEMA_PATH` 可选择兼容的 SQLite 初始化 schema;替换文件必须保留存储实现使用的表和字段契约,并且只能使用 `storage/` 下的普通文件。schema 有大小限制,初始化时禁止 attach、trigger、view、虚拟表、删除对象和业务数据写入。 |
| 121 | + |
| 122 | +SQLite 分表保存 `review_tasks`、`review_inputs`、`sandbox_runs`、`filter_decisions`、`findings`、`monitoring_summaries` 和 `review_reports`,`get_task_details(task_id)` 可查询完整审计记录。任务在 Agent 启动前以 `running` 状态落库,异常终止会更新为 `failed`。SQLite 启用 WAL、等待锁和 digest/profile 索引。对于内容不可变的 diff/fixture,缓存必须同时匹配输入摘要、规则、Skill、模式、模型和审查范围;是否复用仍由 Agent 决定。 |
| 123 | + |
| 124 | +沙箱实现由 `CODE_REVIEW_SANDBOX_BACKEND=docker` 选择,当前仅提供 Docker;新增实现需满足 `SandboxProvider` 并在 `sandbox/factory.py` 注册。可通过 `--output-dir` 和 `--docker-image` 覆盖输出目录和镜像。Docker runtime 按 Agent 的 workspace 工具调用惰性创建;代码只读挂载,diff/fixture 仅挂载任务级副本。容器禁网、非 root、删除 capabilities、启用 `no-new-privileges` 和只读根文件系统,并限制 CPU、内存、PID 与 tmpfs。模型服务仍由宿主进程调用,因此应使用符合代码数据策略的模型服务。 |
| 125 | + |
| 126 | +## 安全和治理 |
| 127 | + |
| 128 | +- 真实执行只通过加固 Docker;fake sandbox 不执行代码。报告目录和 SQLite 使用仅当前用户可读写权限。 |
| 129 | +- diff 任务副本使用仅当前用户可读权限;SQLite 在首次连接前以 `0600` 安全创建,并拒绝符号链接路径。 |
| 130 | +- unified diff 和 Git staged/unstaged diff 均通过聚合脚本调用安全、异步、资源、数据库、测试和敏感信息六个独立规则;结果按最多 24 条记录分页,避免 SDK 的 16KB inline 上限截断 JSON。 |
| 131 | +- 文件列表和受控文件读取同样分页;路径长度、数量、敏感文件和符号链接在容器内再次校验。Git 工作区的直接读取还会重新验证路径属于 changed 或 full scope,避免模型读取未选择文件。 |
| 132 | +- `skill_run` 必须先完成 `skill_load`。前置 Filter 同时检查输入模式、命令、脚本、Git 参数、路径、网络、环境变量和预算;`deny`、`needs_human_review` 不进入沙箱。`compileall` 只做有界语法编译;`unittest` 和 `pytest` 会执行不受信任的仓库代码,默认进入人工复核。仅在确认仓库与挂载内容可信后,才可设置 `CODE_REVIEW_ALLOW_REPOSITORY_EXECUTION=true` 显式放行。 |
| 133 | +- 单次 Skill run 默认 30 秒;整次 review 默认 110 秒、30 次工具调用和 12 次 sandbox run。所有限制均可通过 `.env` 中的 `CODE_REVIEW_*` 字段收紧。 |
| 134 | +- Workflow 可信地记录每个脚本的 cursor;缺少必需的 staged、unstaged、文件枚举或受控读取证据,或者任一 `next_cursor` 未读完时,报告会强制加入人工复核项。 |
| 135 | +- 代码、注释和工具输出均按不可信数据处理;Filter 阻止外部 diff helper、敏感路径和跨输入模式读取。 |
| 136 | +- 输入预览、finding、Filter、sandbox 输出、数据库和报告写入前执行敏感信息脱敏。 |
| 137 | +- 容器进程由容器内 `timeout` 终止;stdout/stderr 在返回模型前按 `CODE_REVIEW_MAX_OUTPUT_BYTES` 硬限制并脱敏。受 Skill 工具 16 KiB inline 契约约束,Docker 传输的两路输出合计还会取配置值与 15 KiB 的较小者,避免 Docker Desktop 在 64 KiB socket 边界产生长时间等待。 |
| 138 | +- findings 按 `(file, line, category)` 去重,置信度低于 `0.70` 自动进入 warnings。 |
| 139 | + |
| 140 | +## 测试 |
| 141 | + |
| 142 | +按要求使用 uv 启动,不运行 Docker: |
| 143 | + |
| 144 | +```bash |
| 145 | +uv run --project examples/skills_code_review_agent --with-editable . \ |
| 146 | + python examples/skills_code_review_agent/tests/run_tests.py |
| 147 | +``` |
| 148 | + |
| 149 | +公开 fixture 指标评测: |
| 150 | + |
| 151 | +```bash |
| 152 | +uv run --project examples/skills_code_review_agent --with-editable . \ |
| 153 | + python examples/skills_code_review_agent/tests/evaluate_fixtures.py |
| 154 | +``` |
| 155 | + |
| 156 | +指标输出包含高风险检出率、clean diff 误报率、敏感信息检出率, |
| 157 | +并确认 8 个必需 fixture 均生成 JSON 和 Markdown 报告。 |
| 158 | + |
| 159 | +不调用模型、但实际启动 Docker runtime 的集成测试: |
| 160 | + |
| 161 | +```bash |
| 162 | +uv run --project examples/skills_code_review_agent --with-editable . \ |
| 163 | + python examples/skills_code_review_agent/tests/run_docker_tests.py |
| 164 | +``` |
| 165 | + |
| 166 | +测试覆盖:无问题、安全问题、异步任务泄漏、资源生命周期、数据库连接生命周期、测试缺失、重复 finding、sandbox 失败/超时、敏感信息脱敏、六类独立规则、配置工厂、分页、挂载最小化和报告注入。Docker 集成脚本验证 Skill 加载、规则执行、Filter、只读输入、禁网、真实超时、分页以及容器资源安全配置;模型效果仍取决于所配置模型,隐藏样本指标不能由公开 fixture 证明。 |
| 167 | + |
| 168 | +使用 `.env` 中的真实模型做完整联调: |
| 169 | + |
| 170 | +```bash |
| 171 | +uv run --project examples/skills_code_review_agent --with-editable . \ |
| 172 | + python examples/skills_code_review_agent/run_agent.py --fixture security |
| 173 | +``` |
| 174 | + |
| 175 | +详细取舍见 [docs/design.md](./docs/design.md)。 |
0 commit comments