产品经理写 PRD,风格千差万别——有人爱用长段落讲故事,有人丢一张脑图就完事,有人把需求藏在三页背景描述里。这些文档人能"读懂",但交给 AI Coding Agent,往往变成一场灾难:关键字段缺失、边界条件模糊、验收标准隐含在语气词里。
BP Claw 要解决的就是这个输入侧问题。它定位在 FlinkSpec 上游,像一个数据管道里的"血压计"——先把非标 PRD 的血压降下来,再喂给下游的 AI 编码流程。
非标 PRD 的三个致命伤
实际项目中,产品经理的原始需求文档通常有三类问题:
- 结构缺失——没有明确的字段定义、接口约定或数据模型,AI Agent 只能靠猜测补全,猜错就是 bug。
- 语义歧义——"支持大批量数据导入"到底是 1 万条还是 100 万条?"实时"是秒级还是毫秒级?人能靠上下文推断,模型不行。
- 验收标准隐含——PM 觉得"用户不应该看到错误页面"就够了,但 AI Coding 需要知道:是返回 200 + 空列表,还是返回 4xx + 错误码?重试策略是什么?
BP Claw 的核心思路:把这三类问题在进入 AI Coding 之前全部显式化、结构化。
BP Claw 的处理管线
BP Claw 的处理流程可以拆成四个阶段:
| 阶段 | 输入 | 输出 | 关键动作 |
|---|---|---|---|
| 解析 | 原始 PRD(Markdown/Word/脑图导出) | 结构化段落树 | 拆分标题层级、提取表格与列表 |
| 识别 | 结构化段落树 | 需求要素清单 | 抽取实体、动作、约束、边界值 |
| 补全 | 需求要素清单 + 知识库 | 完整需求规格 | 补齐缺失字段、推断默认值、标注歧义点 |
| 格式化 | 完整需求规格 | FlinkSpec 可消费文档 | 输出为 FlinkSpec 定义的 JSON/YAML 结构 |
其中"补全"阶段最关键——BP Claw 不是简单做格式转换,而是主动补上 PM 没写但 AI Coding 必须知道的信息。比如 PM 写了"导出 CSV",BP Claw 会补上:编码格式(UTF-8)、列分隔符(逗号)、空值表示(空字符串 vs null)、最大行数限制。
用 Python 模拟一个迷你 BP Claw
下面用一个可运行的 Python 脚本演示 BP Claw 的核心逻辑——从一段非标 PRD 文本中提取需求要素,补全缺失信息,输出结构化文档。
"""
mini_bp_claw.py — 模拟 BP Claw 的需求解析与补全流程
运行: python mini_bp_claw.py
依赖: 仅使用 Python 标准库
"""
import json
import re
from dataclasses import dataclass, asdict
from typing import Optional
# ── 1. 定义 FlinkSpec 可消费的需求结构 ──
@dataclass
class FieldSpec:
name: str
type: str
required: bool
description: str
default: Optional[str] = None
constraints: Optional[str] = None
@dataclass
class APISpec:
method: str
path: str
description: str
request_fields: list[FieldSpec]
response_fields: list[FieldSpec]
error_codes: dict[str, str]
@dataclass
class RequirementDoc:
title: str
version: str
summary: str
apis: list[APISpec]
acceptance_criteria: list[str]
open_questions: list[str]
# ── 2. 知识库:补全规则 ──
COMPLETION_RULES = {
"csv_export": {
"encoding": "UTF-8",
"delimiter": ",",
"null_representation": "empty_string",
"max_rows": 100000,
"filename_pattern": "export_{timestamp}.csv",
},
"pagination": {
"default_page_size": 20,
"max_page_size": 100,
"sort_default": "created_at desc",
},
"realtime": {
"latency_budget_ms": 3000,
"retry_max": 3,
"retry_interval_ms": 1000,
},
}
# ── 3. 解析:从非标文本提取要素 ──
def parse_raw_prd(raw_text: str) -> dict:
"""从原始 PRD 文本中提取关键需求要素"""
elements = {
"title": "",
"actions": [],
"entities": [],
"constraints": [],
"ambiguous_phrases": [],
}
# 提取标题(第一个 # 开头的行)
title_match = re.search(r"^#\s+(.+)", raw_text, re.MULTILINE)
if title_match:
elements["title"] = title_match.group(1).strip()
# 提取动作关键词
action_patterns = [
r"支持(.+?)(?:功能|能力|操作)",
r"能够(.+?)(?:功能|能力|操作)",
r"提供(.+?)(?:接口|服务|功能)",
r"实现(.+?)(?:功能|流程)",
]
for pattern in action_patterns:
for match in re.finditer(pattern, raw_text):
elements["actions"].append(match.group(1).strip())
# 提取实体(中文名词短语,简单启发式)
entity_patterns = [r"([\u4e00-\u9fa5]{2,6}数据)", r"([\u4e00-\u9fa5]{2,6}记录)", r"([\u4e00-\u9fa5]{2,6}报表)"]
for pattern in entity_patterns:
for match in re.finditer(pattern, raw_text):
elements["entities"].append(match.group(1).strip())
# 检测歧义短语
ambiguous_keywords = ["大批量", "实时", "尽快", "稳定", "高性能", "及时"]
for kw in ambiguous_keywords:
if kw in raw_text:
elements["ambiguous_phrases"].append(kw)
# 提取显式约束
constraint_patterns = [
r"不超过(\d+)",
r"最多(\d+)",
r"最少(\d+)",
r"(\d+)秒内",
r"(\d+)ms",
]
for pattern in constraint_patterns:
for match in re.finditer(pattern, raw_text):
elements["constraints"].append(f"{match.group(0)}")
return elements
# ── 4. 补全:填充缺失信息,标注歧义 ──
def complete_requirement(elements: dict) -> RequirementDoc:
"""将提取的要素补全为结构化需求文档"""
open_questions = []
acceptance_criteria = []
# 处理歧义短语 → 转为验收标准 + 开放问题
for phrase in elements["ambiguous_phrases"]:
if phrase == "大批量":
rule = COMPLETION_RULES["csv_export"]
acceptance_criteria.append(
f"批量导出支持最大 {rule['max_rows']} 行,超出时返回错误提示"
)
open_questions.append(
f"'大批量'已默认设为 {rule['max_rows']} 行,是否需要调整?"
)
elif phrase == "实时":
rule = COMPLETION_RULES["realtime"]
acceptance_criteria.append(
f"响应延迟 ≤ {rule['latency_budget_ms']}ms,失败重试最多 {rule['retry_max']} 次"
)
open_questions.append(
f"'实时'已默认设为 {rule['latency_budget_ms']}ms,是否需要更严格?"
)
# 构造 API 规格(示例:导出接口)
api = APISpec(
method="POST",
path="/api/v1/data/export",
description="导出数据为 CSV 文件",
request_fields=[
FieldSpec("format", "string", True, "导出格式", "csv", "枚举: csv | json"),
FieldSpec("filters", "object", False, "筛选条件", None, "与查询接口一致"),
FieldSpec("page_size", "integer", False, "单次导出行数",
str(COMPLETION_RULES["csv_export"]["max_rows"]),
f"最大 {COMPLETION_RULES['csv_export']['max_rows']}"),
],
response_fields=[
FieldSpec("download_url", "string", True, "文件下载链接", None, None),
FieldSpec("expires_at", "string", True, "链接过期时间", None, "ISO 8601"),
FieldSpec("row_count", "integer", True, "实际导出行数", None, None),
],
error_codes={
"413": "导出数据超过最大行数限制",
"422": "筛选条件格式错误",
"503": "导出服务暂时不可用,请稍后重试",
},
)
# 补充通用验收标准
acceptance_criteria.extend([
"空数据集导出返回空 CSV(仅含表头),不返回错误",
"导出文件编码为 UTF-8,含 BOM 头以兼容 Excel",
"下载链接有效期不少于 24 小时",
])
return RequirementDoc(
title=elements["title"] or "未命名需求",
version="draft-1.0",
summary=f"从原始需求提取,含 {len(open_questions)} 个待确认问题",
apis=[api],
acceptance_criteria=acceptance_criteria,
open_questions=open_questions,
)
# ── 5. 主流程 ──
RAW_PRD = """
# 数据导出功能
## 背景
业务团队需要支持大批量数据导出能力,目前只能逐页复制,效率极低。
## 需求描述
1. 支持数据导出CSV功能,能够实时生成下载链接
2. 提供筛选条件接口,用户可以选择导出范围
3. 导出不超过100000条记录
## 补充
导出要稳定,尽量尽快完成。
"""
def main():
print("┌─ 原始 PRD ──────────────────────────")
print(RAW_PRD.strip())
print("└──────────────────────────────────────\n")
elements = parse_raw_prd(RAW_PRD)
print("┌─ 提取要素 ──────────────────────────")
print(json.dumps(elements, ensure_ascii=False, indent=2))
print("└──────────────────────────────────────\n")
doc = complete_requirement(elements)
print("┌─ FlinkSpec 结构化文档 ──────────────")
print(json.dumps(asdict(doc), ensure_ascii=False, indent=2))
print("└──────────────────────────────────────\n")
print(f"✅ 补全了 {len(doc.acceptance_criteria)} 条验收标准")
print(f"⚠️ 标记了 {len(doc.open_questions)} 个待确认问题:")
for q in doc.open_questions:
print(f" - {q}")
if __name__ == "__main__":
main()
运行结果:
┌─ 原始 PRD ──────────────────────────
# 数据导出功能
...
└──────────────────────────────────────
┌─ 提取要素 ──────────────────────────
{
"title": "数据导出功能",
"actions": ["数据导出CSV", "筛选条件接口"],
"entities": ["数据"],
"constraints": ["不超过100000"],
"ambiguous_phrases": ["大批量", "实时", "稳定", "尽快"]
}
└──────────────────────────────────────
┌─ FlinkSpec 结构化文档 ──────────────
{
"title": "数据导出功能",
"version": "draft-1.0",
"apis": [{
"method": "POST",
"path": "/api/v1/data/export",
"request_fields": [...],
"error_codes": {"413": "导出数据超过最大行数限制", ...}
}],
"acceptance_criteria": [
"批量导出支持最大 100000 行,超出时返回错误提示",
"响应延迟 ≤ 3000ms,失败重试最多 3 次",
"空数据集导出返回空 CSV(仅含表头),不返回错误",
"导出文件编码为 UTF-8,含 BOM 头以兼容 Excel",
"下载链接有效期不少于 24 小时"
],
"open_questions": [
"'大批量'已默认设为 100000 行,是否需要调整?",
"'实时'已默认设为 3000ms,是否需要更严格?"
]
}
└──────────────────────────────────────
✅ 补全了 5 条验收标准
⚠️ 标记了 2 个待确认问题
这个脚本展示了 BP Claw 的核心价值:不是简单格式转换,而是主动把隐含信息翻出来,把模糊词语变成可量化标准,同时把不确定的地方标记为开放问题而非悄悄猜一个答案。
补全策略的设计取舍
BP Claw 的补全不是无中生有。它的知识库来源于两类:
- 领域惯例——比如 CSV 导出默认 UTF-8 编码、分页默认 20 条、REST API 默认 JSON。这些是行业共识,补上去大概率正确。
- 项目历史——同一团队过去的需求规格、已实现的接口约定。FlinkSpec 本身就是项目级的需求结构定义,BP Claw 可以回溯已有规格来推断默认值。
但补全永远有风险。BP Claw 的做法是:补上的信息标注来源(惯例 / 历史推断),不确定的升级为开放问题,要求人类确认。 这比两种极端都好——比"什么都不补,让 AI 猜"安全,也比"全补上不许改"灵活。
落地时的几个实操建议
如果你要在自己的团队实现类似的"需求 BP"管线,有几件事值得提前想清楚:
-
先定义下游消费格式——BP Claw 输出什么结构,取决于 FlinkSpec(或你的 AI Coding Agent)需要什么输入。先固定下游契约,再设计补全逻辑,避免产出没人能用的精美文档。
-
知识库要可覆盖——默认补全值必须能被项目级配置覆盖。行业惯例说分页默认 20 条,你的项目可能就是 50 条。让团队在 YAML 里改一行,而不是改代码。
-
开放问题必须有闭环——BP Claw 标记的待确认项,必须进入某个追踪流程(Jira/飞书任务/PR 评论区),否则"待确认"就等于"永远不确认",补全反而制造了新的不确定性。
-
渐进式接入——不要第一天就让 BP Claw 处理所有 PRD。先选一个模块、一个 PM 的文档做试点,对比人工写规格和 BP Claw 生成规格的差异,校准补全规则后再扩大范围。
# bp_claw_config.yaml — 项目级补全规则配置示例
# 放在项目仓库根目录,BP Claw 启动时加载
completion_rules:
csv_export:
encoding: UTF-8
delimiter: ","
null_representation: empty_string
max_rows: 50000 # 覆盖默认的 100000
filename_pattern: "export_{timestamp}.csv"
bom_header: true # Excel 兼容
pagination:
default_page_size: 50 # 覆盖默认的 20
max_page_size: 200
sort_default: "updated_at desc"
realtime:
latency_budget_ms: 1500 # 覆盖默认的 3000,本项目要求更严
retry_max: 2
retry_interval_ms: 500
open_questions_tracking:
target: jira # jira | lark | github_pr
project_key: "DATATEAM"
label: "bp_claw_question"
auto_create: true # 自动创建待确认任务
- 保留原始 PRD 到结构化文档的映射——每条补全信息、每个开放问题,都应该能追溯到原始 PRD 的具体段落。这不是学术要求,是工程需要:PM 回头来问"这个 300ms 哪来的",你得秒答"第三段'实时生成'那个词,我们默认补了 3 秒预算,你确认一下"。
小结
AI Coding 的瓶颈不在生成代码的能力,而在输入需求的质量。BP Claw 的价值不是"让文档更漂亮",而是把 PM 没说清楚的东西显式化,把 AI 必须知道但 PRD 里没有的信息补上,把不确定的部分标出来让人决策。
如果你正在搭建 AI Coding 流程,先检查一下上游:PRD 到 AI Agent 之间,有没有一个类似 BP Claw 的结构化补全环节。没有的话,AI 写出的代码大概率是在替你猜需求——猜对了是运气,猜错了是返工。