产品定制无人化:Spec提取实战

本文档是SpecExtract和SpecExecute技能的完整实战记录,基于真实代码验证。


验证结论

今天验证了SpecExtract和SpecExecute两个技能:

技能 验证结果
SpecExtract ✅ 能从代码真实提取Spec(28个action、8个entity、4个rule)
SpecExecute ✅ 能执行Delta变更(添加compress参数、新建pdf_password模块)

一、背景:为什么需要Spec驱动开发

1.1 传统开发的核心问题

产品A新功能 → 开发从头理解产品A(3天) → 写代码(2天) 产品B新功能 → 开发从头理解产品B(3天) → 写代码(2天) 产品C新功能 → ...

每个产品都需要从零开始理解。开发把80%的时间花在了"理解"而不是"写代码"上。

1.2 为什么会这样

传统方式的问题 说明
需求文档不完整 只写了"做什么",没写"怎么做"
代码和文档脱节 代码改了,文档没改
知识在人脑子里 换个开发,一切重来
AI无法理解产品 AI能写代码,但不能理解产品业务

1.3 AI时代的更大问题

传统开发:人需要理解产品 AI时代开发:AI也需要理解产品

如果AI不能理解产品,AI辅助开发就是空谈。

1.4 解决方案:让AI"看见"产品

产品代码 ──→ SpecExtract ──→ Spec ──→ AI能理解的形式
 ↓
AI基于Spec开发/定制

核心思路:把产品翻译成AI能理解的语言(Spec),然后让AI基于Spec工作。


二、核心定位

我们的两种核心能力

能力 说明
SpecExtract 让产品上能长AI代理(代码 → Spec)
SpecExecute 长了这个AI代理的产品(Spec → 代码+执行)

与OpenSpec的关系

方面 OpenSpec 我们
核心能力 需求变更管理 Spec提取+执行
使用对象 人类协作 AI驱动
来源 需求文档 产品代码

我们借鉴了OpenSpec的格式,但不是OpenSpec本身。


三、我们的Spec规范

3.1 目录结构

specs/{product}/
├── SPEC.md              # 产品概述
├── actions/            # 操作定义(含Scenarios)
│   └── *.md           # 每个Action一个文件
├── entities/           # 实体定义
│   └── *.md           # 每个Entity一个文件
├── rules/              # 业务规则
│   └── *.md           # 每个Rule一个文件
└── changes/           # 增量变更(变更时创建)
    └── {change-name}/
        ├── proposal.md # 变更提案(为什么做)
        ├── delta.md    # Delta specs(变什么)
        ├── design.md  # 技术方案(怎么做)
        └── archive.md  # 归档记录

3.2 每个文件的职责

文件类型 职责 Scenarios 说明
actions/*.md 操作定义 ✅ 有 用户操作流程在这里
entities/*.md 数据模型 ❌ 无 只有数据结构定义
rules/*.md 业务规则 ❌ 无 只有规则逻辑(Trigger+Logic)

核心原则:Scenarios只存在于Action文件中

3.3 Action格式(含Scenarios)

# Action: pdf_merge

## Service
pdf_merge_service.py

## Functions

### pdf_merge_service
- params: files (List[UploadFile]), options (dict, optional)
- returns: {file (url), filename, totalFiles, fileInfos}

## Scenarios

### Scenario: 普通合并
- **GIVEN:** 至少2个PDF文件列表
- **WHEN:** 调用pdf_merge_service
- **THEN:** 返回合并后的PDF文件URL

3.4 Entity格式

# Entity: user

## Basic Info
- table: users
- description: 用户实体,登录凭证为手机号

## Attributes
| Name | Type | Required | Description |
|------|------|----------|-------------|
| id | int | Yes | 用户唯一标识 |
| phone | string | Yes | 手机号 |
| created_at | datetime | Yes | 注册时间 |

## Relationships
- User → 1:N → Task
- User → 1:1 → Membership

3.5 Rule格式

# Rule: rate_limit

## Trigger
when: 请求频率检查时

## Logic
if request_count > LIMIT:
    reject_request()

3.6 与OpenSpec对比

方面 OpenSpec 我们 评价
目录组织 specs/(按领域) actions/entities/rules(按代码) 我们的更贴合代码生成
Scenarios 独立场景文件 只在Actions中 我们更清晰,避免重复
变更管理 changes/目录 changes/目录 一致

四、增量变更规范

4.1 什么时候创建changes/

阶段 Spec状态 changes/
SpecExtract(初始) 全量提取,无Delta ❌ 没有
SpecExecute(变更) 创建changes/目录 ✅ 开始有

4.2 changes/目录结构

changes/
└── {change-name}/
    ├── proposal.md   # 为什么做
    ├── delta.md      # 变什么
    ├── design.md     # 怎么做
    └── archive.md    # 归档记录

五、SpecExtract:从代码提取Spec

5.1 技能进化过程

我们花了大量时间测试和优化技能,发现以下问题:

版本 问题 改进
v6.0 只有格式规范,没有提取逻辑 明确读取真实代码的步骤
v6.1 一次扫描太多文件,容易中断 拆成任务清单,每次3个文件
v6.2 子代理按function拆分action,文件太多 明确按service合并
v6.3 rules文件有Scenarios 明确rules不能有Scenarios
v6.4 文件命名混乱 明确命名规范

5.2 提取什么

类型 内容 说明
Entity 数据模型 user, task, order, payment, vip_plan等
Action 操作(含Scenarios) 按service合并,28个
Rule 业务规则 rate_limit, api_access, auth, config

5.3 深度挖掘 vs 浅看

关键要求:深度挖掘,不要浅看

浅看的问题 深挖的要求
只找到API名称 追踪完整调用链(API→Handler→Service→Repository)
只找到Model 看默认值、验证规则、关联关系
只找到Rule注释 找配置位置、调用方、边界条件
只找到表面逻辑 看异常处理、边界case

深度挖掘案例:VIP队列3:1是怎么来的

浅看:代码里有"VIP优先处理"注释
置信度:60%

深挖:
- 位置:services/task_queue.py:71
- 代码:self.vip_ratio = 3
- 使用:counter % (vip_ratio + normal_ratio) != 0
- 结论:每4次处理,3次VIP,1次普通
置信度:100%

六、真实验证:SpecExtract提取结果

6.1 真实提取统计

从pdfsystem代码真实提取:

类型 数量 说明
Entity 8 user, task, order, payment, vip_plan, admin等
Action 28 按service合并后
Rule 4 rate_limit, api_access, auth, config

Action清单(28个): - admin, auth, dashboard, db - idcard_to_pdf, images_to_pdf, img_ocr - membership, office_converter, order, payment - pdf_compress, pdf_merge, pdf_ocr, pdf_rotate, pdf_split - pdf_to_images, pdf_to_text, pdf_to_word, pdf_utility, pdf_watermark - sms, system, task_queue, user, vip_plan, vip_plan_price, word_to_pdf

6.2 真实文件示例

actions/pdf_merge.md(真实提取):

# Action: pdf_merge

## Service
pdf_merge_service.py

## Functions

### pdf_merge_service
- params: files (List[UploadFile]), options (dict, optional)
- returns: {file (url), filename, totalFiles, fileInfos}

## Scenarios

### Scenario: 合并多个PDF文件
- **GIVEN:** 至少2个PDF文件列表
- **WHEN:** 调用pdf_merge_service
- **THEN:** 返回合并后的PDF文件URL

rules/rate_limit.md(真实提取):

# Rule: rate_limit

## Trigger
when: 请求频率检查时

## Logic
rate_limiter = RateLimiter(rate_limit=100, time_window=60秒)
if is_allowed(client_ip):
    proceed()
else:
    reject_with_429()

6.3 发现真实Delta

真实代码分析:

# backend/utils/pdf_utils.py (line 149)
def merge_pdfs(input_paths: List[str], output_path: str) -> bool:
    # 只有2个参数,不支持compress!
# backend/services/pdf_merge_service.py (line 30)
async def pdf_merge_service(files, options=None):
    # options参数被接收但从未使用!
    merge_pdfs(file_paths, result_path)  # 只传了2个参数

真实Delta发现:

项目 代码实际 状态
merge_pdfs参数 没有compress 缺失
service options 收到但从未使用 Bug

七、真实验证:测试1 - 给merge_pdfs加compress参数

7.1 执行Delta变更

Step 1: 创建changes/add-compress-to-merge/

Step 2: 更新Spec - actions/pdf_merge.md

新增compress参数和压缩合并场景:

### pdf_merge_service
- params: files, options (compress: bool, compress_level: str)
- returns: {file, filename, totalFiles, fileInfos}

### Scenario: 压缩合并
- **GIVEN:** 用户勾选了compress=true
- **WHEN:** 调用pdf_merge_service
- **THEN:** 合并后进行压缩处理

Step 3: 更新代码 - pdf_utils.py

def merge_pdfs(input_paths, output_path, compress=False, compress_level="medium"):
    # 先执行合并到临时文件
    temp_output = output_path + ".tmp.pdf"
    # ...合并逻辑...

    # 如果需要压缩
    if compress:
        compress_pdf(temp_output, output_path, compression_level=compress_level)
        os.remove(temp_output)
    else:
        os.rename(temp_output, output_path)

Step 4: 更新代码 - pdf_merge_service.py

# 提取压缩选项
compress = options.get("compress", False) if options else False
compress_level = options.get("compress_level", "medium") if options else "medium"

# 执行合并(支持压缩)
merge_pdfs(file_paths, result_path, compress=compress, compress_level=compress_level)

7.2 验证结果

验证项 结果
Spec更新
pdf_utils.py更新
pdf_merge_service.py更新
delta.md创建
archive.md创建

八、真实验证:测试2 - 添加新模块pdf_password

8.1 发现可复用代码

扫描代码发现: - pdf_utils.py 已有 encrypt_pdf()decrypt_pdf() 函数 - 只需要创建service层调用即可

8.2 执行新模块添加

Step 1: 创建actions/pdf_password.md

# Action: pdf_password

## Service
pdf_password_service.py (新建)

## Functions

### pdf_encrypt_service
- params: files, password, permissions
- returns: {file, filename, original_filename}

### pdf_decrypt_service
- params: files, password
- returns: {file, filename, original_filename}

## Scenarios

### Scenario: PDF加密
- **GIVEN:** 用户上传PDF并设置密码
- **WHEN:** 调用pdf_encrypt_service
- **THEN:** 返回加密后的PDF文件URL

### Scenario: PDF解密
- **GIVEN:** 用户上传已加密PDF并提供正确密码
- **WHEN:** 调用pdf_decrypt_service
- **THEN:** 返回解密后的PDF文件URL

Step 2: 创建pdf_password_service.py

新建service调用已有的encrypt_pdf/decrypt_pdf工具函数。

8.3 验证结果

验证项 结果
actions/pdf_password.md创建
pdf_password_service.py创建
delta.md创建
archive.md创建

九、实战结果汇总

9.1 pdfsystem Spec完整度

组件 数量 说明
Entity 8 user, task, order, payment, vip_plan等
Action 28 按service合并
Rule 4 rate_limit, api_access, auth, config

9.2 验证结果

场景 结果 说明
SpecExtract提取 ✅ 通过 真实扫描代码,8+28+4个文件
发现真实Delta merge_pdfs缺少compress参数
Delta变更执行 更新Spec+代码+archive
新模块添加 pdf_password功能完整添加

十、核心结论

结论1:技能需要真实测试

纸上谈兵不够。技能必须真实执行代码扫描和提取,才能发现问题。

结论2:按service合并是正确选择

pdfsystem有28个service,如果按function拆分会有60+个action文件。

结论3:Scenarios只在Action中

rules有Trigger+Logic就够了,不需要GIVEN/WHEN/THEN。

结论4:Delta模式可行

测试1证明了Delta模式:识别变更→更新Spec→更新代码→archive。

结论5:新模块可以快速添加

测试2证明了可复用已有工具函数,只需创建service层。

结论6:Spec与代码必须同步

发现Delta是正常的。处理方式: 1. SpecExtract提取现状 2. SpecExecute基于Spec执行变更 3. 变更后同步更新Spec


附录

A. pdfsystem关键发现

问题 答案
VIP队列3:1 硬编码在task_queue.py:71,不可配置
支付→会员链路 handle_notification → _process_successful_payment
merge_pdfs compress 之前缺失,现已添加
merge_pdfs options 之前未使用,现已修复
密码保护 pdf_encrypt/decrypt已存在,新建service即可

B. 技能版本

技能 版本 说明
spec-extract v6.4 按service合并,rules无Scenarios
spec-execute v5.1 Delta模式 + 指令执行

C. 文件路径

Spec目录:

/root/.openclaw/agents/xiaoxuezi/specs/pdfsystem/
├── actions/        # 28个文件
├── entities/      # 8个文件
├── rules/         # 4个文件
└── changes/       # 增量变更
    ├── add-compress-to-merge/
    └── add-pdf-password/

本文档是Spec驱动开发的完整实战记录,基于pdfsystem项目的真实验证。