传统软件开发落地流程
概述
为「不含大模型 / 智能体」的软件(网站、前端、后端、桌面、移动、CLI、库)提供一套可落地、带里程碑闸门的生命周期。复用 AI 开发流(zhao_ai_dev_flow)的骨架(P0–P6、红线闸门、六纪律),但去掉 LLM 专属内容(提示注入 / 越狱 / 记忆投毒 / Prompt 体系 / 轨迹级评测 / 遗忘机制),并把「编码约束(下笔即约束)」作为核心子约束——约束在 P2 定义、P3 遵守并验证。
核心原则:每阶段有明确 Gate;质量内建于设计(不只是测试阶段才查);所有平台事实必带验证标签。
何时使用
- 用户要开发非 LLM/Agent 的软件,或需要开发流程、阶段清单、Gate 定义、代码质量约束。
- 用户要评判、扩展或套用「传统软件开发流程」。
- 注意:若交付物含 LLM/Agent 能力,改用
zhao_ai_dev_flow(其内部也内嵌同一套编码约束子章节)。
红线闸门(最高优先级)
阶段未达 Gate、决策方未说「做 / 执行 / 改」之前,内层「工具调用」降级为只读——禁止建文件、写代码、执行命令。想清楚 ≠ 决策方拍板。
内层六步(每阶段内运行)
意图识别 → 技能路由 → 信息收集 → 规划执行 → 工具调用 → 迭代优化。
①–④ 为分析(红线约束下只读);⑤ 确认后才解锁;⑥ 把 bad case 回流到记忆 / 知识库。
六条贯穿纪律(通用内核)
① 领域先谈(先聊透业务实质再套框架)
② 验证标签(平台事实必带 [已核实 / 待验证 / 推测],禁止用「应该可以」替代实测)
③ 节点-边-条件边(设计用状态图 / 流程图,不画模糊模块图)
④ 安全防护内置(输入校验 / 越权 / 注入(XSS·SQLi·命令) / 敏感数据,设计即考虑,非仅测试)
⑤ 人在回路预设(关键操作如何确认授权、降级到人工)
⑥ 可观测(设计阶段定义 logging / metrics / tracing 规范,支撑 bad case 归因)
阶段骨架
- P0 立项筹备 — Gate 0:决策方确认《项目场景说明书》。动作:场景锁定 + 不做清单;四方角色(发起 / 使用 / 复核 / 接管);形态判定(Web / 移动 / 桌面 / CLI / 库);资源盘点;领域讨论(真实瓶颈?技术能 / 不能解决什么?);产出(场景说明书 + 验收指标 + 成本 + 降级预案)。
- P1 需求分析 — Gate 1:《需求规格》+ 评审签字。动作:调研;可行性 POC(标
[已核实 / 待验证]);风险矩阵(高复杂 / 中 / 低 + 外部依赖);数据合规(隐私 / 版权);MoSCoW;规格文档;跨团队评审。 - P2 系统设计 — Gate 2:架构图 + 状态图 / 流程图 + 技术方案 + 编码约束清单。动作:整体架构(前后端 / 数据 / 第三方边界);状态图 / 流程图(节点-边-条件边,含回环 / 重试上限 / 退出 / 终态);详细设计(数据结构 / 接口契约 / 错误处理 / 超时 / 并发);技术选型(五维:能力 / 速度 / 成本 / 部署 / 安全);2.9 编码约束定义(下笔即约束):动手前列出本模块编码护栏——异步回调须请求-响应配对(token/AbortController/取消上一个);兜底定时器须带「状态仍有效」校验;异步回调引用的当前状态须用 current===n/token 校验不信任闭包捕获值;改 img/video src 带 cache-buster;写「双保险」前先确认两道保险不会互相覆盖 / 顺序错乱;POC;设计评审。
- P3 建包实现 — Gate 3:核心用例可运行 + 约束验证通过。动作:WBS;「自动生成 ≠ 自动上线」闸门;编码规范(AGENTS.md / eslint);工具链打通;质量管控(交叉评审 + 静态扫描 SonarQube / eslint + 人工审查);供应链 / 依赖投毒扫描;3.8 按 P2.9 约束写代码 + 约束验证:编码严格遵循 P2 护栏;交付前逐条验证约束满足(grep / 静态检查 / 真实环境回归,尤其竞态序列、缓存命中、异常输入),而非等 bug 出现再补;Git(AI 辅助 commit 标注)。
- P4 测试验证 — Gate 4:测试报告达标。动作:环境一致;功能 / 兼容 / 安全 / 性能;专项(准确 / 安全 / 一致 / 鲁棒);独立交叉校验(不同人员 / 工具);对抗 / 异常输入测试;性能压测(P50 / P95 / P99、并发、内存);缺陷根因标注;报告。
- P5 评测标定 — Gate 5:评测报告 + 回归通过。动作:指标定义(功能 / 性能 / 体验);在线指标前置(错误率 / 延迟 / 用户满意度 / 负反馈率);标注集 / eval 集(正常 / 边界 / 异常;每类 ≥20 条为
[推测]);阈值标定(基线 → 期望 → 成本);更新后回归(依赖 / 框架 / 接口变更跑全 eval);报告。 - P6 运营进化 — Gate 6:持续运行。动作:部署版本快照;灰度发布(禁直接全量);稳定性监控(7–14 天);效果持续监控(抽检 + 定时 eval);自主迭代护栏(变更须测试门 + 人工抽样,否则只建议不自动生效);合规审计(隐私 / 数据保留 / 删除权);技术债务治理;飞轮(bad case → 根因 → 修复);复盘(含「P1 待验证项是否验证」)。
编码约束(下笔即约束)—— 核心子约束
约束在 P2 设计阶段定义、P3 编码阶段遵守并验证,不要等 bug 出现再补。凡涉及异步、状态、重复触发的代码,下笔即框住自己。
P2:定义约束(Gate 2 必需产物)
动手写代码前,针对本模块列出「编码护栏」,至少回答:
- 是否会被连续 / 高频调用(翻页、跳转、搜索输入、轮询)?→ 若是,异步回调必须做「请求-响应配对」。
- 是否有异步回调(onload / setTimeout / setInterval / Promise / fetch)?→ 若是,定义配对与取消机制。
- 是否改 img / video / iframe 的 src?→ 若是,定义 cache-buster 策略。
- 是否写「双保险 / 兜底」?→ 若是,先确认两道保险不会互相覆盖或顺序错乱。
P3:遵守 + 验证(Gate 3 交付前必做)
- 编码严格按 P2 护栏写。
- 交付前逐条验证约束满足:用 grep / 静态检查 / 真实环境回归(竞态序列、缓存命中、异常输入、兜底触发时机),而非等用户截图打脸才补。
通用约束清单(默认遵守)
- 请求-响应配对:任何带异步回调且可能重复触发的函数,必须有配对机制——计数器
token自增、取消上一个、或AbortController。只有「最后一次 / 最新」调用才允许落地渲染或写状态。 - 兜底不无脑:定时器 / 重试绝不无条件执行,必须带「仍是最新页 / token 匹配 / 请求未取消」校验。
- 不信任闭包捕获的「当前状态」:异步回调里引用的当前页 / 当前选中项 / 当前请求,必须用
current===n或token校验,不信任闭包值。 - 改媒体 src 带 cache-buster(如
?_=${token}),避免命中旧缓存引发 onload 行为异常。 - 双保险互斥:写两道以上保险前,先问「它们会不会互相覆盖 / 顺序错乱」;若会,合并为单一可信路径。
- 最小改动:修 bug 时只加护栏,不重写主逻辑,降低引入新 bug 的概率。
前端异步专项(典型案例)
- 翻页 / 轮询 / 搜索联想:用
token自增,onload / onerror / timeout 回调首行校验if (token !== latest) return; - fetch 竞态:用
AbortController在新请求时 abort 旧请求;或维护latestReqId。 - 图片懒加载:src 带 cache-buster;
complete状态不要误判为「新图已就绪」。 - 反例(曾踩坑):
imgEl.onload = () => render(n)闭包 + 无条件setTimeout(render, 60)→ 快速连点翻页时旧 n 的回调覆盖新渲染,导致「页码与热区数分裂」。修复即上述 token 配对。
UI 区域 / 坐标类专项(典型案例)—— 像素证据 > 肉眼估计
- 禁区:「用户说『区域/位置不对』时凭肉眼估坐标」/「坐标看上去差不多就先写」 → 几乎一定踩坑。
- 正确做法:拿到"不对"反馈后立即用
cv2像素扫描拿真实 bbox,再写坐标: - 白色块(如对话气泡白底):
cv2.inRange(im, (230,230,230), (255,255,255)) + cv2.connectedComponentsWithStats→ 过滤后得连通块 bbox = 真实元素轮廓 - 蓝字 / 红字:转 HSV,
cv2.inRange(hsv, (H_lo,S_lo,V_lo), (H_hi,S_hi,V_hi))+ 连通块扫描 - 红色箭头 / 标志:
cv2.inRange(im, (B_lo,G_lo,R_lo), (B_hi,G_hi,R_hi))BGR 三元组(红 = BGR 低 G、低 B、R 高) - 必须确认:
cv2.inRange第二参是三元组 tuple(标量会被解释成lo==up,要求像素 == 该值)。常见坑:用 235 一个标量结果 0 像素,必须(230,230,230), (255,255,255)。 - 热区/区域 + 2-3% padding = 正确做法;不要硬"对齐到边缘"。
- 写完后双态截图对照像素扫描 bbox,肉眼不替代证据。
验证约束(我的假设 ≠ 用户原话)—— 红闸门
根问题:写完一个 feature / 修完一个 bug / 完成一个页面后,开发者常用「我自己的技术指标」当验证——「hot 数对、坐标对、单元测试绿」——但这不是用户在意的。用户在意的是他截图里那一条条症状有没有消失。
硬约束(红闸门):
写代码前:把"用户原话"列出来当断言
- 禁止写"完美渲染""坐标对""hot 数 == 12""单元测试通过"这类自己的假设当断言。
- 必须把用户原话(或可观测的 bug 症状)逐条转成
if判断: - 用户说"音标完全遮挡了" → 断言 = "大白牌 bbox 与 hot bbox 不重叠"
- 用户说"播放按钮直接取消不需要" → 断言 = ".tag { display: none }"
- 用户说"但是要显示清楚" → 断言 = "popover display:block + ipa 字号 ≥14px"
- 每条断言必须能直接挂到一帧截图的像素或一段 DOM 的属性,禁止"看上去对"。
交付前:双态对照
- 默认态截图(不 hover 不点击) + 触发态截图(hover 或点击之后的瞬间)。
- 对照依据 = 用户最近一次给的截图或文字症状清单。逐条勾掉才能宣称完成。
- 未勾掉的项 = 未完成,无论 self-test 自认为多对。
反模式(已知错误归因)
- ❌"我以为我改了" ≡ "改对了"。
- ❌"代码逻辑顺" ≡ "用户感受对"。
- ❌遇到 bug 反复出现就怪"模型容量不够" —— 真实问题是缺上述验证硬循环,与模型容量无关。
- ❌注释自夸("chant hot 已移到 (3,2,43,16)" 与数据 y=2% 自相矛盾却没发现)—— 改完必须做"代码自检"(注释 vs 数据 / 输入 vs 输出)。
套模板(Playwright 断言骨架)
# 用户原话逐条 -> 断言
# 1. "X 完全遮挡了" -> 不重叠 bbox
assert not bbox_overlap(hot.bbox, popover.bbox), "用户原话: X 完全遮挡了"
# 2. "Y 直接取消不需要" -> 不渲染某元素
assert el_display('.y') in ('none', 'no-element'), "用户原话: Y 直接取消不需要"
# 3. "保留窗口..." -> 默认常驻
assert getComputedStyle(popover).display == 'block', "用户原话: 保留窗口显示"
# 4. 边界 -> 点击仍触发播放(功能不丢)
assert page.evaluate('window.__played') >= 1, "点击 happy 触发 audio.play"
> 验证通过 ≠ 完成 = "用户再来截图还有没有 bug"。
验证标签纪律
每条平台事实或影响决策的判断,必带其一:
- [已核实·来源]:官方文档 / 实测确认,写明来源。
- [待验证·计划:…]:知道去哪查但还没查,写明计划,不得据此让用户动手。
- [推测·依据:…]:基于有限信息推断,可能错,写明依据。
禁止把未核实内容写成确定结论。
详细参考
完整可执行清单(每阶段勾选项、Gate 速查表、落地工具清单)见 references/process.md。