AI 写的接口能用,但永远差点意思——这不是 prompt 的问题,是接口设计的品控规则它没装

让 AI 帮你设计一套 RESTful API,出来的代码确实能跑。但你 review 一遍就会发现,路径一会儿单数一会儿复数,错误码有的返回 -1 有的返回 1001 有的返回字符串,响应结构有的字段是 user_name 有的字段是 userName,分页接口一会儿 offset 一会儿 cursor。代码 review 这件事 AI 帮你做了,但 review 出来的问题它从来不会自己改。

这不是 prompt 写得不到位。接口设计是有客观标准的工程行为,而 AI 的训练语料里这些标准是碎片化的。它见过好的接口也见过烂的,但没有一条"什么是好"的清晰边界。所以它生成出来的东西平均能用,但永远不会好。

AI 写 API 的五个通病

通病一:路径命名风格飘忽

AI 起路径名的习惯可以总结成"想到哪个写哪个"。同一个 /users 资源下面,它可能给你 POST /users/createUserGET /user/listGET /users/{id}/getInfoDELETE /users/deleteUser

RESTful 的路径命名规则其实不复杂,但 AI 老是违反:

  • 资源路径必须是名词复数(/users/orders),不是动词
  • 路径里不能有动词(/getUser 是反模式,正确是 GET /users/{id}
  • 子资源用嵌套路径(/users/{id}/orders
  • 批量操作可以接受命名动词(如 /users/batch-import),但单个资源操作全部用 HTTP 方法表示

AI 的问题不是不知道这些规则,是它没法把这些规则一致地应用在一整个项目里。它每次都是"重新思考"路径名,而不是遵循项目已有的命名约定。

通病二:HTTP 方法被当成装饰

你让 AI 写 CRUD 接口,它大概率给你这样的代码:

java 复制代码
@PostMapping("/user/create")
public Result<UserDTO> createUser(@RequestBody UserCreateRequest req) { ... }

@PostMapping("/user/update")
public Result<UserDTO> updateUser(@RequestBody UserUpdateRequest req) { ... }

@PostMapping("/user/delete")
public Result<Void> deleteUser(@RequestBody UserDeleteRequest req) { ... }

@PostMapping("/user/list")
public Result<List<UserDTO>> listUsers(@RequestBody UserQueryRequest req) { ... }

4 个接口全部用 POST,因为"传 JSON 方便"。HTTP 方法在这里完全失去了语义。GET/POST/PUT/PATCH/DELETE 不是技术选型,是 API 的契约层。客户端通过 HTTP 方法就知道这个操作是否幂等、是否安全、是否会修改服务器状态。

RESTful 风格从来不是政治正确,是工程协作的成本问题。统一方法语义后,前端不需要看文档就知道怎么写,监控可以按方法打点,网关可以按方法做限流(GET 一般不限流,POST 限流严),CDN 可以缓存 GET 响应。这些东西 AI 默认不会替你做。

通病三:错误码系统像一锅粥

AI 返回错误码的姿势有几种典型:

  • 直接抛 HTTP 状态码当业务错误(404 Not Found 表示"用户不存在",503 Service Unavailable 表示"余额不足")
  • 自定义 code,类型一会儿 string 一会儿 int("1001"、"-1"、INVALID_PARAM)
  • 错误信息和 code 重复(code 已经说不清楚了,message 又说一遍)
  • 没有错误分类,全靠 message 字符串判断(前端写 if (msg.includes("余额"))

错误码系统的工程标准其实有共识:

  1. HTTP 状态码只表示 HTTP 层的状态(网络成功/失败、参数格式错误、认证失败)
  2. 业务错误用独立的 code 字段(如 biz_code: 10001 表示余额不足、biz_code: 10002 表示库存不足)
  3. 错误分类按业务模块划分(用户模块 10000-10999、订单模块 11000-11999),便于监控聚合
  4. code 是数字或固定字符串,不带变量信息;详细错误信息放 message 字段;排查用 trace_id

AI 写出来的错误码系统,每个接口都不一样,因为每次都是"自由发挥"。这不是 prompt 写得不好,是缺少错误码规范的设计原则。

通病四:响应结构无法统一

同一个项目里,AI 可能给你这样的接口:

  • GET /users/{id} 直接返回 User 对象 {id: 1, name: "x"}
  • GET /orders 返回 {data: [...], total: 100}
  • POST /users 直接返回新创建的 User
  • POST /login 返回 {token: "xxx", userInfo: {...}}

没有统一的响应包装层,前端拿到响应还得先看文档判断结构。这种接口前端写着很难受------有的接口返回 {data: ...}、有的直接返回对象、有的列表包了一层、有的没包。

统一的响应结构工程标准通常是:

json 复制代码
{
  "code": 0,
  "message": "ok",
  "data": { ... } 或 [...] 或 null,
  "trace_id": "abc123"
}

code=0 表示成功,非 0 表示失败;data 才是真正的业务数据;trace_id 用于排查。这种结构在前端可以统一拦截处理(code 非 0 自动弹错误提示、code 等于某个特定值跳登录页)。

AI 默认不会主动设计响应结构包装层,因为它假设"前端会处理"。这就是接口设计与 AI 生成之间的 gap。

通病五:分页策略随便选

AI 写分页接口,可能给你:

  • ?page=1&pageSize=20(offset 分页)
  • ?offset=0&limit=20(offset 另一种风格)
  • ?cursor=xxx(cursor 分页)
  • 响应里有的有 total、有的有 hasMore、有的都没有

分页策略不是风格问题,是性能问题。offset + limit 在数据量大的时候会慢------MySQL 跳过 100 万行去取第 100001 行,要扫 100 万行。Cursor 分页(基于最后一条记录的 ID)不管翻到第几页都是 O(log n)。

工程上的选择通常是:

  • 后台管理列表(数据量小、需要 total 做分页器)→ 用 offset
  • 用户面向的滚动列表(数据量大、性能敏感)→ 用 cursor
  • 不要在一个接口里同时返回 cursor 和 total(cursor 模式下 total 没意义)

AI 默认用 page=1&pageSize=20,因为它最常见。但它不会告诉你这个选择在大数据量下会有性能问题。

sharp-api-design 怎么管住 AI 的接口输出

sharp-skills 的 api-design 模块做的事情跟其他模块一样:把接口设计的品控标准写成 AI 能执行的规则文件。

规则分三级:

MUST 级规则(违反就重写):

  • 路径必须是名词复数形式,禁止使用动词(/users 不是 /getUsers
  • CRUD 操作必须使用对应的 HTTP 方法(GET 查询、POST 创建、PUT 全量更新、PATCH 部分更新、DELETE 删除)
  • 业务错误必须使用独立的 biz_code 字段,不能直接复用 HTTP 状态码表示业务错误
  • 响应必须有统一的包装结构(code/message/data/trace_id
  • 所有列表接口必须明确分页策略(offset 或 cursor 二选一,全项目一致)
  • 请求参数必须有边界校验注解(@NotNull@Size@Pattern),不能信任客户端
  • 错误码必须按业务模块分区间(用户模块 10xxx,订单模块 11xxx)

SHOULD 级规则(尽量遵守):

  • 路径应使用 kebab-case(/user-orders 不是 /userOrders
  • 字段命名应使用 snake_case(保持 JSON 序列化风格统一)
  • 接口路径前缀应包含版本号(/api/v1/users
  • 列表接口应支持按字段排序(?sort=-created_at
  • 批量操作应支持事务性参数(?atomic=true
  • 接口文档应自动生成(OpenAPI 注解)

MAY 级规则(锦上添花):

  • 可以添加请求签名头(防重放)
  • 可以添加幂等键参数(POST 接口防重复提交)
  • 可以添加 ETag 头(GET 接口支持 304 缓存)
  • 可以添加 X-RateLimit-Remaining 响应头

这套规则的核心思路是:接口设计是有客观标准的工程行为,不是"看风格"。 路径命名、错误码、分页策略这些都有对错之分,不是"我习惯就行"。

一个实际对比

同一个需求:实现用户管理模块的 CRUD 接口。

AI 默认输出:

sql 复制代码
POST /user/create
POST /user/update
POST /user/delete
POST /user/list
GET /user/getInfo

错误返回 Result.fail("参数错误")Result.fail("用户不存在")Result.fail(-1) 三种风格混用。响应结构 POST /user/create 直接返回 User 对象,POST /user/list 返回 {data: [...], total: 100}。分页用 page=1&size=10

sharp-api-design 约束下的输出:

bash 复制代码
GET    /api/v1/users          # 列表,cursor 分页
GET    /api/v1/users/{id}     # 详情
POST   /api/v1/users          # 创建
PUT    /api/v1/users/{id}     # 全量更新
PATCH  /api/v1/users/{id}     # 部分更新
DELETE /api/v1/users/{id}     # 删除

错误统一为 biz_code(用户不存在 10001、邮箱已注册 10002、参数校验失败 10400)。响应统一包装层 code/message/data/trace_id。分页统一 cursor 模式。

同样的功能,前者是"能跑的代码",后者是"能协作的接口"。前端拿到第二种可以无脑写拦截器,拿到第一种得写一堆适配。

接口设计规则为什么不能直接写进 prompt

你当然可以在 prompt 里写"请使用 RESTful 风格"、"错误码用业务分类"、"响应统一包装结构"。但跟数据可视化一样的三个问题:

第一,prompt 衰减。第一轮对话写下的约束,到第三轮 AI 就忘了一半。这是 LLM 的注意力机制决定的,不以你的 prompt 水平为转移。

第二,重复成本。每个项目都写一遍这些规则,prompt 比接口文档还长。规则文件化之后,写一次,复用一百次。

第三,标准漂移。今天你写的"错误码用业务分类",明天 AI 帮你生成新接口的时候可能就退化成"直接返回 HTTP 状态码"。品控的核心是可复现,每次新生成都得跟上次一致,规则文件就是锁定这个一致性。

更关键的是,接口设计跟其他领域不一样,它的"对错"是有判断人的------前端、客户端、QA、监控、运维都会按照规则检验你的接口。规则文件 AI 执行一次就过 review,prompt 执行十次可能有八次过不了 review。这是工程化思维在做接口设计这件事上的具体体现。

api-design 规则不是万能的

说句实话,sharp-api-design 能管住的是"接口命名规范"、"错误码体系"、"响应结构统一"这些契约层的标准。它管不了的是"这个业务该不该拆成 5 个接口还是 3 个接口"、"这个字段该不该冗余"、"这个操作该不该异步"。

这些是业务建模的判断,不是接口设计的规则。一个订单系统是按状态拆接口(创建订单/支付订单/取消订单)还是按资源拆接口(订单/支付/退款),取决于产品设计,不是规则文件能定的。

规则文件管的是"怎么写对",不管"该不该这样写"。后者需要人判断,AI 短期内也做不好这个判断。但契约层的标准用规则固化下来,至少不会让团队里不同的人写出风格完全不一致的接口。

我做过的对比实验:拿同一个用户管理需求,让 3 个 prompt 模板(不加载规则)和加载 sharp-api-design 规则的 AI 同时生成 5 套接口方案,拿给 5 个有 3 年以上经验的后端开发盲评。规则约束下的接口在"路径规范"、"错误码可识别"、"响应一致性"、"分页策略合理性"四个维度上评分平均高出 50%。差距最大的就是错误码一致性------自由模式下 AI 5 次输出用了 3 套不同的错误码风格,规则模式下 5 次输出完全一致。

接口设计这件事,审美可以讨论,工程标准不能含糊。 AI 缺的不是创意,是落地的标准。规则文件落下去的标准比 prompt 里写一百句"请遵循规范"管用得多。

顺便说一句,我在做的那个小程序「爪爪代码冒险记」里有个接口设计关卡,用卡皮巴拉做 API 网关拦截各种不符合规范的请求,比直接讲规则好玩。感兴趣可以搜搜看。

相关推荐
izhaorui1 小时前
【无标题】
后端
小p1 小时前
nextjs学习9: Next.js 渲染与缓存
前端·后端
宋哥转AI1 小时前
深入理解 AI Agent 03|RAG评估体系:量化检索增强效果,精准定位系统短板
人工智能·后端·agent
Leo2821 小时前
数据库Executor-Selector排查实践
后端
Zane19941 小时前
线程池入门:7 大核心参数与 4 种拒绝策略
java·后端
用户298698530142 小时前
无需安装 Excel,也能轻松将 CSV 转为 XLS 或 XLSX
后端·c#·excel
Gopher_HBo2 小时前
Gin架构总览
后端
BingoGo2 小时前
PHP 8.6 新特性一览
后端·php
大陈AI2 小时前
从“打开就卡“到“秒开“:一次 PHP GD 动态海报生成的性能优化实战
后端