1. 为什么我决定让代码来写 PRD
做后端和业务中台的朋友大概率都经历过这种场面:需求评审会上产品经理讲得眉飞色舞,开发在下面疯狂记笔记,等到真正动手写代码的时候,发现当初记的那几条规则根本对不上——字段的边界条件没写清楚,状态流转的触发时机含糊其辞,异常分支更是全靠脑补。最后代码写完了,PRD 还停留在某个共享文档的初稿状态,谁也不敢说这份文档和线上跑的逻辑是一致的。
我所在的团队做的是偏交易和结算方向的系统,业务规则密集、状态机复杂,一个订单从创建到结算要经过十几个状态节点,每个节点都有各自的校验条件和触发动作。这种场景下,PRD 和代码脱节带来的代价特别高:改一个规则要翻三四个文档,新人接手要花两周才能理清主流程,测试同学写用例全靠对着代码反推。我一直在想,能不能让代码本身成为 PRD 的源头,而不是让 PRD 和代码各说各话。
这个想法在接触到 AI Agent 的 Skill 机制之后变得可行了。所谓 Skill,你可以理解成给 AI Agent 装的一个"专业技能包"——它把某类任务的输入格式、处理逻辑、输出规范封装在一起,Agent 调用这个 Skill 就能稳定地完成特定工作。我设计并落地了两个 Skill:一个负责从代码里抽取业务规则,另一个负责把规则渲染成结构化的 PRD 文档。两个 Skill 串起来,就实现了"代码自己写出 PRD"这件事。
这篇文章我会把整套方案的来龙去脉讲清楚:为什么选 Skill 而不是直接写脚本、两个 Skill 各自怎么设计、业务规则怎么从代码里被识别出来、生成的 PRD 怎么保证可追溯、以及我在实操中踩过的那些坑。如果你也在做 AI Agent 相关的开发,或者被 PRD 和代码不一致的问题折磨过,这篇内容应该能给你一些可以直接抄作业的思路。
2. 把业务规则从代码里"捞"出来的第一个 Skill
2.1 业务规则到底藏在代码的哪些角落
在动手写 Skill 之前,我先花了两天时间做了一件事:把现有代码里承载业务规则的地方全部梳理一遍。这个梳理过程比我想象中重要得多,因为它直接决定了 Skill 的输入设计。
以我们系统的 Python 代码为例,业务规则主要分布在这么几个位置。第一类是校验函数,比如validate_order_amount、check_settlement_cycle这种,函数名本身就带着业务语义,函数体里是一堆 if-else 判断。第二类是状态机的转移表,通常是一个字典或者枚举,定义了"从哪个状态可以到哪个状态、触发条件是什么"。第三类是配置化的规则,比如费率表、限额表,这些以常量或配置文件的形式存在。第四类是注释和 docstring,很多老代码里,真正的业务意图其实写在注释里,代码只是实现手段。
这四类位置的信息密度和结构化程度完全不同。校验函数和状态机是结构化的,适合程序化抽取;配置化规则需要结合上下文理解;注释和 docstring 则是非结构化的自然语言,恰恰是 AI 最擅长处理的部分。所以我的第一个 Skill 设计思路就是:用程序化手段抽取结构化部分,用 AI 理解非结构化部分,两者合并成完整的业务规则集。
这里有个经验:不要一上来就想让 AI 读全部代码。代码量一大,上下文窗口根本放不下,而且大量与业务无关的工具代码会稀释 AI 的注意力。先做人工梳理,圈定"业务规则密集区",再让 Skill 聚焦处理这些区域,效果会好很多。
2.2 Skill 的输入契约设计:给 AI 划定工作边界
Skill 设计里最关键的一步是定义输入契约。我见过很多 AI Agent 项目失败,就是因为输入太随意,Agent 每次拿到的信息格式都不一样,输出自然不稳定。
我的第一个 Skill 叫rule_extractor,它的输入契约是这样的:
{ "source_files": [ { "path": "order/validators.py", "content": "...", "language": "python" } ], "rule_scope": "order_lifecycle", "extraction_dimensions": [ "validation_rules", "state_transitions", "config_constraints", "business_intents" ] }source_files是要分析的代码文件列表,每个文件带上路径、内容和语言类型。rule_scope是规则范围,用来告诉 Skill 这次关注的是哪个业务域,避免它去分析无关代码。extraction_dimensions是抽取维度,明确要求 Skill 从哪几个角度去提取规则。
这个契约设计背后有个考量:AI Agent 的输出质量,很大程度上取决于输入约束的清晰度。你告诉它"帮我分析这段代码",它会给你一堆泛泛而谈的总结;你告诉它"从校验规则、状态转移、配置约束、业务意图四个维度分析,每个维度输出结构化 JSON",它就能给出可用的结果。
2.3 抽取逻辑的三层处理管线
rule_extractor内部的处理逻辑我设计成了三层管线,这个分层是踩过坑之后才定下来的。
第一层是语法层解析。用 Python 自带的ast模块把代码解析成抽象语法树,然后遍历树节点,识别出函数定义、条件判断、字典字面量这些结构。这一层完全是确定性的,不涉及 AI,目的是把代码的骨架先提取出来。比如遇到一个函数里有连续的 if-elif-else,语法层就能定位到这些分支的位置和条件表达式。
第二层是语义层理解。把语法层提取出的结构,连同原始代码片段一起送给 AI,让 AI 判断"这段逻辑对应的是什么业务规则"。举个例子,代码里写if order.amount > 10000 and order.type == 'B2B',语法层只能告诉你这是个条件判断,语义层要理解出"B2B 订单金额超过一万元时需要特殊处理"这条业务规则。
第三层是关联层整合。把语义层输出的零散规则,按照业务实体和流程节点做关联整合。比如"订单创建时的金额校验"和"订单结算时的金额校验"可能来自不同文件,但它们属于同一个业务实体的不同生命周期阶段,关联层要把它们串起来。
# 语法层解析的核心逻辑示意 import ast def extract_structural_elements(source_code): tree = ast.parse(source_code) elements = [] for node in ast.walk(tree): if isinstance(node, ast.FunctionDef): elements.append({ "type": "function", "name": node.name, "lineno": node.lineno, "docstring": ast.get_docstring(node) }) elif isinstance(node, ast.If): elements.append({ "type": "condition", "lineno": node.lineno, "test": ast.unparse(node.test) }) return elements这三层管线的价值在于:把确定性工作和不确定性工作分开。语法解析交给程序,保证准确;语义理解交给 AI,发挥它的长处;关联整合再用程序做规则化的拼接。这样整个 Skill 的输出既稳定又灵活。
2.4 让 AI 稳定输出结构化规则的提示词技巧
语义层是整个 Skill 里最不确定的部分,因为 AI 的输出质量波动很大。我试了好几版提示词,最后总结出几个关键技巧。
第一个技巧是用 JSON Schema 约束输出格式。不要只说"输出 JSON",而是把完整的 schema 写进提示词里,包括每个字段的类型、含义、示例值。AI 看到具体的 schema,输出的结构就稳定多了。
第二个技巧是给 few-shot 示例。我在提示词里放了两三个"输入代码片段 → 输出规则 JSON"的完整示例,覆盖了校验规则、状态转移、配置约束三种典型情况。有了示例,AI 就知道该往哪个方向理解。
第三个技巧是要求 AI 标注置信度和来源。每条规则都要带上confidence字段(high/medium/low)和source_location字段(文件路径加行号)。置信度低的规则我会人工复核,来源信息则是后面做可追溯的基础。
{ "rule_id": "order_amount_b2b_threshold", "rule_type": "validation", "description": "B2B 类型订单金额超过 10000 元时触发人工审核", "condition": "order.type == 'B2B' AND order.amount > 10000", "action": "trigger_manual_review", "confidence": "high", "source_location": "order/validators.py:45-52" }这套提示词技巧用下来,AI 输出的规则准确率从最初的六成左右提升到了九成以上。剩下的那一成,主要靠置信度标注筛出来人工处理。
3. 第二个 Skill:把规则渲染成可追溯的 PRD
3.1 PRD 模板的骨架怎么定
第一个 Skill 输出的是结构化的规则 JSON,第二个 Skill 的任务是把它变成人读得懂的 PRD。这里有个设计决策:PRD 的模板骨架是固定的还是动态生成的?
我一开始想做成动态生成,让 AI 根据规则内容自己决定文档结构。试了一版之后发现不行,生成的文档每次结构都不一样,产品经理和测试同学根本没法形成阅读习惯。后来改成固定骨架加动态填充:文档的章节结构是固定的,但每个章节里的内容根据规则动态生成。
固定骨架长这样:文档概述、业务实体说明、状态流转图、规则明细表、异常处理、变更记录。这个骨架覆盖了 PRD 的核心要素,而且和大多数团队的 PRD 阅读习惯吻合。
这里有个容易忽略的点:PRD 的读者不只是产品经理,还有开发、测试、运营。不同角色关注的点不一样。开发关注规则的技术实现细节,测试关注边界条件和异常分支,运营关注业务影响。所以我在规则明细表里加了"影响角色"字段,标注每条规则主要影响哪些角色,方便不同读者快速定位自己关心的部分。
3.2 规则到文档段落的映射逻辑
从规则 JSON 到 PRD 段落,中间需要一个映射逻辑。这个映射不是简单的一对一,而是要根据规则的类型和关联关系做聚合。
校验类规则聚合成"规则明细表"里的行,每条规则一行,列出规则 ID、描述、条件、动作、来源。状态转移类规则聚合成"状态流转图"和配套的转移说明表。配置约束类规则单独成节,因为这类规则通常需要结合具体的配置值来说明。业务意图类规则则融入"文档概述"和各个章节的说明文字里,作为背景信息。
映射逻辑里有个细节值得说:规则的排序。我最初按规则 ID 排序,结果文档读起来很跳跃。后来改成按业务生命周期排序——订单创建的规则在前,支付、发货、结算的规则依次往后。这样读文档就像跟着业务流程走一遍,理解成本低很多。
def map_rules_to_sections(rules, template): sections = {} # 按业务生命周期阶段分组 lifecycle_order = ["creation", "payment", "fulfillment", "settlement"] grouped = group_by_lifecycle(rules, lifecycle_order) for stage, stage_rules in grouped.items(): sections[stage] = { "validation_rules": [r for r in stage_rules if r["rule_type"] == "validation"], "state_transitions": [r for r in stage_rules if r["rule_type"] == "transition"], "config_constraints": [r for r in stage_rules if r["rule_type"] == "config"] } return sections3.3 可追溯性的三个锚点
"可追溯"是这个方案的核心卖点,也是我在设计时最花心思的地方。可追溯意味着从 PRD 里的任何一条规则,都能追溯到它在代码里的来源;反过来,代码改动之后,也能定位到 PRD 里哪些内容需要更新。
我设计了三个追溯锚点。第一个是规则 ID,每条规则有唯一 ID,这个 ID 在规则 JSON 和 PRD 文档里保持一致。第二个是代码位置,每条规则记录它在源代码里的文件路径和行号范围。第三个是版本指纹,每次生成 PRD 时记录当时代码的 commit hash,这样能知道这份 PRD 对应的是哪个版本的代码。
这三个锚点组合起来,追溯链路就完整了:PRD 里的规则 ID → 规则 JSON 里的 source_location → 源代码的具体行 → 对应版本的 commit。任何一环出问题,都能快速定位。
{ "prd_metadata": { "generated_at": "2025-01-15T10:30:00Z", "source_commit": "a3f8c2d", "rule_count": 47, "traceability_index": { "order_amount_b2b_threshold": { "file": "order/validators.py", "lines": "45-52", "commit": "a3f8c2d" } } } }3.4 生成结果的校验与人工复核环节
AI 生成的东西不能直接信,这是我在多个项目里反复验证过的教训。所以第二个 Skill 的输出必须经过校验环节。
自动校验做三件事:检查规则 JSON 的完整性(有没有缺字段)、检查 PRD 文档的结构(章节是否齐全)、检查追溯锚点的一致性(规则 ID 在两边是否对得上)。这三项校验都是程序化的,能拦住大部分低级错误。
人工复核则聚焦在内容质量上。我会让产品经理重点看规则描述是否准确、业务意图是否理解到位;让测试同学重点看边界条件和异常分支是否完整。复核发现的问题,反馈回去调整提示词或者补充 few-shot 示例,让 Skill 下一轮生成得更好。
这个"自动校验加人工复核"的闭环,是保证 PRD 质量的关键。纯自动生成适合做初稿,但最终定稿一定要有人把关。
4. 两个 Skill 串起来之后的实际运行效果
4.1 一次完整的生成流程演示
说了这么多设计,来看一次实际的运行流程。假设我们刚改完订单模块的代码,需要更新 PRD。
第一步,触发rule_extractorSkill。输入是订单模块的几个核心文件:validators.py、state_machine.py、config.py。Skill 跑完输出一份规则 JSON,包含 47 条规则,其中校验规则 23 条、状态转移 12 条、配置约束 8 条、业务意图 4 条。
第二步,人工快速过一遍规则 JSON。重点看置信度标注为 medium 和 low 的规则,这次有 5 条需要复核,其中 2 条 AI 理解有偏差,手动修正。
第三步,触发prd_rendererSkill。输入是修正后的规则 JSON 和 PRD 模板配置。Skill 输出一份完整的 PRD 文档,Markdown 格式,包含所有章节和追溯信息。
第四步,自动校验加人工复核。自动校验通过,人工复核发现状态流转图里少了一个异常分支,补充之后重新生成。
整个流程走下来,从代码改动到 PRD 更新,大概花了四十分钟。对比之前纯手工写 PRD 动辄半天的效率,提升还是很明显的。
4.2 生成质量的数据观察
跑了一个多月,积累了二十多次生成记录,我统计了一下质量数据。
规则抽取的准确率,按置信度分层看:high 置信度的规则准确率在 96% 左右,medium 在 82% 左右,low 在 60% 左右。这个分布符合预期,也验证了置信度标注的有效性——它确实能把不确定的规则筛出来。
PRD 文档的可用性,我让产品经理和测试同学做了主观评分。结构完整性评分 4.5/5,内容准确性评分 4.2/5,可读性评分 4.0/5。扣分主要在可读性上,AI 生成的文字有时候还是偏机械,需要人工润色。
追溯功能的实际使用频率超出我预期。代码 review 的时候,开发会直接查 PRD 里的规则来源,确认改动影响范围。测试写用例的时候,也会顺着追溯链路去看代码实现,理解边界条件。这个功能成了整个方案里被使用最多的部分。
4.3 哪些场景下这套方案特别香
用下来,这套方案在几类场景下价值特别突出。
业务规则密集且频繁变更的系统。比如交易、结算、风控这类系统,规则多、改得勤,手工维护 PRD 根本跟不上。用 Skill 自动生成,每次代码改动后重新跑一遍,PRD 始终和代码同步。
多人协作、交接频繁的团队。新人接手项目,最痛苦的就是理不清业务规则。有了可追溯的 PRD,新人可以顺着规则来源去看代码,理解速度快很多。
需要审计和合规的场景。有些业务需要证明"系统行为符合业务规则",可追溯的 PRD 就是最好的证据。每条规则都能追到代码,每个代码改动都能追到 PRD 更新记录。
反过来,如果业务规则很简单、变更很少,或者团队规模很小、沟通成本本来就低,这套方案的投入产出比就没那么高。工具要匹配场景,不能为了用而用。
5. 实操中踩过的坑和对应的解法
5.1 AI 把工具代码误判成业务规则
这是最早踩的坑。rule_extractor第一次跑的时候,把日志打印、参数格式化这些工具代码也当成业务规则抽出来了,输出里混了一堆"记录订单日志""格式化金额显示"这种根本不是业务规则的东西。
根因是 Skill 没有区分"业务代码"和"工具代码"。解法是在输入契约里加了rule_scope字段,并且在提示词里明确说明"只抽取与业务逻辑相关的规则,忽略日志、格式化、序列化等工具性代码"。同时,语法层解析的时候加了一个过滤规则:函数名里包含log、format、serialize、parse这类关键词的,直接跳过。
这个坑的教训是:AI 不会自动区分什么重要什么不重要,你得明确告诉它。输入契约里的 scope 定义,比事后过滤有效得多。
5.2 状态转移规则抽取不完整
状态机是我们系统的核心,但rule_extractor一开始抽出来的状态转移规则总是缺几条。排查发现,状态转移的定义方式有好几种:有的是字典字面量,有的是枚举类,有的是数据库配置。Skill 只识别了字典字面量这一种。
解法是扩展语法层的识别逻辑,把枚举类和数据库配置也纳入解析范围。枚举类通过ast识别Enum子类,数据库配置则通过读取配置文件来获取。同时,在提示词里补充了这几种定义方式的 few-shot 示例,让 AI 知道状态转移可能以多种形式出现。
这个坑提醒我:代码里的同一种业务概念,可能有多种实现形式。设计 Skill 的时候,要把这些形式都考虑到,否则抽取结果就是残缺的。
5.3 生成的 PRD 里规则描述太技术化
第一版生成的 PRD,规则描述写得很技术化,比如"当 order.type 字段值为 B2B 且 order.amount 字段值大于 10000 时,调用 manual_review 服务"。产品经理看了直摇头,说这不是 PRD,这是代码注释。
根因是提示词里没有强调"面向业务读者"这个要求。解法是在prd_renderer的提示词里加了明确的角色设定:"你是一个资深产品经理,面向业务读者撰写 PRD,避免使用代码变量名和技术术语,用业务语言描述规则"。
改完之后,同样的规则被描述成"B2B 类型订单金额超过一万元时,系统自动提交人工审核"。这个描述产品经理和运营都能看懂。
5.4 追溯锚点在代码重构后失效
代码重构是常态,但重构之后行号会变,追溯锚点里的行号就对不上了。这个问题困扰了我一阵子。
解法是把追溯锚点从"行号"改成"函数名加规则特征"。行号会变,但函数名相对稳定,规则特征(比如条件表达式的关键部分)也不容易变。追溯的时候,先用函数名定位到函数,再用规则特征在函数内定位具体位置。这样即使代码重构,追溯链路也不会断。
def resolve_traceability(anchor, source_code): # 先用函数名定位 func_node = find_function(source_code, anchor["function_name"]) if not func_node: return None # 再用规则特征在函数内定位 for node in ast.walk(func_node): if matches_feature(node, anchor["rule_feature"]): return node.lineno return None5.5 大文件处理时的上下文超限
有个核心业务文件有三千多行,直接塞给 AI 会超出上下文窗口。解法是分块处理:先按函数边界把文件切成多个块,每块单独送给 AI 分析,最后把结果合并。分块的时候要注意保持函数的完整性,不能把一个函数从中间切开。
分块处理还带来一个额外好处:可以并行处理多个块,速度更快。我用 Python 的concurrent.futures做了并行化,三千行的文件处理时间从原来的三分钟降到了四十秒左右。
6. 关于 Skill 设计和 AI Agent 落地的一些个人体会
这套方案跑下来,我对 AI Agent 的 Skill 设计有了些更具体的认识,分享几条我觉得最有价值的。
Skill 的边界要清晰,职责要单一。我一开始想把抽取和渲染做成一个 Skill,结果提示词越写越长,AI 的输出越来越不稳定。拆成两个 Skill 之后,每个 Skill 的提示词都短了很多,输出质量反而上去了。一个 Skill 只做一件事,做好一件事,这个原则在 AI Agent 开发里同样适用。
确定性工作交给程序,不确定性工作交给 AI。这是我在整个方案里贯彻最彻底的一条原则。语法解析、格式校验、追溯锚点管理,这些都是确定性的,用程序做又快又准。语义理解、自然语言生成,这些是不确定性的,交给 AI。两者结合,才能既稳定又灵活。
输入契约的设计比提示词技巧更重要。我花在输入契约设计上的时间,比花在提示词调优上的时间多得多。事实证明这个投入是值得的。清晰的输入契约能让 AI 的输出质量提升一个档次,而且更稳定。
人工复核环节不能省。AI 生成的内容,无论准确率多高,都需要人工把关。这不是对 AI 不信任,而是对业务负责。我的做法是把人工复核聚焦在 AI 不确定的部分(低置信度规则)和高风险部分(核心业务规则),这样既保证了质量,又控制了人工成本。
可追溯性是 AI 生成内容可信度的基石。AI 生成的东西,最怕的就是"不知道它从哪来、为什么这么写"。有了可追溯性,每一条生成内容都能找到来源和依据,可信度就上来了。这个思路不仅适用于 PRD 生成,任何 AI 生成内容的场景都值得借鉴。
最后说个实际的:这套方案我目前只在订单和结算两个模块落地了,其他模块还在逐步推广。推广过程中最大的阻力不是技术,而是习惯——大家习惯了手工写 PRD,对 AI 生成的东西有天然的不信任。我的做法是先在小范围跑通,用实际效果说话,等大家看到效率提升和追溯带来的便利,接受度自然就上来了。技术方案落地,从来都不只是技术问题。