本页目录

需求拆解与方案设计

把 AI 功能映射到界面、接口、数据和执行流程,写出可以验收的需求。

L2 · 能交付约 25 分钟阅读含示例、练习与验收

建议先读:TypeScript 与接口契约

本页内容

从功能描述到可验收需求#

“做一个 AI 助手”不是实现规格。它没有说明用户是谁、输入是什么、成功是什么、失败时怎么办。作为偏前端的全栈工程师,你需要把交互、数据、接口和执行状态连接起来。目标是 L2:能把一句需求拆成一个可实现、可验证的纵向功能,而不是先列一大串技术名词。

前置是系统边界和接口契约。本章以“上传制度文档后回答员工问题”为例,说明产品决策如何影响代码。即使 AI 协助写实现,这些决策仍必须显式记录,否则它会补出看似合理但彼此矛盾的行为。

先定义用户任务和错误成本#

员工想知道报销需要哪些材料,产品目标是让他获得有出处且适用当前制度的说明。这里的成功不是“生成了流畅文字”,而是引用正确文件、没有遗漏关键条件、权限正确、答复时间可接受。错误成本决定是否需要人工复核或限制自动执行。

先写三类样例:正常问题、无资料的问题、权限不允许的问题。再明确哪些需求使用普通代码解决,例如精确查制度版本;哪些需要模型处理,例如自然语言归纳。模型并不是每条路径的必选组件。

把一条需求映射到四层#

层次 需要确定的内容 示例
用户界面 用户能看到和操作什么 上传、解析状态、回答、引用、重试
接口契约 请求、响应、身份和错误 返回 documentId 与 processing 状态
数据模型 要长期保存哪些事实 所有人、版本、解析状态、索引版本
执行流程 谁执行,何时完成,失败怎么办 后台解析、发布索引、失败可重试

如果 UI 需要显示“上次解析失败原因”,后端就必须保存可展示的失败类别。如果需要查看旧回答的出处,就需要记录当时使用的文档版本。原型中的一个小标签可能意味着真实的数据生命周期,而不是只加一个枚举。

用状态表消除含糊#

下面的状态设计是讨论模板,不是任何框架的内置格式。状态描述的是知识资料是否可使用,不能把上传进度百分比混进业务枚举。

text
uploaded    原文件已保存,等待安排解析
processing  正在解析、分块或建立索引
ready       当前版本已发布,可用于检索
failed      当前处理失败,可查看原因并重试
deleted     已撤销访问,相关索引进入清理流程

每个转移都要定义触发者与前提。客户端可以申请重试,但不能直接把文档改为 ready;后台任务完成后由服务端更新。删除时应先撤销访问,再清理存储,避免异步清理过程中仍能检索到已删除资料。

版本更新还需要明确:新版本处理中,旧版本是否继续可用?如果继续,应把“文档版本”与“当前发布版本”分开。这个选择影响用户体验、一致性、存储和回滚,不能等代码写完再补。

用验收场景约束实现#

下面是一组可复制到需求文件中的验收文本,不需要运行。它帮助测试覆盖用户行为,而不是覆盖某个实现细节。

gherkin
Feature: 使用有权限的资料回答问题

Scenario: 当前资料包含答案
  Given 用户 Alice 可以阅读 ready 状态的文档 A
  When Alice 提问文档 A 中明确解释的问题
  Then 回答应附带文档 A 的可打开引用
  And 引用应指向回答所使用的文档版本

Scenario: 用户没有资料权限
  Given 用户 Bob 无权阅读文档 A
  When Bob 提问与文档 A 相关的问题
  Then 文档 A 不应进入发送给模型的上下文
  And 回答与日志不应泄露文档 A 的私人内容

Scenario: 请求中断
  Given 回答已经产生部分文本
  When 客户端连接断开
  Then 已保存文本应标记为不完整
  And 页面应允许发起一次明确的新尝试

Given 定义条件,When 定义触发,Then 定义可观察结果。这里没有指定必须使用哪个向量库或 Agent 框架,因为验收需要约束业务,而不是把技术选择当成功标准。涉及模型时,某些标准需要人工评分规则,不能全部化成精确字符串比较。

拆成可以交付的纵向切片#

第一个切片可以只支持一种文本文件:上传、保存归属、后台处理、状态查询、页面展示。第二个切片增加对单文档提问与引用。第三个切片增加多文档检索和版本更新。每个切片都包含必要的权限、失败状态和日志,形成可演示的闭环。

不要按“先写所有表、再写所有 API、最后写所有页面”把风险延后。纵向切片能尽早发现接口不匹配、状态无法展示、检索证据不够等问题。UI 可以先使用契约一致的模拟数据,但要明确模拟服务与真实服务的切换点。

方案记录与范围控制#

方案至少写清选项、选择理由和代价。例如第一版使用关系数据库和简单关键词检索,是因为资料少且需要先验证交互;以后加入向量检索的触发条件是同义问题无法召回,而不是“AI 项目都应该有向量数据库”。

把没有决定的事情单列出来:账号体系、文档权限、保留期限、模型供应商、允许的自动操作。影响安全或数据一致性的未知项需要确认;按钮间距等可逆实现细节可以由工程师按已有规范决定。不要把所有小问题都抛回用户,也不要擅自决定真正的产品语义。

常见遗漏#

只设计成功页,导致首次进入、无资料、解析失败和模型拒答时不知道显示什么。只定义创建,不定义更新和删除,导致旧知识长期残留。只验收正确答案,不验收“不知道”,导致系统在证据不足时仍自信编造。只考虑一个用户,导致权限和并发在后期大面积返工。

需求可以逐步增加,但每一步的状态与边界必须自洽。个人项目也应该写最小需求记录,它能帮助你和 AI 在数天之后恢复上下文。

从一句模糊需求推导出可以开发的规格#

下面完整推导一个案例。它是用于学习的假设产品,不代表某家公司的真实规定。假设需求方说:“把公司的制度上传,让员工问 AI;制度有更新时替换一下,回答要准确。”先不要问用哪个模型,也不要马上建 documents 表。第一步是找出这句话包含的业务承诺。

“公司的制度”可能包含公开制度和仅人事可见的文件。“员工”可能分正式员工、外包和管理员。“替换”可能意味着立即隐藏旧版,也可能意味着新版处理完才替换。“准确”可能意味着回答符合原文,也可能还要符合生效日期与员工所属地区。每个词都会改变查询条件和界面行为。

第一步:识别真正会改变实现的未知项#

不要把所有未知都当成阻塞问题。问题是否需要确认,取决于答案会不会改变业务结果、权限、数据保存或不可逆操作。主题色深浅通常可按现有规范决定;员工能否阅读历史版本则必须在实现前讲清楚。

原始说法 隐藏的问题 本案例采用的决定 对实现的直接影响
员工都能问 是否包含所有文件 普通员工只读公开制度 检索前过滤资料权限
管理员上传 谁是管理员 角色来自登录后的服务端会话 不信任请求体中的角色
替换制度 新版处理时旧版怎么办 旧版继续服务,新版就绪后切换 分开保存当前发布版本与候选版本
删除制度 已生成的回答怎么办 撤销资料访问,历史回答保留但引用不可再打开 删除影响检索和引用访问,不假装能收回已读信息
回答准确 什么算有依据 结论必须被当前有权访问的片段支持 记录检索证据并建立人工评分集
上传成功 文件存好还是可问答 分成“已上传”和“可检索”两个结果 前端分别展示存储状态与解析状态
文件较大 多大、超限怎么办 第一版仅支持不超过明确上限的文本文件 前后端限制一致,服务端最终执行限制

你不必在第一版设计所有未来情形,但必须让选定情形自洽。例如暂不支持历史版本浏览是可以的,仍要记录回答引用了哪个版本,否则更新后无法解释旧回答。暂不支持多租户也是可以的,但不能声称单用户 demo 已验证企业租户隔离。

第二步:把“好用”转成可观察行为#

“员工可以方便地查询制度”无法直接测试。把它改成:“已登录员工输入一个问题后,能看到处理阶段、回答正文和对应资料的文件名;点击引用可以打开当时使用且当前仍有权访问的原文位置。”这时,界面、数据和权限要求就都有了观察点。

还有一些行为不是功能按钮,却属于产品承诺。例如用户关掉页面后文件解析继续执行;同一次上传重试不会生成两个候选版本;没有可支持答案的资料时显示依据不足;模型故障不能显示为“没有相关制度”。这些区别影响用户采取什么行动,不能用一个通用错误气泡替代。

第三步:为第一版写清不包含什么#

范围排除应该解释边界,而不是逃避必要的失败处理。本案例第一版不支持扫描 PDF 的 OCR,不支持自动创建审批单,不支持跨组织共享;但仍然支持上传失败、解析失败、无权限和重复请求。后一组属于已有功能的完整性,不属于可随意推迟的“高级功能”。

好的范围说明能帮助你拒绝无关扩张。例如有人提出“顺便让 AI 自动发送审批邮件”,你可以指出它新增了外部副作用、收件人校验、确认、幂等和审计,不只是添加一个工具函数。把新增成本写清楚,再决定是否进入下一版本。

逐字段建立前端到数据库的映射#

字段映射的用途是防止前端、接口和存储各自使用相似但不等价的词。下面的表可以作为实际开发前的起点。字段名是本案例的约定,不是行业强制标准。

页面字段或行为 接口字段 持久化事实 校验与空值规则
文档名称 title documents.title trim 后非空;不把空字符串变成“未命名”而不告知用户
原始文件名 originalFileName versions.original_file_name 用于展示,不作为服务器磁盘路径
文件类型 mediaType versions.media_type 由服务端检查,不能只相信扩展名
文件大小 byteSize versions.byte_size 非负整数;与实际接收字节数一致
上传人 createdBy versions.created_by 来自会话,不由表单填写
可见范围 visibility documents.visibility 仅允许约定枚举;修改必须鉴权
当前可检索版本 activeVersionId documents.active_version_id 首次处理未完成时可为 null
新版处理状态 candidate.status versions.status 与当前发布版相互独立
失败原因 candidate.errorCode versions.error_code 稳定业务码;不返回内部堆栈
可否重试 candidate.retryable 由状态与错误规则计算 不是客户端自行推断的常量
引用页码或位置 citations[].location chunks.source_location 格式因文件类型不同,需注明单位
回答完成状态 completionState messages.completion_state complete、partial 等枚举,不能由正文是否非空推断
一次生成尝试 attemptId attempts.id 每次重新生成都有新标识
追踪请求 requestId 日志关联字段 不等同于会话 ID 或业务幂等键

注意表里有些字段不需要直接存储。例如 retryable 可以由失败码和当前版本状态计算。冗余保存会引入同步问题:状态已经恢复就绪,旧 retryable 仍为 true。另一些字段必须存下来,例如产生旧回答时使用的版本 ID,不能事后用当前发布版补填。

什么叫“同名但不同义”#

前端的 status 可能指上传控件状态,后端的 status 指解析任务状态,数据库的 status 指文档是否删除。如果直接复用一个字段,上传完成就可能误显示“资料可用”。给不同领域对象各自命名和定义,即使字段名都叫 status,也必须通过对象边界区分。

还要明确时间、金额和计数的单位。duration: 5 是秒还是毫秒?size: 100 是字节还是 KiB?updatedAt 是用户修改时间,还是后台最后一次处理时间?这些细节不会被 TypeScript 自动识别,却会直接造成错误展示和错误排序。

把状态图写成可以执行检查的转移规则#

只有状态列表还不够,还需要事件、前置条件和产生的副作用。下面只描述一个候选版本的处理,不把文档发布指针混进同一个枚举。

当前状态 事件 下一状态 必须同时成立的条件
uploaded 开始处理 processing 已领取任务,版本未撤销
processing 处理成功 ready 解析与索引已经完整保存
processing 处理失败 failed 保存稳定错误码与尝试信息
failed 请求重试 uploaded 错误允许重试,版本仍有效
uploaded / processing / failed / ready 撤销版本 deleted 立即不再允许访问和发布
ready 发布为当前版 ready 另一个事务更新文档的 activeVersionId

发布事件没有改变版本的 ready 状态,因为“准备好了”和“当前正在服务”是不同事实。一个历史版本仍然可以是 ready,但不再是当前发布版本。模型准确性排查经常需要知道这两个事实,不能只看到一行 status=success

可运行实验:用状态契约阻止非法转移#

保存为 document-transition.mjs,运行 node document-transition.mjs。这是零依赖 Node 示例,用于验证业务规则;它不包含数据库事务或真正的任务队列。

js
import assert from 'node:assert/strict';

const rules = {
  uploaded: { start: 'processing', remove: 'deleted' },
  processing: { succeed: 'ready', fail: 'failed', remove: 'deleted' },
  failed: { retry: 'uploaded', remove: 'deleted' },
  ready: { remove: 'deleted' },
  deleted: {},
};

function transition(version, event) {
  // 真实服务端还要先确认调用者身份、资源权限和任务所有权。
  const next = rules[version.status]?.[event.type];
  if (!next) throw new Error(`ILLEGAL_TRANSITION:${version.status}:${event.type}`);
  if (event.type === 'retry' && !version.retryable) {
    throw new Error('NOT_RETRYABLE');
  }
  if (event.type === 'succeed' && !event.indexCommitted) {
    throw new Error('INDEX_NOT_READY');
  }
  if (event.type === 'fail' && !event.errorCode) {
    throw new Error('ERROR_CODE_REQUIRED');
  }
  return {
    ...version,
    status: next,
    revision: version.revision + 1,
    errorCode: event.type === 'fail' ? event.errorCode : null,
    retryable: event.type === 'fail' ? Boolean(event.retryable) : false,
  };
}

let version = { id: 'v2', status: 'uploaded', revision: 1,
  errorCode: null, retryable: false };
version = transition(version, { type: 'start' });
assert.equal(version.status, 'processing');
assert.throws(() => transition(version, { type: 'succeed' }), /INDEX_NOT_READY/);
version = transition(version, { type: 'fail', errorCode: 'TEMPORARY_STORAGE', retryable: true });
version = transition(version, { type: 'retry' });
version = transition(version, { type: 'remove' });
assert.equal(version.status, 'deleted');
assert.throws(() => transition(version, { type: 'start' }), /ILLEGAL_TRANSITION/);
console.log('通过:索引未提交不能就绪,删除后不能重新启动');

revision 表示状态版本,方便讨论并发更新。这个纯函数里增加数字并不会自动解决数据库竞争。真实数据库更新可以用“旧 revision 必须等于预期值”作为条件,影响行数为 0 时说明状态已被其他操作改变。你需要重新读取或拒绝过期操作,而不是覆盖更新。

这个例子也说明业务函数的测试价值:你可以不启动页面和数据库,先验证规则内部是否矛盾。接着再用集成测试确认数据库条件更新真正实现了这些规则。两个层次都要存在,不能让纯函数测试替代并发数据库实验。

一次版本更新如何跨越多个组件#

假设文档 A 的 v1 正在服务,管理员上传 v2。服务端先把原文件与版本记录可靠保存,返回 v2 的标识和 uploaded 状态;后台任务领取后改为 processing,解析文本、切块并生成索引。只有所有必需部分准备好,v2 才能进入 ready。

切换发布指针时,服务端在事务中检查文档没有被删除、v2 仍属于文档 A、操作者仍有权限、当前版本没有被另一次更新改变。条件满足后,将 activeVersionId 从 v1 改为 v2。旧索引的清理可以异步进行,但新查询必须按发布指针选择版本,不能把所有 ready 版本混在一起检索。

为什么不能“解析一块就立刻对外可见”#

假设新制度前半部分写“适用所有员工”,后半部分写“某地区除外”。如果索引只建立了一半就参与问答,模型可能给出缺少例外条件的结论。原子发布的目的是让一次查询看到一个一致的知识版本,而不只是让数据库字段好看。

删除与解析成功同时发生时怎么办#

管理员撤销文档,后台任务此时刚好完成。如果任务只执行 UPDATE status='ready',它可能把已删除版本重新激活。状态更新必须带上期望的前置条件,例如只有 processing 且未撤销时才能改 ready;发布指针也必须检查文档仍有效。这个竞争条件应写进需求验收,而不是靠一个开发者“记得注意”。

数据库写入成功,但任务没有入队怎么办#

数据库事务和外部队列发送不是同一个原子操作。直接先写库再入队,中间进程崩溃会留下无人处理的记录;先入队再写库,消费者可能读取不到记录。一个常见解决方向是在同一数据库事务中写入待发布任务记录,由独立过程投递队列并标记结果,也就是 outbox 思路。

第一版也可以不用外部队列,直接让后台工作者从数据库领取任务,但仍需租约、重试和幂等。需求只要求可靠处理,不要求某个特定中间件。选型应服务于这个可靠性条件,而不是反过来。

把接口样例写到前端能直接接入的程度#

以下 JSON 是完整合法对象,可以复制到 mock 数据中。它们是案例契约,不代表现有服务器已经实现。上传接口成功表示资源已登记,并不表示可检索。

json
{
  "documentId": "doc-a",
  "activeVersionId": "v1",
  "candidate": {
    "versionId": "v2",
    "status": "uploaded",
    "errorCode": null,
    "retryable": false
  },
  "requestId": "req-upload-2"
}

前端收到这个对象后显示“新版已上传,正在等待处理;当前问答仍使用旧版”。如果 activeVersionId 为 null,则应显示“文件已上传,处理完成后可以提问”。同一个候选状态,因为是否存在旧版,用户可执行的操作会不同;这就是组合状态,不适合只靠一个字典映射文本。

查询失败时,定义稳定错误对象。例如用户能修正输入的错误可以包含字段名;内部依赖失败不要把原始堆栈传出去。下面的 error code 用于程序分支,message 用于用户说明,两者不要互相替代。

json
{
  "error": {
    "code": "DOCUMENT_PROCESSING",
    "message": "资料还在处理中,请稍后再试。",
    "retryable": true
  },
  "requestId": "req-question-7"
}

同一个 retryable 在不同接口可能代表不同动作。它可能表示“稍后重新查询”,不表示“重新上传文件”。因此接口文档应写清允许重试的方法、是否复用幂等键,以及服务器是否提供重试时间。一个布尔值没有足够信息替你完成这些产品语义。

为什么接口文档需要说明失败时机#

HTTP 响应头尚未发送时,可以返回正常错误码;开始流式回答后,只能按流协议发送错误事件或结束连接。前端要区分“请求没有开始”“得到部分内容后失败”和“成功完成但保存历史失败”。这些状态影响提示、重试和历史记录展示,不能统称为请求失败。

业务操作尤其需要说明“结果未知”。例如创建任务时网络断开,不能直接说创建失败,因为数据库可能已经提交。应查询 operationId 或用相同幂等键恢复结果。需求中承认“未知”状态,往往比强行二分成功与失败更准确。

把异常矩阵变成可执行验收计划#

验收应包含测试数据、操作、预期结果和观察证据。下面的表不仅给出场景名称,还告诉你去哪里确认结果。它可以直接转成集成测试与端到端测试的任务列表。

场景 具体操作 必须观察到的结果 证据位置
首次上传 上传有效文本 有文档 ID,尚不可检索 API、数据库与页面状态
新版处理中 v1 就绪后上传 v2 问答仍使用完整 v1 本次检索版本记录
文件超限 发送超过上限的请求 及时拒绝,不继续消耗解析资源 HTTP 结果与任务数量
越权读取 Bob 请求 Alice 私有文档 不返回原文和摘要 响应与模型调用日志
越权检索 Bob 提问私有资料内容 私有片段不进入上下文 受控测试追踪
重复上传请求 同一键同一内容提交两次 按约定返回同一结果 唯一约束与记录数量
同键不同内容 复用键但更改正文 明确冲突,不静默覆盖 HTTP 错误码与原记录
处理中删除 任务未完成时撤销文档 后台完成也不能重新发布 状态与发布指针
无依据问题 提问资料不包含的内容 说明依据不足,不伪造引用 固定评测样例
模型服务失败 注入上游 503 显示服务失败,不说资料不存在 错误分类与请求次数
连接中断 回答一半断开 保留 partial 状态 页面与消息记录
新版发布后 同一问题重新提问 使用 v2,旧回答仍标 v1 版本与引用记录

表里的“模型调用日志”只应记录受控测试所需的标识、阶段和脱敏信息。生产环境不能为了证明权限而长期记录全部私人文档。如果需要检查上下文是否泄露,可以在测试中用合成的特征字符串和内存 mock 捕获请求,避免真实敏感内容离开边界。

主观质量怎么写验收#

答案质量可以分成有依据、完整性、相关性、表达清晰等维度,并给每个维度明确评分例子。不要只写“正确率达到 95%”,却没有样本分布、判定规则与失败类别。一个只包含十个简单问题的高分,不能代表复杂问题也可靠。

保留无答案、冲突资料、过期制度、权限受限和用户含糊提问等样例。对同一修改,使用同一批问题比较,并记录模型、提示词和索引版本。这个项目的质量结论应限定在已评测的范围内,而不是扩展成“任何制度都能准确回答”。

需求变更时,如何判断影响范围#

假设新增要求:“上传后的新版本必须由另一位管理员审核才能发布。”这不是把按钮文案改成“审核”就够了。版本需要新增等待审核阶段,数据需要保存提交人、审核人、审核时间和意见,权限规则需要禁止本人审核,发布流程需要验证审核仍适用于当前版本。

前端需要显示审核队列与拒绝原因,接口需要提交、批准、拒绝动作,数据库需要约束和审计字段,后台任务不能绕过审核直接更新发布指针。历史数据迁移也要决定已经 ready 的版本如何处理。分析一个变更时沿 UI、接口、数据、执行、权限、测试六条线检查,可以避免只修一个页面。

一份更完整的参考方案#

把解析状态和审核状态分开:processing/ready/failed 描述处理,pending/approved/rejected 描述审批。发布条件是“解析 ready,审批 approved,文档未删除,审批对应版本未变,操作者有发布权限”。拒绝审核不会要求重新解析相同文件;修改文件会创建新版本,并使旧审批不能用于新内容。

练习时先写这条发布谓词,再补状态转移测试。不要先加两个布尔值 isReadyisApproved,然后在按钮上判断一次就认为控制完成。真正的发布入口必须在服务端重新执行同样的业务条件,客户端只负责提前解释为什么当前不能操作。

练习:实现发布条件,而不只写方案摘要#

下面给出完整参考实现,保存为 publish-policy.mjs,运行 node publish-policy.mjs。它只检查案例发布策略,不执行数据库写入。实际发布应在事务中读取可信记录并原子更新,以防检查之后状态变化。

js
import assert from 'node:assert/strict';

function canPublish({ actor, document, version, approval }) {
  if (!actor?.permissions?.includes('document:publish')) return { ok: false, reason: 'FORBIDDEN' };
  if (document.deleted) return { ok: false, reason: 'DOCUMENT_DELETED' };
  if (version.documentId !== document.id) return { ok: false, reason: 'WRONG_DOCUMENT' };
  if (version.status !== 'ready') return { ok: false, reason: 'NOT_READY' };
  if (!approval || approval.status !== 'approved') return { ok: false, reason: 'NOT_APPROVED' };
  if (approval.versionId !== version.id) return { ok: false, reason: 'STALE_APPROVAL' };
  if (approval.reviewerId === version.createdBy) return { ok: false, reason: 'SELF_REVIEW' };
  return { ok: true, versionId: version.id };
}

const input = {
  actor: { id: 'publisher', permissions: ['document:publish'] },
  document: { id: 'doc-a', deleted: false },
  version: { id: 'v2', documentId: 'doc-a', status: 'ready', createdBy: 'alice' },
  approval: { status: 'approved', versionId: 'v2', reviewerId: 'bob' },
};
assert.deepEqual(canPublish(input), { ok: true, versionId: 'v2' });
assert.equal(canPublish({ ...input, document: { ...input.document, deleted: true } }).reason, 'DOCUMENT_DELETED');
assert.equal(canPublish({ ...input, approval: { ...input.approval, versionId: 'v1' } }).reason, 'STALE_APPROVAL');
assert.equal(canPublish({ ...input, approval: { ...input.approval, reviewerId: 'alice' } }).reason, 'SELF_REVIEW');
assert.equal(canPublish({ ...input, actor: { id: 'guest', permissions: [] } }).reason, 'FORBIDDEN');
console.log('通过:发布成功、删除、过期审批、本人审核和无权限五种情况');

你应该先独立写出测试,再看参考实现。尝试添加新的失败条件,例如候选版本已经被后来的上传替代。说明这个条件应作用在版本记录、文档指针还是审批记录,写出一个会失败的测试,再修改实现。这比继续阅读更多术语更能证明你理解了需求对代码的影响。

把需求文档交给 AI 前,最后检查一次#

确认 AI 能从文档中回答:用户是谁,能操作哪些资源,输入允许什么,成功表示什么,失败是否可重试,数据怎样更新与删除,怎么判断实现完成。任何一个答案需要猜测,都可能在生成代码时变成未经确认的产品决定。

你不必一次提供整个系统。可以把本章发布策略、字段映射与五个测试作为一个独立任务,要求先实现纯业务规则;随后再接数据库事务,最后接页面。每一步的输入输出稳定,AI 就能在可审查的范围内帮助你,而你始终掌握最终的业务含义。

练习#

为“让助手帮我创建任务”补齐操作草稿、用户确认、提交中、成功和失败状态。考虑用户点击两次确认、确认后网络断开、任务已创建但响应丢失。

参考答案

先生成可编辑草稿,展示关键字段;确认后由服务端重新检查权限与输入,用幂等键创建任务。网络失败时先查询同一操作状态或使用相同幂等键重试,不能盲目创建新任务。已执行结果应包含任务 ID,页面刷新后可恢复。模型只提出草稿,最终执行由程序和用户授权共同约束。

验收与自测#

  • 能把一个 AI 需求映射到 UI、接口、数据和执行流程。
  • 至少覆盖正常、无数据、无权限、依赖失败和重复请求。
  • 能解释一个技术选择的收益、代价和后续升级条件。

问:验收写“回答智能、准确”足够吗? 答:不够,需要样例、评分规则和可观察的失败标准。

问:原型没有错误页,是否可以忽略? 答:应补充必要状态并明确产品行为。

问:为什么在实现前讨论删除? 答:删除影响文件、索引、缓存和历史引用,属于完整的数据生命周期。

官方参考#

原有课程整理于 2026-09-10;Node / Electron 扩充于 2026-09-11。示例环境与验证范围以正文为准。
原创中文学习手册,阅读结构参考 Vue 文档;非 Vue 官方教材。
下载本章 Markdown

支持中文和英文全文搜索 · ↑ ↓ 选择 · Enter 打开 · Esc 关闭