# [Project] 8. NL 胶水层 — Vibe-Coding 时代的需求工程实践

# 我的Vibe-Coding实践方向——NL胶水层

## 问题：AI写代码太快了
Vibe-Coding正在改变软件开发的节奏。AI编码工具让代码生成速度提升了10倍甚至100倍。但这种速度带来了一个显而易见的问题：**代码失控**。

### Vibe-Coding的甜蜜陷阱
Vibe-Coding的体验是这样的：你告诉AI——"帮我搭一个订单系统，要支持下单、支付、退款，支付用webhook回调，退款要走审批流，所有操作要有审计日志"。

十分钟后，你面前出现了：
- `order_service.py` — 完整的订单状态机（pending → paid → shipped → completed / refunded）
- `payment_gateway.py` — 支付网关集成，带签名验证、幂等性检查、超时重试
- `refund_workflow.py` — 退款审批流，三级审批，自动通知
- `audit_logger.py` — 审计日志，异步写入，支持查询
- `models.py` — 数据库模型，带索引、约束、软删除
- `tests/` — 一整套单元测试，覆盖率看着有90%+

你跑一下测试，全绿。启动服务，调几个API，都通。代码质量看着也不错——类型标注完整、错误处理到位、日志分级清晰。

但这只是开始。你不可能一句话就搞定整个系统——你得一轮一轮地和AI对话，逐步细化：

- 第一轮："搭一个订单系统的基本框架"→ 生成了订单模型和基础CRUD
- 第二轮："加上支付集成，用webhook回调"→ 生成了支付网关和签名验证
- 第三轮："退款要走审批流，三级审批"→ 生成了退款工作流和审批链
- 第四轮："所有操作要有审计日志"→ 生成了审计日志模块
- 第五轮、第六轮……每一轮都在补充细节、修复边界情况、调整业务规则

每一轮对话，AI都根据你的描述生成了高质量的代码。你跑测试，全绿。你提交了。感觉自己一天干了别人一周的活。

**然后问题开始出现了。**

第二周，你让AI加一个"部分退款"功能。AI生成了`partial_refund.py`，逻辑完整，测试通过。但你没注意到：
- 原来的`refund_workflow.py`里，退款金额校验是`refund_amount == order_amount`（全额退款）
- 新的`partial_refund.py`里，校验是`refund_amount <= order_amount`
- 两个模块各自独立运行，没有共享校验逻辑
- 如果有人同时调用全额退款和部分退款接口，订单金额可能被退两次

第三周，支付网关那边改了webhook的签名算法。你让AI更新签名验证。AI改了`payment_gateway.py`里的`verify_signature()`函数。但你没注意到：
- `refund_workflow.py`里也有一个签名验证——是AI当初生成退款模块时独立写的，用的是旧算法
- 支付验证通过了，退款验证失败了，但失败被`try/except`吞掉了，只打了一行warning日志

第四周，你回头看这个系统——12个文件，3000行代码，每个文件都写得很专业，但**没有人（包括你自己）真正理解它们之间的所有交互**。你不知道哪些模块共享了逻辑，哪些模块各自为政，哪些隐含的假设在某个角落被违反了。

这就是Vibe-Coding的甜蜜陷阱：**每一次生成都是完美的，但累积起来是混乱的**。AI每次只看到一个文件，它不知道整个系统的全貌。而你，因为代码生成得太快，也来不及建立这个全貌。

### 代码失控的三个信号
这种混乱不是突然爆发的，它有三个渐进的信号。

**信号一：重复实现**

订单系统里，退款金额校验这个逻辑，AI在三个地方各写了一次：

<img src="/images/mermaid/nl-glue-zh-1.svg" alt="Figure 1" style="max-width:100%;">
**Figure 1.3 — 退款金额校验的三个实现**

每个实现都能跑，每个实现都有自己的"风格"。但当你需要修改退款规则——比如加上"退款金额不能超过实付金额"——你需要找到所有三个地方，分别修改，还要确保修改后的行为一致。

AI不会帮你做这件事。它每次只看到一个文件。

**信号二：隐性依赖**

`payment_gateway.py`的webhook处理器依赖`audit_logger.py`的一个特定行为——"当日志写入失败时，主流程不应该中断"。但这个依赖没有写在任何地方，它只存在于AI生成代码时的那次对话里。

三周后，你让AI优化审计日志的性能，AI把异步写入改成了批量写入。批量写入失败时会抛异常。支付webhook处理器没有捕获这个异常，导致支付成功但订单状态没更新。

没有人知道这两个模块之间有依赖关系。代码里没有注释，没有文档，没有契约。

**信号三：知识流失**

代码写完后，连作者自己都记不清"为什么这么写"。你看着`refund_workflow.py`里的三级审批逻辑，完全不记得为什么是三级而不是两级。

是因为金额阈值？是因为合规要求？还是AI当时就这么生成的，你觉得能跑就接受了？

三个月后的你，和一个新加入团队的成员，面对的是同样的困境：只有代码，没有上下文。

<img src="/images/mermaid/nl-glue-zh-2.svg" alt="Figure 2" style="max-width:100%;">
**Figure 1.1 — 代码失控的三个信号**

### 为什么需要在代码上抽象一层
问题的根源是：**代码是细节层，不是理解层**。

当你直接让AI从意图生成代码，中间没有任何缓冲层：

<img src="/images/mermaid/nl-glue-zh-3.svg" alt="Figure 3" style="max-width:100%;">
**Figure 1.2 — 直接生成 vs 抽象后生成**

没有抽象层时，每次AI生成都是一次独立的"翻译"——从自然语言到代码。每次翻译都可能产生不同的结果，因为AI没有记忆，没有上下文，没有标准。

有了抽象层，情况完全不同：
- 你先把意图写成**结构化的自然语言**（比如User Story）
- AI从这个结构化的描述生成代码
- 每次生成都有同一个"真相源"作为参照
- 代码可以变，但意图不变

这个抽象层的目的不是减慢速度，而是：
- 提供一个**稳定的理解锚点**——不管代码怎么变，意图是固定的
- 让AI生成的代码有一个**可追溯的源头**——每段代码都能追溯到哪条需求
- 在代码变化时，保持**意图的连续性**——重构代码时，你知道"应该做什么"不变

这个抽象层可以是API文档、接口契约、或者需求文档。我选择的是**User Story**。

## 选择：为什么是User Story
抽象层的选择决定了整个工作流的形态。不同的抽象层有不同的特性和局限。

### 抽象层的候选方案
常见的抽象层包括：
- **API文档**：描述接口签名、参数、返回值
- **接口契约**：描述模块间的协议、数据格式、行为约束
- **需求文档**：描述功能目标、用户场景、验收标准
- **User Story**：以用户视角描述需求，包含角色、目标、价值

每种方案都试图在代码之上建立一个"真相源"，但效果不同。

<img src="/images/mermaid/nl-glue-zh-4.svg" alt="Figure 4" style="max-width:100%;">
**Figure 2.1 — 抽象层候选方案对比**

### API文档的局限
API文档的优势是**精确**：
- 函数签名、参数类型、返回值都是确定的
- 可以直接从代码生成，保持同步

但API文档的局限是**缺乏上下文**：
- 知道"这个函数做什么"，但不知道"为什么要做"
- 知道"参数是什么"，但不知道"什么场景下会用到"
- 无法回答"这个功能对用户有什么价值"

一个具体的例子：你看到`exportCSV(filters: FilterOptions): Promise<Buffer>`这个签名，你知道它导出CSV。但你不知道：
- 谁在用这个功能？（运营？数据分析师？）
- 为什么要导出？（做报表？做审计？）
- 导出的数据量级是多少？（100条？100万条？）
- 导出失败时应该怎么处理？（重试？通知用户？）

这些信息对AI生成正确的代码至关重要，但API文档里完全没有。

<img src="/images/mermaid/nl-glue-zh-5.svg" alt="Figure 5" style="max-width:100%;">
**Figure 2.2 — API文档的信息覆盖**

### 接口契约的局限
接口契约的优势是**约束明确**：
- 定义模块间的边界和协议
- 可以验证是否符合契约

但接口契约的局限是**过于技术化**：
- 描述的是"系统内部如何协作"，而不是"用户需要什么"
- 对于非技术角色（产品、运营）难以理解
- 无法作为"需求的真相源"

接口契约告诉你"模块A通过gRPC调用模块B的`ProcessOrder`方法，超时时间5秒，重试3次"。但它不告诉你"用户下单后，系统应该在3秒内确认订单，如果支付网关超时，应该保留订单并通知用户稍后重试"。

前者是实现细节，后者是业务需求。接口契约只能粘合代码和代码，粘不住人和代码。

<img src="/images/mermaid/nl-glue-zh-6.svg" alt="Figure 6" style="max-width:100%;">
**Figure 2.3 — 接口契约的信息覆盖**

### User Story的优势
User Story的结构是：
```
As a {角色}, I want {目标}, so that {价值}

Acceptance Criteria:
- Given {上下文}, When {动作}, Then {结果}
```

这个结构的优势：
- **以用户为中心**：从用户的视角描述需求，而不是从系统的视角
- **包含上下文**：角色、目标、价值、场景都有明确的描述
- **可验证**：Acceptance Criteria提供了具体的验收标准
- **易于理解**：非技术角色也能读懂

回到订单系统的例子，User Story会这样写：
```
As a 买家, I want to 对已支付的订单申请部分退款,
so that 当部分商品有问题时，我不需要退掉整个订单。

AC-1: Given 订单状态为已支付且未退款, When 申请部分退款且金额≤实付金额, Then 创建退款单并进入审批流
AC-2: Given 退款金额超过实付金额, When 申请退款, Then 拒绝并返回"退款金额不能超过实付金额"
AC-3: Given 同一订单已有进行中的退款单, When 再次申请退款, Then 拒绝并返回"存在未完成的退款申请"
AC-4: Given 退款审批通过, When 执行退款, Then 调用支付网关退款接口并更新订单状态为部分退款
```

AI读到这个描述，它知道：
- 用户是谁（买家）
- 要做什么（部分退款）
- 为什么（部分商品有问题）
- 边界情况怎么处理（超额退款、重复退款、审批流程）

这些信息足以生成正确的代码，也足以生成正确的测试。更重要的是——当AI生成`partial_refund.py`时，它不会再和`refund_workflow.py`里的全额退款逻辑冲突，因为User Story已经明确了金额校验规则。

但User Story的价值不止于此。它提供了两个关键能力：

**全局视野**：当你有20个User Story描述整个订单系统时，你可以一眼看到系统的全貌——哪些功能已经定义了，哪些还缺失，哪些之间有依赖关系。这是代码做不到的，因为代码分散在几十个文件里，没有人能一次性读完所有代码并理解它们的关系。

**从故事到代码的清晰路径**：User Story不是写完就扔在一边的文档，它是开发的起点。工作流变成了：
1. 写User Story → 2. 从Story生成代码 → 3. 从Story生成测试 → 4. 验证代码和Story一致

这条路径是明确的、可追溯的。每一段代码都能追溯到哪条User Story，每一条User Story都能检查是否有对应的代码实现。

<img src="/images/mermaid/nl-glue-zh-7.svg" alt="Figure 7" style="max-width:100%;">
**Figure 2.4 — User Story结构**

<img src="/images/mermaid/nl-glue-zh-8.svg" alt="Figure 8" style="max-width:100%;">
**Figure 2.5 — User Story的信息覆盖**

### User Story作为胶水的定位
User Story不是需求的终点，而是**胶水层**：
- 向上粘合**用户意图**（产品需求、业务目标）
- 向下粘合**代码实现**（函数、模块、接口）
- 向外粘合**测试用例**（Acceptance Criteria → Test Case）

<img src="/images/mermaid/nl-glue-zh-9.svg" alt="Figure 9" style="max-width:100%;">
**Figure 2.6 — User Story作为胶水层**

作为胶水层，User Story的核心职责是**保持一致性**：
- 代码实现是否符合User Story的描述
- 测试用例是否覆盖了User Story的验收标准
- 文档是否反映了User Story的意图

这就是为什么我选择User Story而不是API文档或接口契约——**User Story是唯一能同时粘合人、代码和测试的抽象层**。

## 核心原则：NL是中心，代码是细节
一旦确立了User Story作为胶水层的定位，整个工作流的视角就发生了转变：**NL（自然语言）是中心，代码是实现细节**。

### NL不需要"完整"，需要"可靠"
传统的文档思维追求"完整性"：
- 每个功能都要有文档
- 每个细节都要描述
- 文档要和代码100%同步

但作为胶水层，NL不需要完整：
- 可以只描述核心功能，忽略边缘情况
- 可以只描述"应该是什么"，不描述"现在是什么"
- 可以有重复、有冗余、有粗略的描述

**唯一的要求是：NL不能错。**

<img src="/images/mermaid/nl-glue-zh-10.svg" alt="Figure 10" style="max-width:100%;">
**Figure 3.1 — NL质量状态转换**

<img src="/images/mermaid/nl-glue-zh-11.svg" alt="Figure 11" style="max-width:100%;">
**Figure 3.2 — NL的质量要求**

### NL可以重复，不能错误
重复的NL不是问题：
- 同一个功能在多个User Story中描述，不会造成混乱
- 重复反而提供了多个视角，增强理解

错误的NL是致命的——这里说的"错误"不是指代码和NL不一致（那是代码的问题），而是**NL本身就是错的、自相矛盾的**：
- US-05说"退款金额不能超过实付金额"，US-08说"退款金额可以包含补偿金，允许超过实付金额"——两条Story自相矛盾，开发者不知道该听哪个
- US-12说"退款审批只需主管一级"，US-15说"所有退款必须经过财务审批"——两条Story对审批流程的描述冲突
- US-03说"支付成功后立即发货"，但业务规则其实是"T+1结算后才能发货"——NL本身就写错了，和真实业务规则不符

这些NL错误比代码bug更危险——因为NL是胶水，是真相源。如果NL本身是错的，那基于它生成的代码、测试、文档全都是错的，而且你很难发现，因为"文档里就是这么写的"。

### NL可以粗略，不能模糊
粗略的NL是可以接受的：
- "订单支持退款"——虽然没有细节，但方向是对的
- "支付回调要安全"——虽然没有量化，但意图是清楚的

模糊的NL是无法作为胶水的：
- "系统应该表现良好"——什么是"良好"？无法验证
- "处理用户的请求"——什么请求？怎么处理？无法实现
- "更好的体验"——什么是"更好"？无法衡量

<img src="/images/mermaid/nl-glue-zh-12.svg" alt="Figure 12" style="max-width:100%;">
**Figure 3.3 — NL质量分类**

### 从"代码覆盖率"到"NL落地率"
传统的覆盖率思维是：**代码被测试覆盖了多少**。

NL胶水层的覆盖率思维是双向的：
- **NL落地率**：NL在代码中落地了多少（NL → Code）
- **代码NL率**：代码被NL覆盖了多少（Code → NL）

<img src="/images/mermaid/nl-glue-zh-13.svg" alt="Figure 13" style="max-width:100%;">
**Figure 3.4 — 覆盖率思维的转变**

这两个指标回答不同的问题：
- **NL落地率**：你写的需求有多少变成了代码？（未实现的NL是backlog）
- **代码NL率**：你写的代码有多少被需求描述了？（未覆盖的代码是"野生代码"，没人知道它为什么存在）

代码NL率低意味着系统中有大量"野生代码"——它们存在，但没有NL解释它们为什么存在。这些代码在重构时最危险，因为没有人知道它们的业务背景，改了可能破坏某些隐含的业务规则。

这个转变的意义：
- 不再关心"代码有没有被测试覆盖"（那是测试覆盖率的事）
- 关心"NL描述的功能有没有在代码中实现"（NL落地率）
- 关心"代码有没有被NL描述"（代码NL率）
- 未实现的NL是backlog，不是问题
- 未覆盖的代码是风险，需要补充NL或确认是否可以删除
- 已实现但与NL矛盾的代码是问题，必须修复

**NL覆盖率是这个思维转变的度量工具**——它回答的核心问题不是"代码好不好"，而是"NL落地了多少、落地得对不对、代码被NL覆盖了多少"。

## 三个核心指标
基于"NL是中心"的原则，我定义了三个核心指标来度量NL的健康度。

### NL实现率：这条NL落地了吗
**定义**：已实现的NL数量 / 总NL数量（排除模糊的NL）

**含义**：有多少User Story的Acceptance Criteria在代码中找到了对应的实现。

**示例**：
```
US-05: As a 买家, I want to 查看订单的退款进度

AC-1: Given 订单存在退款单, When 查看退款进度, Then 显示当前审批节点和预计完成时间
  → 代码中有 get_refund_progress() 函数 → ✅ 已实现

AC-2: Given 退款单被驳回, When 查看退款进度, Then 显示驳回原因和可重新申请的提示
  → 代码中没有驳回原因的展示逻辑 → ❌ 未实现
```

**未实现的NL是backlog**。在敏捷开发中，backlog指的是"已识别但尚未实现的需求列表"——简单说就是"待办事项"。未实现的NL就是待办事项，让你知道哪些功能还没做。这不是问题，而是正常的开发节奏。

### NL准确率：NL和代码一致吗
**定义**：已实现且一致的NL数量 / 已实现的NL数量

**含义**：在已实现的NL中，有多少是和代码实际行为一致的。

**示例**：
```
US-08: As a 财务, I want to 审批退款申请

AC-1: Given 退款金额≤1000元, When 主管审批通过, Then 自动进入财务审批
  → 代码中阈值写死为 500 元 → ⚠️ 冲突
  → NL说1000元，代码是500元
```

**冲突是最严重的问题**：NL作为胶水断了，它会误导所有人。

### 代码NL率：代码被NL描述了吗
**定义**：被NL覆盖的代码行为数量 / 总代码行为数量

**含义**：有多少代码行为有对应的NL描述。与NL实现率（NL→Code）相反，这是Code→NL方向的度量。

**示例**：
```
代码中存在一个 retry_with_backoff() 函数，实现了指数退避重试逻辑
  → 检查所有User Story，没有找到描述"重试机制"或"退避策略"的AC
  → ❌ 未覆盖：这段代码没有NL解释它为什么存在

代码中存在一个 validate_signature_v2() 函数
  → US-03 AC-2 描述了"webhook签名验证使用HMAC-SHA256"
  → ✅ 已覆盖：这段代码有NL解释其业务目的
```

**未覆盖的代码是"野生代码"**：它们存在，但没有NL解释它们为什么存在。这些代码在重构时最危险，因为没有人知道它们的业务背景，改了可能破坏某些隐含的业务规则。

### 指标之间的关系
三个指标形成了一个**双向度量体系**：

<img src="/images/mermaid/nl-glue-zh-14.svg" alt="Figure 14" style="max-width:100%;">
**Figure 4.1 — NL覆盖率双向度量**

- **NL实现率**（NL→Code）：你写的需求有多少变成了代码？未实现的NL是backlog
- **NL准确率**（NL↔Code一致性）：已实现的NL中，有多少和代码行为一致？不一致的是冲突
- **代码NL率**（Code→NL）：你写的代码有多少被NL描述了？未覆盖的代码是"野生代码"，存在风险

**NL覆盖率不是单一数字，而是这个双向度量的完整画像**——它告诉你NL落地了多少、落地得对不对、代码被NL覆盖了多少。

### 为什么不打分
传统的做法是给NL打分：
- 精确度80分、完整度70分、一致性90分
- 综合得分80分，"良好"

但打分有问题：
- **阈值怎么定**：80分算好还是70分算好？不同项目标准不一样
- **难以行动**：知道"70分"，但不知道具体哪里有问题
- **容易作弊**：为了分数而优化，而不是为了质量而优化

我的做法是**直接报问题**：
- 不告诉你"这条NL得70分"
- 告诉你"这条NL和代码有冲突：NL说X，代码做Y"
- 告诉你"这条NL模糊：'快速'没有定义"

**问题比分数更有行动价值。**

## 三个核心检测
基于三个指标，我设计了三个检测机制来发现问题。

### 冲突检测：NL说X，代码做Y
**目标**：发现NL和代码之间的矛盾。

**检测方法**：
1. 提取NL中的关键值（数字、条件、行为）
2. 在代码中找到对应的实现
3. 比较NL描述和代码实际行为
4. 如果不一致，标记为冲突

<img src="/images/mermaid/nl-glue-zh-15.svg" alt="Figure 15" style="max-width:100%;">
**Figure 5.1 — 冲突检测流程**

**示例**：
```
US-08, AC-1: "退款金额≤1000元时，主管审批通过后自动进入财务审批"
  → 代码 refund_workflow.py:67 阈值写死为500元
  → ⚠️ 冲突：NL说1000元，代码是500元

US-03, AC-2: "支付webhook签名验证使用HMAC-SHA256"
  → 代码 payment_gateway.py:34 使用的是MD5
  → ⚠️ 冲突：NL说HMAC-SHA256，代码是MD5
```

**冲突的优先级最高**：它直接破坏了NL作为胶水的价值。

### 模糊检测：粘不住下游的NL
**目标**：发现无法作为下游输入的NL。

**检测方法**：
1. 检查NL是否包含具体的值（数字、条件、状态）
2. 检查NL是否使用了主观语言（"快速"、"良好"、"更好"）
3. 检查NL是否可以转化为测试用例
4. 如果无法转化，标记为模糊

<img src="/images/mermaid/nl-glue-zh-16.svg" alt="Figure 16" style="max-width:100%;">
**Figure 5.2 — 模糊检测流程**

**示例**：
```
US-12, AC-1: "退款审批流程要安全"
  → "安全"没有定义 → ⚠️ 模糊
  → 建议：改成"需要三级审批，每级审批人不能是申请人"

US-15, AC-1: "支付回调要处理好"
  → 什么算"处理好"？幂等？重试？超时？→ ⚠️ 模糊
  → 建议：具体化幂等策略、重试次数、超时时间
```

**模糊不是错误**：但它需要改进，否则无法粘住下游。

### Backlog检测：待办事项可视化
**目标**：发现还没有在代码中落地的NL，形成待办事项清单。

**检测方法**：
1. 提取NL的Acceptance Criteria
2. 在代码中搜索对应的实现
3. 如果找不到，加入backlog

<img src="/images/mermaid/nl-glue-zh-17.svg" alt="Figure 17" style="max-width:100%;">
**Figure 5.3 — Backlog检测流程**

**示例**：
```
US-09, AC-1: "支持退款到原支付渠道（微信/支付宝/银行卡）"
  → 代码中只实现了退款到余额，没有原路退回逻辑 → 📋 加入backlog

US-11, AC-1: "退款审批支持批量操作（一键通过/驳回多条）"
  → 代码中只有单条审批接口 → 📋 加入backlog
```

**Backlog不是问题**：它是待办事项的可视化，让你知道哪些功能还没做。

### 检测的优先级
三个检测的优先级：

<img src="/images/mermaid/nl-glue-zh-18.svg" alt="Figure 18" style="max-width:100%;">
**Figure 5.4 — 检测优先级**

- **冲突**：NL和代码矛盾，胶水断了，必须修复
- **模糊**：NL无法粘住下游，建议改进
- **未实现**：NL还没落地，是backlog，不是问题

## 实践：从处理代码到处理User Story
理论的最终目的是指导实践。NL胶水层的建立，意味着工作范式的转变。

### 工作流的转变
传统的工作流：
```
需求 → 代码 → 测试 → 部署
```

NL胶水层的工作流：
```
需求 → User Story → 代码 → 测试 → 验证NL一致性
```

<img src="/images/mermaid/nl-glue-zh-19.svg" alt="Figure 19" style="max-width:100%;">
**Figure 6.1 — 工作流对比**

关键的变化：
- **起点变了**：从"写代码"变成"写User Story"
- **终点变了**：从"代码跑通"变成"NL和代码一致"
- **验证变了**：从"测试通过"变成"NL落地且准确"

### NL覆盖率工具的设计思路
基于上述理论，一个理想的NL覆盖率工具应该具备以下特征：

**核心功能**：
- 提取所有User Story的Acceptance Criteria
- 在代码中搜索对应的实现
- 检测冲突、模糊、未实现
- 生成NL覆盖率报告

**设计原则**：
- **不打分**：直接报问题，不给分数
- **可行动**：每个问题都有具体的描述和建议
- **优先级清晰**：冲突 > 模糊 > 未实现

**输出示例**：
```
# NL Coverage Report

## 冲突（NL和代码不一致）
| Story | AC | NL描述 | 代码实际行为 | 位置 |
|:---|:---|:---|:---|:---|
| US-08 | AC-1 | 退款金额≤1000元主管审批 | 阈值写死500元 | refund_workflow.py:67 |

## 模糊（无法粘住下游）
| Story | AC | 描述 | 模糊点 |
|:---|:---|:---|:---|
| US-12 | AC-1 | 退款审批流程要安全 | "安全"无定义 |

## 未实现（NL还没落地）
| Story | AC | 描述 |
|:---|:---|:---|
| US-09 | AC-1 | 退款到原支付渠道 |
```

### 与现有工具链的集成
NL覆盖率工具不是孤立的工具，它与整个req工具链集成：

**与req-refresh集成**：
- 在刷新需求文档后，自动运行NL覆盖率分析
- 发现冲突时，提示用户修复

**与req-catalog集成**：
- 在生成需求目录时，嵌入NL覆盖率指标
- 提供全局的NL健康度视图

**与req pipeline集成**：
- 在justify阶段，检查NL覆盖率
- 如果冲突数量过多，标记为"NL gap"

<img src="/images/mermaid/nl-glue-zh-20.svg" alt="Figure 20" style="max-width:100%;">
**Figure 6.2 — NL覆盖率工具与工具链集成**

### 实际使用场景
**场景一：新功能开发**
1. 写User Story和Acceptance Criteria
2. 用AI生成代码
3. 运行NL覆盖率工具检查NL落地情况
4. 修复冲突，改进模糊的NL
5. 确认NL和代码一致后，提交

<img src="/images/mermaid/nl-glue-zh-21.svg" alt="Figure 21" style="max-width:100%;">
**Figure 6.3 — 新功能开发流程**

**场景二：代码重构**
1. 运行NL覆盖率工具检查现有NL覆盖率
2. 发现冲突：NL说X，代码做Y
3. 决定：是改NL还是改代码
4. 重构代码
5. 再次运行NL覆盖率工具确认一致性

<img src="/images/mermaid/nl-glue-zh-22.svg" alt="Figure 22" style="max-width:100%;">
**Figure 6.4 — 代码重构流程**

**场景三：需求评审**
1. 运行NL覆盖率工具生成报告
2. 查看backlog：这是待办事项
3. 查看模糊的NL：这是需要细化的需求
4. 查看冲突的NL：这是需要立即修复的问题
5. 基于报告进行需求评审

<img src="/images/mermaid/nl-glue-zh-23.svg" alt="Figure 23" style="max-width:100%;">
**Figure 6.5 — 需求评审流程**

## 测试的真相：AI写测试的问题
NL胶水层不仅改变了开发流程，也暴露了AI写单元测试的一个根本性错误。

### AI写测试的陷阱
当前AI写单元测试的方式是这样的：
- 读取代码实现
- 根据代码逻辑生成测试用例
- 测试100%通过

这看起来很完美，但实际上是**循环论证**：
- 代码说X，测试验证X → 通过
- 代码说Y，测试验证Y → 通过
- 代码错了，测试也跟着错 → 还是通过

<img src="/images/mermaid/nl-glue-zh-24.svg" alt="Figure 24" style="max-width:100%;">
**Figure 7.1 — AI写测试的循环论证**

这种测试的价值是零：它只能证明"代码做了代码做的事"，不能证明"代码做了应该做的事"。

### 测试应该从User Story来
正确的测试生成路径：
- 从User Story的Acceptance Criteria生成测试
- 测试描述的是"应该是什么"，不是"现在是什么"
- 如果代码错了，测试会失败 → 发现冲突

<img src="/images/mermaid/nl-glue-zh-25.svg" alt="Figure 25" style="max-width:100%;">
**Figure 7.2 — 从User Story生成测试**

这个区别是本质性的：
- **基于代码的测试**：验证代码的自洽性（代码和自己一致吗？）
- **基于NL的测试**：验证代码的正确性（代码和需求一致吗？）

### 一个具体的例子
假设User Story说：
```
US-08: As a 财务, I want to 审批退款申请

AC-1: Given 退款金额≤1000元, When 主管审批通过, Then 自动进入财务审批
```

**AI基于代码生成的测试**（代码中阈值写死为500元）：
```python
def test_refund_approval_auto_forward():
    refund = create_refund(amount=500)
    approve_by_supervisor(refund)
    assert refund.status == "finance_review"  # ✅ 通过，但验证的是错误的阈值
```

**基于User Story生成的测试**：
```python
def test_refund_approval_auto_forward():
    refund = create_refund(amount=1000)
    approve_by_supervisor(refund)
    assert refund.status == "finance_review"  # ❌ 失败！代码阈值是500，NL说1000
```

第二种测试才能发现问题。

### NL作为测试的真相源
这进一步强化了NL胶水层的定位：

<img src="/images/mermaid/nl-glue-zh-26.svg" alt="Figure 26" style="max-width:100%;">
**Figure 7.3 — NL作为测试的真相源**

NL胶水层的完整价值链：
- **NL → 代码**：指导实现
- **NL → 测试**：生成验证标准
- **测试 → 代码**：验证一致性
- **冲突检测**：发现NL和代码的矛盾

当测试从NL来，而不是从代码来，测试才真正有了价值——它验证的是"代码做了应该做的事"，而不是"代码做了代码做的事"。

## 更大的图景：NL作为万能胶水层
当我们把NL胶水层的思维从"代码和代码之间"推广出去，会发现一个更大的图景：**AI本身就是胶水层，而NL是它的粘合剂**。

### 代码与代码之间的胶水
这是最直接的层面，也是本文前面讨论的核心：
- 模块A和模块B之间的依赖关系，用NL描述比用代码注释更清晰
- 函数之间的契约，用User Story表达比用类型签名更完整
- 重构时的意图保持，用NL锚定比用代码推断更可靠

AI在这里的角色是**翻译器**：把NL翻译成代码，把代码翻译成测试，把测试翻译成报告。NL是粘合剂，AI是执行者。

### 程序与程序之间的胶水
当你有多个系统需要集成时，NL的价值更加明显：
- 系统A的API说"返回用户信息"，系统B期望"返回客户档案"——这是同一个东西吗？
- 微服务之间的数据流，用代码定义只能看到格式，用NL定义能看到语义
- 第三方集成时，对方文档说"支持批量操作"——批量是多少？100？10000？

<img src="/images/mermaid/nl-glue-zh-27.svg" alt="Figure 27" style="max-width:100%;">
**Figure 8.1 — NL作为系统间胶水**

传统的做法是用IDL（Interface Definition Language）或OpenAPI Spec来定义接口。这些是精确的，但缺乏语义。NL补充了语义层——不仅定义"格式是什么"，还定义"这意味着什么"。

### 人与人之间的胶水
这是最容易被忽视的层面。在软件开发中，人与人之间的沟通成本往往高于代码编写成本：
- 产品经理说"用户体验要好"，开发理解为"响应要快"，测试理解为"不能有bug"
- 前端说"这个组件要可复用"，后端理解为"要抽象"，设计理解为"要一致"
- 新成员问"这个功能为什么这么做"，老成员说"当时就这么定的"

NL作为胶水层的价值：
- **消除歧义**：把"好"定义成"< 200ms响应时间"
- **对齐理解**：把"可复用"定义成"支持3种以上场景"
- **传递上下文**：把"为什么"写进User Story的value子句

<img src="/images/mermaid/nl-glue-zh-28.svg" alt="Figure 28" style="max-width:100%;">
**Figure 8.2 — NL作为团队间胶水**

AI在这里的角色是**对齐器**：把不同角色的NL表述统一成同一个真相源，把模糊的共识转化为精确的验收标准。

### 团队与团队之间的胶水
当组织规模扩大，团队之间的协作成为瓶颈：
- 平台团队说"我们提供了用户服务"，业务团队说"我需要的是客户管理"
- 数据团队说"数据仓库已就绪"，分析团队说"我找不到我需要的指标"
- 安全团队说"符合合规要求"，产品团队说"用户注册流程太复杂了"

传统的解决方案是**架构评审会**、**跨团队文档**、**API网关**。这些都是有效的，但它们有一个共同的问题：**更新成本高，容易过时**。

NL胶水层的优势：
- **低成本更新**：改一条User Story比改一份架构文档快10倍
- **高保真传递**：NL比代码更容易被非技术人员理解
- **可验证性**：NL可以通过AI自动检查一致性

<img src="/images/mermaid/nl-glue-zh-29.svg" alt="Figure 29" style="max-width:100%;">
**Figure 8.3 — NL作为跨团队胶水**

### AI作为胶水层的本质
回到最根本的问题：AI在软件开发中的角色是什么？

传统观点：AI是**加速器**——让代码写得更快。

我的观点：AI是**胶水层**——让不同的事物粘合在一起。

<img src="/images/mermaid/nl-glue-zh-30.svg" alt="Figure 30" style="max-width:100%;">
**Figure 8.4 — AI作为胶水层的全景**

而NL（自然语言）是这个胶水层的**粘合剂**：
- 没有NL，AI只是快速生成代码的工具
- 有了NL，AI成为连接意图、代码、测试、团队的枢纽

这就是为什么NL覆盖率如此重要——它度量的不是"代码写得好不好"，而是**"胶水粘得牢不牢"**。

当NL覆盖率高且准确时：
- 代码改动有迹可循
- 测试失败有因可查
- 团队协作有据可依
- 系统演化有向可追

当NL覆盖率低或不准确时：
- 代码成为黑盒
- 测试成为装饰
- 团队协作靠猜
- 系统演化靠运气

## 总结：可靠的胶水
Vibe-Coding让代码生成变得极其快速，但这种速度需要被**约束**和**引导**。

<img src="/images/mermaid/nl-glue-zh-31.svg" alt="Figure 31" style="max-width:100%;">
**Figure 9.1 — NL胶水层全景**

NL胶水层的建立，本质上是**工作范式的转变**：
- 从"处理代码"变成"处理User Story"
- 从"代码覆盖率"变成"NL落地率"
- 从"测试通过"变成"NL和代码一致"

这个转变的意义：
- **代码是细节**：AI可以快速生成，但NL是真相源
- **NL是中心**：它粘合了用户意图、代码实现、测试用例
- **一致性是目标**：NL和代码必须一致，否则胶水就断了

三个核心指标（实现率、准确率、代码NL率）和三个核心检测（冲突、模糊、未实现）提供了度量和改进的框架。

最终的目标不是"完美的文档"，而是**可靠的胶水**——让NL能够有效地粘合上下游，让Vibe-Coding在速度的同时保持可控。


