1. 一个让很多团队都栽过跟头的真实场景
CI 流水线全绿,构建日志干干净净,单元测试覆盖率还涨了两个百分点,结果需求评审会上产品经理一句“这不是我要的东西”,整个迭代的交付节奏就被打乱了。这个场景在引入 AI Coding 之后变得格外常见,因为过去写代码的是人,需求理解偏差会在编码过程中被反复暴露;现在写代码的可能是 AI,它只对你给它的那段提示词负责,不对你脑子里那个真实需求负责。
我自己带过的一个文档站项目就是典型例子。需求是“给 MkDocs 站点加一套自动发布流程,推送到主分支后自动构建并部署到 Pages”,我用 AI 生成了 GitHub Actions 的 workflow 文件,跑起来一路绿灯,构建产物也正常上传。但验收的时候被卡住了,原因是需求方要的其实是“每次发布自动生成版本变更日志,并且旧版本文档要能通过版本切换器访问”,而 AI 交付的只是一个最朴素的单版本构建部署。CI 绿了,需求没绿。
这篇文章想聊的就是这件事:CI 全绿和需求验收通过之间,隔着的到底是什么。我会围绕 CI、MkDocs、GitHub Actions、Markdown、AI Coding 这几个关键词,把“AI 写的流程为什么容易假绿”这件事拆开讲,包括需求拆解、验收标准定义、AI 提示词工程、流水线设计、Markdown 内容校验、常见排查手段。适合正在用 AI 辅助写 CI 配置的开发者、负责文档站维护的技术写作者,以及任何被“绿灯但返工”折磨过的团队参考。
2. 为什么 AI 写的 CI 特别容易“假绿”
2.1 CI 绿的本质:它只验证了你告诉它的东西
先把这个概念说透。CI 流水线的绿色,从来不代表“功能正确”,它只代表“我配置的这些检查项全部通过了”。这是一个非常关键的认知差。你让 CI 跑 lint,它就只检查代码风格;你让它跑单元测试,它就只验证你写的那些断言;你让它构建,它就只确认构建命令退出码是 0。
AI 生成 CI 配置的时候,它的输入是你的提示词,输出是一份“语法正确、逻辑自洽、能跑通”的 YAML。它不知道你的验收标准里还有“版本切换器要能用”“变更日志要自动生成”“中文搜索要能命中”这些隐性要求。于是它给你一份能跑通的流水线,你看着绿灯很安心,但需求方要的东西一个都没验证。
我踩过的坑是这样的:AI 生成的 workflow 里,构建步骤用的是mkdocs build,部署用的是官方推荐的 Pages 上传 action,看起来无懈可击。但需求里明确要求“文档站要支持数学公式渲染”,而 AI 生成的mkdocs.yml里根本没配数学公式插件。构建当然成功,因为 Markdown 里的$...$在没插件的情况下就是普通文本,不会报错。CI 绿得毫无破绽,公式在页面上却是一堆乱码般的原始符号。
2.2 AI Coding 的“局部最优”陷阱
AI 写代码和写配置有一个共同特点:它倾向于给出局部最优解。你问它“怎么用 GitHub Actions 部署 MkDocs”,它会给你一份社区里最常见的模板,这份模板在“部署 MkDocs”这个局部问题上是最优的。但你的真实需求是一个更大的系统问题,涉及版本管理、内容校验、多环境发布、回滚策略,这些它不会主动帮你补全,除非你在提示词里明确要求。
这就引出一个很实用的判断方法:AI 交付的 CI 配置,你要拿它去反推“它到底验证了什么”,而不是看它“跑没跑通”。把 workflow 里的每一个 step 列出来,逐个问自己:这一步对应哪条验收标准?如果某条验收标准在流水线里找不到对应的检查步骤,那这条标准就是“裸奔”的,CI 绿了也白绿。
2.3 需求验收和 CI 验收是两套语言
需求验收用的是业务语言:“用户能切换文档版本”“搜索能搜到中文”“公式能正常显示”。CI 验收用的是工程语言:“build 退出码为 0”“测试全部通过”“产物上传成功”。这两套语言之间需要一次翻译,而 AI 不会自动帮你翻译,它只会按你给的工程语言去执行。
我后来总结出一个习惯:在让 AI 写 CI 之前,先自己把需求翻译成一份可执行的验收清单,每一条都要能对应到一个具体的命令或检查。比如“公式能正常显示”翻译成“构建后的 HTML 里,公式容器元素数量大于 0”。这份清单才是你给 AI 的真正输入,而不是那句笼统的“帮我配个发布流程”。
3. 把需求翻译成 CI 能验证的检查项
3.1 需求拆解的三层结构
我习惯把需求拆成三层:业务目标层、功能行为层、技术验证层。业务目标层是产品经理说的话,功能行为层是用户能感知到的操作,技术验证层是 CI 能跑的检查。三层之间要能一一对应,任何一层断链,都会导致“绿了但没通过”。
拿文档站发布这个场景举例:
| 层级 | 具体内容 | 对应 CI 检查 |
|---|---|---|
| 业务目标 | 文档站要能长期维护、多版本共存 | 版本目录结构校验 |
| 功能行为 | 用户能切换 v1/v2 文档,能搜到中文 | 版本切换器元素存在性检查、搜索索引包含中文词条 |
| 技术验证 | 构建产物包含指定文件、指定元素 | 构建后脚本扫描 HTML |
这张表看起来简单,但它是整个流程能不能通过验收的关键。AI 拿到“技术验证”这一列,才能生成真正有用的 CI 步骤;你拿到这一列,才能在验收会上有理有据地说“这条需求我验证过了”。
3.2 用 Markdown 内容校验补上“内容正确性”这一环
CI 通常只校验代码,不校验内容。但文档站的核心资产就是 Markdown 内容,内容错了,构建再成功也没用。我现在的做法是在流水线里加一个内容校验脚本,专门检查 Markdown 的几类高频问题。
第一类是图片路径。Markdown 里写,本地预览正常,推到 CI 上因为工作目录不同就 404 了。校验脚本要能扫描所有 Markdown 文件,提取图片引用路径,逐个检查文件是否存在。
第二类是数学公式语法。用了数学公式插件之后,$...$和$$...$$的配对、大括号多行公式的写法都容易出错。可以写个简单的正则检查,统计$的数量是否为偶数,\begin{...}和\end{...}是否配对。
第三类是内部链接。文档之间互相引用很常见,链接目标文件被重命名或删除后,链接就失效了。校验脚本要能解析相对链接,检查目标文件是否存在。
import re from pathlib import Path def check_image_paths(md_file: Path, root: Path): text = md_file.read_text(encoding="utf-8") pattern = re.compile(r'!\[.*?\]\((.*?)\)') errors = [] for match in pattern.finditer(text): img_path = match.group(1) if img_path.startswith(("http://", "https://")): continue target = (md_file.parent / img_path).resolve() if not target.exists(): errors.append(f"{md_file}: 图片不存在 {img_path}") return errors这个脚本跑在 CI 里,任何一条内容错误都会让流水线变红。这样一来,“内容正确性”这条隐性需求就被显性化了,AI 生成的流程也不再是“只构建不校验”的空壳。
3.3 验收标准要写成可执行的断言
我见过太多团队的验收标准是“文档站看起来正常”,这种标准没法执行,也没法交给 AI。正确的做法是把它写成断言。比如:
- 构建产物中
index.html存在,且包含<div class="md-version">元素 - 搜索索引文件
search_index.json存在,且包含至少 100 个中文词条 - 所有 Markdown 文件的图片引用路径均有效
- 数学公式渲染后的 HTML 中,
.arithmatex类元素数量大于 0
这些断言可以直接写进 CI 脚本,也可以写成独立的测试文件。关键是它们可执行、可复现、可交给 AI 生成。你把这份断言清单丢给 AI,它生成的 CI 配置就会从“能跑通”升级到“能验收”。
4. 用 GitHub Actions 搭一条真正能验收的流水线
4.1 流水线的分层设计
一条能通过验收的流水线,不应该是一个大 job 从头跑到尾,而应该分层。我通常分成四层:环境准备层、内容校验层、构建层、验收层。每层职责单一,失败时能快速定位问题。
环境准备层负责装依赖、缓存、设置 Python 版本。内容校验层跑前面说的 Markdown 检查脚本。构建层执行mkdocs build。验收层则是对构建产物做断言检查,这一层是很多团队缺失的,也是“假绿”的重灾区。
name: docs-pipeline on: push: branches: [main] pull_request: jobs: content-check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: '3.11' - name: 安装校验依赖 run: pip install pyyaml - name: 校验 Markdown 内容 run: python scripts/check_content.py build-and-verify: needs: content-check runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: '3.11' - name: 安装 MkDocs 及插件 run: pip install -r requirements.txt - name: 构建站点 run: mkdocs build --strict - name: 验收断言检查 run: python scripts/verify_output.py注意mkdocs build --strict这个参数,它会把警告当成错误,很多隐性内容问题在这一步就会暴露。AI 生成的配置里经常不带这个参数,导致警告被忽略,构建照样绿。
4.2 验收层脚本怎么写
验收层脚本的核心思路是:打开构建产物,检查关键元素是否存在。不需要真的起浏览器,用简单的 HTML 解析就够了。
from pathlib import Path from bs4 import BeautifulSoup def verify_site(site_dir: Path): errors = [] index = site_dir / "index.html" if not index.exists(): errors.append("index.html 不存在") return errors soup = BeautifulSoup(index.read_text(encoding="utf-8"), "html.parser") if not soup.select(".md-version"): errors.append("版本切换器元素缺失") search_index = site_dir / "search" / "search_index.json" if not search_index.exists(): errors.append("搜索索引文件缺失") formula_nodes = soup.select(".arithmatex") if len(formula_nodes) == 0: errors.append("未检测到数学公式渲染结果") return errors这个脚本跑在构建之后,任何一条断言失败都会让流水线变红。它验证的正是需求方真正关心的东西,而不是“构建命令有没有报错”。
4.3 把 AI 生成的配置改造成可验收版本
AI 给你的初始配置通常长这样:checkout、setup-python、pip install、mkdocs build、deploy。这份配置能跑通,但缺了内容校验层和验收层。改造的思路是:
- 在 build 之前插入内容校验 job,作为 build 的前置依赖
- 在 build 之后插入验收脚本,作为 build 的后置步骤
- 把
mkdocs build改成mkdocs build --strict - 把验收脚本的失败信息写清楚,方便定位
改造完之后,你再让 AI 帮你 review 一遍,问它“这条流水线覆盖了哪些验收标准,还有哪些没覆盖”。AI 在“找遗漏”这件事上其实挺好用,前提是你已经给了它一份明确的验收清单。
5. 那些让 CI 绿了但验收挂掉的典型坑
5.1 数学公式插件配了但没生效
这是最高频的坑。mkdocs.yml里加了pymdownx.arithmatex,但忘了在extra_javascript里引入 MathJax 或 KaTeX 的脚本。构建不报错,公式在页面上就是原始文本。验收脚本里检查.arithmatex元素数量就能抓到这个问题。
还有一种情况是公式语法本身写错了,比如大括号多行公式\begin{aligned}...\end{aligned}里少了个\\换行符,渲染出来挤成一行。这种问题构建也不报错,只能靠人工或更细的渲染检查发现。
5.2 Markdown 换行和表格的隐性差异
Markdown 的换行规则在不同渲染器下行为不一致。有的要求行尾两个空格才换行,有的直接换行就生效。AI 生成的文档内容经常忽略这个差异,本地预览正常,部署后段落全挤在一起。表格也是重灾区,|数量对不齐、表头分隔行少了冒号,渲染出来就乱套。
我的做法是在内容校验脚本里加一条:检查所有表格的行列数是否一致。虽然不能覆盖所有渲染差异,但能挡住大部分低级错误。
5.3 图片路径在本地和 CI 下不一致
本地写./images/a.png,CI 里工作目录变了,路径就失效。更隐蔽的是大小写问题,本地 macOS 不区分大小写,CI 的 Linux 区分,Images/a.png和images/a.png在本地都能找到,CI 上就 404。校验脚本里统一做resolve()和存在性检查,能提前发现。
5.4 搜索索引没包含中文
MkDocs 的搜索插件默认对中文分词支持一般,如果没配separator或没装中文分词库,搜索索引里可能全是单字,搜“发布流程”搜不到。验收脚本里检查search_index.json是否包含完整中文词条,能挡住这个问题。
5.5 常见问题速查表
| 现象 | 可能原因 | 排查手段 |
|---|---|---|
| CI 绿但公式不显示 | 插件未引入 JS | 检查.arithmatex元素数量 |
| 图片 404 | 路径大小写或相对路径错误 | 内容校验脚本检查文件存在性 |
| 搜索搜不到中文 | 分词配置缺失 | 检查 search_index.json 词条 |
| 版本切换器不显示 | 版本插件未配置 | 检查.md-version元素 |
| 构建有警告但绿 | 未加--strict | 改用mkdocs build --strict |
| 表格渲染错乱 | 分隔行格式错误 | 校验表格行列一致性 |
6. 让 AI 真正帮上忙的提示词写法
6.1 把验收清单写进提示词
AI 不是读心术,你不告诉它验收标准,它就只能给你通用模板。我现在的提示词结构是这样的:
我要给一个 MkDocs 文档站配置 GitHub Actions 发布流程。验收标准如下:1)构建产物包含版本切换器元素;2)搜索索引包含中文词条;3)数学公式能渲染;4)所有 Markdown 图片路径有效。请生成包含内容校验、构建、验收三层结构的 workflow,并在验收层加入对应的断言检查脚本。
这样生成的配置,从一开始就带着验收意识,而不是等你事后补。
6.2 让 AI 做“遗漏检查”
配置写完之后,把 workflow 和验收清单一起丢给 AI,问它:“这份配置覆盖了清单里的哪些项,哪些项没有覆盖,没覆盖的项应该怎么加检查。”AI 在对照检查这件事上表现不错,能帮你发现盲区。
6.3 让 AI 生成校验脚本而不是只生成配置
很多人只让 AI 生成 YAML,其实校验脚本才是验收的关键。让 AI 生成 Python 校验脚本,明确告诉它要检查哪些元素、哪些文件、哪些字段。脚本生成后你自己 review 一遍逻辑,跑一遍确认能抓到问题,再放进流水线。
7. 我个人的几条实操心得
第一条,CI 绿不等于需求绿,这两件事必须分开验证。每次配置完流水线,我都会拿验收清单逐条对照,确认每条都有对应的检查步骤。没有对应步骤的,要么补检查,要么在验收会上明确说明“这条靠人工验证”。
第二条,内容校验脚本要早写。不要等出了问题再补,一开始就把图片路径、公式配对、表格一致性这些检查加上。脚本写一次,后面所有提交都受益。
第三条,--strict参数能救命。MkDocs 的警告里藏着大量内容问题,加上这个参数,很多问题在构建阶段就暴露了,不用等到验收。
第四条,AI 生成的配置一定要自己过一遍。不是不信任 AI,而是 AI 不知道你的隐性需求。它给的是通用解,你要把它改造成你的专属解。
第五条,验收脚本的报错信息要写清楚。不要只报“验收失败”,要报“版本切换器元素缺失,检查 mkdocs.yml 的 version 插件配置”。报错信息越具体,排查越快。
这套流程跑下来,我现在配置文档站发布的时间大概在半小时以内,而且验收会上基本不会被卡。核心不是 AI 有多强,而是你把验收标准翻译成了 AI 能执行、CI 能验证的东西。CI 绿和需求绿之间的那道沟,靠的就是这份翻译工作来填平。