# 完整执行产物 · 沙箱真跑输出 本次并行方式产出的 4 个文件·合并成一个报告便于阅读。 --- ## 📄 prd_evaluator.py (5,785 bytes) ```python #!/usr/bin/env python3 """PRD 评分器 + Loop 收敛判定。 真跑:python3 prd_evaluator.py demo """ import json import re import sys from dataclasses import dataclass, asdict from typing import Optional WEIGHTS = {"D1": 0.25, "D2": 0.20, "D3": 0.15, "D4": 0.20, "D5": 0.10, "D6": 0.10} MAX_ROUNDS = 3 PASS_THRESHOLD = 7.5 HIGH_RISK_THRESHOLD = 4.0 STALL_DELTA = 0.3 CONDITION_PATTERNS = [ r"if\s+.+then", r"如果.+则", r"当.+时", r"若.+则", ] BOUNDARY_KEYWORDS = ["空", "超限", "并发", "异常", "越界", "超时", "重试", "回滚", "降级"] FEASIBILITY_KEYWORDS = ["schema", "api", "接口", "依赖", "工期", "estimate", "架构"] METRIC_KEYWORDS = ["指标", "kpi", "北极星", "达标", "阈值", "转化率", "留存"] @dataclass class Score: D1: int; D2: int; D3: int; D4: int; D5: int; D6: int S: float weakest: str round: int status: str def to_dict(self): return asdict(self) def count_conditions(text: str) -> int: total = 0 for p in CONDITION_PATTERNS: total += len(re.findall(p, text, re.IGNORECASE)) return total def score_d1(text: str) -> int: """条件覆盖度:基于 if-then 句式数""" n = count_conditions(text) if n >= 15: return 10 if n >= 12: return 8 if n >= 8: return 6 if n >= 4: return 4 if n >= 1: return 2 return 1 def score_d2(text: str) -> int: """逻辑完整性:条件是否有失败/降级""" conds = count_conditions(text) fallbacks = sum(text.count(k) for k in ["失败", "错误", "降级", "回滚", "else", "否则"]) if conds == 0: return 1 ratio = min(fallbacks / conds, 1.0) return max(1, min(10, int(ratio * 10))) def score_d3(text: str) -> int: """实现可行性:技术关键词""" hits = sum(1 for k in FEASIBILITY_KEYWORDS if k.lower() in text.lower()) return max(1, min(10, hits * 2)) def score_d4(text: str) -> int: """边界清晰度""" hits = sum(1 for k in BOUNDARY_KEYWORDS if k in text) return max(1, min(10, hits + 1)) def score_d5(text: str) -> int: """可验证性:含 assert / 可测语句 / 数字阈值""" asserts = len(re.findall(r"assert|验收|verify|测试", text, re.IGNORECASE)) numbers = len(re.findall(r"\d+(\.\d+)?%?", text)) return max(1, min(10, asserts + numbers // 3)) def score_d6(text: str) -> int: """价值锚点:业务指标""" hits = sum(1 for k in METRIC_KEYWORDS if k in text.lower()) return max(1, min(10, hits * 2 + 1)) def score_prd(text: str, round_num: int = 1) -> Score: dims = { "D1": score_d1(text), "D2": score_d2(text), "D3": score_d3(text), "D4": score_d4(text), "D5": score_d5(text), "D6": score_d6(text), } S = round(sum(dims[k] * WEIGHTS[k] for k in dims), 2) weakest = min(dims, key=lambda k: dims[k]) status = decide_status(S, round_num, prev_S=None) return Score(**dims, S=S, weakest=weakest, round=round_num, status=status) def decide_status(S: float, round_num: int, prev_S: Optional[float]) -> str: if S >= PASS_THRESHOLD: return "PASSED" if round_num >= MAX_ROUNDS: return "HIGH_RISK" if S < HIGH_RISK_THRESHOLD else "CONVERGED_LOW" if prev_S is not None and abs(S - prev_S) < STALL_DELTA: return "CONVERGED_LOW" if round_num >= 2 and S < HIGH_RISK_THRESHOLD: return "HIGH_RISK" return "IN_LOOP" PROMPT_TEMPLATES = { "D1": "补 ≥{gap} 条 'if 用户…则…' 场景,覆盖新用户/付费/回访/异常 4 角色", "D2": "为每个 if 分支补失败响应+用户反馈+降级方案", "D3": "补 DB schema + API 契约 + 依赖 + 工期", "D4": "列 5 类边界(空/超限/并发/异常/越界)并给策略", "D5": "验收改成 assert: <可测> 格式", "D6": "补北极星指标 + 阈值 + 回滚线", } def build_feedback(score: Score) -> str: tpl = PROMPT_TEMPLATES[score.weakest] if score.weakest == "D1": gap = max(0, 15 - count_conditions_from_score(score)) tpl = tpl.replace("{gap}", str(gap or 5)) return f"[Round {score.round+1} 迭代] 最弱维度 {score.weakest}={getattr(score, score.weakest)}: {tpl}" def count_conditions_from_score(s: Score) -> int: # 反推:D1=10 -> 15+, D1=8 -> 12, D1=6 -> 8, D1=4 -> 4 mapping = {10: 15, 8: 12, 6: 8, 4: 4, 2: 1, 1: 0} return mapping.get(s.D1, 0) def run_loop(prd_text: str, prd_id: str = "P-DEMO") -> list: """模拟 loop:不真调 LLM,只演示评分+收敛判定""" log = [] prev_S = None for r in range(1, MAX_ROUNDS + 1): score = score_prd(prd_text, round_num=r) score.status = decide_status(score.S, r, prev_S) entry = {"prd_id": prd_id, **score.to_dict()} log.append(entry) if score.status in ("PASSED", "HIGH_RISK", "CONVERGED_LOW"): break prev_S = score.S # 演示:假设迭代后条件数+5、边界+2 prd_text += "\n如果用户超限则限流。如果用户异常则降级。如果用户并发写则加锁。" return log if __name__ == "__main__": demo_prd = """ 产品需求:新用户注册流程。 如果用户填写完整信息则进入下一步;如果用户手机号已存在则提示登录; 当用户点击注册时校验验证码;若验证码错误则失败提示。 验收:注册成功率 ≥95%。北极星指标:日新增注册用户。 """ log = run_loop(demo_prd, prd_id="P-DEMO-001") for e in log: print(json.dumps(e, ensure_ascii=False)) # 写文件 with open("prd_score_log.jsonl", "w") as f: for e in log: f.write(json.dumps(e, ensure_ascii=False) + "\n") print(f"\n--- Wrote {len(log)} rounds to prd_score_log.jsonl ---") ``` --- ## 📄 prd_scoring_system.md (4,020 bytes) # PRD 补全反馈 Loop 与评分体系 ## 背景 基于上一步发现:达标 PRD 平均包含 15 个「if 用户…则…」句式。本步骤建立可追踪的评分-迭代-收敛机制。 ## 一、六维评分体系(每维 1-10 分,总分 60) | 维度 | 权重 | 定义 | 打分锚点 | |------|------|------|---------| | **D1 条件覆盖度** (Conditional Coverage) | 25% | "if 用户…则…" 句式数量与业务分支覆盖率 | 1=0-3条, 5=8-12条, 10=≥15条且覆盖所有主流程分支 | | **D2 逻辑完整性** (Logic Completeness) | 20% | 每个条件是否有对应的系统响应/降级方案 | 1=大量悬空条件, 10=每条件双向闭环(成功+失败) | | **D3 实现可行性** (Feasibility) | 15% | 技术栈/依赖/工期是否明确 | 1=纯业务描述, 10=含技术选型+接口契约+估时 | | **D4 边界清晰度** (Boundary Clarity) | 20% | 空值/超限/并发/异常场景明确度 | 1=只写 happy path, 10=列出≥5类边界并给策略 | | **D5 可验证性** (Verifiability) | 10% | 验收标准是否可自动化测试 | 1=主观描述, 10=100%可写成 assert | | **D6 用户价值锚点** (Value Anchor) | 10% | 是否绑定可测量的业务指标 | 1=无指标, 10=北极星指标+达标阈值+回滚线 | **加权总分 S = 0.25·D1 + 0.20·D2 + 0.15·D3 + 0.20·D4 + 0.10·D5 + 0.10·D6**(0-10 归一化) ## 二、达标率关联假设(需 A/B 数据回填校准) | 加权分 S | 预测上线数据达标率 | 处置 | |---------|-------------------|------| | S ≥ 7.5 | ≥80% (高信心) | 直接进入研发 | | 6.0 ≤ S < 7.5 | 50-80% (中信心) | 允许进入·标记观察 | | S < 6.0 | <50% (高风险) | 打回补全 or 拆分 | | S < 4.0 且迭代 ≥2 轮 | 结构性问题 | 标记「高风险 PRD」·人工介入 | ## 三、Loop 机制(伪代码) ``` prd = draft history = [] for round in range(1, MAX_ROUNDS+1): # MAX_ROUNDS = 3 prd = ai_complete(prd, feedback=history[-1] if history else None) scores = score_six_dims(prd) # 输出 {D1..D6, S} history.append(scores) # 收敛判定 if scores.S >= 7.5: return prd, "PASSED", scores if round >= 2 and scores.S < 7.0: return prd, "HIGH_RISK", scores # 高风险 · 人工介入 if len(history) >= 2 and delta(history[-1], history[-2]) < 0.3: return prd, "CONVERGED_LOW", scores # 收敛在低分 · 结构性问题 # 迭代 prompt 增强 weakest = argmin(scores by dim) feedback = PROMPT_TEMPLATES[weakest] # 针对最弱维度的补写指令 ``` ## 四、迭代 Prompt 模板(按最弱维度) - **D1 弱**:「请补充 ≥{15 - current} 条 "if 用户…则…" 场景,覆盖新用户/付费用户/回访用户/异常用户 4 类角色」 - **D2 弱**:「以下条件缺失失败分支:{list}。对每条补充系统响应+用户可见反馈+降级方案」 - **D3 弱**:「补充技术方案:DB schema 变更、API 契约、依赖服务、预估工期」 - **D4 弱**:「列出以下 5 类边界并给策略:空数据/超限输入/并发写入/网络异常/权限越界」 - **D5 弱**:「将每条验收标准改写成 `assert: <可测语句>` 格式」 - **D6 弱**:「补充北极星指标 + 达标阈值 + 回滚触发线」 ## 五、收敛判定规则 1. **成功收敛**:S ≥ 7.5 → PASSED 2. **失败收敛**:S < 4.0 且 2 轮后无 ≥0.5 提升 → HIGH_RISK 3. **停滞收敛**:连续 2 轮 |ΔS| < 0.3 → CONVERGED_LOW (无论分数) 4. **硬上限**:MAX_ROUNDS = 3,超过则强制退出并记录 case 5. **回填校准**:上线 30 天后回填数据达标结果,季度重新拟合 S vs 达标率曲线 ## 六、可追踪产物 每次 loop 产出 `prd_score_log.jsonl`: ```json {"prd_id":"P-2026-Q3-042","round":1,"S":5.4,"D1":4,"D2":5,"D3":7,"D4":4,"D5":6,"D6":8,"weakest":"D1","status":"IN_LOOP"} {"prd_id":"P-2026-Q3-042","round":2,"S":7.8,"D1":9,"D2":8,"D3":7,"D4":7,"D5":7,"D6":8,"weakest":"D3","status":"PASSED"} ``` --- ## 📄 result.json (3,488 bytes) ```json { "output": "建立 PRD 补全反馈 loop 与评分体系。核心产出:(1) 六维评分 rubric —— D1 条件覆盖度(25%)、D2 逻辑完整性(20%)、D3 实现可行性(15%)、D4 边界清晰度(20%)、D5 可验证性(10%)、D6 价值锚点(10%),加权总分 S∈[0,10];(2) S→数据达标率映射:S≥7.5 预测达标率≥80%,6.0≤S<7.5 中信心,S<6.0 打回,S<4.0 且 round≥2 标记 HIGH_RISK;(3) Loop 机制:MAX_ROUNDS=3、PASS_THRESHOLD=7.5、STALL_DELTA=0.3;伪代码 + 可执行 prd_evaluator.py 均已交付;(4) 迭代 prompt 模板按最弱维度触发(D1 弱→补足到 15 条 if-then,D4 弱→列 5 类边界等);(5) 收敛判定 4 规则:成功(S≥7.5)、失败(S<4.0 round≥2)、停滞(|ΔS|<0.3)、硬上限(round=3)。真跑 python3 prd_evaluator.py:demo PRD 跑 3 轮,S 从 2.65→4.15→4.35,最终 CONVERGED_LOW(|ΔS|=0.2<0.3 触发),日志写入 prd_score_log.jsonl 共 3 行 JSONL。文档 prd_scoring_system.md 4020 字节,脚本 5785 字节。", "gotchas": [ "round 2 的 HIGH_RISK 触发条件是 S