⏱ 预计阅读:10 分钟
[!summary] 开发中的麻烦,通常不是某一层完全做错,而是数据、后端、Agent 和前端分别做对了自己的部分,接口却说着不同语言。这篇从四张详细设计契约开始,一路讲到跨层评审、任务 DAG 和带证据的代码实现。
下面仍以“资料问答工作台”为假设样例:管理员导入部门文档,成员在权限范围内获得带引用的回答。它不是某个真实项目的复盘,而是为了把删除传播、接口错误、Agent 权限和流式状态放进同一条链路里。下面七个 Skill 覆盖从详细设计到代码实现的完整过程。
先理解四条必须对齐的握手面
一条“提问并返回引用”的链路至少跨越四层握手面:S005-1 规定文档、分块、删除传播和引用字段;S005-2 规定 API、权限、超时和错误;S005-3 规定模型何时能调用哪些检索工具、何时停止;S005-4 规定页面如何展示流式事件、取消、错误和恢复。只要有一层把 documentId 改名、把“删除已生效”理解成不同时间点,系统就会出现最难排查的幽灵问题。
S005-1:先把数据当作可治理的产品契约
1. $haonan-s005-1-lld-data 如何设计数据、检索和删除传播
图注:S005-1 将数据许可、实体、处理状态、质量门禁和 RAG 检索契约连成闭环。
先别选 PostgreSQL 还是向量库。把数据从进入系统、被处理、参与检索到最终删除完整走一遍,真正需要什么存储通常就清楚了。每个数据源要记录所有者、许可、用途、更新频率、敏感级别、版本和校验和;再定义核心实体、标识符、关系与数据所有权。对资料问答工作台,原始文件、解析版本、文档片段、索引版本、引用记录和访问授权必须分开表达,一个 documents 表装不下这些语义。
接着它定义数据状态机:原始区、处理中、已发布、隔离、删除。上传会经过校验、标准化、去重、脱敏和分块;失败项进入隔离区并可重放;同一个导入请求重复到达时要有幂等策略。若使用 RAG(检索增强生成),契约还必须说明 chunk(分块)的边界、元数据、召回过滤、重排、引用格式、索引版本和删除传播。否则“用户删掉文档”后,旧向量索引仍可能被 Agent 引用。
这一步会留下数据字典、Schema、管道状态机、质量矩阵以及迁移、回填、对账和回滚方案。后端据此获得事务与查询契约,Agent 则拿到检索与引用契约。Top-K、分块长度和质量阈值如果没有真实样本验证,就只能标为待测假设。我见过更常见的过度设计,是为了“架构完整”一次引入关系库、缓存、向量库、图数据库和搜索引擎;每一种存储都应能对应一个真实的访问模式、规模、可靠性或成本依据。
S005-2:把服务写成调用方可恢复的协议
2. $haonan-s005-2-lld-back 如何约束 API、事务和外部依赖
图注:S005-2 把服务边界、API、并发语义、异步任务和故障恢复写成后端契约。
一个 DELETE /documents/{id} 接口,最能看出后端契约有没有写透。它究竟同步删除、异步受理,还是只做标记删除?重复请求返回成功还是冲突?索引何时失效?这些答案都会改变前端状态和数据删除传播。S005-2 因此要先盘点运行时、既有模块、部署边界和调用方,再为每个服务写清职责、数据所有权与禁止跨越的边界。成功响应之外,认证、请求/响应 DTO(数据传输对象)、分页、版本、错误目录、客户端恢复动作和兼容策略也要进入契约。
写操作必须明确事务边界、并发冲突和幂等语义。长耗时解析或重建索引不应假装成一个永远会成功的同步请求;若需要异步任务,要定义任务状态、租约、超时、取消、重试、重放、死信和结果通知。外部模型或身份服务也要有超时、退避、熔断、限流和降级:模型服务不可用时是返回可解释错误、排队还是只提供搜索结果?这不是实现细节,而是产品体验的一部分。
API 和事件契约、统一错误目录、授权矩阵、事务与异步状态机、外部依赖故障矩阵,以及日志、指标、追踪设计,会在这里汇总。S005-3 接走工具 Schema、权限、超时和错误;S005-4 接走流式、错误与恢复契约。至于分布式锁或消息队列,不能因为“听起来可靠”就无差别套用。先把写冲突、重复投递和失败后果讲清楚,再选最小的控制手段。
S005-3:让 Agent 作为受约束的工作流,而不是会说话的黑箱
3. $haonan-s005-3-lld-agent 如何控制上下文、工具、预算和审批
图注:S005-3 用状态机、最小权限工具、硬预算和验证点约束非确定性模型行为。
模型说“完成了”不算完成。进入 Prompt 之前,S005-3 先判断任务是否真的需要 Agent:固定查询或普通函数能解决,就没有必要加入循环规划。确实需要时,再定义任务目标、输入/输出 Schema、非目标、成功条件和人类责任。资料问答工作台里的 Agent 可以根据成员身份调用检索工具,基于允许返回的片段组织回答并给出引用;它没有理由获得文件删除、成员管理或支付操作的权限。
它将行为写成状态机:计划、执行、等待、重试、人工审批、完成、失败、取消。每个工具都有目的、输入 Schema、资源范围、最小权限、幂等、超时、错误和审计字段;每次执行都有轮次、时间、Token(模型输入输出单位)、成本、并发和最大工具调用数等硬预算。没有无进展检测和终止条件的 Agent,迟早会把“请再试一次”循环成成本事故。
上下文被分成系统指令、当前任务、用户允许访问的检索结果、短期状态和经批准的记忆;敏感数据尽量少进上下文,Prompt 与工具版本也要能回滚。关键输出还要通过 Schema、业务规则、工具结果或人工复核验证。测试会从这里接走 Evals(AI 评测)契约,安全接走 Prompt 注入和工具越权攻击面,前端则接流式事件与审批状态。最终目标很明确:模型可以出现偏差,但系统仍然可观察、可中止、可追责。
S005-4:把接口事实翻译成用户可理解的状态
4. $haonan-s005-4-lld-front 如何设计状态、流式交互和恢复动作
图注:S005-4 将屏幕、组件、数据状态、流式事件、恢复动作和可访问性统一起来。
后端返回 tool_running 时,界面究竟显示“正在检索”,还是“答案生成中”?这个看似很小的文案差异,会直接影响用户对结果可信度的判断。S005-4 先读取现有路由、目录、状态管理、样式和测试约定,再建立“路由/屏幕—FR/AC—API—状态”追溯表。它还要区分本地状态、服务端状态、URL 状态、表单状态和持久化边界:输入框内容属于本地状态,会话与引用属于服务端状态,筛选条件可能进入 URL,上传进度则来自异步任务。
对于问答流式输出,它必须约定事件类型、顺序、断线续传、取消、工具状态、引用和安全渲染。后端说 tool_running,前端不能把它画成“答案已验证”;后端返回权限错误,前端不能只显示“发生错误”。每类错误要映射到用户可做的恢复动作:重试、返回登录、申请权限、检查网络、重新上传或稍后查看。加载、空、部分数据、错误、权限、离线、超时、重复提交、成功和恢复不是异常补丁,而是产品状态模型的一部分。
组件职责、事件与副作用表、类型契约、缓存失效、乐观更新、并发冲突、视觉 Token、响应式、键盘焦点、屏幕阅读器和前端测试边界,都会在这里落表。它从 UI 继承视觉 Token 与资产约束,再向 S006 提供跨端握手表。视觉稿没有定义的计费、权限或数据规则,前端不能自行推断;S005-4 应把这些空白暴露出来,交还给有权决定的人。
S006:不审单篇文档,专门审它们之间的缝
5. $haonan-s006-review 如何在编码前发现“每层都对、合起来不对”
图注:S006 在设计评审和发布门禁中检查跨资产的字段、状态、权限、时序与证据。
看一个删除契约就够了:PRD 写“删除后成员不得再引用文档”,S005-1 写删除传播,S005-2 写异步删除接口,S005-3 写检索过滤,S005-4 写“删除处理中”提示。任何一环缺失,设计就仍有发布风险。S006 的 DESIGN_REVIEW(设计评审)专门检查这种缝隙,逐项比对 PRD/原型、HLD/LLD、数据/后端、后端/Agent、后端/前端、UI/前端之间的字段、状态、错误、时序、权限和 NFR。
它为问题留下证据位置、契约双方、影响、发生条件、可检测性、修复成本、最小修复动作、责任 Skill 和验证方式,并按 P0 到 P3 分级。设计阶段结论是 APPROVED / CONDITIONALLY_APPROVED / REVISE,不是虚构一个“匹配率 93%”。当输入不全时,S006 可以做局部审查,但必须写明盲区,不能给全局保证。
S007 接到的应是明确阻断项和闭环条件,而非一份泛泛的“优化建议”。好的评审会把那些接口迟早会撞上的问题,提前暴露在还没有数据迁移和用户依赖的时候。
S007:拆的是可验收纵向切片,不是技术部门的待办清单
6. $haonan-s007-planner 如何生成带依赖和回滚的任务 DAG
图注:S007 将需求、设计和代码区域拆为可并行、可验证、可回滚的纵向任务切片。
“完成问答模块”是一张看似完整、实际上无法执行的工单。S007 会读取需求/AC、HLD/LLD、评审问题、当前仓库、构建测试命令和未提交改动,先建立“需求/问题—设计契约—代码区域—验证证据”映射,再按用户价值、契约或风险切片。比如“成员只能检索到授权文档并看见引用”,会包含最小的数据过滤、API 传递、Agent 工具约束、前端状态和测试,但仍能独立验收;这比一张横跨两周的“大模块”工单更容易控制。
每个任务都有稳定 ID、范围、依赖、允许修改区、禁止项、风险、回滚和 DoD(完成定义)。DAG 要标出硬依赖、可并行组、测试夹具依赖与发布依赖:例如先定义文档/片段 schema,再让后端与检索并行;视觉样式可以与服务实现并行;但公开接口或不可逆迁移需要先形成明确的前置任务。
接口或 Schema 变更要带兼容和迁移策略,高风险任务要写数据保护与验证,测试、安全、可观测性和文档也直接进入 DoD。S008 最终拿到的是一个最小上下文包。任务既不能写成“实现问答功能”“优化性能”这种无法验收的标题,也不能为了显得原子,把一个完整行为拆成十几个彼此等待的碎片。
S008:按工单做最小完整改动,并用真实证据收口
7. $haonan-s008-coder 如何避免“代码写了,但谁也不知道是否完成”
图注:S008 从任务 DoD 出发,经风险匹配验证和 diff 检查,报告真实完成状态。
真正进入代码后,我只关心两件事:改动有没有越界,DoD 有没有被真实命令验证。S008 因此先读取仓库说明、任务/DoD、相关 PRD/HLD/LLD、既有代码与测试以及版本控制状态。它要保护用户未提交和无关修改,并识别项目实际使用的格式化、类型检查、测试与构建命令。若任务涉及公共 API、数据迁移或安全边界,却没有授权或设计契约,就不能以“顺手改了”为理由越过去。
实现循环是:把 DoD 转为最小失败或验收检查;按风险选单元、契约、集成、E2E(端到端)或视觉/可访问性验证;做满足当前范围的最小完整修改;先运行最窄测试,再扩大到受影响的格式化、类型检查、测试与构建;最后检查 diff、生成物、依赖、秘密、日志和意外文件。失败时先定位原因,不能靠降低断言、删测试或吞错误得到绿灯。
状态也要说准确:文件或测试被修改是 CREATED,看到运行现象是 OBSERVED,与 DoD 对应的命令成功才是 VERIFIED,被环境、权限或外部依赖挡住则是 BLOCKED。交付说明需要列出变更文件、行为影响、实际命令与结果、未运行项、兼容/迁移/回滚风险和下一任务。S008 最终只报告证据能证明的部分,不会把“代码写完了”自动等同于“任务完成了”。
开发中的最小验收:不要让并行变成互相覆盖
进入测试与发布前,至少做四个交叉检查:
- 数据的字段、生命周期、删除传播,是否已在后端 API、Agent 工具和前端状态中逐一落地?
- 所有写操作是否都有幂等、并发、重试、错误和恢复语义,而不是只定义成功响应?
- Agent 是否有最小权限、硬预算、无进展终止和输出验证,而不是只靠 Prompt 约束?
- 每个 S007 工单是否能指出具体的 DoD 与验证证据,S008 是否确实运行了它?
四个问题都能回答,才说明“设计契约”真正进入了代码;否则并行只是在更快地制造耦合债务。
明日预告|第 4 篇:代码写完以后,怎样真正发布
代码通过本地验证,距离“用户可以放心使用”还差最后一段路。下一篇会把场景推到发布前一晚:一次越权引用为什么会同时牵动 AI Evals、安全威胁模型、索引迁移、回滚演练和 Runbook,以及 S009 到 S012 怎样把一个能跑的 demo 收口成可交付产品。