PRD 评审与团队对齐机制
PRD 评审会最常见的结局是:所有人说"没问题",然后开发一半发现理解完全不同。对齐不是"没有反对意见",是"每个人对关键决策的理解一致"。
PRD 评审的标准流程
graph TD
A[PRD 初稿完成] --> B[预评审:PM 自检]
B --> C{自检通过?}
C -- 否 --> A
C -- 是 --> D[发出评审文档\n提前 48 小时]
D --> E[正式评审会\n60-90 分钟]
E --> F{各角色对齐状态}
F --> G[设计:界面/流程理解一致]
F --> H[工程:技术方案无歧义]
F --> I[AI 工程:能力边界已确认]
F --> J[测试:验收标准已接受]
G --> K{是否有分歧?}
H --> K
I --> K
J --> K
K -- 是 --> L[记录分歧点\n会后 24 小时内决策]
K -- 否 --> M[签字确认版本]
L --> N[PM 决策或升级]
N --> M
style A fill:#e3f2fd,stroke:#1565c0
style M fill:#e8f5e9,stroke:#2e7d32
style L fill:#fff9c4,stroke:#f9a825
评审前:PM 自检清单
发出 PRD 之前,PM 必须先对自己的文档做一轮自检。以下问题你应该能直接回答:
| 自检项 | 如果答不上来 |
|---|---|
| 这个功能解决的核心问题是什么?一句话 | 目标章节需要重写 |
| 用户场景写了几个?边界场景有没有? | 场景章节不完整 |
| AI 失败时用户会看到什么? | 失败机制章节缺失 |
| 验收标准的数字从哪来的?有没有基准 | 验收标准不够严谨 |
| 哪些事情本期明确不做? | 非目标章节需要补充 |
常见对齐偏差模式
AI 产品评审中,以下四种偏差最常出现:
| 偏差类型 | 表现 | 预防方法 |
|---|---|---|
| 能力边界模糊 | 工程理解"AI 处理所有情况",PM 理解"AI 处理常见情况" | PRD 明确列出排除场景 |
| 质量标准不同 | PM 认为"85% 准确率"是好结果,研发认为"肯定能达到 95%" | 评审时同步历史 benchmark |
| 降级路径未讨论 | 工程认为失败时静默处理,PM 期望有用户提示 | 每个失败场景写用户体验 |
| 优先级被忽视 | 研发把 P1 功能当 P2 排期 | 评审会上逐一确认排期影响 |
Python 示例:PRD 评审会追踪器
"""
PRD 评审会追踪器
PM 视角:记录评审会的讨论、分歧点和决策,确保对齐可追溯
"""
from dataclasses import dataclass, field
from typing import List, Optional, Dict
from enum import Enum
from datetime import date, timedelta
class AlignmentStatus(Enum):
ALIGNED = "已对齐"
PENDING = "待决策"
DEFERRED = "延后讨论"
BLOCKED = "阻塞需升级"
class StakeholderRole(Enum):
PM = "产品经理"
DESIGN = "设计师"
ENGINEER = "研发工程师"
AI_ENGINEER = "AI 工程师"
QA = "测试工程师"
BUSINESS = "业务方"
@dataclass
class ReviewPoint:
"""评审讨论点"""
point_id: str
section: str # PRD 章节
description: str
raised_by: StakeholderRole
status: AlignmentStatus
decision: Optional[str] = None
decision_owner: Optional[StakeholderRole] = None
deadline: Optional[date] = None
impact_if_unresolved: str = ""
@dataclass
class ReviewSession:
"""评审会记录"""
prd_name: str
prd_version: str
review_date: date
attendees: List[StakeholderRole]
facilitator: str
review_points: List[ReviewPoint] = field(default_factory=list)
pre_read_sent_days_before: int = 0
@dataclass
class ReviewReport:
"""评审报告"""
session: ReviewSession
alignment_rate: float
critical_pending: List[ReviewPoint]
overdue_points: List[ReviewPoint]
readiness_assessment: str
def calculate_alignment_rate(points: List[ReviewPoint]) -> float:
"""计算对齐率"""
if not points:
return 1.0
aligned = sum(1 for p in points if p.status == AlignmentStatus.ALIGNED)
return aligned / len(points)
def find_critical_pending(points: List[ReviewPoint]) -> List[ReviewPoint]:
"""找出关键未决项(阻塞性)"""
return [
p for p in points
if p.status in (AlignmentStatus.PENDING, AlignmentStatus.BLOCKED)
]
def find_overdue_points(points: List[ReviewPoint],
reference_date: date) -> List[ReviewPoint]:
"""找出已过期未决项"""
return [
p for p in points
if p.status == AlignmentStatus.PENDING
and p.deadline is not None
and p.deadline < reference_date
]
def assess_readiness(session: ReviewSession,
alignment_rate: float,
critical_pending: List[ReviewPoint]) -> str:
"""评估 PRD 是否达到可开发状态"""
issues = []
if session.pre_read_sent_days_before < 1:
issues.append("预读时间不足(建议提前 48 小时发出)")
if StakeholderRole.AI_ENGINEER not in session.attendees:
issues.append("AI 工程师未参加评审,AI 能力边界可能未确认")
if StakeholderRole.QA not in session.attendees:
issues.append("测试工程师未参加评审,验收标准可能未对齐")
blocked_points = [p for p in critical_pending
if p.status == AlignmentStatus.BLOCKED]
if blocked_points:
issues.append(f"存在 {len(blocked_points)} 个阻塞问题,需升级决策后才能继续")
if alignment_rate < 0.6:
issues.append(f"对齐率仅 {alignment_rate:.0%},分歧过多,建议再次评审")
if issues:
return "未达到开发就绪状态:\n" + "\n".join(f" - {i}" for i in issues)
if alignment_rate < 0.8:
return f"基本可以开始开发,但有 {len(critical_pending)} 个待决项需在开发启动前解决"
return "已达到开发就绪状态,可以进入开发排期"
def generate_review_report(session: ReviewSession) -> ReviewReport:
"""生成评审报告"""
today = date.today()
alignment_rate = calculate_alignment_rate(session.review_points)
critical_pending = find_critical_pending(session.review_points)
overdue = find_overdue_points(session.review_points, today)
readiness = assess_readiness(session, alignment_rate, critical_pending)
return ReviewReport(
session=session,
alignment_rate=alignment_rate,
critical_pending=critical_pending,
overdue_points=overdue,
readiness_assessment=readiness,
)
def print_review_report(report: ReviewReport):
session = report.session
print(f"\n{'='*55}")
print(f" PRD 评审报告:{session.prd_name} v{session.prd_version}")
print(f" 评审日期:{session.review_date} 主持人:{session.facilitator}")
print(f" 参会角色:{', '.join(r.value for r in session.attendees)}")
print(f"{'='*55}")
print(f"\n 总体对齐率:{report.alignment_rate:.0%} "
f"(共 {len(session.review_points)} 个讨论点)")
# 按状态统计
status_counts: Dict[AlignmentStatus, int] = {}
for point in session.review_points:
status_counts[point.status] = status_counts.get(point.status, 0) + 1
for status, count in status_counts.items():
print(f" {status.value}:{count} 条")
if report.critical_pending:
print(f"\n 待决/阻塞项({len(report.critical_pending)} 条):")
for p in report.critical_pending:
deadline_str = f"(截止 {p.deadline})" if p.deadline else ""
owner_str = f" 负责人:{p.decision_owner.value}" if p.decision_owner else ""
print(f"\n [{p.point_id}] [{p.status.value}] {p.section}")
print(f" 问题:{p.description}")
print(f" 影响:{p.impact_if_unresolved}{deadline_str}{owner_str}")
if report.overdue_points:
print(f"\n 已过期未决项({len(report.overdue_points)} 条,需立即处理):")
for p in report.overdue_points:
print(f" ⚠ [{p.point_id}] {p.description}(截止 {p.deadline})")
print(f"\n 开发就绪评估:")
print(f" {report.readiness_assessment}")
# ── 演示 ──────────────────────────────────────────────
if __name__ == "__main__":
today = date.today()
session = ReviewSession(
prd_name="AI 意图识别与自动回复",
prd_version="1.2",
review_date=today,
attendees=[
StakeholderRole.PM,
StakeholderRole.ENGINEER,
StakeholderRole.AI_ENGINEER,
StakeholderRole.QA,
],
facilitator="张三(PM)",
pre_read_sent_days_before=2,
review_points=[
ReviewPoint(
point_id="R01",
section="03-AI 能力描述",
description="置信度阈值 0.85 的依据是什么?工程侧认为实际很难稳定达到",
raised_by=StakeholderRole.AI_ENGINEER,
status=AlignmentStatus.PENDING,
decision_owner=StakeholderRole.PM,
deadline=today + timedelta(days=2),
impact_if_unresolved="阈值不确定会导致用户体验设计无法定稿",
),
ReviewPoint(
point_id="R02",
section="04-失败机制",
description="超时降级时转人工队列的优先级如何?是否插队?",
raised_by=StakeholderRole.ENGINEER,
status=AlignmentStatus.ALIGNED,
decision="超时转入高优队列,与用户主动转人工同等优先级",
decision_owner=StakeholderRole.PM,
),
ReviewPoint(
point_id="R03",
section="05-验收标准",
description="测试集 500 条由谁标注?标注规范是否已有?",
raised_by=StakeholderRole.QA,
status=AlignmentStatus.PENDING,
decision_owner=StakeholderRole.AI_ENGINEER,
deadline=today + timedelta(days=3),
impact_if_unresolved="验收测试无法启动",
),
ReviewPoint(
point_id="R04",
section="02-用户场景",
description="多图片消息场景未在 PRD 中描述,但前端已有该入口",
raised_by=StakeholderRole.DESIGN,
status=AlignmentStatus.DEFERRED,
decision="本期仅支持文字,图片场景列入 v1.3 讨论",
decision_owner=StakeholderRole.PM,
),
ReviewPoint(
point_id="R05",
section="06-上线计划",
description="Beta 阶段流量分配机制(随机 / 按用户分层)未定义",
raised_by=StakeholderRole.ENGINEER,
status=AlignmentStatus.ALIGNED,
decision="按注册时间随机分组,同用户在整个 Beta 期间保持分组不变",
decision_owner=StakeholderRole.ENGINEER,
),
],
)
report = generate_review_report(session)
print_review_report(report)
本章 checklist
- [ ] 评审文档在会议开始前 48 小时发出,给与会者预读时间
- [ ] AI 工程师和测试工程师都出席了评审会
- [ ] 评审会上每个分歧点都记录了负责人和截止时间
- [ ] 评审后 24 小时内,所有待决项的决策都通知给相关方
- [ ] PRD 版本有明确的"已对齐"确认记录,可以作为后续变更的基准
本章小结
- 评审会的目的不是"过稿",是让每个角色能独立复述关键决策,做不到就说明没有真正对齐
- AI 产品评审特别需要 AI 工程师在场确认能力边界,PM 不能替代这个角色发言
- 分歧点要公开记录并给出决策截止时间,让"没有明确反对"变成有记录的"已确认"
本章完:下一章进入 10-协作编排,学习如何与设计师、工程师、AI 工程师建立高效的协作机制。