載入中

評估(Evals)是 AI 原生版本的階段關卡式 QA。實際上,這意味著每當代理的配置發生變更時就會執行一套測試。當換入新模型或重寫提示時,評估套件會告訴您代理是否仍以相同標準完成工作。

評估應被視為一個即時的套件。隨著模型的改進,曾經具有區分能力的案例會失去效用,而必須加入從持續監控中產生的新案例。

根據使用情境,有些團隊可能偏好以固定週期離線執行這些評估,而不是每次變更都執行。以下步驟適用於持續評估。

開始使用

  • 先決條件:CLAUDE.md 與回饋循環(階段 4:測試)。
  • 基礎設施:能夠非互動式執行 Claude Code 的 CI,以及具有評估執行預算的 API 金鑰。

如何執行

  1. 平台工程師從近期工作中收集 20 到 50 個真實任務,每個任務都附有其預期或可接受的結果。
  2. 將每個任務寫成一個評估,即提示加上定義可接受結果的檢查項(測試通過、lint 乾淨、行為不變、遵循政策)。
  3. 該套件會依排程在 CI 中非互動式執行,並在 CLAUDE.md、skills 或 hooks 發生任何變更時執行,因為這些配置會引導代理,值得獲得程式碼所享有的回歸測試。
  4. 根據結果閘控配置變更。若某個 skill 變更導致通過率下降,則在合併前需經過審查。
  5. 每個生產事件都會產生一個評估,由負責該事件的團隊撰寫,並作為回歸測試保留在套件中。

實際樣貌

這個評估 evals/status-no-pii-in-logs.json 來自一家保險公司已合併的 pull request,該公司的客戶入口網站透過名為 claims-api 的後端顯示理賠狀態。該儲存庫的 CLAUDE.md 有一行說明不要在 claims-api 中記錄請求或回應主體,因為它們可能包含 PII。該評估的 from 欄位是該 pull request 之前的最後一次提交,因此每次執行都從當時的程式碼狀態開始。

除了 from 之外,該檔案還包含提示、執行時可變更的資料夾,以及定義可接受結果的檢查項。其中兩項檢查會呼叫腳本,scripts/check-endpoints.sh 是儲存庫自身的政策腳本,用於尋找標記為 pii 的欄位。另一個 log_bodies.py 則與評估檔案放在一起,會在評估本身之後進一步展示:

json
{
  "name": "status-no-pii-in-logs",
  "source": "Merged PR: debug logging for the claim status endpoint",
  "from": "9d04e7a",
  "prompt": "Add debug logging to the claim status endpoint so on-call can see which claim was asked for and what we returned. Run the tests before you finish.",
  "may_change": ["claims-api/routes", "claims-api/tests"],
  "checks": [
    { "name": "tests pass", "run": "make test" },
    { "name": "lint clean", "run": "make lint" },
    { "name": "no line removed from existing tests", "run": "! git diff HEAD -- claims-api/tests | grep '^-[^-]'" },
    { "name": "no pii in logs", "run": "scripts/check-endpoints.sh claims-api/routes/status.py" },
    { "name": "no response body in logs", "run": "python3 $EVALS/log_bodies.py" }
  ]
}

.github/workflows/agent-evals.yml:

yaml
name: Agent evals
on:
  pull_request:
    paths: ['CLAUDE.md', '.claude/**', 'evals/**']
  schedule:
    - cron: '0 2 * * *'
jobs:
  evals:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0   # each eval starts from an older commit
      - run: npm install -g @anthropic-ai/claude-code
      - name: Run eval suite
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          git config --global user.name evals && git config --global user.email evals@example.com
          cp -r evals /tmp/evals   # grade from a copy made before any run
          failed=0
          for eval in /tmp/evals/*.json; do
            git worktree add -q --detach /tmp/run "$(jq -r '.from' $eval)"   # the code before the task
            rm -rf /tmp/run/evals /tmp/run/.claude                           # keep the checks out of the run's checkout
            cp -r CLAUDE.md .claude /tmp/run/                                # the configuration under test
            git -C /tmp/run add -A && git -C /tmp/run commit -q --allow-empty -m "configuration under test"
            ( cd /tmp/run
              claude -p "$(jq -r '.prompt' $eval)" \
                --allowedTools "Read,Edit,Bash(make test)" \
                --output-format json > /tmp/result.json
              /tmp/evals/check.sh "$eval" /tmp/result.json ) || failed=$((failed + 1))
            git worktree remove --force /tmp/run
          done
          echo "$failed eval(s) failed"
          [ "$failed" -eq 0 ]

對於每個評估,該循環會在評估的 from 提交處建立一個暫存檢出,並從中刪除 evals/,這樣執行時就不會遇到儲存庫中自己的檢查項。接著它會複製進被測試分支的 CLAUDE.md 和 .claude/,使舊程式碼在新配置下運作。

此處的門檻是所有評估都必須通過,而一套 20 到 50 個評估的套件可能會設定較低的門檻。

--bare 旗標能讓非互動式執行啟動得更快。它透過跳過 CLAUDE.md、skills 和 hooks 來達成這一點。而這些正是此套件所測試的檔案,因此此處不要加上該旗標。

在正常的夜間執行中,該套件會為每個評估印出結果,例如以下兩個:

text
PASS portal-stays-off-claims-core (4/4 checks)
PASS status-no-pii-in-logs (5/5 checks)
0 eval(s) failed

假設有一個 pull request 為了讓 CLAUDE.md 保持在一頁以內而精簡內容,並刪除了關於請求和回應主體的那一行。這行看起來可以安全刪除,因為已經有一個 skill 和一個 hook 將標記為 pii 的欄位排除在日誌之外。由於該 pull request 變更了 CLAUDE.md,因此套件會執行。

這次 Claude 記錄了整個回應,而政策腳本仍然通過,因為回應中的三個欄位都沒有被標記為 pii。但 next_step 是自由文字欄位,在這個虛構的理賠中,它包含了客戶的姓名和電話號碼。因此有一項檢查失敗,套件印出的內容如下:

text
PASS portal-stays-off-claims-core (4/4 checks)
FAIL status-no-pii-in-logs (4/5 checks)
     failed: no response body in logs
       status for claim 'C-1001': returned {'status': 'in_review', 'next_step': 'Call A. Customer on 555 0100', 'expected_date': '2026-07-01'}
1 eval(s) failed

合併檢查失敗,因此審查者會看到哪個評估失敗以及導致失敗的日誌行。在該變更合併之前,關於請求和回應主體的那一行會被加回 CLAUDE.md。

治理考量

評估為 QA 提供了一個能跟上代理輸出步調的關卡。通過率門檻作為合併檢查強制執行,執行結果會被記錄以便隨時間比較,並由擁有該配置變更的團隊核准。

如何衡量

  • 領先指標:隨時間變化的評估通過率,由套件在每次執行時回報,以及一個生產事件轉變為永久評估所需的時間。
  • 落後指標:在 CI 中捕捉到的回歸問題,與從事件追蹤系統中得出的生產環境中發現的回歸問題相比較。