从 CI 红线到 AI 助手:用 Agent Skill 在本地搞定代码格式检查

一个关于 GitHub Actions CI、ruff/clang-format,以及如何用 AI Agent Skill 把「提交 → 被 CI 打回 → 修格式 → 再提交」的循环砍掉的故事。


1. 整体思路

1.1 TileLang 简介

TileLang 是一个简洁的领域专用语言(DSL),旨在简化高性能 NPU/GPU/CPU 算子(如 GEMM、FlashAttention、LinearAttention 等)的开发。它采用 Pythonic 语法,底层基于 TVM 编译器架构,让开发者既能保持高效生产力,又不牺牲顶级性能所需的底层优化。项目代码以 Python 为主,底层涉及 C++ 实现,同时维护了多个 CI 流水线来保证代码质量。

一个多人协作、跨语言(Python + C++)的开源项目,贡献者众多、编码风格各异,靠人工在 code review 时逐行纠正格式显然不现实,于是 CI 格式检查就成了必备项。

1.2 从 CI 到本地 Skill 的思路

CI 格式检查虽然守住了代码质量的门槛,但它有个天然的短板——反馈太滞后。等 CI 告诉你格式不对,代码已经 push 完了,只能 amend + force-push,来来回回体验很差。

于是有了这样的思路:

本地 Skill 自动检查修复(push 前搞定)
  → CI 格式检查(最后一道防线,确保合入质量)

核心逻辑:把格式问题消灭在 push 之前,CI 只作为兜底验证。 Skill 负责自动化——检查、报告、修复合一——开发者只需要说一句话。

下面从实现侧,逐层拆解是怎么落地的。


2. 第一层:本地 Skill —— push 前搞定一切

这是整个方案的核心。目标是把格式检查-修复流程完全自动化,开发者 push 之前就能发现并解决问题。

2.1 要解决什么

传统方式下,开发者在 push 前要么完全不知道要检查格式,要么需要手动跑脚本、装工具、读报告、改代码——每一步都是摩擦。Skill 要做的就是把这一串变成一句话的事情。

2.2 实现:需要哪些文件

整个 Skill 的文件结构:

.agents/skills/tilelang-custom-skill/tilelang-review-skill/
├── SKILL.md                 # Skill 定义:流程、规则、交互方式
└── scritps/
    ├── check-python.sh      # Python 检查(lint + format)
    ├── check-cpp.sh         # C++ 检查
    ├── fix-python.sh        # Python 修复
    └── fix-cpp.sh           # C++ 修复

与 GitHub CI 流水线共用的配置文件:

./
├── pyproject.toml           # ruff 规则配置
└── .clang-format            # C++ 格式规则

Agent 遵循 SKILL.md 的流程定义执行时,会自动调用上述四个脚本完成检查和修复,并严格遵循 pyproject.toml.clang-format 中的规则——保证和 CI 行为一致。下面逐个看这些文件做了什么。

2.3 SKILL.md:流程定义,写给 Agent 看的说明书

SKILL.md 是 Skill 的大脑——它定义了 Agent 在接到「检查代码格式」指令后的完整行为链:

询问检查范围 → 环境检测(自动安装缺失工具)→ 运行检查 → 生成报告
  → 醒目询问用户 → 用户确认 → 执行修复 → 验证并更新报告

几个关键设计:

先问范围。 默认仅检查 git status 中的变更文件,也支持 --all 全量。日常只用前者。

自动补齐环境。 ruff 或 clang-format 没装?Agent 自己装:

curl -LsSf https://astral.sh/ruff/install.sh | sh
sudo apt-get install clang-format-18

不需要开发者操心「装什么版本、怎么装」。

检查和修复严格分离。 这是 SKILL.md 中反复强调的红线。检查阶段绝不改任何文件;Agent 跑完后生成 Markdown 报告醒目展示问题摘要:

╔═══════════════════════════════════════════════════════════════╗
║  📋 代码格式检查完成                                           ║
╠═══════════════════════════════════════════════════════════════╣
║  发现问题数: 15                                                ║
║  - Python: 3 个文件有 lint 问题                                ║
║  - C++: 2 个文件需要格式化                                     ║
║                                                               ║
║  🔧 是否进行自动修复?[ 是 / 否 ]                               ║
╚═══════════════════════════════════════════════════════════════╝

只有用户明确说「是」才执行修复。修复完成后自动重新验证,把结果追加到报告里。报告文件 format-report-{timestamp}.md 每次生成新文件,不覆盖历史。

完整实现见 .agents/skills/tilelang-custom-skill/tilelang-review-skill/SKILL.md

2.4 配置文件:所有环节共享的规则来源

pyproject.toml.clang-format 是唯一真相来源——Skill 脚本读它,后面的 CI 也读它,规则只定义一次:

# pyproject.toml(ruff 相关部分)
[tool.ruff]
target-version = "py39"   # 目标 Python 版本
line-length = 140          # 单行最大字符数

[tool.ruff.format]
quote-style = "double"     # 统一双引号
indent-style = "space"     # 空格缩进

[tool.ruff.lint]
select = [
    "E", "W",     # pycodestyle:代码风格错误与警告
    "F",          # Pyflakes:逻辑错误检测
    "UP", "FA",   # pyupgrade:语法升级建议
    "B",          # flake8-bugbear:常见 bug 检测
    "SIM",        # flake8-simplify:简化写法建议
]
# .clang-format
BasedOnStyle: LLVM    # 基于 LLVM 代码风格
IndentWidth: 2        # 缩进 2 空格
ColumnLimit: 80       # 单行最大 80 字符
Standard: c++17       # C++17 标准

完整实现见 pyproject.toml.clang-format

2.5 检查脚本

check-python.shcheck-cpp.sh 负责检查阶段。文件获取通过 git status --porcelain 拿变更文件(或 --allfind 全量),然后调用对应工具:Python 走 ruff check(lint)+ ruff format --check(格式检查),C++ 走 clang-format --dry-run --Werror。输出为 JSON 格式,Agent 直接解析生成报告。

完整实现见 check-python.shcheck-cpp.sh

2.6 修复脚本

fix-python.shfix-cpp.sh 负责修复阶段——Python:ruff check --fix + ruff format;C++:clang-format -i --style=file。不做版本校验和环境检测,这些在前面的检查阶段已经处理好了,脚本只做一件事:修。

完整实现见 fix-python.shfix-cpp.sh


3. 第二层:CI 流水线 —— 守住最后一道防线

本地 Skill 保证了 push 前代码已经合规,但 CI 这层不能省——它是兜底,防止有人跳过 Skill 直接 push,也保证合入 main 分支的代码经过统一校验。

文件:.github/workflows/ci_ascend.yml,核心 format-check job:

format-check:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v6
      with:
        fetch-depth: 0

    # 精准拿到 PR 变更的 Python 文件
    - name: Get changed Python files
      id: changed-files
      run: |
        CHANGED_FILES=$(git diff --name-only --diff-filter=AM \
          origin/${{ github.base_ref }}...HEAD | grep '\.py$' | tr '\n' ' ' || true)
        echo "files=$CHANGED_FILES" >> $GITHUB_OUTPUT

    # ruff 格式检查 + lint
    - name: Ruff format check
      uses: astral-sh/ruff-action@v3
      with:
        args: format --check --diff --color=always
        src: ${{ steps.changed-files.outputs.files }}

    - name: Ruff lint
      uses: astral-sh/ruff-action@v3
      with:
        args: check --output-format=github
        src: ${{ steps.changed-files.outputs.files }}

    # 同理:C++ 文件
    - name: Get changed C++ files
      id: changed-cpp-files
      run: |
        CHANGED_CPP_FILES=$(git diff --name-only --diff-filter=AM \
          origin/${{ github.base_ref }}...HEAD \
          | grep -E '\.(cpp|cc|cxx|h|hpp|hh|icc)$' | paste -sd " " -)
        echo "files=$CHANGED_CPP_FILES" >> $GITHUB_OUTPUT

    - name: clang-format check
      uses: DoozyX/clang-format-lint-action@v0.18
      with:
        source: ${{ steps.changed-cpp-files.outputs.files }}
        clangFormatVersion: 18
        style: file

设计要点和 Skill 一致:增量检查git diff --name-only --diff-filter=AM 只拿 PR 变更文件,分语言丢给对应工具。读取的也是同一份 pyproject.toml.clang-format,保证线上线下行为一致。

完整实现见 .github/workflows/ci_ascend.yml


4. 完整闭环

写代码 → 说一句 "检查代码格式"
  → Skill 自动检查 + 展示报告
  → 确认修复 → Skill 自动修 + 验证
  → git add + commit + push
  → CI 🟢 直接通过
阶段 旧流程 新流程
安装工具 手动 pip/apt-get Skill 自动检测安装
了解规则 自己翻 pyproject.toml Skill 自动读取
运行检查 手动敲命令(可能忘) 自然语言触发
看结果 刷终端 + git diff 结构化 Markdown 报告
修复 直接改,靠 diff 反查 先确认,后修复,自动验证
CI 首次通过率 看运气 接近 100%

5. 总结

  • 配置是唯一真相来源——Skill 脚本和 CI 读同一份 pyproject.toml.clang-format,不存在「本地过了 CI 挂了」的灰色地带。
  • 检查与修复分离——Agent 可以自主检查,但改代码之前必须等开发者确认。这是 AI Agent 开发中最重要的安全原则之一。
  • 从脚本到 Skill,本质是从「给人用」到「给 Agent 用」的思维转变——传统方式是手动跑脚本、看输出、改代码,每一步都依赖人;Skill 让 Agent 来调脚本、Agent 来跟人交互,弥补了「人会忘记」「人不爱读终端输出」「新人不知道从哪开始」这些短板。

代码格式检查本身不复杂,但从「被 CI 打回来再改」到「本地 Skill 一步搞定」的演进,折射出了开发者工具链正在发生的变化:从后置到前置、从手动到自动、从文档到对话


本文基于 TileLang 项目的实际 CI 配置和 Agent Skill 实现撰写。Skill 定义和脚本位于 .agents/skills/tilelang-custom-skill/tilelang-review-skill/ 目录。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐