这个系列写到第三篇了。前两篇聊了 Claude 能做什么、怎么建立有效的对话习惯,这一篇直接上硬菜——从一段含糊的需求,到一个能跑的接口,完整走一遍用 Claude 做接口开发的过程。先说我观察到的一个普遍现象:很多人打开对话框第一句就是“帮我写个用户接口”,等代码出来又开始头疼,“这也不是我要的”。问题其实不在生成质量,而在于需求根本没被翻译成 Claude 能理解的粒度。这篇 Claude 开发入门的内容,适合刚学会写接口、但还没把 AI 辅助开发用顺手的读者。我会拿一个待办事项接口当例子,演示怎么把零散需求拆成接口要素、怎么写提示词、怎么验证生成结果、怎么处理翻车现场。看完你就能照着走一遍。
1. 需求没拆干净之前,先别急着让 Claude 开写
1.1 大多数开发者向 Claude 提需求时的三个通病
我见过不少刚接触 Claude 的开发者,包括我自己最早试用的时候,都有类似的通病。第一个通病是需求过于笼统,“帮我写个商品接口,要能增删改查”这种话一说出去,Claude 只能靠猜。它猜出来的接口路径、字段命名、返回结构大概率和你项目里已有的风格对不上,最后花在改代码上的时间比手写还长。
第二个通病是只描述功能,不描述约束。很多人会说“做一个登录接口”,但不说清楚用户名长度规则、密码是否要加密、登录失败返回什么错误码、接口是给 App 用还是给网页用。Claude 完全可以生成一个能跑的登录接口,但它会按照它自己最熟悉的默认方案来设计,那个方案通常不是你项目需要的方案。
第三个通病是忽略上下文。接口从来不是孤立的一段代码,它依赖技术栈、已有代码风格、数据存储方式、鉴权方式。你只丢一句“用 Python 写”,Claude 可能给你生成一个 Flask 版本,而你们团队用的是 FastAPI;可能给你生成一个连接 PostgreSQL 的完整项目,而你现在只需要一个还在联调阶段的内存版本。这些信息不补全,生成的代码再漂亮也是负担。
1.2 把“人话需求”拆成接口四要素
我自己在长期使用中总结出一个习惯,不管需求多简单,动手前先把它拆成四个方面,也就是我常说的接口四要素。
一是路径与资源。这个接口操作的对象是什么,它应该放在哪个 URL 下。是/api/todos还是/api/todo,是一级资源还是嵌套资源,这些看起来是小问题,但定了之后前端要照着联调,改起来很痛。
二是 HTTP 方法与语义。你要做的是获取、创建、修改还是删除。对应 GET、POST、PUT、PATCH、DELETE。很多人习惯所有操作都用 POST,接口确实能跑,但语义混乱后,Claude 生成的代码里很难出现清晰的路由划分,后续做缓存、限流、权限控制都会别扭。
三是入参与出参。请求需要带哪些字段,哪些必填,哪些可选,字段类型是什么。返回结构是什么样,成功和失败分别长什么样。比如统一返回{“code”: 0, “data”: ..., “message”: “ok”}还是直接把数据裸返回,这个决定越早越好。
四是业务规则。这是最容易被忽略的部分。标题能不能为空,长度有没有上限,列表按什么排序,删除一个不存在的 ID 要返回 404 还是静默成功,标记完成之后能不能重复标记。把这些规则写清楚,Claude 生成的代码直接就能体现出来。
四个要素可以用一张表整理,方便直接贴给 Claude。比如:
| 要素 | 要问的问题 | 例子 |
|---|---|---|
| 路径 | 资源放哪里 | /api/todos |
| 方法 | 操作是什么 | GET / POST / PATCH / DELETE |
| 入参 | 需要什么数据 | 请求体字段title,1-50 字符 |
| 出参 | 返回什么结构 | {code, data, message} |
| 业务规则 | 有哪些限制 | 标题必填,列表按创建时间倒序,删除不存在返回 404 |
这一张表,就是你后续和 Claude 对话的基础。它不需要多长,但每条信息都会直接体现在代码里。
1.3 同一个需求,两种提示词的效果差异
我把同一个需求用两种方式发给 Claude,对比非常明显。第一种是这样:帮我写一个待办事项接口。Claude 通常会生成一个带数据库、带用户体系、带前端页面模板的全套项目。不是它做错了,而是信息太少的时候,它只能选择“最大可能性”来补全。
第二种是这样:我要实现一个待办事项管理接口,技术栈用 Python 的 FastAPI,暂时不引入数据库,数据先放在内存列表里。接口包括:创建待办、查询未完成列表、标记完成、删除待办。创建时标题必填,长度 1-50 字符;列表按创建时间倒序;删除不存在的 ID 返回 404。请先给出项目文件结构,再给出核心代码。
同样是写待办接口,第二种提示词把技术栈、存储方式、接口范围、业务规则、输出形式全说清楚了。Claude 拿到这样的输入,生成的代码基本就是可用的初稿,不需要大改。这里面的核心逻辑是:Claude 不是不能写代码,而是它只能按你给的确定性信息写代码,信息不足时它一定会脑补。脑补的越多,你需要返工的就越多。
2. 完整实操:从一句话需求到能跑通的待办事项接口
2.1 先让 Claude 确认技术选型,别让默认选项替你决定
很多人打开 ChatGPT 或 Claude 就问“帮我写个接口”,完全没提技术栈,最后拿到手的往往是项目里根本用不上的方案。正确的做法是先定好技术栈,再让 Claude 在既定框架里发挥。
选择技术栈时,我建议优先考虑团队正在用的、你手头最熟的,而不是让 Claude 推荐一个“更好”的。对接口开发这个场景来说,Python 生态里 FastAPI 是我个人比较常用的选择,因为它自带类型校验和自动接口文档,生成出来的代码结构也比较清晰。Node.js 生态里 Express 也很常见,适合和前端项目保持同一个语言。
如果你实在不确定选哪个,可以把你的运行环境、部署方式、团队语言偏好告诉 Claude,让它给方案,但你必须自己做最终决定。因为一旦代码生成,后续的维护、排错、部署全都要你来扛。
2.2 用一段有上下文的提示词拿到首版代码
我们以 FastAPI 为例,完整提示词可以这样写:
用 FastAPI 实现一个待办事项接口,Python 3.11。 不需要数据库,数据先放在内存列表中。 接口包括: 1. POST /api/todos 创建待办,请求体 JSON 字段 title,必填且长度 1-50 字符; 2. GET /api/todos?status=pending 查询未完成列表,按创建时间倒序; 3. PATCH /api/todos/{id}/done 标记为完成; 4. DELETE /api/todos/{id} 删除待办,不存在返回 404。 响应统一使用 {"code": 0, "data": ..., "message": "ok"} 结构。 请生成完整代码,并加上基本类型校验。Claude 返回的代码可能比下面的版本更长更啰嗦,因为提示词里没有限制文件数,它可能会拆成main.py、models.py、schemas.py几个文件。我做过精简之后,核心代码大致是这个样子:
from typing import Optional from datetime import datetime from fastapi import FastAPI, HTTPException from pydantic import BaseModel, Field app = FastAPI() todos = [] todo_id = 1 class TodoCreate(BaseModel): title: str = Field(..., min_length=1, max_length=50) @app.post("/api/todos") def create_todo(todo: TodoCreate): global todo_id item = { "id": todo_id, "title": todo.title, "done": False, "created_at": datetime.now().isoformat(), } todos.append(item) todo_id += 1 return {"code": 0, "data": item, "message": "ok"} @app.get("/api/todos") def list_todos(status: Optional[str] = None): result = todos if status == "pending": result = [t for t in todos if not t["done"]] result = sorted(result, key=lambda t: t["created_at"], reverse=True) return {"code": 0, "data": result, "message": "ok"} @app.patch("/api/todos/{id}/done") def mark_done(id: int): for t in todos: if t["id"] == id: t["done"] = True return {"code": 0, "data": t, "message": "ok"} raise HTTPException(status_code=404, detail="todo not found") @app.delete("/api/todos/{id}") def delete_todo(id: int): for i, t in enumerate(todos): if t["id"] == id: todos.pop(i) return {"code": 0, "data": None, "message": "ok"} raise HTTPException(status_code=404, detail="todo not found")注意,这份代码目前只是“能跑”的版本,远不是“生产可用”的版本。内存列表存数据,重启就丢;并发写同一个全局变量也可能出问题;没有做任何鉴权。但我特意没让 Claude 一开始就引入数据库和复杂设计,因为联调阶段需求还在变,先把接口形状打出来比什么都重要。
2.3 本地启动与验证:用 curl 和浏览器把接口跑起来
拿到代码之后,最重要的一步是验证。先安装依赖并启动服务:
pip install "fastapi[all]" uvicorn main:app --reload启动成功后,我会先用浏览器打开http://127.0.0.1:8000/docs。这是 FastAPI 自动生成的接口文档页面,能看到所有接口的定义、参数、请求示例,甚至可以直接在页面上点击“Try it out”发送请求。这个页面本身就是验证接口是否正确的一个快捷工具。
除了在浏览器里点,我更推荐用 curl 测一遍核心场景,因为脚本化验证以后可以写进自动化测试。先创建一个待办:
curl -X POST http://127.0.0.1:8000/api/todos \ -H "Content-Type: application/json" \ -d '{"title": "写一篇接口开发实战"}'正常情况下会返回类似这样的 JSON:
{ "code": 0, "data": { "id": 1, "title": "写一篇接口开发实战", "done": false, "created_at": "2025-01-15T20:30:00" }, "message": "ok" }再测两个边界场景。一个是创建空标题,因为 Pydantic 里写了min_length=1,应该返回 422 校验错误而不是成功将空数据写进去。另一个是删除一个不存在的 ID,比如curl -X DELETE http://127.0.0.1:8000/api/todos/999,应该返回 404。这两个场景能快速暴露接口校验逻辑是否生效。实测下来,只要提示词里明确写了规则,Claude 在这个环节很少翻车。
3. Claude 生成代码的漏洞,得靠人工审查补上
3.1 生成代码里最常见的三类隐性缺陷
Claude 生成的接口代码,第一版基本都能跑,但“能跑”和“能用”之间还有一段距离。我总结了三类最常出现的隐性缺陷。
第一类是输入校验不完整。它会校验标题长度,但可能忘了限制分页参数的大小,忘了校验枚举值,忘了处理请求体里多余的字段。比如查询列表时传了status=abc,可能只会被当作无过滤条件处理,正常返回全部数据,而正确的做法是返回参数非法。
第二类是敏感信息硬编码。当需求里涉及到数据库、Redis、第三方服务时,Claude 很容易把连接串、密钥直接写在代码里。你用本地环境测试没问题,一旦代码提交,密钥就可能跟着进仓库。生成代码后要专门搜索一遍password、secret、api_key这类关键词。
第三类是异常处理过于粗糙。很多生成出来的代码喜欢用一个大大的try...except Exception把整个方法包起来,遇到错误返回一个空消息。对调用方来说,收到一个没有错误码、没有详细信息的失败响应,基本等于没有响应,排错时只能靠猜。
发现这些问题不能靠肉眼硬看,我常用的方法是让 Claude 自己审一遍,但仍由我拍板。
3.2 怎么让 Claude 把代码自审一遍:先给结论再给代码
给 Claude 发审查请求时,我会刻意先拦一步。提示词这样写:
现在请你以资深 Python 后端工程师的身份,审查下面这段接口代码。先不要急着修改,请重点检查: 1. 参数校验是否完整,有没有遗漏的非法输入场景; 2. 异常处理是否合理,错误信息是否对排查有帮助; 3. 是否包含硬编码的敏感信息; 4. 命名是否一致,响应结构是否统一。 请按严重程度列出问题清单,每条给出理由,然后再给出修改后的完整代码。注意最后一句的“先不要急着修改”。如果一开始就让 Claude 直接改,它常常会把整个文件重写一遍,你根本看不出它动了哪里。让它先列问题清单,你就能像 code review 一样逐条确认,再决定哪些接受、哪些忽略。
审查提示词里还可以追加一句:如果有不确定的地方,直接说"这里需要你提供更多上下文",不要猜测。这一条能明显减少 Claude 自作主张的行为。生成式的模型天生倾向于给出完整答案,而不是承认信息不足,明确允许它追问之后,反而能得到更准确的修改方案。
3.3 一次 500 错误排查的完整链路
审查之后代码质量会好很多,但运行时的坑才是真正考验排错能力的地方。我讲一个很典型的例子。有一次我让 Claude 生成一个带内存存储的待办接口,它同时定义了存储用的字典结构{"todo_id": 1, "title": "x", "done": false}和返回模型TodoOut(BaseModel),返回模型里的字段是id: int。
创建接口没报错,但调用GET /api/todos时,服务端直接返回 500。第一次遇到这种情况,很容易以为是数据库或路由出了问题,其实真正的排错链路是这样的。
第一步,看服务端控制台的完整 Traceback。FastAPI 的日志会精确打印出错误文件和行号,那一行通常是响应序列化时报的pydantic.error_wrappers.ValidationError,提示id field required。
第二步,对比存储的字典键名和响应模型字段名。存储结构用的是todo_id,响应模型要求的是id,Pydantic 在序列化返回对象时找不到id字段,于是抛校验错误,FastAPI 只好统一返回 500。
第三步,修复方案有两种。要么把存储字典的键改成id,要么把响应模型字段改成todo_id。这个决定要看前端的约定,我当时选择了修改存储结构,保持对外响应模型字段为id,因为这样对外接口更规范。
第四步,把问题和自己的处理倾向一起发给 Claude,让它基于“保持对外字段为 id”这个前提给出修改后的代码,再重新跑一遍 curl 验证。整个过程下来,真正花时间的不是让 Claude 改代码,而是通过 Traceback 定位到字段不一致这个根因。养成看日志的习惯,比让 AI 替你猜强得多。
这个例子也提醒我:接口联调阶段,500 错误十有八九是数据结构和响应模型不一致造成的,不必一上来就怀疑框架问题。先看日志,再比对字段,这个排查顺序能省很多时间。
4. 把“生成-验证-反馈”固化成接口开发小流水线
4.1 用“接口卡片”管理需求,让 Claude 每次都有完整上下文
一旦接口数量变多,你会发现每次重新打开对话都要重复一遍需求描述,非常浪费上下文空间。我后来养成一个习惯,把每个接口整理成一张“接口卡片”,存在项目文档里,要用的时候直接整段贴给 Claude。
接口卡片的格式大概是这样的:
接口名称:待办列表查询 路径:GET /api/todos 入参:status,可选值 pending / completed,缺省返回全部 出参:code(0成功), data(数组), message 元素:id, title, done, created_at 规则: - 列表按创建时间倒序 - status 传非法值返回 400,提示 supported: pending, completed - 不返回已删除的数据 依赖:内存列表 TODO_STORE这张卡片本质上是把前面四个要素固化下来。好处很明显:同一段上下文可以反复使用;Claude 生成的代码不会因为你换了措辞而出现理解偏差;你换一个 AI 工具或让另一个同事接手时,需求也不会被重新解读一遍。
我还会把旧版本代码和接口卡片一起发给 Claude,形成“旧代码 + 契约 + 变更点”的组合。比如需求改为“新增更新标题接口”,我会这样写:
现有接口代码如下。现在需求变化:增加 PUT /api/todos/{id},允许更新标题,标题仍然必填且 1-50 字符。请基于现有代码风格做增量修改,不要重写整个文件。“基于现有风格做增量修改”,这一句话能避免 Claude 把文件推倒重来。它知道你只需要一个动作,而不是一次重构。
4.2 让 Claude 附带生成测试用例和 Mock 数据
接口开发最容易被跳过的环节是测试。我自己刚开始也觉得,接口能调通就行了,何必写测试。直到有一次改动“列表按创建时间倒序”这条规则时,没注意到一个分支把已完成的待办也带了进来,线上接口数据顺序直接错乱。之后我就习惯让 Claude 在生成接口的同时,生成一组测试用例。
提示词可以这样写:
根据上面的接口卡片,生成 pytest 测试用例,使用 fastapi.testclient。 覆盖六个场景: 1. 正常创建待办,返回 code=0; 2. 创建空标题,返回 422; 3. 创建超过 50 字符的标题,返回 422; 4. 查询 status=pending 只返回未完成项,且按创建时间倒序; 5. 标记不存在的 ID 为完成,返回 404; 6. 删除不存在的 ID,返回 404。这类测试用例生成的代码通常可以直接运行。你不需要从零构思场景,但一定要在生成后自己过一遍,看看它测的是不是需求里真正重要的规则。Claude 擅长列举常规场景,但业务上最昂贵的那个“边界条件”,往往只有你真的踩过坑才知道。
Mock 数据也一样。前端联调时最讨厌后端没准备好,我一般会顺手让 Claude 生成一份模拟数据文件,比如mock_todos.json:
[ { "id": 1, "title": "完成接口文档", "done": false, "created_at": "2025-01-14T10:00:00" }, { "id": 2, "title": "和前端对齐错误码", "done": true, "created_at": "2025-01-13T09:30:00" } ]这份文件可以直接交给前端先用起来,也可以作为测试数据源。实际开发中,Mock 数据的主要作用不是骗前端,而是让联调双方提前把字段结构、嵌套层级、错误响应这些契约问题暴露出来,等后端真正跑通时,两边已经对过一轮了。
4.3 多接口项目里的风格统一和上下文管理
单接口做得顺,不代表多接口项目能一直顺下去。Claude 每轮对话的上下文有限,你写到第五个接口时,它很可能已经忘了第一个接口的错误码风格。这时我建议做两件事。
第一件事,在项目里维护一个“代码风格对照文件”,里面放一段具有代表性的已有代码,以及几条明确的风格要求,比如“错误响应统一使用message字段”“时间字段统一用 ISO 8601 字符串”“接口路径统一小写加连字符”。每次让 Claude 生成新接口前,把这些片段贴进提示词,它就会按照同样的风格输出。说到底,Claude 在短样本上的模仿能力很强,关键在于你舍不舍得给它样本。
第二件事,每个独立功能尽量单独开对话,不要让“待办接口”和“用户接口”混在同一个上下文里搅来搅去。一个对话负责一个稳定的需求范围,生成结果清爽,后续要基于旧代码改动时也更容易把上下文控制住。我甚至会在对话标题里写上接口名,方便几小时后回来继续追问时不至于迷失。
这套流水线走到这里,基本就形成了一个闭环:接口卡片定契约,提示词生成初稿,curl 和测试用例做验证,审查提示词补漏洞,旧代码加变更需求做迭代。每一步做的事情都很小,但合在一起,足够让一个简单接口在几轮对话内稳定跑起来。
最后再分享一个我个人的体会。Claude 开发接口的能力上限,其实很大程度上取决于你愿意在需求整理上花多少功夫。不是你的提示词写得有多花哨,而是你有没有把接口开发里那些确定性的信息收集齐。这个习惯刚开始很费时间,但坚持几次之后,从需求到能跑的接口通常只需要几轮对话,而且返工率低得多。如果你也在用 Claude 做接口开发,我建议先别急着让它生成大而全的系统,从一个最朴素的接口开始,把“拆需求、生成、验证、反馈”这个循环走顺,再慢慢加数据库、鉴权、错误码这些复杂度。跑通之后再回头看你第一次让 Claude 写接口时的手忙脚乱,应该会有完全不一样的感觉。