游乐游手机版
首页/AI教程/文章详情

SkillSentry CI集成:每次代码变更自动质量门禁

时间:2026-06-01 13:17
CI流水线分为触发层与门禁层:触发层监测SKILL md变更自动运行测评,门禁层依据FAIL结果阻止PR合并。通过GitHubActions配置、exitcode设计及BranchProtection规则落实质量门禁,并积累历史趋势数据以监控质量变化。
```html

CI 集成分两层架构:触发层决定何时启动质量测评(SKILL.md 变更时自动触发),门禁层则控制测评结果如何影响 PR 合并(FAIL 时阻止合并)。仅配置触发层而忽略门禁层,测评机制形同虚设。唯有两层均部署到位,质量门禁才能真正发挥效力。

本文将详细提供:

  • GitHub Actions 完整 workflow 配置方案
  • exit code 设计与 CI 状态映射关系
  • Branch Protection 规则配置指引
  • 历史趋势数据的采集与积累方法

10—把 SkillSentry 接入 CI:每次改动都有质量门禁

一、为什么 CI 环境可以使用 --dangerously-skip-permissions

许多开发者初次见到这个 flag 时的第一反应:“这名字听起来风险极高,真的能放心使用?”结论先行:在 CI 环境中,该 flag 是安全且推荐的用法;在本地开发环境则不应使用。

根本原因在于两种环境的权限模型存在本质差异:

环境 人工审批的实际价值 skip-permissions 的影响
本地(开发者机器) 开发者可在测评过程中选择允许或拒绝特定操作 跳过审批后,风险操作无人审核
CI 容器 无人值守运行,任何权限弹窗都会导致流程卡死 在隔离容器中跳过属于正常设计模式

CI 容器属于一次性隔离环境——每次 workflow 运行均启动全新容器,无持久状态留存,操作不会影响真实生产环境,运行结束后自动销毁。因此 --dangerously-skip-permissions 在 CI 中的真实含义是:“在这个一次性容器内,跳过权限确认环节,使测评全程无需人工介入。” 真正危险的场景是“绕过生产系统的权限控制”,而非“跳过 AI 工具的调用确认”。

二、GitHub Actions 完整配置

基础配置:SKILL.md 变更时自动触发

# .github/workflows/skill-eval.yml
name: SkillSentry Evaluation
on:
  pull_request:
    paths:
      - 'skills/*/SKILL.md' # 任意 Skill 的 SKILL.md 变更时触发
  push:
    branches: [main]
    paths:
      - 'skills/*/SKILL.md'

jobs:
  skill-eval:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
        with:
          fetch-depth: 2 # 需要对比前一个版本
      - name: Detect changed skills
        id: changed-skills
        run: |
          CHANGED=$(git diff --name-only HEAD~1 HEAD -- 'skills/*/SKILL.md' | sed 's|skills/||' | sed 's|/SKILL.md||' | tr '\n' ',')
          echo "skills=${CHANGED}" >> $GITHUB_OUTPUT
          echo "Changed skills: ${CHANGED}"
      - name: Install Claude Code
        run: |
          npm install -g @anthropic-ai/claude-code
          # 验证安装
          claude --version
      - name: Run SkillSentry evaluation
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          # 对每个变更的 Skill 运行 smoke 测评
          IFS=',' read -ra SKILLS <<< "${{ steps.changed-skills.outputs.skills }}"
          OVERALL_EXIT=0
          for SKILL in "${SKILLS[@]}"; do
            if [ -z "$SKILL" ]; then continue; fi
            echo "=== Evaluating: $SKILL ==="
            claude --dangerously-skip-permissions \
              -p "smoke 测评 ${SKILL} 自动" \
              --output-format stream-json | tee "eval-${SKILL}.log"
            EXIT_CODE=${PIPESTATUS[0]}
            if [ $EXIT_CODE -ne 0 ]; then
              echo "::error::Skill ${SKILL} evaluation FAILED (exit code: ${EXIT_CODE})"
              OVERALL_EXIT=1
            fi
          done
          exit $OVERALL_EXIT
      - name: Upload evaluation reports
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: skill-eval-reports-${{ github.run_id }}
          path: |
            **/*.eval-report.html
            **/sessions/**/*.html
          retention-days: 30

完整门禁配置:standard 测评与发布等级检查

# .github/workflows/skill-eval-full.yml
name: SkillSentry Full Evaluation (Pre-release)
on:
  push:
    branches: [release/*]
    paths:
      - 'skills/*/SKILL.md'

jobs:
  detect-skills:
    runs-on: ubuntu-latest
    outputs:
      skills: ${{ steps.changed-skills.outputs.skills }}
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 2
      - name: Detect changed skills
        id: changed-skills
        run: |
          SKILLS=$(git diff --name-only HEAD~1 HEAD -- 'skills/*/SKILL.md' | sed 's|skills/||' | sed 's|/SKILL.md||' | jq -R -s -c 'split("\n")[:-1]')
          echo "skills=${SKILLS}" >> "$GITHUB_OUTPUT"
          echo "Changed skills: ${SKILLS}"
  skill-eval-standard:
    needs: detect-skills
    if: needs.detect-skills.outputs.skills != '[]'
    runs-on: ubuntu-latest
    timeout-minutes: 60
    strategy:
      matrix:
        skill: ${{ fromJson(needs.detect-skills.outputs.skills) }}
      fail-fast: false # 一个 Skill FAIL 不影响其他 Skill 的测评继续
    steps:
      - uses: actions/checkout@v6
      - name: Install Claude Code
        run: |
          npm install -g @anthropic-ai/claude-code
          claude --version
      - name: Run standard evaluation
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude --dangerously-skip-permissions -p "standard 测评 ${{ matrix.skill }} 自动" --output-format stream-json
      - name: Check release grade
        run: |
          # 从报告提取发布等级
          GRADE=$(find "sessions/${{ matrix.skill }}" -name "*.json" -print0 | xargs -0 -r grep -h -o '"release_grade":"[A-Z]*"' | tail -1 | sed 's/.*:"//;s/"$//' || true)
          echo "Release grade: ${GRADE}"
          echo "GRADE=${GRADE}" >> "$GITHUB_ENV"
          case "$GRADE" in
            "S"|"A"|"B"|"C")
              echo "Grade ${GRADE}: PASS"
              ;;
            "D"|"F"|"FAIL"|"")
              echo "::error::Skill ${{ matrix.skill }} did not pass (grade: ${GRADE})"
              exit 1
              ;;
            *)
              echo "::error::Unknown grade for ${{ matrix.skill }}: ${GRADE}"
              exit 1
              ;;
          esac
      - name: Sa ve trend data
        if: always()
        run: |
          # 记录历史趋势数据到 gh-pages 或 artifact
          DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)
          echo "{\"date\":\"${DATE}\",\"skill\":\"${{ matrix.skill }}\",\"grade\":\"${GRADE}\",\"run\":${{ github.run_number }}}" >> trend-data.jsonl
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: eval-${{ matrix.skill }}-${{ github.run_id }}
          path: |
            sessions/${{ matrix.skill }}/**/*.html
            trend-data.jsonl
          retention-days: 90

三、exit code 设计规范

CI 系统通过 exit code 判断步骤是否执行成功。SkillSentry 的 exit code 约定如下:

exit code 含义说明 CI 步骤状态
0 测评通过(S/A/B 级) ✅ success
1 测评 FAIL ❌ failure
2 环境错误(MCP 不可用、Skill 未找到) ❌ failure
3 测评结果不稳定(quick 两次差距超过 15%) 默认标记为 failure;若团队希望仅标 warning,必须显式捕获后转为 ::warning::

核心设计要点:GitHub Actions 本身仅识别 0 和非 0 两种状态。exit code 1(测评 FAIL)和 exit code 2(环境错误)必须阻止 PR 合并;exit code 3 如果被定义为“不稳定但不阻断”,就不能直接将 3 作为步骤退出码返回,而需在脚本中捕获后输出 warning,再由团队策略决定是否放行。

--output-format stream-json--output-format json 的用途差异:

格式 适用场景 用法建议
stream-json 长时间运行的 CI 步骤 边执行边输出日志,适合配合 tee 保存完整执行过程
json 后续脚本需要解析最终结果 输出完整 JSON 到文件,适合用 jq 读取判定字段

前述 workflow 使用 stream-json 是为了让 CI 页面实时展示执行过程;下面的示例使用 json 是为了演示如何从结构化结果中解析 pass/fail。

等待 exit code 的两种方式:

# 方式一:直接检查 claude 命令的退出码
claude --dangerously-skip-permissions -p "smoke 测评 my-skill 自动"
if [ $? -ne 0 ]; then
  echo "Evaluation failed"
  exit 1
fi

# 方式二:从输出的 JSON 中解析结果
claude --dangerously-skip-permissions -p "smoke 测评 my-skill 自动" --output-format json > result.json
PASS=$(jq -r '.result.pass' result.json)
if [ "$PASS" != "true" ]; then
  echo "Evaluation failed: $(jq -r '.result.reason' result.json)"
  exit 1
fi

如需将“结果不稳定”标记为 warning 而非失败,需显式处理:

set +e
claude --dangerously-skip-permissions -p "quick 测评 my-skill 自动"
EXIT_CODE=$?
set -e
case "$EXIT_CODE" in
  0)
    echo "Evaluation passed"
    ;;
  3)
    echo "::warning::Evaluation is unstable; mark as conditional pass and require follow-up"
    exit 0
    ;;
  *)
    echo "::error::Evaluation failed with exit code ${EXIT_CODE}"
    exit "$EXIT_CODE"
    ;;
esac

四、Branch Protection 配置方法

在 GitHub 仓库设置中配置 branch protection rule,让 CI 状态决定 PR 是否可合并:

  1. 进入仓库 Settings → Branches → Add branch protection rule
  2. Branch name pattern:main(或你的主分支名称)
  3. 勾选 Require status checks to pass before merging
  4. 在 Status checks 搜索框中添加:skill-eval / skill-eval
  5. 勾选 Require branches to be up to date before merging

配置完成后效果:PR 中包含 SKILL.md 变更 → 自动触发测评 → 测评 FAIL → PR 显示红色 × → 无法合并;测评通过 → PR 显示绿色 ✓ → 允许合并。

五、历史趋势数据积累

单次测评只能告诉你“当前是否通过”,历史趋势则能揭示“质量是在提升还是在下降”。

数据采集方案

每次 CI 运行将测评结果写入 trend JSONL 文件:

{"date":"2026-04-10T09:00:00Z","skill":"em-reimbursement-v3","grade":"A","pass_rate":0.92,"delta":0.67,"run":142}
{"date":"2026-04-11T14:30:00Z","skill":"em-reimbursement-v3","grade":"A","pass_rate":0.91,"delta":0.65,"run":145}
{"date":"2026-04-12T11:00:00Z","skill":"em-reimbursement-v3","grade":"B","pass_rate":0.83,"delta":0.52,"run":148}

趋势预警规则

在 CI 中加入趋势分析逻辑:

# 检查最近 5 次的趋势
TREND=$(tail -5 trend-data.jsonl | jq -s '[.[].pass_rate] | (last - first)')
if (( $(echo "$TREND < -0.1" | bc -l) )); then
  echo "::warning::Pass rate has dropped by more than 10% in last 5 runs"
fi

报告持久化

将 HTML 报告上传至 GitHub Actions artifacts,保留 90 天:

- uses: actions/upload-artifact@v4
  with:
    name: skill-report-${{ github.run_number }}
    path: sessions/**/*.html
    retention-days: 90

配合 GitHub Pages,可将趋势数据可视化为折线图,在团队 wiki 中直接查看质量变化趋势。

六、常见 CI 问题与处理方案

问题现象 根本原因 处理方法
CI 卡住不退出 测评等待用户确认(忘记添加 自动 在 prompt 末尾添加 自动 参数
exit code 总是 0 即使测评 FAIL claude 命令未正确传递测评结果 改用 --output-format json 解析结果字段
MCP 工具在 CI 容器中不可用 CI 容器未配置 MCP Server 确认 MCP Server 可通过网络访问,或配置为 text_generation 降级
Token 消耗超出预算 standard/full 模式在 CI 中成本较高 PR 评审使用 smoke,release 分支使用 standard
并发 Skill 测评相互干扰 会话目录冲突 确保每个 Skill 使用独立的 session 目录
API key 在 PR 中无法访问 fork 的 PR 无法读取 secrets 使用 pull_request_target 事件,或为 fork PR 单独配置

七、分级门禁策略

并非所有 SKILL.md 改动都需要同等严格程度的测评。推荐采用分级策略:

触发条件 测评模式 是否阻断 PR? 典型应用场景
任意 PR + SKILL.md 变更 smoke ✅ FAIL 阻断 日常开发迭代
release 分支 + SKILL.md 变更 standard ✅ FAIL 阻断 提测前验收
main 分支合并 + S/A 级 Skill full ✅ FAIL 阻断 正式发布前
定时任务(每天凌晨) quick ❌ 不阻断 环境健康检查

定时健康检查能够发现“Skill 未变更但环境变化导致测评失败”的情况,例如 MCP Server 升级引起工具调用行为变化。

# 定时健康检查
on:
  schedule:
    - cron: '0 2 * * *' # 每天凌晨 2 点(UTC)
jobs:
  health-check:
    # ... 对所有已注册 Skill 运行 quick 测评
    # FAIL 不阻断,但通过 Slack/飞书通知

八、工程落地建议:CI 分为两条线

前述 workflow 是门禁骨架。实际落地时,建议让 CI Runner 以结构化测评结果为准,读取 grading-summary.json / session.json / authoritative_pass_rate,再返回明确的 exit code。

推荐脚本分工:

  • sentry_ci.py:核心判决脚本,读取 grading-summary.json / session.json / authoritative_pass_rate → PASS/FAIL 判决 → exit code
  • update_history.py:追加 history.json 历史记录,支持趋势分析与回归检测
  • report_to_checks.py:将结果推送为 GitHub Checks 注解,PR 页面直接可见

相比前述 YAML 骨架,结构化 Runner 的改进点:

本文描述 当前实现
grep CLI 输出判 PASS/FAIL grading-summary.json / session.json 结构化数据,不依赖 CLI 输出格式
硬编码阈值 --threshold 参数化(默认 0.80)
无历史对比 history.json + Δ < 0 自动 FAIL
单 Skill matrix 自动检测变更的 SKILL.md 并行测评
无 GitHub Checks 集成 report_to_checks.py 推送注解

CI 建议分为两条线,避免混成一条 workflow:

  1. 业务 Skill 质量门禁skill-eval.yml,用于评估被测 Skill 的 smoke / standard / full 结果,核心是让 FAIL 阻断合并。
  2. SkillSentry 本体自检skillsentry-self-test.yml,用于验证 SkillSentry 自身脚本、契约、模板和工作流未被改坏。

本体自检的推荐入口是确定性脚本,而非再次启动真实 LLM 测评:

python scripts/verify_deterministic.py --format json

手动触发深度自检时再开启 full 模式:

python scripts/verify_deterministic.py --full --format json

GitHub Actions 示例应使用当前 Node 运行时兼容的 action 版本:

steps:
  - uses: actions/checkout@v6
  - uses: actions/setup-python@v6
    with:
      python-version: '3.11'

这类工程落地常见陷阱是:workflow 模板已升级到新 major,但仓库中的实际 workflow 仍停留在旧 major,容易触发运行时退役提醒或造成模板与线上不一致。后续 workflow 模板和仓库内实际 workflow 应保持同步,并用 verify_workflow_action_versions.py 扫描旧 major,避免模板已修复、线上 workflow 未更新的问题。

另一个易被忽视的点是 GitHub 权限。推送 .github/workflows/*.yml 不仅需要普通 repo 权限,还需 token 携带 workflow scope;否则代码改好后会被远端拒绝。

九、实战补充:最小 CI Gate

如果团队暂时无法运行 full 测评,至少应先部署一个最小静态门禁:

PR 提交 -> 自动静态检查 -> 检查准入标准 -> PASS:允许进入后续流程 -> FAIL:阻断 + 通知 + 修复建议

最小准入标准可先设定如下:

评估维度 阈值 设置理由
L1 description >= 3/5 核心字段不可缺失
L2 HiL 风险 >= 3/5 必须包含 HiL 节点
L3 复杂度 <= 25 复杂度需在可控范围内
总分 >= 15/25 B 级以上才可进入后续流程

最小 GitHub Actions 结构:

name: Skill Static Gate
on:
  pull_request:
    paths:
      - "skills/*/SKILL.md"
jobs:
  static-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: Run static check
        run: |
          for skill_dir in skills/*/; do
            skill_name=$(basename "$skill_dir")
            python tools/sentry-static.py "$skill_dir/SKILL.md" --format json > "static-${skill_name}.json"
          done

CI 失败时,通知内容不应仅写“失败”,而应提供:

Skill 名称 | 总分 | 失败维度 | 修复建议 | 报告链接

这个最小 Gate 不替代完整测评,也不替代人工发布判断。其核心价值在于将低质量 Skill 阻挡在 review 之前。

总结

将 SkillSentry 接入 CI 的核心工作归结为三件事:

  1. 触发paths: skills/*/SKILL.md → SKILL.md 变更时自动执行
  2. 阻断:exit code 1/2 → CI 失败 → branch protection 阻止合并
  3. 积累:每次结果写入 trend JSONL → 质量趋势清晰可见

关键原则:测评不阻断发布 = 没有门禁。只有 FAIL 真正能阻止 PR 合并,质量保证才是实质性的,而非仅仅报表上的数字。

```
来源:https://juejin.cn/post/7645849125788434459
上一篇星图AI平台PETRV2-BEV模型新手入门教程 下一篇AnimateDiff新手友好型AI视频工具部署与使用完整教程
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
OpenClaw浏览器自动化控制 Playwright MCP与Mcporter方案实现完整流程步骤详解教程
AI教程 · 2026-06-01

OpenClaw浏览器自动化控制 Playwright MCP与Mcporter方案实现完整流程步骤详解教程

概述 这篇文章记录了把Playwright MCP集成到OpenClaw中,并用Mcporter作为中间桥梁的完整测试过程。内容包括问题诊断、架构理解,以及正确的使用方法——说白了,就是带大家把整个链路彻底捋清楚。 先交代一下背景:为啥折腾这个方案?说实话,就是熬夜后闲得慌,突发奇想想在家里搞搞Op

AI写业务代码后必须坚持的过程控制
AI教程 · 2026-06-01

AI写业务代码后必须坚持的过程控制

前言AI 已经能极其高效地帮我们搞定业务代码了。这个结论经过反复验证,基本上没什么悬念。但问题也随之而来:越是这样,越容易陷入失控状态——想到哪写到哪,总盼着 AI 一口气把活儿全干了。业务代码和 demo 最大的不同在于,业务从来不是孤立的。它牵扯着一连串的业务流程、历史包袱、数据状态、权限边界、

我用两个高效技巧解决AI开发文档记录难题
AI教程 · 2026-06-01

我用两个高效技巧解决AI开发文档记录难题

我用 AI 写了三个月代码,结果连自己写的东西都看不懂了 一个开发者的普遍困境 从去年开始,大量开发者涌入 Claude Code 进行 AI 辅助开发。效率提升令人振奋——过去需要两天的功能,现在一个下午就能搞定。但很快,一个尴尬的问题浮出水面:三个月前自己写的代码,如今竟然看不懂了。 问题不在于

AI改坏真实App的常见问题与解决技巧
AI教程 · 2026-06-01

AI改坏真实App的常见问题与解决技巧

探索AI辅助移动端开发的过程中,我属于较早深入实践并持续积累经验的那一批。过去几个月里,我几乎每天都会在真实的iOS与Flutter项目中与AI协作调整代码:涵盖SDK封装、旧代码迁移、Demo补全、使用文档优化、多语言适配、界面检查、验证执行以及工作交接整理。因此,本文无意纠缠“AI究竟能否编写代

领导要求部署OpenClaw?先看这篇指南
AI教程 · 2026-06-01

领导要求部署OpenClaw?先看这篇指南

前几天,领导丢过来一句话:你去看一下 OpenClaw,评估一下能不能在公司内部部署。紧接着又问了一个很典型的问题:这东西到底算什么?是一种云服务吗? 仔细一想,这个问题的答案并不简单。OpenClaw 本身不等于“云平台”,但一旦真正用起来,云环境通常会深度参与。它更像一层编排和运行框架,负责把袋