简介:本资源是一份面向数据科学与AI开发者的PRD(产品需求文档)实践模板,聚焦Jupyter Notebook场景下的AI项目需求定义与工程化落地。它帮助产品经理、算法工程师及跨职能团队统一需求理解,解决AI产品从概念到开发的沟通断层问题,尤其适用于机器学习平台、数据分析工具类项目的前期规划。压缩包共4个文件,含2个Python脚本(fluideDataset.py、R2Plus1D.py)用于数据预处理与模型构建,2个Jupyter Notebook(Version_refactoris俥.ipynb、Classificateur.ipynb)承载可执行的需求验证逻辑、模型训练流程与分类结果可视化,完整呈现PRD中功能描述→代码实现→效果验证的闭环。包体仅2.04MB,轻量易用,结构紧凑。目前已有336人学习下载,读者可直接复用其中模块化代码结构、需求条目映射示例及Notebook交互式说明方式,快速构建具备版本管理、协作支持与性能指标对齐能力的AI项目PRD交付物。1. PRD 不是文档模板,而是需求落地的“校验黑匣子”:它用 Jupyter Notebook 把模糊需求变成可执行、可回溯、可协作的动态验证现场很多人第一次接触 PRD(Product Requirement Document)时,以为只是产品经理写给开发看的 Word 或 PDF 文件——写完就归档,评审靠嘴,变更靠吼,上线后才发现“当初说的不是这个意思”。但真实项目里,PRD 的失效往往不是因为没人写,而是因为写出来的东西无法被工程侧实时验证、参数化推演、版本化比对。而这份名为 “PRD” 的资源,本质是一个以 Jupyter Notebook 为载体的轻量级需求建模与验证框架:它不替代传统 PRD 文档,而是把关键需求逻辑(如业务规则约束、状态流转条件、数据边界判定)全部封装成可运行的 Python 单元格,支持输入样例数据→自动触发校验→高亮失败路径→导出结构化断言报告。适合正在推进中台能力沉淀的某公司后台团队、需要快速对齐算法输入输出边界的某高校图像处理 Demo 项目,以及所有被“需求理解偏差”反复背刺过的全栈开发者。它不是教你写文档,而是帮你把文档里最易歧义的那 20% 内容,变成跑得通、改得清、查得准的代码事实。2. 为什么选 Jupyter Notebook 而非 Markdown/Notion/Confluence:动态性、可调试性与工程链路直连是刚需2.1 静态文档的三大硬伤,在需求验证场景下会被指数级放大传统 PRD 文档(Word/PDF/Markdown)在需求落地阶段暴露三个结构性缺陷:第一,条件逻辑不可执行——比如“当用户等级 ≥3 且近 7 日下单频次 <2 时,触发优惠券发放”,这句话在 Word 里只是文字,开发需手动翻译成 if-else,测试需另写 case;第二,边界值无显式声明——“订单金额 > 0 且 ≤ 99999.99”这种约束,静态文档里容易漏掉小数位数、负数兜底、空值处理等细节;第三,版本变更不可追溯对比——V1.2 和 V1.3 的差异,靠人工 diff 段落,极易遗漏隐含逻辑调整。这些缺陷在小型项目里尚可容忍,但在涉及多端(Web/App/小程序)、多角色(运营/风控/客服)协同的中型系统中,会直接导致联调阶段 60% 以上的返工来自“对同一句话的理解不一致”。2.2 Jupyter Notebook 的四个不可替代优势:从文档到验证现场的跃迁Jupyter Notebook 在此场景下不是“换了个编辑器”,而是重构了需求验证的工作流:单元格即验证点:每个核心业务规则(如“支付成功后 30 秒内必须生成账单”)对应一个独立 cell,输入 mock 数据 → 运行 → 返回 True/False + 失败原因,逻辑与实现完全同源;参数化驱动:用@interact或ipywidgets构建简易 UI 控件(滑块、下拉框),让产品/测试人员无需写代码即可拖动调整阈值、切换状态机,实时观察规则触发结果;与工程环境零割裂:Notebook 可直接 import 项目中的核心 service 模块(如from billing_service import validate_order),验证逻辑复用生产代码,避免“文档逻辑”和“实现逻辑”双轨并行;天然支持断言快照:通过nbconvert --to html --no-input导出无代码 HTML 报告,嵌入 CI 流程,每次 PR 提交自动运行全部 PRD cell,失败则阻断合并——此时 PRD 不再是交付物,而是准入门禁。提示:这不是让产品经理写 Python,而是让开发把最易出错的需求逻辑“翻译”成 notebook,再由产品在 notebook 里填数据、点按钮、看结果。双方看到的是同一份可执行事实。2.3 对比主流替代方案:为什么 Notion/Confluence/Excel 全部掉队工具是否支持逻辑执行是否支持参数化交互是否能 import 生产代码是否可集成 CI/CD是否支持版本间逻辑 diffNotion❌❌(仅基础表单)❌❌❌(仅页面级 diff)Confluence❌❌❌❌❌Excel⚠️(公式有限)⚠️(控件复杂难维护)❌❌❌Jupyter NB✅(原生)✅(ipywidgets)✅(同 Python 环境)✅(nbconvert+pytest)✅(git diff .ipynb + 自定义 parser)关键结论:当需求验证需要可计算、可干预、可自动化时,Jupyter Notebook 是当前技术栈下唯一满足全部硬性要求的载体。它不解决“怎么写需求”,但彻底解决了“写的是否真能跑通”。3. 快速上手:5 分钟初始化你的 PRD Notebook 工程骨架3.1 环境准备:最小依赖集与隔离建议本框架设计为轻量嵌入,不强制绑定特定框架。推荐使用venv创建独立环境(避免污染全局 Python),核心依赖仅 3 个:python -m venv prd_env source prd_env/bin/activate # Windows: prd_env\Scripts\activate pip install jupyter ipywidgets nbconvert pytest注意:ipywidgets需要额外启用前端扩展(JupyterLab 用户执行jupyter labextension install @jupyter-widgets/jupyterlab-manager;经典 Notebook 执行jupyter nbextension enable --py widgetsnbextension)。若跳过此步,交互控件将不渲染,但基础运行功能不受影响。3.2 目录结构:让 PRD Notebook 成为可维护的工程资产不要把所有内容堆在一个.ipynb文件里。按模块拆分,便于协作与 CI 切片执行:prd_project/ ├── requirements.txt # 仅记录 notebook 专用依赖(如 pandas, requests) ├── prd_core/ # 核心需求逻辑目录(存放 .py 模块,供 notebook import) │ ├── __init__.py │ ├── order_rules.py # 订单类规则(金额校验、状态流转) │ └── user_profile.py # 用户类规则(等级计算、权益发放) ├── notebooks/ # Notebook 主体(按业务域划分) │ ├── 01_order_prd.ipynb # 订单 PRD 验证主本 │ ├── 02_user_prd.ipynb # 用户 PRD 验证主本 │ └── _utils/ # 公共工具 notebook(如 mock 数据生成器) ├── tests/ # pytest 用例(将 notebook cell 转为 test function) │ └── test_order_rules.py └── scripts/ # 辅助脚本 └── run_prd_tests.py # 批量运行所有 PRD notebook 并生成报告关键设计:prd_core/下的.py文件是真正的业务规则实现,notebook 只负责调用和验证。这样既保证逻辑复用,又让 PRD 保持“面向验证”的轻量定位。3.3 第一个可运行 cell:从“用户等级判定”开始建立信任在notebooks/02_user_prd.ipynb中,创建第一个 cell,实现某高校图像处理 Demo 中的用户权限规则:# cell 1: 定义核心规则函数(复用 prd_core/user_profile.py) from prd_core.user_profile import calculate_user_level # 输入:mock 用户行为数据(字典格式,模拟真实 API 请求体) mock_user_data = { "total_orders": 12, "last_order_days_ago": 5, "is_vip": True, "login_frequency_last_30d": 28 } # 执行规则计算 level_result = calculate_user_level(mock_user_data) print(f"用户等级计算结果: {level_result}") # 断言:确保规则符合 PRD 约定(此处 level 应为 4) assert level_result == 4, f"预期等级 4,实际得到 {level_result}"逻辑说明:calculate_user_level()函数在prd_core/user_profile.py中实现,其内部逻辑(如“总订单≥10 且近 30 天登录≥25 次 → 等级+1”)就是 PRD 文档中“用户成长体系”章节的代码化表达。cell 中的assert是 PRD 的“法律条款”——运行失败即证明实现与需求冲突,必须修正代码或更新 PRD。3.4 加入交互验证:让产品同学自己拖动阈值看效果接着添加一个交互式 cell,暴露关键参数供非技术人员调节:# cell 2: 使用 ipywidgets 构建交互界面 import ipywidgets as widgets from IPython.display import display # 定义可调节参数(对应 PRD 中的可配置阈值) total_orders_slider = widgets.IntSlider(value=12, min=0, max=100, description='总订单数:') login_freq_slider = widgets.IntSlider(value=28, min=0, max=50, description='30天登录频次:') vip_toggle = widgets.Checkbox(value=True, description='是否 VIP:') # 组合控件 ui = widgets.VBox([total_orders_slider, login_freq_slider, vip_toggle]) # 定义响应函数(当任一控件变化时重新计算) def on_value_change(change): mock_data = { "total_orders": total_orders_slider.value, "last_order_days_ago": 5, # 固定为 5,简化 demo "is_vip": vip_toggle.value, "login_frequency_last_30d": login_freq_slider.value } result = calculate_user_level(mock_data) print(f"\r当前参数下用户等级: {result}", end="") # 绑定事件 total_orders_slider.observe(on_value_change, names='value') login_freq_slider.observe(on_value_change, names='value') vip_toggle.observe(on_value_change, names='value') display(ui) on_value_change(None) # 初始化显示参数说明:IntSlider的min/max值直接映射 PRD 中“合理取值范围”的文字描述(如“总订单数应介于 0~100”),Checkbox对应布尔型业务开关。产品同学拖动滑块时,背后运行的是同一份生产代码,结果实时可见——这比“我理解是这样”高效十倍。4. 避坑:PRD Notebook 实战中踩过的 5 个血泪坑,每一条都让团队少返工 2 天4.1 现象:Notebook 运行结果正常,但上线后相同输入却报错原因:Notebook 中import了本地prd_core/模块,但 CI 环境未安装该包,或路径未加入PYTHONPATH,导致测试时实际运行的是旧版缓存代码。解决:在 notebook 开头强制插入路径检查与模块重载:import sys import os # 确保 prd_core 在 sys.path 中(相对于 notebook 当前目录) core_path = os.path.abspath("../prd_core") if core_path not in sys.path: sys.path.insert(0, core_path) # 强制重载模块(避免 IDE 缓存旧逻辑) import importlib import prd_core.user_profile importlib.reload(prd_core.user_profile)4.2 现象:交互控件(ipywidgets)在导出 HTML 后完全消失原因:nbconvert --to html默认不嵌入前端 JavaScript,widget 渲染依赖@jupyter-widgets/jupyterlab-manager的 JS runtime。解决:导出时启用--embed-images并指定--no-input(隐藏代码,只留输出):jupyter nbconvert --to html --no-input --embed-images notebooks/02_user_prd.ipynb补充:若需完整交互能力,改用voilà部署为 Web 应用(pip install voilà; voilà notebooks/02_user_prd.ipynb),但需注意生产环境权限控制。4.3 现象:多人协作时,git diff 显示大量 JSON 冗余变更(如"collapsed": false)原因:.ipynb是 JSON 格式,cell 的元数据(折叠状态、执行计数)随每次运行自动更新,污染 git 历史。解决:配置.gitattributes强制使用nbdime工具进行语义化 diff:*.ipynb diff=nbdime并在本地安装:pip install nbdime && nbdime config-git --enable --global。此后git diff只显示代码/输出变更,忽略元数据。4.4 现象:PRD Notebook 中的 mock 数据与真实数据库 schema 不一致,导致验证通过但线上失败原因:mock 数据手动生成,未与 ORM 模型或数据库 DDL 同步,字段名、类型、空值约束脱节。解决:在prd_core/中增加mock_generator.py,基于 SQLAlchemy Model 自动生成 mock:from sqlalchemy import create_engine from prd_core.models import User, Order # 假设这是你的 ORM 模型 from faker import Faker fake = Faker() def generate_mock_user(): return { "id": fake.uuid4(), "username": fake.user_name(), "email": fake.email(), "total_orders": fake.random_int(min=0, max=50), "created_at": fake.date_time_this_decade() } # 后续 notebook 中直接调用 generate_mock_user(),保证结构一致性4.5 现象:CI 流程中 notebook 运行超时,被 Jenkins/GitLab CI 强制 kill原因:某些 cell 包含耗时操作(如调用外部 API、加载大文件),而 CI 默认 timeout 为 5 分钟。解决:对耗时 cell 添加超时装饰器,并在 CI 脚本中设置合理 timeout:import signal class TimeoutError(Exception): pass def timeout(seconds): def decorator(func): def wrapper(*args, **kwargs): def handler(signum, frame): raise TimeoutError(f"Function {func.__name__} timed out after {seconds}s") signal.signal(signal.SIGALRM, handler) signal.alarm(seconds) try: result = func(*args, **kwargs) finally: signal.alarm(0) return result return wrapper return decorator # 在 notebook 中使用 @timeout(30) # 限制 30 秒 def call_external_api(): # ... requests.get(...) passCI 脚本中同步设置:pytest --timeout=300 notebooks/(全局 5 分钟)。5. 进阶技巧:把 PRD Notebook 变成需求变更的“后悔药”与跨团队对齐的“公证处”5.1 需求变更追踪:用 Git Commit Hash 锁定 PRD 与代码的精确对应关系当 PRD 规则调整(如“VIP 用户免运费门槛从 99 降至 59”),不能只改 notebook,必须同步更新prd_core/中的实现,并用 commit hash 建立双向锚点。操作流程如下:修改prd_core/order_rules.py中的常量FREE_SHIPPING_THRESHOLD = 59;在notebooks/01_order_prd.ipynb中更新对应 cell 的断言:assert shipping_fee == 0;提交时 message 明确关联:feat(prd): update free shipping threshold to 59 (ref PRD-V2.3);在 notebook 的 README.md 中维护变更日志表:PRD 版本Commit Hash变更内容影响模块验证人V2.3a1b2c3d免运费门槛下调至 59订单结算、购物车A同学V2.2e4f5g6h新增订单取消后库存回滚规则库存服务、订单状态机某导师关键价值:当线上出现争议(“V2.3 上线后,用户反馈满 59 不免邮”),可立即 checkouta1b2c3dcommit,运行 notebook 复现问题,排除“是不是部署错了版本”的干扰,直击代码逻辑。5.2 跨团队对齐:用 notebook 输出生成三方可验证的“需求快照”某高校图像处理 Demo 项目中,算法组、前端组、测试组常因“输入图像尺寸要求”争执。解决方案:在notebooks/_utils/image_prd_utils.ipynb中构建标准化快照生成器:import json from PIL import Image import numpy as np def generate_image_spec_snapshot(width, height, channels, dtype="uint8", max_size_mb=5): """生成图像规格的机器可读快照""" spec = { "input_requirements": { "width_px": {"min": 32, "max": width, "recommended": 512}, "height_px": {"min": 32, "max": height, "recommended": 512}, "channels": channels, # "RGB", "RGBA", "grayscale" "dtype": dtype, "max_file_size_mb": max_size_mb }, "validation_examples": [ { "name": "valid_example_1", "shape": [height, width, channels if channels != "grayscale" else 1], "dtype": dtype, "file_size_mb": round((height * width * (3 if channels=="RGB" else 1)) / (1024*1024), 2) } ] } # 导出为 JSON(供前端/测试直接读取) with open("image_prd_spec.json", "w") as f: json.dump(spec, f, indent=2) # 同时生成可视化说明图(用 matplotlib) fig, ax = plt.subplots(figsize=(6, 2)) ax.text(0.1, 0.7, f"✅ 支持尺寸: {width}x{height}", fontsize=12) ax.text(0.1, 0.4, f"✅ 通道数: {channels}", fontsize=12) ax.axis('off') plt.savefig("image_prd_spec.png", bbox_inches='tight', dpi=150) plt.show() return spec # 调用示例(前端组确认后锁定) spec = generate_image_spec_snapshot(width=1024, height=768, channels="RGB")输出物:image_prd_spec.json(供自动化测试读取)、image_prd_spec.png(贴在 Confluence 供视觉确认)。三方只需核对同一份快照,彻底终结“你们说的尺寸是啥意思”的扯皮。5.3 CI/CD 深度集成:让 PRD Notebook 成为发布流水线的“质量守门员”在scripts/run_prd_tests.py中,将 notebook 运行封装为 pytest fixture,接入 GitLab CI:# scripts/run_prd_tests.py import pytest import subprocess import sys def test_run_all_prd_notebooks(): """pytest 用例:批量运行所有 PRD notebook""" notebooks = ["notebooks/01_order_prd.ipynb", "notebooks/02_user_prd.ipynb"] for nb in notebooks: # 使用 nbconvert 执行并捕获输出 result = subprocess.run([ sys.executable, "-m", "nbconvert", "--to", "notebook", "--execute", "--output", f"/tmp/{nb.split('/')[-1]}", nb ], capture_output=True, text=True) if result.returncode != 0: raise AssertionError(f"Notebook {nb} failed:\n{result.stderr}") # 检查输出中是否有 FAILED 断言 with open(f"/tmp/{nb.split('/')[-1]}", "r") as f: nb_content = f.read() if "AssertionError" in nb_content or "FAILED" in nb_content: raise AssertionError(f"Notebook {nb} contains failed assertions") if __name__ == "__main__": pytest.main([__file__, "-v"])CI 配置(.gitlab-ci.yml):stages: - test prd_validation: stage: test image: python:3.9 before_script: - pip install jupyter nbconvert pytest script: - python scripts/run_prd_tests.py allow_failure: false效果:任何 PR 提交,只要修改了notebooks/或prd_core/,CI 就自动运行全部 PRD 验证。失败则阻断合并,确保“文档即契约”真正落地。从那以后我每次启动新项目,都会先花 30 分钟搭好这个 PRD Notebook 骨架——不是为了炫技,而是给后续所有协作埋下一条“可验证”的底线。当产品说“这里应该加个判断”,我不再回复“好的”,而是打开 notebook 新建一个 cell,写三行代码跑通再截图发过去。需求模糊的幽灵,永远死于可执行的代码。希望帮到你。本文还有配套的精品资源,点击获取
简介:本资源是一份面向数据科学与AI开发者的PRD(产品需求文档)实践模板,聚焦Jupyter Notebook场景下的AI项目需求定义与工程化落地。它帮助产品经理、算法工程师及跨职能团队统一需求理解,解决AI产品从概念到开发的沟通断层问题,尤其适用于机器学习平台、数据分析工具类项目的前期规划。压缩包共4个文件,含2个Python脚本(fluideDataset.py、R2Plus1D.py)用于数据预处理与模型构建,2个Jupyter Notebook(Version_refactoris俥.ipynb、Classificateur.ipynb)承载可执行的需求验证逻辑、模型训练流程与分类结果可视化,完整呈现PRD中功能描述→代码实现→效果验证的闭环。包体仅2.04MB,轻量易用,结构紧凑。目前已有336人学习下载,读者可直接复用其中模块化代码结构、需求条目映射示例及Notebook交互式说明方式,快速构建具备版本管理、协作支持与性能指标对齐能力的AI项目PRD交付物。1. PRD 不是文档模板,而是需求落地的“校验黑匣子”:它用 Jupyter Notebook 把模糊需求变成可执行、可回溯、可协作的动态验证现场很多人第一次接触 PRD(Product Requirement Document)时,以为只是产品经理写给开发看的 Word 或 PDF 文件——写完就归档,评审靠嘴,变更靠吼,上线后才发现“当初说的不是这个意思”。但真实项目里,PRD 的失效往往不是因为没人写,而是因为写出来的东西无法被工程侧实时验证、参数化推演、版本化比对。而这份名为 “PRD” 的资源,本质是一个以 Jupyter Notebook 为载体的轻量级需求建模与验证框架:它不替代传统 PRD 文档,而是把关键需求逻辑(如业务规则约束、状态流转条件、数据边界判定)全部封装成可运行的 Python 单元格,支持输入样例数据→自动触发校验→高亮失败路径→导出结构化断言报告。适合正在推进中台能力沉淀的某公司后台团队、需要快速对齐算法输入输出边界的某高校图像处理 Demo 项目,以及所有被“需求理解偏差”反复背刺过的全栈开发者。它不是教你写文档,而是帮你把文档里最易歧义的那 20% 内容,变成跑得通、改得清、查得准的代码事实。2. 为什么选 Jupyter Notebook 而非 Markdown/Notion/Confluence:动态性、可调试性与工程链路直连是刚需2.1 静态文档的三大硬伤,在需求验证场景下会被指数级放大传统 PRD 文档(Word/PDF/Markdown)在需求落地阶段暴露三个结构性缺陷:第一,条件逻辑不可执行——比如“当用户等级 ≥3 且近 7 日下单频次 <2 时,触发优惠券发放”,这句话在 Word 里只是文字,开发需手动翻译成 if-else,测试需另写 case;第二,边界值无显式声明——“订单金额 > 0 且 ≤ 99999.99”这种约束,静态文档里容易漏掉小数位数、负数兜底、空值处理等细节;第三,版本变更不可追溯对比——V1.2 和 V1.3 的差异,靠人工 diff 段落,极易遗漏隐含逻辑调整。这些缺陷在小型项目里尚可容忍,但在涉及多端(Web/App/小程序)、多角色(运营/风控/客服)协同的中型系统中,会直接导致联调阶段 60% 以上的返工来自“对同一句话的理解不一致”。2.2 Jupyter Notebook 的四个不可替代优势:从文档到验证现场的跃迁Jupyter Notebook 在此场景下不是“换了个编辑器”,而是重构了需求验证的工作流:单元格即验证点:每个核心业务规则(如“支付成功后 30 秒内必须生成账单”)对应一个独立 cell,输入 mock 数据 → 运行 → 返回 True/False + 失败原因,逻辑与实现完全同源;参数化驱动:用@interact或ipywidgets构建简易 UI 控件(滑块、下拉框),让产品/测试人员无需写代码即可拖动调整阈值、切换状态机,实时观察规则触发结果;与工程环境零割裂:Notebook 可直接 import 项目中的核心 service 模块(如from billing_service import validate_order),验证逻辑复用生产代码,避免“文档逻辑”和“实现逻辑”双轨并行;天然支持断言快照:通过nbconvert --to html --no-input导出无代码 HTML 报告,嵌入 CI 流程,每次 PR 提交自动运行全部 PRD cell,失败则阻断合并——此时 PRD 不再是交付物,而是准入门禁。提示:这不是让产品经理写 Python,而是让开发把最易出错的需求逻辑“翻译”成 notebook,再由产品在 notebook 里填数据、点按钮、看结果。双方看到的是同一份可执行事实。2.3 对比主流替代方案:为什么 Notion/Confluence/Excel 全部掉队工具是否支持逻辑执行是否支持参数化交互是否能 import 生产代码是否可集成 CI/CD是否支持版本间逻辑 diffNotion❌❌(仅基础表单)❌❌❌(仅页面级 diff)Confluence❌❌❌❌❌Excel⚠️(公式有限)⚠️(控件复杂难维护)❌❌❌Jupyter NB✅(原生)✅(ipywidgets)✅(同 Python 环境)✅(nbconvert+pytest)✅(git diff .ipynb + 自定义 parser)关键结论:当需求验证需要可计算、可干预、可自动化时,Jupyter Notebook 是当前技术栈下唯一满足全部硬性要求的载体。它不解决“怎么写需求”,但彻底解决了“写的是否真能跑通”。3. 快速上手:5 分钟初始化你的 PRD Notebook 工程骨架3.1 环境准备:最小依赖集与隔离建议本框架设计为轻量嵌入,不强制绑定特定框架。推荐使用venv创建独立环境(避免污染全局 Python),核心依赖仅 3 个:python -m venv prd_env source prd_env/bin/activate # Windows: prd_env\Scripts\activate pip install jupyter ipywidgets nbconvert pytest注意:ipywidgets需要额外启用前端扩展(JupyterLab 用户执行jupyter labextension install @jupyter-widgets/jupyterlab-manager;经典 Notebook 执行jupyter nbextension enable --py widgetsnbextension)。若跳过此步,交互控件将不渲染,但基础运行功能不受影响。3.2 目录结构:让 PRD Notebook 成为可维护的工程资产不要把所有内容堆在一个.ipynb文件里。按模块拆分,便于协作与 CI 切片执行:prd_project/ ├── requirements.txt # 仅记录 notebook 专用依赖(如 pandas, requests) ├── prd_core/ # 核心需求逻辑目录(存放 .py 模块,供 notebook import) │ ├── __init__.py │ ├── order_rules.py # 订单类规则(金额校验、状态流转) │ └── user_profile.py # 用户类规则(等级计算、权益发放) ├── notebooks/ # Notebook 主体(按业务域划分) │ ├── 01_order_prd.ipynb # 订单 PRD 验证主本 │ ├── 02_user_prd.ipynb # 用户 PRD 验证主本 │ └── _utils/ # 公共工具 notebook(如 mock 数据生成器) ├── tests/ # pytest 用例(将 notebook cell 转为 test function) │ └── test_order_rules.py └── scripts/ # 辅助脚本 └── run_prd_tests.py # 批量运行所有 PRD notebook 并生成报告关键设计:prd_core/下的.py文件是真正的业务规则实现,notebook 只负责调用和验证。这样既保证逻辑复用,又让 PRD 保持“面向验证”的轻量定位。3.3 第一个可运行 cell:从“用户等级判定”开始建立信任在notebooks/02_user_prd.ipynb中,创建第一个 cell,实现某高校图像处理 Demo 中的用户权限规则:# cell 1: 定义核心规则函数(复用 prd_core/user_profile.py) from prd_core.user_profile import calculate_user_level # 输入:mock 用户行为数据(字典格式,模拟真实 API 请求体) mock_user_data = { "total_orders": 12, "last_order_days_ago": 5, "is_vip": True, "login_frequency_last_30d": 28 } # 执行规则计算 level_result = calculate_user_level(mock_user_data) print(f"用户等级计算结果: {level_result}") # 断言:确保规则符合 PRD 约定(此处 level 应为 4) assert level_result == 4, f"预期等级 4,实际得到 {level_result}"逻辑说明:calculate_user_level()函数在prd_core/user_profile.py中实现,其内部逻辑(如“总订单≥10 且近 30 天登录≥25 次 → 等级+1”)就是 PRD 文档中“用户成长体系”章节的代码化表达。cell 中的assert是 PRD 的“法律条款”——运行失败即证明实现与需求冲突,必须修正代码或更新 PRD。3.4 加入交互验证:让产品同学自己拖动阈值看效果接着添加一个交互式 cell,暴露关键参数供非技术人员调节:# cell 2: 使用 ipywidgets 构建交互界面 import ipywidgets as widgets from IPython.display import display # 定义可调节参数(对应 PRD 中的可配置阈值) total_orders_slider = widgets.IntSlider(value=12, min=0, max=100, description='总订单数:') login_freq_slider = widgets.IntSlider(value=28, min=0, max=50, description='30天登录频次:') vip_toggle = widgets.Checkbox(value=True, description='是否 VIP:') # 组合控件 ui = widgets.VBox([total_orders_slider, login_freq_slider, vip_toggle]) # 定义响应函数(当任一控件变化时重新计算) def on_value_change(change): mock_data = { "total_orders": total_orders_slider.value, "last_order_days_ago": 5, # 固定为 5,简化 demo "is_vip": vip_toggle.value, "login_frequency_last_30d": login_freq_slider.value } result = calculate_user_level(mock_data) print(f"\r当前参数下用户等级: {result}", end="") # 绑定事件 total_orders_slider.observe(on_value_change, names='value') login_freq_slider.observe(on_value_change, names='value') vip_toggle.observe(on_value_change, names='value') display(ui) on_value_change(None) # 初始化显示参数说明:IntSlider的min/max值直接映射 PRD 中“合理取值范围”的文字描述(如“总订单数应介于 0~100”),Checkbox对应布尔型业务开关。产品同学拖动滑块时,背后运行的是同一份生产代码,结果实时可见——这比“我理解是这样”高效十倍。4. 避坑:PRD Notebook 实战中踩过的 5 个血泪坑,每一条都让团队少返工 2 天4.1 现象:Notebook 运行结果正常,但上线后相同输入却报错原因:Notebook 中import了本地prd_core/模块,但 CI 环境未安装该包,或路径未加入PYTHONPATH,导致测试时实际运行的是旧版缓存代码。解决:在 notebook 开头强制插入路径检查与模块重载:import sys import os # 确保 prd_core 在 sys.path 中(相对于 notebook 当前目录) core_path = os.path.abspath("../prd_core") if core_path not in sys.path: sys.path.insert(0, core_path) # 强制重载模块(避免 IDE 缓存旧逻辑) import importlib import prd_core.user_profile importlib.reload(prd_core.user_profile)4.2 现象:交互控件(ipywidgets)在导出 HTML 后完全消失原因:nbconvert --to html默认不嵌入前端 JavaScript,widget 渲染依赖@jupyter-widgets/jupyterlab-manager的 JS runtime。解决:导出时启用--embed-images并指定--no-input(隐藏代码,只留输出):jupyter nbconvert --to html --no-input --embed-images notebooks/02_user_prd.ipynb补充:若需完整交互能力,改用voilà部署为 Web 应用(pip install voilà; voilà notebooks/02_user_prd.ipynb),但需注意生产环境权限控制。4.3 现象:多人协作时,git diff 显示大量 JSON 冗余变更(如"collapsed": false)原因:.ipynb是 JSON 格式,cell 的元数据(折叠状态、执行计数)随每次运行自动更新,污染 git 历史。解决:配置.gitattributes强制使用nbdime工具进行语义化 diff:*.ipynb diff=nbdime并在本地安装:pip install nbdime && nbdime config-git --enable --global。此后git diff只显示代码/输出变更,忽略元数据。4.4 现象:PRD Notebook 中的 mock 数据与真实数据库 schema 不一致,导致验证通过但线上失败原因:mock 数据手动生成,未与 ORM 模型或数据库 DDL 同步,字段名、类型、空值约束脱节。解决:在prd_core/中增加mock_generator.py,基于 SQLAlchemy Model 自动生成 mock:from sqlalchemy import create_engine from prd_core.models import User, Order # 假设这是你的 ORM 模型 from faker import Faker fake = Faker() def generate_mock_user(): return { "id": fake.uuid4(), "username": fake.user_name(), "email": fake.email(), "total_orders": fake.random_int(min=0, max=50), "created_at": fake.date_time_this_decade() } # 后续 notebook 中直接调用 generate_mock_user(),保证结构一致性4.5 现象:CI 流程中 notebook 运行超时,被 Jenkins/GitLab CI 强制 kill原因:某些 cell 包含耗时操作(如调用外部 API、加载大文件),而 CI 默认 timeout 为 5 分钟。解决:对耗时 cell 添加超时装饰器,并在 CI 脚本中设置合理 timeout:import signal class TimeoutError(Exception): pass def timeout(seconds): def decorator(func): def wrapper(*args, **kwargs): def handler(signum, frame): raise TimeoutError(f"Function {func.__name__} timed out after {seconds}s") signal.signal(signal.SIGALRM, handler) signal.alarm(seconds) try: result = func(*args, **kwargs) finally: signal.alarm(0) return result return wrapper return decorator # 在 notebook 中使用 @timeout(30) # 限制 30 秒 def call_external_api(): # ... requests.get(...) passCI 脚本中同步设置:pytest --timeout=300 notebooks/(全局 5 分钟)。5. 进阶技巧:把 PRD Notebook 变成需求变更的“后悔药”与跨团队对齐的“公证处”5.1 需求变更追踪:用 Git Commit Hash 锁定 PRD 与代码的精确对应关系当 PRD 规则调整(如“VIP 用户免运费门槛从 99 降至 59”),不能只改 notebook,必须同步更新prd_core/中的实现,并用 commit hash 建立双向锚点。操作流程如下:修改prd_core/order_rules.py中的常量FREE_SHIPPING_THRESHOLD = 59;在notebooks/01_order_prd.ipynb中更新对应 cell 的断言:assert shipping_fee == 0;提交时 message 明确关联:feat(prd): update free shipping threshold to 59 (ref PRD-V2.3);在 notebook 的 README.md 中维护变更日志表:PRD 版本Commit Hash变更内容影响模块验证人V2.3a1b2c3d免运费门槛下调至 59订单结算、购物车A同学V2.2e4f5g6h新增订单取消后库存回滚规则库存服务、订单状态机某导师关键价值:当线上出现争议(“V2.3 上线后,用户反馈满 59 不免邮”),可立即 checkouta1b2c3dcommit,运行 notebook 复现问题,排除“是不是部署错了版本”的干扰,直击代码逻辑。5.2 跨团队对齐:用 notebook 输出生成三方可验证的“需求快照”某高校图像处理 Demo 项目中,算法组、前端组、测试组常因“输入图像尺寸要求”争执。解决方案:在notebooks/_utils/image_prd_utils.ipynb中构建标准化快照生成器:import json from PIL import Image import numpy as np def generate_image_spec_snapshot(width, height, channels, dtype="uint8", max_size_mb=5): """生成图像规格的机器可读快照""" spec = { "input_requirements": { "width_px": {"min": 32, "max": width, "recommended": 512}, "height_px": {"min": 32, "max": height, "recommended": 512}, "channels": channels, # "RGB", "RGBA", "grayscale" "dtype": dtype, "max_file_size_mb": max_size_mb }, "validation_examples": [ { "name": "valid_example_1", "shape": [height, width, channels if channels != "grayscale" else 1], "dtype": dtype, "file_size_mb": round((height * width * (3 if channels=="RGB" else 1)) / (1024*1024), 2) } ] } # 导出为 JSON(供前端/测试直接读取) with open("image_prd_spec.json", "w") as f: json.dump(spec, f, indent=2) # 同时生成可视化说明图(用 matplotlib) fig, ax = plt.subplots(figsize=(6, 2)) ax.text(0.1, 0.7, f"✅ 支持尺寸: {width}x{height}", fontsize=12) ax.text(0.1, 0.4, f"✅ 通道数: {channels}", fontsize=12) ax.axis('off') plt.savefig("image_prd_spec.png", bbox_inches='tight', dpi=150) plt.show() return spec # 调用示例(前端组确认后锁定) spec = generate_image_spec_snapshot(width=1024, height=768, channels="RGB")输出物:image_prd_spec.json(供自动化测试读取)、image_prd_spec.png(贴在 Confluence 供视觉确认)。三方只需核对同一份快照,彻底终结“你们说的尺寸是啥意思”的扯皮。5.3 CI/CD 深度集成:让 PRD Notebook 成为发布流水线的“质量守门员”在scripts/run_prd_tests.py中,将 notebook 运行封装为 pytest fixture,接入 GitLab CI:# scripts/run_prd_tests.py import pytest import subprocess import sys def test_run_all_prd_notebooks(): """pytest 用例:批量运行所有 PRD notebook""" notebooks = ["notebooks/01_order_prd.ipynb", "notebooks/02_user_prd.ipynb"] for nb in notebooks: # 使用 nbconvert 执行并捕获输出 result = subprocess.run([ sys.executable, "-m", "nbconvert", "--to", "notebook", "--execute", "--output", f"/tmp/{nb.split('/')[-1]}", nb ], capture_output=True, text=True) if result.returncode != 0: raise AssertionError(f"Notebook {nb} failed:\n{result.stderr}") # 检查输出中是否有 FAILED 断言 with open(f"/tmp/{nb.split('/')[-1]}", "r") as f: nb_content = f.read() if "AssertionError" in nb_content or "FAILED" in nb_content: raise AssertionError(f"Notebook {nb} contains failed assertions") if __name__ == "__main__": pytest.main([__file__, "-v"])CI 配置(.gitlab-ci.yml):stages: - test prd_validation: stage: test image: python:3.9 before_script: - pip install jupyter nbconvert pytest script: - python scripts/run_prd_tests.py allow_failure: false效果:任何 PR 提交,只要修改了notebooks/或prd_core/,CI 就自动运行全部 PRD 验证。失败则阻断合并,确保“文档即契约”真正落地。从那以后我每次启动新项目,都会先花 30 分钟搭好这个 PRD Notebook 骨架——不是为了炫技,而是给后续所有协作埋下一条“可验证”的底线。当产品说“这里应该加个判断”,我不再回复“好的”,而是打开 notebook 新建一个 cell,写三行代码跑通再截图发过去。需求模糊的幽灵,永远死于可执行的代码。希望帮到你。本文还有配套的精品资源,点击获取