:Cursor 一分钟写完接口后,我才真正理解:后端工程师最值钱的从来不是写代码)
我第一次真正把 Cursor 用进一个稍微复杂点的后端项目时有一个瞬间印象特别深。当时只是要加一个接口。如果放在以前我大概会先翻一下项目结构看看现有的 Model数据模型、Service业务服务层怎么组织再补 Request、Response接着写数据库逻辑最后补测试。不算难但怎么也得花点时间。那次我直接把需求交给了 AI。没多久代码出来了。目录放对了。接口有了。SQLAlchemy 也写了。异常处理看上去像那么回事。连 pytest 测试都顺手补上了。我跑了一遍。通过。那一刻其实挺容易产生一种错觉后端开发好像突然不值钱了。以前需要半小时、一小时甚至更久完成的事情现在 AI 几分钟就能干完。如果顺着这个感觉继续想很自然就会问既然 Cursor、Codex 以后越来越强后端工程师还剩下什么后来我发现这个问题从一开始就问错了。真正值得问的不是AI 能不能替我写代码而是当代码越来越容易被生成以后到底什么东西还需要工程师负责我想把这个问题作为整个系列的第一课。因为如果这件事没想明白后面不管学 Cursor、Codex、Agent智能体、RAG检索增强生成还是 MCP模型上下文协议最后很容易走向同一个结果AI 写得越来越多人却越来越不知道代码为什么是对的。而这恰恰是最危险的状态。先别谈 AI我们看一段普通得不能再普通的代码假设产品给了一个需求用户提交订单后端把订单保存下来。AI 很快写出了这样一个接口app.post(/orders) def create_order( request: CreateOrderRequest, db: Session Depends(get_db) ): order Order( user_idrequest.user_id, product_idrequest.product_id, quantityrequest.quantity ) db.add(order) db.commit() db.refresh(order) return order先不要急着往下看。我希望你真的停几秒自己判断一下这段代码到底对不对如果发送一个请求POST /orders数据库里成功多出一条订单记录。接口返回 200。订单 ID、商品 ID、数量全部正确。测试也通过。那它是不是已经完成需求了如果这是刚学后端的时候我大概率会说完成了。但工作时间越长我越发现“代码对不对”其实是一个非常容易骗人的问题。因为“对”至少有好几个层次。而 AI 今天最擅长解决的恰恰是最表面的那几层。第一层代码能运行最简单的一层叫 Syntax Correctness语法正确性。Python 没报语法错误。FastAPI 能正常启动。SQLAlchemy 调用没有写错。函数能执行。这一层今天已经越来越不稀缺。以前忘了某个 API 怎么写还要翻文档、搜 Stack Overflow。现在很多时候一句话就够了。甚至你根本不需要记住某个参数叫什么。AI 会帮你补。所以如果一个程序员最大的优势只是“这个框架的 API 我特别熟。”这项能力不会消失但它的稀缺程度一定会下降。因为“记住怎么写”这件事机器已经越来越擅长。但事情才刚刚开始。第二层正常情况下它能完成需求再往上一层是 Functional Correctness功能正确性。也就是用户正常调用接口的时候系统能不能给出正确结果刚才那个订单接口显然可以。用户提交商品 1001数量 2。数据库插入一张订单。接口返回订单信息。所以它在 Happy Path正常路径上是正确的。很多 Demo演示程序其实做到这里就结束了。“看AI 三分钟帮我们完成订单系统。”如果你只是演示一个概念完全没问题。但真实系统最麻烦的地方从来不是 Happy Path。真实世界不会一直按照你写 Demo 时设计的剧本运行。我们稍微改变一下条件。用户连续点了两次“提交订单”会发生什么第一次请求已经到达服务器。数据库也成功创建了订单。但是返回结果的时候用户网络突然抖了一下。前端没有收到响应。用户看到页面一直转圈。他不知道订单到底成功没有于是又点了一次。于是服务器收到了两个请求。刚才那段代码会怎么做很简单。创建两张订单。注意这里最有意思的地方每一行代码可能都是正确的。数据库没有报错。框架没有报错。两个请求也都返回了 200。可整个系统就是错了。为什么因为真正的业务规则可能是同一次下单行为无论客户端重复提交多少次都只能产生一张订单。这时候你才真正进入后端工程。这里会碰到一个词Idempotency幂等性。第一次看到这个词很容易觉得玄乎。其实意思非常朴素同一件事情重复执行不应该产生你不希望出现的额外结果。查询订单重复执行十次通常没什么。但是支付接口执行两次呢扣库存执行两次呢优惠券领取执行两次呢发货指令执行两次呢到了这些场景幂等就不是一个“高级知识点”。它直接决定系统会不会出事故。所以你现在应该已经能感觉到一个变化。我们讨论的已经不再是“Python 怎么写”而是真实世界出现重复、失败和异常以后系统应该保持什么状态这就是 Engineering工程。代码能跑和系统真的正确中间隔着很远我们继续把订单场景往真实世界推一步。真实下单通常不会只做一件事情。它可能需要创建订单。扣减库存。写支付记录。发送消息。记录操作日志。现在假设创建订单成功了库存也扣了。但是发送消息的时候MQMessage Queue消息队列突然超时。怎么办订单应该保留还是回滚如果保留消息怎么补发如果回滚库存怎么办再换一个情况。数据库已经 Commit提交成功但服务器在把结果返回给客户端之前挂掉了。客户端不知道到底成功还是失败于是 Retry重试。第二次请求应该返回第一次的订单还是重新创建再来一个。库存只剩 1 件。两个用户几乎同时提交订单。请求 A 查询库存 1。请求 B 也查询库存 1。于是 A 认为可以买。B 也认为可以买。最后卖出了两件。代码还能不能运行当然能。甚至两个请求都有可能返回 200。但是你的库存已经变成了一个谎言。这就是为什么我后来越来越不喜欢一句话“这个接口已经写完了。”我更愿意问它已经解决了哪些情况还有哪些情况没有被定义这两个问题听起来差不多背后的工程水平完全不同。真正的后端工程往往从“失败”开始刚学后端的时候我们通常是顺着成功路径理解系统的。请求进来。参数校验。调用 Service。写数据库。返回结果。这个学习顺序没问题。但是一旦进入真实项目我建议你开始训练另一种思维不要只顺着成功往下走要故意把系统“掰断”。数据库写到一半失败了呢Redis 不可用了呢第三方接口 30 秒不返回呢客户端重复请求呢两个请求同时修改同一条数据呢Worker后台任务进程执行到一半重启呢一条消息被消费两次呢代码发布了一半需要回滚呢用户没有权限却构造请求呢日志只有一句 “Internal Server Error”线上怎么定位呢这些问题第一次看会觉得特别杂。实际上它们背后都在问同一件事情当现实世界不配合你的代码时系统还能不能保持正确这句话我认为是理解 Production Engineering生产级工程非常重要的一把钥匙。Demo 关注成功的时候能不能跑通。Production生产环境更关心失败的时候会不会失控。一旦真正理解这句话很多以前觉得“为什么要学”的东西就突然串起来了。Transaction事务为什么重要因为执行到一半可能失败。Retry重试为什么危险因为同一件事可能被执行两次。Idempotency幂等为什么重要因为网络世界里你永远不能假设请求只到一次。Lock锁和 Concurrency Control并发控制为什么存在因为两个正确的请求同时执行也可能得到错误结果。Logging日志和 Tracing链路追踪为什么不是“上线以后再说”因为系统一旦复杂你必须知道到底是哪一步出了问题。这些词并不是后端工程师故意把事情搞复杂。它们都是现实世界逼出来的。到这里我们终于可以重新看 AI Coding现在再回过头看 Cursor 和 Codex就会清楚很多。AI 今天非常擅长什么你给它一个相对明确的需求它可以快速把这个需求翻译成代码。例如“实现一个分页查询接口。”“给这个模型增加 CRUD增删改查。”“按照现有模式补一个 Service。”“给这些函数生成单元测试。”这些事情本质上有一个共同点目标已经比较明确剩下的是实现。而软件开发过去最耗时间的一部分恰恰就是把这些明确意图一点点翻译成代码。以前你脑子里知道应该怎么做还需要找 API。写样板代码。改类型。补 import。调格式。写重复的 Repository。补测试骨架。现在 AI 把这段距离大幅压缩了。所以我更愿意这样描述 AI Coding 带来的变化AI 没有先拿走“软件工程”它先拿走的是大量“把明确设计翻译成代码”的劳动。这两件事情不是一回事。一个非常关键的分界线AI 可以替你实现但它不能凭空知道你的业务世界还是刚才那个订单接口。如果你只告诉 AI“实现创建订单。”它不知道什么它不知道同一个请求能不能重复。不知道库存是否必须同时扣减。不知道订单创建和库存修改是否要求强一致。不知道失败后是 Rollback回滚还是 Compensation补偿。不知道系统有没有 Redis。不知道有没有统一错误码。不知道数据库事务在哪一层管理。不知道这个项目禁止不禁止 Controller控制器直接访问数据库。不知道你的日志规范。不知道历史架构为什么这么设计。那它怎么办它只能根据过去学过的大量代码给你一个“通常看起来合理”的答案。这里有一个我觉得非常值得警惕的地方生成式 AI 最危险的能力之一是它可以把“合理猜测”写得非常像“确定答案”。代码命名很好。注释很完整。抽象看起来也专业。甚至还有测试。人一看很容易放松。传统的新手代码有时候反而比较安全。因为写得乱你一眼知道需要 Review审查。AI 代码的问题是它经常长得太像正确答案。所以我现在拿到 AI 生成代码首先看的已经不是“写得漂不漂亮”而是它做出这些决定时到底掌握了哪些信息这个问题会直接把我们带到整套课程后面一个非常重要的主题Context Engineering上下文工程。Prompt 不是最重要的AI 知道什么才重要Prompt提示词当然有用。但很多人刚开始 AI Coding 时会把大量时间花在研究有没有“万能 Prompt”怎么写一句话让 Cursor 更聪明有没有一段神级指令让 AI 一次写对后来我越来越觉得方向有点偏。比如还是做登录。你只说“帮我实现用户登录。”AI 必须自己猜密码算法是什么JWT 放在哪里Token令牌多久过期用户不存在返回什么错误密码错误返回什么Controller 能不能碰数据库项目有没有 Repository Pattern仓储模式测试放在哪安全模块能不能改这种情况下 Prompt 再漂亮AI 还是缺信息。换一种方式。我会先让它读项目里的架构说明、用户模型、现有认证 Service、安全模块和测试。然后告诉它这次需要增加什么能力。哪些现有设计不能改。必须复用哪些已有组件。错误响应必须遵守什么规范。需要补哪些测试。最后再加一句先分析不要写代码。差别马上就出来了。第一种方式本质上是在问“你觉得登录应该怎么写”第二种方式是在告诉它“在我的系统里登录应该满足什么规则。”这就是 Prompt 和 Context上下文的区别。Prompt 更像是你现在想让我做什么Context 更像是我在做决定之前应该知道哪些事实复杂项目里后者通常更重要。有一个概念我希望你从第一课就学会InvariantInvariant中文一般翻译为“不变量”。名字有点数学味。但它是一个非常适合工程师思考问题的概念。什么叫不变量最简单的理解无论系统经历多少请求、失败、重试和并发有些规则始终不能被破坏。比如库存系统库存不能无缘无故变成负数。支付系统同一笔业务不能因为重试被重复扣款。权限系统普通用户不能读取管理员数据。优惠券系统如果规则规定每人只能领取一次同一个用户就不能因为并发请求拿到两张。转账系统钱不能凭空产生也不能凭空消失。你会发现这些才是真正应该被系统保护的东西。代码只是保护这些规则的一种手段。这会彻底改变你看需求的方式。新手拿到需求“做一个优惠券领取接口。”第一反应往往是URL 怎么设计POST 还是 GETService 怎么写高级一点的工程师会先问这个功能有哪些规则绝对不能被破坏比如优惠券必须存在。必须在有效期内。库存必须大于 0。同一用户只能领取一次。总领取数量不能超过发行量。没有登录不能领取。失败不能留下半条脏数据。注意我们现在还没有写任何代码。但真正重要的设计已经开始了。接下来才轮到这些规则由数据库约束保证还是业务层保证需要唯一索引吗需要事务吗需要锁吗需要幂等 Key幂等键吗哪些场景必须测试这就是我认为 AI 时代一个非常值得训练的习惯拿到需求先找不变量再想代码。因为 AI 特别擅长写代码。但“不变量到底是什么”往往来自你对业务和系统的理解。为什么高级工程师经常不急着写代码以前我刚开始做开发的时候也不太理解。明明需求已经来了为什么有些人还要开会、画流程、看旧代码、讨论边界赶紧写不就行了吗后来做的系统越复杂越明白工程里最贵的错误往往不是代码写错而是把错误的理解实现得非常完整。这件事在 AI Coding 时代会更加明显。以前一个错误方案你可能写两天才写完。写到一半发现不对还有机会停下来。现在呢AI 十分钟就能改十几个文件。Service 写完。Repository 写完。Migration数据库迁移写完。测试也写完。甚至文档都给你补好了。看上去效率爆炸。问题是如果方向错了它只是帮你更高效地走错路。所以我现在越来越重视一个很简单的习惯Plan First先做方案再写代码。“给任务增加取消功能”到底难在哪里举一个后面做 AI Backend 时特别常见的例子。需求只有一句“给 AI TaskAI 任务增加取消功能。”看起来简单。可能很多人已经准备让 Cursor 写Implement task cancellation。也就是实现任务取消。但先别写。问一个问题什么叫“取消成功”任务还在 Pending等待中状态很简单改成 Cancelled已取消。如果任务已经被 Worker 取走了呢如果正在调用 LLM大语言模型呢如果 LLM 已经返回正在写数据库呢如果用户点击取消的同时Worker 正好把任务执行完成呢如果客户端连续发两次取消请求呢如果取消后服务重启呢取消以后还能不能 Retry重试用户看到的是“取消请求已接收”还是“任务已经停止”这时候你会突然发现真正困难的不是cancel() 这个函数怎么写。真正困难的是系统对“取消”这两个字到底怎么定义。定义没弄清楚之前让 AI 开始写代码本质上就是让它替你做产品定义和架构决策。它当然可以给答案。但你凭什么认为那个答案适合你的系统所以复杂 Feature功能以后不要习惯Requirement需求→ Code代码。更合理的顺序是Requirement需求→Analysis分析→Plan方案→Review审查→Code编码表面上多了几步。实际上项目越大越省时间。我现在使用 AI Coding基本遵循这样一个循环这也是整套课程后面会反复使用的一条主线。我把它叫做AI Native Development LoopAI 原生开发循环。很简单六步Context→Plan→Code→Test→Review→Production不要急着背。我们把它翻译成人话。Context先让 AI 有资格回答这个问题第一步不是问“我要它写什么”而是“它如果想把这件事情做对必须先知道什么”可能是项目架构。可能是数据库模型。可能是现有 Service。可能是团队的 Coding Rules编码规则。可能是 API 规范。可能是历史设计决策。可能是哪些目录允许改、哪些禁止改。可能是现有测试。Context 做得差AI 就是在一个它自己想象出来的项目里写代码。Context 做得好它才真正开始在你的项目里工作。Plan让错误尽量死在代码出现之前让 AI 先告诉你它理解的需求是什么准备修改哪些模块为什么改这些地方有没有数据库变化会不会影响已有接口有哪些并发风险有没有安全问题测试准备怎么做有没有更简单的方案这一步有一个非常重要的经济账。修改一段 Plan成本可能是几分钟。AI 已经改完十五个文件之后再推倒重来成本就完全不同了。所以 Plan 不是形式主义。它是在控制错误扩散的成本。CodeAI 最应该发挥优势的地方前面两步完成以后才真正开始 Coding编码。这时候 AI 手里已经有需求。上下文。约束。方案。测试要求。于是它的任务发生了变化。不再是“你猜一下这个功能应该怎么做。”而是“按照已经确认的工程方案把它实现出来。”这才是 Coding Agent编程智能体最舒服的位置。我一直觉得一句话很重要Agent 应该承担大量执行但不应该在你毫不知情的情况下替你决定系统长什么样。Test测试不是证明代码跑过一次AI 很会写 Test测试。但“会生成测试代码”和“知道什么值得测试”是两回事。比如创建订单。AI 很容易写def test_create_order(): response client.post(/orders, jsondata) assert response.status_code 200没有问题。但它只证明了一件事正常情况下接口返回成功。真正更值钱的测试是什么同一个请求执行两次呢库存不足呢两个用户同时购买最后一件商品呢数据库在执行中间报错呢Retry 会不会重复创建订单呢没有权限呢参数刚好在边界值呢你会发现好的测试本质上是在保护前面找到的那些 Invariant不变量。一旦理解这个逻辑Testing测试就不再是“写几个 assert。”而是在问我怎么证明系统最重要的规则不会被破坏这是完全不同的层次。Review别再只看代码风格AI 时代 Review代码审查会越来越重要。原因很简单AI 生成代码的速度已经开始超过人类认真阅读代码的速度。以前一天写三百行你 Review 三百行。以后 Agent 十几分钟改两千行。难道真的逐字符看两千行不现实。所以 Review 思路本身也要升级。你需要看Architecture架构有没有被破坏。Transaction Boundary事务边界对不对。Data Consistency数据一致性有没有风险。Concurrency并发有没有问题。Security安全有没有漏洞。Failure Path失败路径有没有遗漏。Observability可观测性够不够。Test测试到底证明了什么。这时候你会发现AI Coding 并没有让工程判断变少。恰恰相反。因为机器可以更快地产生更多代码判断哪些代码可以进入系统反而更重要。Production真正精彩的地方从“代码能跑”之后才开始这是整个系列我最想反复讲的一件事。很多教程在这里结束“运行成功。”我更关心后面。比如 AI 写了这样一段逻辑for item in items: result call_llm(item) save_result(result)本地跑十条数据完美。现在放到 Production生产环境。如果是五千条呢LLM 第 237 条调用超时呢跑了二十分钟服务重启呢第三方模型接口限流呢前三千条已经成功后两千条失败呢重新执行会不会把前三千条再处理一次用户关掉浏览器以后任务还继续吗进度保存在哪里任务怎么取消失败以后能不能恢复调用费用怎么限制线上出了问题怎么找到这一次 Task 的完整执行链路看到了吗代码没变。环境一变问题完全不同。所以 Production Engineering生产级工程真正研究的是如何让一个功能在真实流量、真实失败、真实并发和真实运维条件下继续可信。这才是后端工程师越来越值钱的地方。如果以后只允许我给 AI Coding 用户一张检查清单我会留下这 8 个问题以后拿到任何稍微重要一点的后端需求不管代码准备自己写还是交给 AI先问1. 到底什么才算成功“取消成功”“支付成功”“发送成功”“保存成功”这些词必须能被精确定义。定义不清楚后面的代码一定会乱。2. 什么事情绝对不能发生找 Invariant不变量。钱不能重复扣。库存不能乱。权限不能越界。数据不能无缘无故丢。3. 做到一半失败怎么办考虑 Transaction事务、Rollback回滚、Compensation补偿。4. 同一个请求来两次怎么办考虑 Idempotency幂等性。尤其涉及扣款、下单、发券、发送消息时。5. 两个请求同时发生怎么办考虑 Concurrency并发、Race Condition竞态条件以及必要的锁或数据库约束。6. 依赖的系统不工作怎么办数据库慢了。Redis 挂了。LLM 超时了。第三方 API 返回 500。这时要考虑 Timeout超时、Retry重试、Fallback降级等策略。7. 出问题以后我怎么知道发生了什么考虑 Logging日志、Tracing链路追踪、Metrics指标监控。8. 我怎么证明这个实现真的没有破坏规则这才轮到 Test测试。而且不要只测正常路径。重复、失败、边界、并发往往才是最值钱的地方。这八个问题不是什么高级架构师专属能力。我反而认为AI Coding 普及以后它们会逐渐变成后端工程师的基本功。现在我们终于可以回答文章开头的问题了Cursor、Codex 越来越强之后后端工程师还重要吗重要。但值钱的部分正在发生变化。以前一个工程师要花大量时间亲自把设计变成代码。记 API。写 CRUD。补样板代码。查文档。改重复逻辑。这些工作不会一夜之间消失。但是 AI 会持续降低它们的成本。真正开始变贵的是什么是这些问题这个需求到底应该怎么定义系统有哪些不能被破坏的规则这段操作应该同步还是异步为什么这里必须幂等事务边界应该在哪里Retry 为什么可能造成重复副作用这个方案在并发下还成立吗AI 第一次生成的代码到底哪里“不够对”怎么证明它可以进入生产环境这些事情有一个共同名字Engineering Judgment工程判断。所以我越来越认可一个结论代码生成正在变便宜工程判断正在变贵。AI Native Backend Engineer到底“Native”在哪里这套课程后面会反复出现一个词AI Native Backend EngineerAI 原生后端工程师。它不是指“100% 的代码都必须让 AI 写。”也不是“谁 Prompt 写得厉害谁就是 AI Native。”我理解的 AI Native是从开发流程设计开始就默认 AI 是工程执行体系的一部分。你会主动思考AI 需要读取哪些 Context上下文。哪些架构规则必须提前告诉它。哪些文件可以改。哪些文件不能碰。复杂需求是不是必须先 Plan规划。什么测试必须通过。生成完以后应该做哪些 Review审查。上线前必须做哪些 Production Check生产检查。也就是说你已经不是单纯在“用一个写代码工具”。你开始设计AI 应该怎样参与软件工程。这是两个完全不同的层级。我们真正要走的不是 Prompt to Code现在大量 AI Coding 内容都停在一条很短的路线Prompt→Code给一句提示词。生成代码。运行成功。结束。但真实的软件世界远远不是这样。我们真正要走的是Prompt→Context→Plan→Architecture→Code↓Test→Review→Deploy→Observe→Production也就是Prompt to Production从提示到生产。从一个模糊需求开始。直到它成为一个真实用户可以放心使用、出了问题工程师也有能力定位和恢复的系统。这才是整套课程真正要研究的事情。我们当然会写 FastAPI。会碰 PostgreSQL。会用 Redis。会做异步任务。会接 LLM大语言模型。会做 RAG检索增强生成。会实现 Agent智能体。会研究 Tool Calling工具调用和 MCP模型上下文协议。最后还会走到 Docker、CI/CD持续集成与持续交付、Observability可观测性和 Production生产环境。但所有这些技术都只是手段。真正想训练的是同一种能力AI 可以替你大量生成实现但你必须越来越清楚什么才叫正确。第一课学到这里我只希望你真正带走三件事第一件代码能跑和系统正确不是一回事。以后看到 AI 生成代码不要只验证“成功路径”。主动去找重复、失败、并发、边界和真实生产环境里的问题。第二件AI 最擅长降低的是实现成本不是替你定义业务世界。需求的边界、不变量、风险和工程约束仍然需要有人真正理解。第三件复杂任务不要从 Requirement需求直接跳到 Code编码。逐渐形成自己的开发节奏Context→Plan→Code→Test→Review→Production如果这三件事真的进入你的开发习惯那么以后即使 Cursor 被另一个工具替代、Codex 继续升级、Coding Agent 再强十倍这套方法依然成立。因为工具会变。框架会变。模型会变。但只要软件最终还要运行在真实世界里就一定有人需要回答什么叫正确失败了怎么办我怎么证明它值得上线这个人依然是工程师。只不过从今天开始我们要学着成为另一种工程师AI Native Backend Engineer。不是比 AI 更快地敲代码。而是比以前更清楚什么代码值得被写出来。下一课我们继续往下拆当 Coding编码越来越容易以后程序员真正稀缺的能力到底还剩什么答案会比“学好架构”这四个字具体得多。