一个没有专职产品经理的小团队,怎么保证文档不掉队
Flashduty 的值班管理有个功能叫「公平轮换」。开启后,系统会自动调整排班顺序,避免同一个人总是轮到周末值班。前端代码长这样:
<div className='flex items-center'>
{t('Fair Rotation')}
<Tooltip>
The system automatically adjusts rotation order to ensure
each member gets on-call shifts across different time periods.
</Tooltip>
</div>
<Form.Item name='fair_rotation' valuePropName='checked'>
<Switch size='small' />
</Form.Item>
功能做得很用心,前后端都实现了,上线了,跑在生产环境里,用户也在用。
但文档里一个字都没有。
除非你恰好在编辑轮换规则时注意到一个不起眼的开关,否则你根本不知道这个功能存在。这就是文档漂移的样子:不是灾难性事故,只是一个接一个的小缺口,最后让用户不再相信文档。
我们没有继续催工程师补文档,而是让 agent 每周把漂移变成可审核的 PR。
为什么文档总是跟不上
我们在做 AI 客服。这个 AI 靠读文档来回答用户问题。文档有缺漏,AI 就答不上来;文档有错误,AI 就答错。以前文档质量主要影响人类读者:凌晨三点被告警吵醒的工程师翻文档查问题,找不到就骂两句。现在它直接决定 AI 客服的回答质量。垃圾文档进去,垃圾回答出来。
问题是,没人写文档。
Flashduty 没有专职产品经理。工程师就是产品经理:分析需求、写 PRD、开发、测试、部署、处理客户反馈,全是同一拨人。没有人的岗位职责里写着「确保文档同步更新」。花了两周做出公平轮换的人,不想再花一天写文档说明;他想做的是下一个功能。于是文档就不写了。答案散落在飞书、企微、钉钉的聊天记录里,始终没进文档。
我们的规模不算小:12 个产品模块、20 多个微服务、中英双语文档、几百个页面。每一个合入的 PR 都可能悄悄让其中某条描述变成错误的。手动审查理论上可以做,实际上从来没人做。
局面很清楚:工程师不想写文档,用户需要文档,AI 客服的质量完全取决于文档。靠「请大家注意更新文档」解决不了问题。既然人靠不住,那就不靠人了。
我们造了什么
我们做了一个 Claude Code skill,一个可复用的 AI agent。工程师敲一条命令就能跑,也可以挂定时任务自动跑。
核心设计思路:一个 YAML 映射文件,把每个文档页面和背后的源码路径对应起来。agent 之所以知道去哪里找,是因为我们告诉了它哪段代码对应哪篇文档。没有这个映射,它要么搜索范围太大(淹没在无关的内部代码里),要么漏掉关键变更。
flowchart TD
T1["代码推送 / 定时任务"] --> SCAN["扫描源码仓库"]
T2["手动触发"] --> SCAN
SCAN --> DIFF{"模式?"}
DIFF -- "diff" --> GD["读取 git diff\n识别新路由、开关、默认值"]
DIFF -- "audit" --> WF["遍历前端代码\n盘点所有功能"]
GD --> XREF["与文档交叉比对"]
WF --> XREF
XREF --> FIND["findings.yaml"]
FIND --> AUTO{"自动模式?"}
AUTO -- 否 --> HUMAN["工程师审核\n去除误报"]
HUMAN --> FIX
AUTO -- 是 --> FIX["读取源码\n生成文档(中 + 英)"]
FIX --> PR["提交 PR"]
PR --> REVIEW["工程师审核内容"]
REVIEW --> MERGE["合并"]
两种模式:
Diff 模式问的是「最近两周改了什么?」agent 读取所有关联仓库的 git diff,找文档相关的信号:
- 新增的 API 路由或接口
- 新增的 UI 开关或表单字段
- 变更的默认值或校验规则
- 删除或重命名的功能
每个信号都会和现有文档交叉比对。已经有文档覆盖的跳过,没有的就记录为一个发现。适合日常维护:在漂移堆积之前把它抓住。
Audit 模式问的是「所有功能都有文档吗?」这个更彻底。它先遍历前端代码,盘点每一个用户可见的功能:页面、表单字段、开关、下拉选项。然后逐一检查文档覆盖情况。
为什么从前端入手?因为前端是产品能力的诚实呈现。后端有内部接口、预留字段、客户定制逻辑、UI 上根本不会展示的保留枚举值。前端展示的,才是用户能看到和操作的。
Audit 模式还会做准确性检查:从现有文档里提取可机械验证的事实,比如字段名、默认值、导航路径和校验规则,再逐一和代码比对。文档里说轮换周期支持「天、周、自定义」,代码里支持的是小时、天、周、月。这就是一个发现。
两种模式都会输出一份结构化的发现文件。然后进入修复阶段:agent 读取每个发现对应的源码,生成中英双语的完整文档,包括段落、表格和配置步骤,然后提交 PR。没有占位符,也没有 TODO。工程师审核内容后合并。
我们发现了什么
先说全貌:跑完 diff + audit 两种模式后,总共产出 20 个 PR,超过 9000 行新文档,覆盖 370 多个文件,数百个发现。
第一次跑的是 diff 模式:/doc-review --mode diff --since "1 month"。它只看最近一个月的代码变更,得到了这个 PR。光这一次就揪出 21 个缺口,33 个文件变更,两种语言共新增超过一千行文档。以下是其中几个典型的:
| 发现 | 具体情况 |
|---|---|
| 公平轮换 | 文章开头的故事。功能完整,文档为零。 |
| 权限体系 | 从扁平权限改成了基于作用域的权限,文档还是老版本。 |
| Nagios 集成 | 整个集成已在生产环境运行,文档没有。 |
| 团队管理 | 团队详情页里添加成员、移除成员、退出团队这些操作完全没有文档。 |
| RUM Source Maps | Android ProGuard 和 iOS dSYM 的上传流程,上线好几个月了,从没写过。 |
| 协作空间导航 | UI 从 Tab 页切换成了侧边栏,文档还在描述旧布局。 |
这些都不是冷门功能。它们是真实用户在文档里找不到的真实功能。
21 个缺口已经让我们吃惊了。然后跑了 audit 模式,对全量前端代码做功能盘点。结果是 21 的十几倍。这让我们下定决心,把它从一次性清理变成每周例行运行。
自己动手做一个
不用从零开始写。Claude Code 有一个 skill-creator,可以根据描述生成 skill。下面是一个能用的 prompt 模板:
/skill-creator Create a doc-review skill that cross-references
source code against documentation to find documentation drift.
Context:
- Docs repo: company-docs (Docusaurus, English only)
- Source repos: billing-service (Go), web-app (React), api-gateway (Go)
- Docs structure: docs/ with subdirectories per product area
- Key concern: new features ship without doc updates
The skill should have two modes plus a fix phase:
1. Diff mode: scan recent git changes for doc-relevant signals
2. Audit mode: walk frontend code to inventory features, check coverage
After either mode, a fix phase generates complete documentation and opens a PR.
skill-creator 会帮你生成映射配置、prompt 和整体串联逻辑。搭出框架很快,大概一个小时。但调到好用需要迭代,我们大约调了四轮才把信噪比控制到满意的程度。关键在于你写进 prompt 的设计原则。以下是我们踩坑后总结出来的:
-
模块到仓库的映射。 一个 YAML 文件,把每个文档页面和对应的源码路径关联起来。没有这个,agent 要么被不相关的代码淹没,要么会遗漏关键变更。这是整套系统的骨架。
-
从前端入手盘点。 前端定义了用户可见的功能边界。后端有内部接口、预留字段、保留类型。从前端组件出发:页面、表单、开关、下拉框。后端代码只用来补充前端已经暴露出来的功能细节。
-
用产品经理的视角判断。 在 prompt 里写明:「像产品经理一样判断什么该写进公开文档。」只记录用户在生产环境中实际能操作的功能。跳过测试工具、调试面板、测试框架、内部管理功能、客户定制逻辑。
-
只检查可机械验证的事实。 检查字段名、默认值、API 路由、校验规则。不要试图验证行为描述类的文字;那需要人类判断,而且误报率很高。
-
前端是约束条件的权威来源。 后端说上限 100,但前端表单只允许填 50,用户看到的就是 50。文档该写 50。只有文档和前端矛盾时才记录为发现。
-
生成完整内容,不要占位符。 修复阶段必须读源码、写出完整文档:段落、表格、配置详情都要有。审核者的工作是润色文字,不是填空。这是「有用的 PR」和「一堆 TODO」的区别。
-
两阶段流程加人工关卡。 分析 → 发现文件 → 人工去除误报 → 修复。发现文件是两个阶段之间的检查点。信噪比调到满意后,可以用
--auto跳过发现审核环节,但最终的 PR 仍然由人审核后才合并。
第一次跑出来肯定比较乱。先用 --dry-run 看看发现列表,调整 prompt。用 skill-creator 来迭代:把出了什么问题喂给它,让它优化 prompt 和映射配置。
调好之后就可以自动化了。我们用 cron 定时任务每周跑一次 diff 模式,有发现就自动提 PR。工程师只需要审核 PR。检测、撰写、提交都由系统完成。
我们学到了什么
文档漂移不能靠要求工程师变成更好的写手解决。有效的办法是把遗漏暴露出来,再给工程师一个内容完整的 PR。审核这样的 PR,五分钟的事。从零写一篇文档,半天起步,优先级永远排不上去。
我们本以为自己的文档还过得去,跑完才发现差得远。你的文档大概率也有类似规模的缺口,只是还没人去翻。
AI 擅长处理繁琐的部分:读几百个文件、交叉比对字段名、检查默认值是否和代码一致。它不擅长判断一个功能值不值得写进文档,也不擅长判断一句话会不会让用户困惑。PR 仍然需要工程师审核。我们去掉的是工程师最讨厌的那部分苦活。
一个实操建议:如果你的产品有 Web 界面,从前端代码开始扫,别从后端开始。我们前两轮迭代是后端优先,结果被一堆谁都不该写文档的内部工具淹没了。前端是天然的过滤器。如果你的产品是 API 优先、CLI 工具或 SDK,没有 UI,那就换个入口;API 路由定义或 CLI 命令注册是不错的起点。
下一步
公平轮换那个开关现在有文档了。数百个发现也都修好了。但这只是起点。
我们正在做两件事:一是把 diff 模式接入 CI,让代码合入时自动检测文档漂移,像跑测试一样跑文档检查,在缺口产生时就拦住它,而不是等每周定时扫描才发现。二是扩展检测范围到 API 文档。目前系统主要从前端入手,但我们的 Open API 也需要同样的覆盖率保障。
我们的文档在 docs.flashduty.com。现在工程师审核文档 PR,不再从零写文档。对我们有效的路径很简单:一个小时搭框架,四轮迭代调好,之后每周花五分钟审一次 PR。


