---
date: 2026-05-11
type: error
tags: [ai-review, claude-cli, prompt-engineering, gitea-actions, agent-mode]
---

# AI Review SKILL 设计成 agent / runner 写成 API → 错位导致大 PR 爆 prompt 且无项目上下文

## 现场

PR #325（`feat(audit): ...`）触发 ai-review workflow，job 7328 在 "调用 claude CLI" 步骤 fail：

```
api_error_status: 400
result: "Prompt is too long"
terminal_reason: "prompt_too_long"
diff 2344179 bytes
```

PR diff 2.3MB，被 `scripts/ops/ai-review-runner.sh` 整坨塞进 prompt → 撞 Claude 单次 prompt 上限。

## 表面 vs 直接 vs 元根因（按 11-troubleshooting-methodology）

- **表面**：大 PR 触发 ai-review 报 `Prompt is too long`，CI 红
- **直接原因**：runner 把 `git pulls/N.diff` 拉来的 2.3MB 字符串塞 prompt 一次性喂给 `claude --print`
- **元根因**：**SKILL 设计和 runner 实现错位**。`.agents/skills/code-review/SKILL.md` 全文按 agent 模式写（L9-10 "阅读 project-overview"、L68-72 "按变更路径定位模块文档"、L78-79 "分层审阅、跨文件验证"、frontmatter `allowed-tools: Bash(gh pr view:*)` 等），明确指导 claude 主动 Read 项目文档、跨文件验证；但 runner 把 claude 当 completion API 用（`--print` + 无工具白名单 + diff 塞 prompt），claude **物理上做不到** SKILL 要求的任何探查动作

## 影响（比"大 PR 爆 prompt"严重得多）

1. 大 PR：直接撞上限，review 完全跑不动
2. **小 PR：照样裸审** —— claude 只看到 diff 文本 + CLAUDE.md + SKILL.md，**模块的 PRD / data-model / API / state-machine 一个字读不到**。它在审"代码本身对不对"，而不是"代码符不符合契约"。这是为什么 review 质量长期不高的根因，不只是 token 上限问题
3. SKILL 文档里的"按目标分支调整深度"、"分层审阅"、"事实源冲突上报"等高级行为全部失效

## 修复（push → pull / agent 模式切换）

`scripts/ops/ai-review-runner.sh` + `scripts/dev/ai-review-local.sh` 同步改造：

1. **删掉 diff 塞 prompt**：不再 API 拉 `.diff`，不再 heredoc 塞 2.3MB 进 prompt 字符串
2. **prompt 改为探查指引**：告诉 claude "仓库在 cwd，base=X，head=Y，按 SKILL.md 走完整流程"，给出建议探查路径（git diff --stat → 按文件 diff → Read 上下文 → 对照 docs/modules/）
3. **开工具白名单**：`--allowedTools Read Grep Glob Bash(git diff:*) Bash(git log:*) Bash(git show:*) Bash(git status:*) Bash(git ls-files:*) Bash(wc:*)` + `--permission-mode auto`。**不放** Write/Edit/NotebookEdit，runner 容器不会被 review 误改
4. **超时拉长**：workflow `timeout-minutes: 10 → 20`（多轮探查需要时间，单次 review 2-5 min）
5. **幂等短路改本地算 hash**：`git diff base...HEAD | md5sum`，单 pipe tee 算 bytes + hash 避免双跑 git diff
6. **diff 范围统一三点**：runner 原本用 `base..HEAD`（两点 tip-to-tip，base 推进会带回 base 提交），改成 `base...HEAD`（三点 merge-base 起算，PR review 标准语义）。本 PR self-review 第一次跑就被 agent 自己抓到这个 bug ✅

## 5 条元根因规则（按 12-five-meta-rules）

- **契约面**：SKILL.md 是 runner 调用 claude 时的契约面之一，但本质上是单向声明。SKILL 改了，没有任何检测说"你的调用方式跟我写的不匹配"。**类似坑可能存在于其他自定义 skill 调用点**——值得做一次 sweep：所有用 `claude --print` 调 skill 的脚本是不是都开了工具？
- **环境一致**：runner 容器里 `actions/checkout@v4 fetch-depth=0` 已经把仓库 + 所有 origin 分支 fetch 全了，**仓库就在本地**。但 runner 不知道这一点，绕回 API 拉 diff。"本地有的别走远路"
- **实测完工**：之前 runner 上线时没用大 PR + 引用契约的 case 实测过，所以这两个问题（token 爆 / 不读 docs）一直存在直到 PR #325 撞上
- **监控告警**：当前没有"AI review 是否真的引用了 docs/modules/" 的指标。新模式下应该在 state header 里记录"本轮 claude 读了哪些 docs/ 文件"，作为 review 质量的代理指标

## 通用教训（适用于所有 Claude Code CLI 集成）

**Claude Code 不是 completion API，它是 agent。** 用它的正确姿势：
- ✅ 给一个仓库 checkout + 小 prompt（任务描述）+ 工具白名单 → 让它自己探查
- ❌ 把所有上下文塞进 prompt 字符串，期望它一次性产出答案

把它当 API 用，等于花了 agent 的钱、拿到的是 completion 的能力。任何"prompt 越来越长、塞不下了"的告警都是这个错位的症状。

下次写新的 `claude --print` 调用点之前先问：
1. 仓库 / 文档 / 历史是不是已经在执行环境里？→ 是，**不要塞 prompt**，开工具让它 Read
2. SKILL.md 是不是引导它跨文件验证？→ 是，**必须开工具**否则 SKILL 文档失效
3. 输入有上限风险（diff / 文件 / log）？→ 是，**只能开工具**，prompt 塞不下

## 相关文件

- `scripts/ops/ai-review-runner.sh` — 改造主体
- `scripts/dev/ai-review-local.sh` — 同步改造（本地前置）
- `.gitea/workflows/ai-review.yml` — timeout 拉长
- `.agents/skills/code-review/SKILL.md` — 设计源（未改，但终于跟实现对齐了）
- Gitea actions run 2236 / job 7328 — 触发本次修复的 fail
