当前位置: 首页 > news >正文

如何为AI编写功能规格说明

编程智能体正在改变工程 effort 创造最大价值的环节。现在更多的杠杆作用集中在实现开始之前。结果的质量不再取决于代码输入的速度,而更多地取决于功能定义的清晰度、行为固定的精确度,以及实现开始后留给解释的空间有多小。

这是一个好的转变。它将注意力转向那些本应始终重要的部分:显式契约、确定性行为、精确边界,以及证明功能按预期工作的验证。在这种环境下,功能规格说明不再是一份软性的规划文档。它本身成为工程表面的一部分。

编程智能体需要的不仅仅是一个功能名称和请求格式。它需要一个清晰的命令边界。规格说明必须定义决策、相关的事实上下文、验收条件以及成功时产生的事实。命令上下文一致性将其转化为一个精确的工程表面。边界位于决策本身,而不是模糊的用例描述中。一旦这个边界明确,功能就不会再溶解到共享逻辑中,实现也会变得更加直接。

在本文中,我将讨论是什么让功能规格说明可执行、哪些部分必须在实现开始前明确,以及提示词应该如何指向这些决策而不是试图自己承载它们。这是智能体编程中最实用的方面:不是生成更多代码,而是在代码生成之前做更多工程工作。

1、什么让功能规格说明可执行

如果功能规格说明定义了实现本需要自行发明的行为,那它就是可执行的。它定义了入口点、有效输入、无效输入、需要做出的决策、决策所依赖的上下文、成功决策的结果、失败案例以及验证契约的测试。

定义必须精确。规格说明必须定义什么触发功能以及什么构成成功的结果。它还必须以足够的精度定义请求的形式,以确保验证是确定性的。必填字段、可选字段、修剪、规范化、格式、范围和语义检查必须包含在契约中。如果这些规则没有明确定义,实现就会从猜测开始。

规格说明必须定义功能被允许做出哪些决策、哪些现有事实与该决策相关,以及如果决策成功会产生什么事实或结果。它还必须定义什么构成重复输入。重新创建、拒绝或将其视为幂等重复是不同的行为。只有定义了这种行为,功能才算完全明确。

可执行功能规格说明的核心是一条固定路径:触发器、契约、上下文、决策和定义的结果。

外部失败契约也必须明确。格式错误的请求、无效的业务输入、冲突和内部运行时失败是不同的结果,需要不同的含义。一旦记录下来,实现路径就会变得更小。同样适用于验证。一个强大的功能规格说明已经暗示了它的证明:成功、无效输入、冲突或重试行为,以及边界情况。

2、简单示例:open_account

open_account 规格说明之所以可执行,是因为它在实现通常会开始偏离的点上固定了行为。第一个点是边界。

## 接口形态 - 方法和路径:POST /accounts - 成功状态:201 Created - 失败状态:400 Bad Request, 422 Unprocessable Entity, 500 Internal Server Error

这足以阻止功能扩散到多个端点或未记录的结果中。操作从一个 HTTP 边界开始,返回一组定义的状态。实现不再需要决定功能如何暴露。

第二个点是输入契约。

#### date_of_birth - 必填 - ISO 日期格式:YYYY-MM-DD - 必须可解析为日历日期 - 必须是过去的日期 - 申请人必须年满 18 岁 #### residential_address.country_code - 必填 - 修剪后恰好为 2 个字母字符 - 存储为大写

现在功能不再只是一个粗略的需求规格说明。它成为一个确定性契约。这些规则定义了语法分析、语义有效性、规范化和存储格式。编程智能体没有空间去发明关于年龄、日期处理或国家代码规范化的行为。

第三个点是决策和重试行为。

## 业务规则 1. 系统生成 account_id。 2. 账户以 open 状态开启。 3. 账户以 EUR 货币开启。 4. 初始余额为零。 ## 幂等性和重复策略 此功能不是幂等的。 请求不会通过申请人姓名、出生日期、地址或 government_id 去重。 在此示例中,重复的合法请求可能会开启多个账户。

本节阐明了通常被隐含的的行为。调用者不指定账户 ID;功能生成它。重复相同的请求不会触发隐藏的重复规则;相反,会创建一个新账户。一旦这些决策被记录,实现就不再需要猜测重复输入的含义。

第四个点是失败契约。

### 400 Bad Request - INVALID_JSON - INVALID_FIELD_TYPE - INVALID_DATE_FORMAT ### 422 Unprocessable Entity - FIRST_NAME_REQUIRED - LAST_NAME_REQUIRED - DATE_OF_BIRTH_INVALID - APPLICANT_MUST_BE_ADULT - ADDRESS_REQUIRED - COUNTRY_CODE_INVALID - GOVERNMENT_ID_REQUIRED ### 500 Internal Server Error - INTERNAL_ERROR

这将格式错误的输入、无效的业务输入和内部运行时失败分开。这使得外部行为更小更清晰。实现遵循契约,而不是在过程中发明错误映射。

最后一个点是验证。

## 测试用例 1. 正常路径:有效的申请人数据返回 201 和生成的 account_id。 2. 验证失败:空白的 first_name 返回 422 FIRST_NAME_REQUIRED。 3. 验证失败:格式错误的 date_of_birth 返回 400 INVALID_DATE_FORMAT。 4. 边界情况:第二个相同的请求创建第二个账户,因为此功能不是幂等的。 5. 内部失败:模拟的持久化失败返回 500 INTERNAL_ERROR。

这些测试是契约的一部分。它们定义了实现必须证明的内容。这就是规格说明可执行的原因。它在代码生成之前固定了边界、输入规则、决策行为、失败契约和证明路径。

3、提示词不应承载功能

一旦规格说明固定了行为,提示词就可以保持操作性。它的工作不再是描述功能本身。它的工作是将智能体指向契约、当前事实来源、本地实现边界和所需验证。这是一个更小更可靠的角色。

这里有一个提示词示例:

使用 $feature-slice-rust 和 $factstore-usage 来实现功能切片:<feature-name>。 首先检查 factstore 仓库并使用其当前 API 作为事实来源。不要发明包装器或 CRUD 抽象。 在现有的 Rust 服务中实现一个小型端到端功能。将其保持在 `src/features/<feature-name>/` 下本地,保持 IO 显式,如果功能有多个关注点则使用小的内部分割,避免 HTTP 动词文件名,并避免通用的技术角色。 直接使用 factstore 进行写入。保持启动/配置更改最小化。不要添加投机性抽象。 验证方式: - cargo check - cargo test - cargo fmt --check - cargo clippy -- -D warnings

这种区别很重要,因为如果提示词试图覆盖整个功能,它就会成为第二个更弱的规格说明,以浓缩形式存在。这创造了两个事实来源。一个在功能规格说明中,另一个在提示词中。它们很快会分道扬镳,实现最终遵循更容易满足的来源。因此提示词应该保持狭窄和程序性。规格说明应该描述行为。

技能定义了实现必须遵守的结构规则。规格说明定义了功能,提示词定义了如何在项目中执行它。当这三部分保持分离时,智能体几乎没有即兴发挥的空间,生成的代码在第一次尝试时就会变得更小更接近预期行为。

4、审计收紧规格说明

功能规格说明可能已经很强,但在边缘仍留有足够的漂移空间。这在 open_account 示例中立即显现出来。主要行为足够清晰可以实现,但第一次通过时仍在契约未完全确定的地方留下了外部行为开放。存在最大长度规则,但这些情况的失败映射不够明确。内部失败行为也必须成为外部契约的一部分,而不是保持为实现细节。

关键不在于第一次就得到完美的规格说明。关键在于将剩余的模糊性转移到一个可见、可审查且易于收紧的地方。一旦实现根据书面契约进行审计,规格说明中的薄弱环节就不再隐藏在工作代码后面。

这也改变了审计的角色。审计不仅检查代码是否编译、端点是否存在或测试是否通过。它检查实现的行为是否与书面契约完全匹配。这包括未记录的状态、未记录的错误代码、缺失的测试、薄弱的边界情况定义,以及代码不得不发明行为的情况,因为规格说明没有首先确定它。

这是智能体编程中最有用的转变之一。实现不再将模糊的工程决策隐藏在代码审查或后续清理中。审计将它们推回契约所属的地方。一旦发生这种情况,下一次实现通过就会变得更小、更直接,并且更少依赖于解释。

因此,功能规格说明通过实现和审计不断改进,直到契约足够紧密,代码几乎没有即兴发挥的空间。这就是工程工作真正向上移动的时刻。代码遵循契约。契约承载艰难的决策。

5、结束语

你可以在这里查看完整示例。

编程智能体将工程 effort 向上转移。更少的价值存在于输入代码中。更多的价值存在于将功能定义得足够紧密,使实现可以遵循契约而不是发明行为。这就是可执行功能规格说明所提供的:固定的边界、确定性规则、明确的结果和证明路径。

一旦这些决策被记录下来,提示词可以保持小型,实现可以保持本地,审计可以保持严格。代码不再需要承载未解决的行为。契约已经完成了这项工作。

功能规格说明越精确,实现需要猜测的就越少。

干杯


原文链接:如何为AI编写功能规格说明 - 汇智网

http://www.jsqmd.com/news/667556/

相关文章:

  • PgQue:复兴经典 Postgres 队列架构,在多平台畅行无阻!
  • 别再写脚本了!用sql_exporter把MySQL业务数据变成Prometheus监控指标(附实战配置)
  • 为什么头部科技公司已启动“AGI设计审计”?奇点大会披露的5类高危产品架构(附自检评分表)
  • 别再傻傻分不清了!Arduino编程中I/O和GPIO到底有啥区别?(附实战代码)
  • 【虚幻引擎】UE4/UE5 容器实战指南:Map、Set、Array 的核心操作与性能考量
  • 从宏观到微观:交通流模型如何驱动现代仿真系统
  • 全球仅存12套完整AGI天文发现训练数据集(含SKA Phase1真实噪声注入样本),今日限时开放3个核心子集下载权限
  • 10个最佳Unity开源游戏项目:开发者必备的终极学习宝库 [特殊字符]
  • 保姆级教程:在Windows 10/11上搞定Vivado 2018.3与ModelSim SE的安装与破解(附资源)
  • AGI客服系统效能瓶颈大起底(92%企业正在忽视的3个隐性体验断点)
  • 从零到一:使用Rufus打造你的万能系统安装U盘(Ubuntu 20.04与Win11 PE)
  • XFCE桌面环境深度定制:彻底禁用自动锁屏与待机策略
  • 告别迷茫!手把手教你用IQxel搞定Wi-Fi 6E信号测试(附详细配置截图)
  • RAG 只是权宜之计
  • 高效批量处理工具:3步完成飞书文档迁移的完整指南
  • Vivado里AXI接口IP核怎么选?从DMA到VDMA,一次讲清ZYNQ数据搬运的“十八般兵器”
  • 【MicroPython ESP32】SPI总线驱动SD卡:从硬件连接到文件系统挂载实战
  • 从零到一:在国产化ARM麒麟系统上构建Prometheus监控体系
  • 终极BongoCat指南:让电脑操作变得生动有趣的虚拟猫咪伴侣
  • DDR4 笔记本内存条引脚定义
  • Scapy实战:从ARP缓存投毒到中间人攻击的攻防演练
  • 零代码调用Unet预训练模型【Pytorch实战】【即开即用】
  • WindowResizer:轻松解决Windows窗口调整难题的终极工具
  • 5步高效配置LXMusic开源音源:专业级音乐播放解决方案
  • Qt/C++ 信号阻塞的RAII实践:QSignalBlocker的进阶用法与场景剖析
  • 从结构到实战:深度解析Xilinx Transceiver的ibert自测与性能验证
  • 【JAVA基础面经】线程安全的List
  • [CTF实战]从数字密文到Flag:Base与凯撒的联合破译
  • killall报no process found?先别急,用ps aux | grep查查进程名到底叫啥
  • 用STM32和PID算法,我给自己做了个可调压调流的桌面数控电源(附完整代码)