ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

编程远未结束:AI代码生成背后的真实挑战

编程远未结束:AI代码生成背后的真实挑战 这些年每隔一段时间“编程已死”的话题就会被重新翻出来一次。这两年的版本更直接编程已经被解决了。理由听起来也充分——你只要把需求描述给 AI它就能写函数、补测试、生成接口代码甚至把一个模块完整地搭出来。有人据此推测以后程序员只需要会提需求、会点确认不再需要真的会写代码更不需要理解什么算法、并发、网络协议和底层机制。我一开始也以为这个判断有道理。但实际用了大半年各种 AI 编程工具之后我的结论完全相反编程没有被解决被解决掉的只是“把脑海里的逻辑翻译成语法”这一层。编程里真正困难的部分例如理解问题、拆解系统、验证正确性、做长期维护远未完成。Lauren Tan 说“远未完成”我理解她不是否定工具而是在提醒我们可能把终点线画错了位置。代码生成能力确实在变强但这和“编程已经结束”是两码事。下面我会从现象、原因、工作流、适用边界和排查路径几个角度把这件事讲透。1. 为什么“编程已解决”看起来合理却是一种误判1.1 代码生成能力确实到了一个新高度先说事实。过去十年IDE 已经解决了很多重复劳动语法高亮、自动补全、重构、格式化。这些能力让“写代码”更像是在语法规则内拼积木而不是从零开始记忆每一个 API。生成式 AI 又把这条线往前推了一大截。它不再等你想清楚每一个函数名而是根据自然语言描述直接给出候选实现。用 Cursor、Codex 这类工具时一个常见体感是中等难度的函数第一次生成往往八九不离十。你给它一个“读取某个目录下所有 JSON 文件合并成一个列表”的任务它通常能直接给出可运行的代码。这确实把“写代码”这一层大幅压缩了。但这里要停下来区分一件事“能生成代码”不等于“能交付软件”。生成代码只解决了一个局部问题就是把逻辑映射到语法。而软件交付还包含需求理解、接口约定、数据流设计、权限模型、异常处理、监控、回滚、团队协作。这些信息很多根本不在提问里而在业务上下文、代码历史、团队约定和运行环境里。1.2 代码生成解决的是“写”不是“想”用一个类比来说AI 写代码有点像一台性能很强的打印机。它能把文字排版印得又快又漂亮但内容写什么、逻辑是否成立、有没有冒犯读者打印机不负责。同样AI 能生成一个“读取 JSON 再合并”的函数但它不知道遇到损坏文件时应该跳过还是抛异常不知道是单线程处理还是异步处理不知道要不要保留原始文件名不知道日志应该打印到哪个级别。这些决策不是代码生成问题而是业务判断问题。它们恰恰是编程中最有价值的部分。当你说“AI 已经把编程解决了”时其实是在说“AI 已经学会了把明确的逻辑翻译成语法”。但真实工作中大多数人面对的并不是“明确逻辑”而是模糊需求。模糊需求怎么变成精确约束这才是编程真正的门槛。1.3 生成式工具制造了一种“已解决错觉”还有一个隐蔽的问题AI 生成的代码看起来太像“正确答案”了。它会使用合理的命名会把函数拆得整整齐齐会加注释甚至会按照常见的设计模式组织代码。这种视觉上的完整性很容易让人放松警惕。尤其当代码能成功运行、输出也符合预期时新手很容易认为“代码质量没有问题”。但代码质量不看表面形态而是看异常路径、时间依赖、数据一致性、可维护性、安全边界。一个函数在正常输入下跑通只是在测试用例里跑通它在生产环境里可能要面对空数据、超大输入、并发写、网络超时、第三方接口宕机。是否能在这些场景下保持正确恰恰是生成式模型最难替你把关的部分。2. 编程远未完成的四个真实原因2.1 描述问题比写代码更难很多人误以为“提问”是一件简单的事。实际上把问题描述清楚是编程中最困难的一环。产品经理说“用户要能方便地导入大量数据”这句话离可执行代码还差很远。需要继续追问支持什么格式多大量级才算大量导入过程中失败怎么办要不要去重是同步等待还是异步通知权限怎么控制用户导错了能不能撤销这些决策没有写在产品文档里也不会自动出现在需求里。把它们问出来、定下来就是编程的一部分。这也是为什么“AI 编程提示词”会成为一个热门话题。表面看大家在讨论怎么写提示词。往深了看是在讨论如何把模糊需求翻译成精确约束。这个能力不会因为 AI 更强大而消失反而会变得更加关键。因为工具越强大它对输入质量的要求就越高。你给它的约束越完整它的输出才越接近可用状态。2.2 局部正确不等于全局可靠AI 非常擅长补“点状能力”但不擅长理解“系统全貌”。它能为一个函数写出正确的实现不代表整个系统在边界条件、并发写、故障恢复下仍然正确。写程序最害怕的不是某个函数写错了而是模块之间的约束不一致。A 模块假设字段非空B 模块在某条路径下传了空值C 模块假设操作是串行的D 模块却把同一行数据做了并发更新。这些问题的根因往往不在代码生成端而在设计阶段。举个例子一个电商系统里支付服务和订单服务各自都能正确运行。但如果支付成功后订单状态更新失败怎么办或者订单取消时支付已经完成又该怎么处理这类事务问题、幂等设计、对账逻辑都不是“让 AI 生成一个函数”能解决的。它们需要理解业务目标、数据一致性等级、失败恢复策略这些从来都是编程的核心。2.3 验证和纠错比生成更花时间一个直白的感受是生成一个用例可能是 10 秒但验证它是否满足业务约束要多久你要构造边界输入、写测试、跑回归、看日志、检查数据是否一致。这些工作不会因为代码生成变快而自动消失。更常见的情况是AI 在几秒内生成了一段代码然后你花了半天时间审查、改错、补边界、确认它不会破坏其他模块。这未必是坏事。它说明编程的时间结构正在发生变化写代码的时间变少了看代码、测代码、改代码的时间变多了。但这也意味着编程这项活动并没有消失它只是从“产出代码”变成了“判断代码是否正确”。判断能力不会凭空出现它需要开发者对系统、语言和领域有足够深的理解。2.4 长期维护会让生成效率快速贬值第一次生成代码可能很快但半年后需求发生变化你面对的是别人或 AI 写出的、你并不完全理解的代码。如果当初边界和约束没有写清楚没有测试兜底修改成本会非常高。长期维护拼的不是初始生成速度而是代码的可读性、测试覆盖、文档记录和模块边界。这些正是 AI 生成能力的最大短板。AI 不会主动告诉你“这段代码半年后可能出问题”它只会针对当前任务给出当前看起来正确的答案。所以当你评价一个 AI 编程工具好不好用时不能只看“第一次生成是否一次通过”还要看“三个月后改需求是否容易”。后者才是决定工程效率的核心指标。3. 新一代编程工作流从“写代码”到“定义、生成、验证”如果我们接受“编程远未完成”那接下来的问题是面对 AI 编程工具应该怎么干活我的建议是把工作流从“写代码”改为“定义、生成、验证”。核心不是不让 AI 写代码而是把更多精力放在它不擅长的事情上。3.1 先定义最小可验证目标开始生成代码前先回答三个问题这次要解决的最小问题是什么成功的验收标准是什么有哪些边界条件不能碰还是拿“读取 JSON 文件”举例。最小问题不是“写一个文件读取服务”而是“实现一个函数读取指定目录下的所有 JSON 文件合并成一个列表”。验收标准是“给两个样例文件跑出来顺序正确”。边界条件是“损坏文件跳过并记录日志目录不存在时返回空列表”。一旦目标足够小AI 输出错误的概率就会降低你审查代码的负担也会小很多。不是任务越简单越好而是任务边界越清楚越好。不要一上来就让 AI 生成一个完整系统。先让一小块可验证的路径跑通再一层层往外扩展。3.2 用“任务—边界—验收”三段式描述任务给 AI 的提示词不需要花哨但一定要包含三部分任务、边界、验收。任务写一个 Python 函数从指定目录读取所有 JSON 文件按文件名排序后合并成一个列表。 边界只处理一级目录不递归子目录文件不存在或为空时跳过单个 JSON 损坏时跳过并记录日志。 验收给出两个样例文件确认返回顺序正确没有文件时返回空列表损坏文件不影响其他正常文件。这种写法并不难难的是你能否把边界想全。这不就是编程吗是的。写提示词不是技巧问题而是建模问题。你越能把业务约束拆成机器可理解的条件提示词就越有效。这比记一堆提示词模板更重要。3.3 审查生成结果时只看四个点AI 生成代码后不要通篇精读先按四个点检查输入边界空值、非法值、超长值、缺失字段有没有处理异常路径网络超时、文件不存在、资源不足、并发竞争会不会导致崩溃副作用代码是否修改了全局状态、是否写了不该写的文件、是否执行了不可逆操作可测试性外部依赖是否容易被替换输出是否稳定、可断言这四个点可以覆盖大部分隐藏问题。如果 AI 生成的代码在这四点上都做得不错再进入测试阶段。如果不行优先补充约束而不是靠人工硬改。3.4 一个例子从单线程到异步代码只占一半异步编程是很多开发者的痛点AI 工具能把这类代码快速生成出来。比如这样一个函数# 示例结构拉取多个 URL失败不中断整体 import asyncio import httpx async def fetch_one(url: str) - tuple[str, int]: async with httpx.AsyncClient() as client: resp await client.get(url, timeout10.0) return url, resp.status_code async def main(): urls [https://example.com, https://example.org] results await asyncio.gather( *(fetch_one(url) for url in urls), return_exceptionsTrue, ) for item in results: if isinstance(item, Exception): print(ffailed: {item!r}) else: print(item) asyncio.run(main())这段代码生成很快但真正的编程工作发生在哪里在于追问这几个问题如果某个 URL 长时间不响应整体要等多长时间要不要限制并发数量100 个 URL 一次性 gather 会不会把连接池打满失败后要不要重试重试几次间隔多久返回结果时要不要保留异常信息用于排查如果不回答这些问题这段异步代码只是“能跑”不是“能稳定地跑”。你可能会在小规模测试时觉得一切正常一到批量任务就遇到超时、连接耗尽、日志缺失。这些问题不是 AI 生成代码能自动避开的需要你自己定义清楚。所以我说新一代编程工作流里生成代码只占一半另一半是定义边界和验证结果。4. 面对生成式编程真正值得培养的三个能力4.1 把模糊需求翻译成精确约束未来最能拉开开发者差距的能力不是谁记得更多 API而是谁能在两句话的需求里拆出十个隐含约束。这种能力没有捷径只能靠对一个领域的长期理解和持续追问。你可以把它当作一个习惯来练每次接需求时不要急着写代码或让 AI 写代码先写下所有能想到的边界、限制和验收标准。哪怕一开始不完整也比没有强。AI 编程时代需求翻译能力决定了 AI 生成结果的上限。4.2 把大问题拆成可验证的小任务不要试图让 AI 在一次对话里把整个系统生成出来。相反把大系统拆成若干可独立验证的小任务。例如“做一个用户注册登录系统”应该拆成用户表设计和字段校验注册接口的输入校验和异常处理密码加密与存储登录流程与 Token 签发登录态校验与权限控制每一块都单独生成、单独验证最后再组装。这样做的好处是出问题时你知道问题在哪一层不会面对一堆黑盒互相干扰。4.3 用足够小的实验去判断工具输出很多人在 AI 编程上踩坑是因为步子迈得太大。第一次使用就直接生成整个模块结果代码能跑但性能、并发、异常处理都有问题短时间内又定位不到根因。更稳妥的做法是先让 AI 生成一个纯函数跑一组单元测试再加 IO 层验证文件或网络交互再接并发最后接业务逻辑。每一层都用“最小可验证目标”去控制这样你才能判断哪一步是 AI 的问题哪一步是你需求没说清。4.4 两个最容易犯的行动错误第一个错误是只看正常路径。测试时只验证了正确输入下的输出没有验证空值、超大输入、断网、权限不足。这不是 AI 的问题而是审查习惯的问题。第二个错误是把上下文管理当成唯一稻草。很多人以为只要把尽可能多的代码贴进上下文AI 就能生成更准确的答案。上下文确实重要但如果没有清晰的边界和验收标准AI 还是会靠猜。5. 适用边界这套工作流适合谁不适合谁5.1 适合的场景场景建议前端页面初始化适合用 AI 快速搭结构但要人工审查状态管理和接口错误处理常见 CRUD 接口适合用小任务快速生成边界要写清楚脚本工具适合一次性使用长期使用要补日志和异常处理算法原型适合用 AI 先给一版实现再用测试验证边界测试用例生成适合辅助生成覆盖但断言必须由人确认这些场景有一个共同点任务边界相对清晰失败成本相对可控。即使第一次生成不完美修复成本也不高。5.2 不适合的场景不适合直接依赖 AI 生成能力的场景通常有这几个特征高并发交易系统一致性、幂等、并发控制复杂不能靠“生成代码”兜底。强安全敏感模块权限校验、加密密钥管理、数据脱敏需要人工严格审查。底层驱动和硬件交互细节依赖硬件版本和环境AI 很难掌握所有约束。生命周期极长的系统需求会不断变化代码的可读性和架构边界比初始生成速度更重要。这些场景不是说不能用 AI而是不能把 AI 生成结果当作最终交付。你需要把它当作一个“初稿来源”再用更严格的代码评审、测试和灰度验证来兜底。5.3 落地前需要确认的前置条件如果你想把 AI 编程工具真正引入项目先确认下面几点代码库有没有基础测试没有测试AI 生成的代码很容易被误判为正确。团队有没有代码评审评审是发现 AI 输出问题的最后一道防线。开发者能不能理解生成结果如果你看不懂就无法审查更不能维护。模块边界是否清晰边界不清AI 很容易猜错接口约定。5.4 如果想长期使用还缺哪几块拼图长期使用 AI 编程工具真正影响效率的不是第一次生成结果而是后续的日志、监控、权限、版本管理、依赖锁定和 CI。代码生成只能帮你交付“功能”但这些工程能力负责的是“稳定”。缺少它们再快的代码生成也会在运行阶段出问题。6. 常见失败模式与排查链路AI 编程时代同样的 bug 会换一种形式出现。下面是我见过的三类高频问题以及对应的排查思路。6.1 生成的代码能跑但结果不对不要在代码里一行行找错而是按这个顺序排查先看输入传入的数据格式、字段名、编码是否和预期一致再看边界空值、缺失字段、超长字符串、重复数据有没有处理再看依赖外部服务、数据库、文件系统在当前环境是否可用再看逻辑AI 生成的分支条件是否有漏洞比如if过多、短路逻辑写错最后看数据结果是不是被某一步修改过但你没有感知这类问题里大概率不是语法错误而是对业务约束理解不足。回到“任务—边界—验收”的提示词重新补约束。6.2 单次正常批量一上来就崩这是异步并发场景最常见的坑。单条任务能跑通不代表 50 条并发能跑通。排查顺序先看并发上限是否把并发数调到了资源无法承受的程度再看超时设置单个请求最长等待多久整体任务最长容忍多久再看连接复用会不会因为频繁创建新连接打满端口或连接池再看资源占用内存、CPU、磁盘、带宽是否被批量任务撑爆再看日志批量任务失败时有没有关键日志能定位到具体是哪个子任务失败并发问题优先从资源层面排查而不是只盯代码逻辑。先用小并发跑通再渐进式加压是最稳妥的方式。6.3 改了一处另一处坏了这是代码变更中的经典问题在 AI 编程时代反而容易出现。原因是 AI 只看到了局部代码不了解全局约束因此给出的修改方案可能破坏了其他模块的假设。遇到这类问题不要急着再次生成。先看报错位置再看被修改模块的依赖关系最后确认是不是某个公共函数或数据结构的约定被破坏了。最直接的预防方式是在开始修改前先跑一遍已有测试修改后再跑全量回归。6.4 AI 编程时代的“最小排查清单”检查层需要确认的问题典型做法输入格式、字段、编码、大小是否正确用最小样例把边界跑一遍环境依赖版本、权限、网络、端口是否可用锁定报错所在层再确认环境参数并发数、超时、重试、批量大小是否合理小参数先跑通再逐步加压日志是否覆盖异常路径能否定位失败任务在关键节点增加可观测输出工具边界当前版本功能是否支持是否匹配业务模型不可控时回到人工实现7. 编程没有结束只是换了一条更难的赛道回到最初的问题编程是否已经解决从代码生成的角度看它确实解决了很多机械劳动。原来需要几分钟甚至更久才能写出来的函数现在几秒钟就有初稿。但把“写代码”压缩之后剩下的编程工作反而更加考验人的判断力。你需要更清楚地定义问题更准确地描述边界更严格地审查输出更冷静地处理异常更耐心地维护长期质量。这些能力不是靠提示词技巧就能替代的。它们来自对系统的理解对业务的洞察对代码的敬畏。所以 Lauren Tan 说“远未完成”我更愿意把它理解成一种提醒编程远未结束它只是把最机械的部分交给了工具而把更难的判断留给了人。这不是坏消息反而说明程序员这个职业没有变成“提需求”的旁观者而是进入了更强调设计、验证和维护的阶段。真正的编程工作才刚刚开始。
返回列表