跳到主要内容

把“加个筛选”写进验收表,交给 Coding Agent 去跑

你有没有这种时刻:产品经理扔过来一句“商品列表里加个按最高价筛选”,你心里想的是“好嘞,一会儿让 Agent 去实现”,结果代码一上线,测试回来:“为什么 0 元商品没被筛出来?”或者“负数价格居然显示出来了?”

这不是 Agent 不够聪明,是你没把它需要的“验收规则”说清楚。

下面我用一个非常小的场景——商品列表的价格筛选,一步步说明:怎么从一句模糊的需求,变成一份能直接丢给 Coding Agent 的、可执行的小任务包。文末附了完整模板,你可以直接复制去改。


一、先拿一个具体需求当例子​

假设我们有一个商品列表接口(或者前端组件),它接收商品对象列表,每个商品至少包含:

  • name:商品名称
  • price_cents:商品价格,单位是“分”的整数

当前输入顺序为:

索引商品名price_cents
A香蕉0
B苹果1990
C橙子990
D牛奶5000

需求是:增加一个“按最高价筛选”功能。用户可以在列表旁输入一个价格上限(max_price_cents),系统只返回不超过这个上限的商品,且保持原有顺序。

这句话听着简单,但如果直接丢给 Agent:“实现按最高价筛选商品的功能”,它大概率会猜:

  • 0 算不算“小于等于 max_price”?
  • 没传参数是全部还是报错?
  • 负数、小数、字符串怎么处理?
  • 结果顺序要不要稳定?

这些看起来都是“常识”,但在工程里都不是。


二、把功能拆成可检查的验收条件​

我们不再只谈“做什么”,而是列出:在什么输入下,应该出现什么输出;以及什么输入必须被拒绝。

1. 输入与参数约定​

项目名称约定说明
输入列表由商品对象组成,每个对象至少含 name 和 price_cents
price_cents原始值应为非负整数(分),单位统一为“分”
max_price_cents可选参数(number | undefined);未提供(undefined)表示不过滤且不参与比较

2. 过滤规则​

  • 当 max_price_cents 未提供:返回全部商品,顺序与输入一致。
  • 当 max_price_cents 已提供且为合法值:
    • 保留所有 price_cents ≤ max_price_cents 的商品;
    • 0 是合法上限,对应价格为 0 的商品会被纳入;
    • 结果维持输入中的相对顺序(稳定过滤)。

3. 边界与空值处理​

场景预期输出
未提供 max_price_centsA/B/C/D(全部)
max_price_cents = 0A(仅价格为 0 的商品)
max_price_cents = 989A
max_price_cents = 990A/C
max_price_cents = 1990A/B/C
max_price_cents = 10000A/B/C/D
输入只有 B/C/D,max_price_cents = 0[](合法空列表)
无匹配商品(如所有价格都大于上限)[](合法空列表)

4. 非法输入必须拒绝​

这里需要格外注意一个细节:只有当参数 max_price_cents 本身合法时,商品数据才会被过滤;一旦它不合法,整个筛选请求就直接被拒绝(返回约定错误),商品列表保持原样不动。

我们需要校验的正是这个 max_price_cents。它必须是一个非负整数。如果它是负数、小数或字符串,哪怕只有一点点不对劲,都要判定为非法。

具体例子:

  • -1 → 是负数,直接拒绝请求。
  • 1.5 → 是小数,直接拒绝请求。
  • "990" → 是字符串类型,直接拒绝请求。

5. 行为一致性要求​

  • 输入列表在筛选前后保持不变(只生成新结果集);
  • 商品对象内部内容(name、price_cents)在筛选过程中不被修改;
  • 比较始终使用原始 price_cents 与统一的分单位,不做额外转换。

三、写成可交给 Coding Agent 的任务说明​

下面这份可以直接复制,替换其中的项目约定即可。结构上我按“背景 → 接口约定 → 核心规则 → 边界处理 → 验收清单”来排,方便 Agent 逐条对照实现。

任务:在现有商品列表组件/接口中增加“按最高价筛选(max_price_cents)”功能。

一、数据模型与单位
- 商品对象至少包含:
- name: string
- price_cents: number(原始值,单位为“分”)
- 过滤参数:
- max_price_cents: number | undefined(可选;undefined 表示不筛选)

二、核心过滤规则
1) 当 max_price_cents 未提供(undefined):
- 返回全部商品,保持输入顺序。

2) 当 max_price_cents 已提供且合法时:
- 合法值定义:非负整数(0, 1, 2, ...)
- 保留规则:仅保留 price_cents ≤ max_price_cents 的商品
- 0 是有效上限:价格为 0 的商品会被纳入
- 输出顺序:维持输入中的相对顺序(稳定过滤)

三、非法输入处理
核心规则很明确:**只有 `max_price_cents` 合法,筛选才生效。**

* **合法定义**:`max_price_cents` 必须是非负整数(0, 1, 2...)。
* **拒绝行为**:一旦检测到以下情况,立即返回项目约定的“整个请求被拒绝”的错误响应,不要尝试进行后续的商品过滤逻辑:
1. 传入的是负数(如 -1)。
2. 传入的是小数(如 1.5)。
3. 传入的是字符串(如 "990")。

四、边界与空值行为
- 输入只有 B/C/D,max_price_cents = 0 → 返回 [](合法空列表)
- 无匹配商品(所有价格 > max_price_cents)→ 返回 []
- 筛选前后:
- 原始输入列表不被修改;
- 每个商品的 name 和 price_cents 保持原值不变。

五、验收对照表(使用示例数据)
输入顺序:
A: price_cents = 0
B: price_cents = 1990
C: price_cents = 990
D: price_cents = 5000

预期结果:
- max_price_cents 未提供 → [A, B, C, D]
- max_price_cents = 0 → [A]
- max_price_cents = 989 → [A]
- max_price_cents = 990 → [A, C]
- max_price_cents = 1990 → [A, B, C]
- max_price_cents = 10000 → [A, B, C, D]

六、实现建议(非强制)
- 使用稳定过滤(如 Array.prototype.filter 即可)。
- 合法判断:Number.isInteger(val) && val >= 0。
- 将规则集中到一个纯函数中,例如:filterByMaxPrice(items, maxPriceCents?)。

请确保代码行为与上述验收对照表完全一致。

四、实现后如何核对:一张“最小验收清单”​

不要急着跑全量数据。拿到代码后,先快速验证筛选逻辑的核心路径,再根据接入改动做对应的回归检查。建议你把下面这些输入填进接口,把实际返回结果记下来,特别留意那些“没命中的边界”。

  • ✅ 未传参数:是否返回全部商品且顺序不变?
  • ✅ max_price_cents = 0:0 元商品是否被正确纳入?
  • ✅ max_price_cents = 989 vs 990:边界值差 1,结果是否只有单条差异?
  • ✅ 非法上限拒绝:传入 -1、1.5 或 "990" → 整个请求被拒绝,商品列表保持原样(未被过滤)。
  • ✅ 空结果:无匹配时是否返回空数组而不是 undefined/null?

不变性校验(筛选前后一致性)
验证筛选操作本身不修改原始数据结构:输入商品的ID、名称、价格等元数据,以及初始顺序,在过滤前后必须完全一致。仅输出新列表,绝不就地覆盖或触发隐性状态变更。

请在测试环境中逐项执行边界、空结果与不变性校验,记录每项的预期值、实际输出及通过/失败状态。对于尚未执行的场景(如多商品混合排序、负数价格等),建议单独标记为“未验证”,后续补全以确保规则覆盖无死角。


五、留个习惯:每次小功能都先写“验收条件”​

很多小需求之所以出问题,不是因为技术难,而是因为:

  • 假设太多(“大家都懂”);
  • 边界没想透(0 算不算?没传算什么?);
  • 错误行为含糊(“大概报错就行”)。

你不需要为每个需求写几十行文档,但至少要答清这六个问题:

  1. 输入长什么样?单位是什么?
  2. 参数是否可选?可选时的默认含义?
  3. 合法值范围如何定义(含边界)?
  4. 非法或异常输入怎么处理?
  5. 输出顺序和结构有什么约定?
  6. 用什么简单数据能在一分钟内验证核心行为?

把答案写下来,丢给 Coding Agent;实现完,对照清单跑一次。这样,哪怕需求很碎、场景很小,也能在“说清楚 → 执行 → 核对”的闭环里稳定落地。

相关教程​