AI Coding Agent 时代:代码越便宜,约束越贵

📅 2026/7/8 4:12:15
AI Coding Agent 时代:代码越便宜,约束越贵
码不再昂贵了那什么变贵了二十多年前Linus在Linux邮件列表上留下一句话Talk is cheap. Show me the code.这句话后来几乎成了程序员圈最常被引用的行规嘴上说没用代码才是真章。但在AI普及的今天这个前提正在悄悄变化。不是代码不重要了而是写出一段代码这件事正在变得越来越便宜。真正变便宜的到底是什么过去一个功能从想法变成代码最大的瓶颈往往是人力谁来写、写多久、熟不熟悉框架、会不会踩API的坑。今天这一层成本被大幅压低了。你描述一个需求Agent可以很快生成路由、服务、数据库访问、测试样例甚至帮你改掉一轮报错。所以很多人开始说代码免费了。这句话有传播力但也很容易误导。因为真正变便宜的不是软件本身而是代码文本的生成成本。更准确地说是代码生产的边际成本塌陷了。但另一部分成本并没有随之消失代码是不是符合真实需求边界是不是清楚异常路径有没有处理安全风险有没有暴露测试能不能证明它没有破坏旧逻辑半年后另一个人或者另一个Agent还敢不敢继续改这些成本没有因为AI会写代码而自动下降。在我看来某些情况下它们反而变得更贵。当代码生产的边际成本趋向于零‘确定性’便成了系统中最昂贵的资产。代码免费这句话只讲了一半为什么说更贵因为代码生成速度越快错误扩散的速度也越快。PR产出越容易验证、Review、测试、维护的压力就越大。过去一个工程师一天只能写几百行坏结构扩散得慢资深同学还能在Review里拦一拦。今天Agent一次可以生成过去几天的工作量如果前面没有足够清晰的边界和约束技术债也会以同样的速度被放大。只讲代码免费这一半很容易得出一个危险结论软件工程过时了。但把另一半补上结论恰好相反AI没有让软件工程过时它让软件工程的杠杆变陡了。那么真正贵的是什么当代码生成的成本下降真正变贵的是那些决定代码是否值得存在的东西架构判断、模块边界、接口契约、不变量表达、测试体系、依赖规则、Review标准、上线后的反馈闭环。这些东西过去看起来像好工程师的额外讲究今天正在变成Agent能不能稳定产出的前置条件。换句话说Agent不是让工程基本功失效了而是把工程基本功的收益放大了。写代码的人按回车键的频率变高了但让代码变得可信的那些工作并没有自动发生。所以AI时代真正昂贵的不是写出代码而是让代码在长期演进中依然可靠。如果说过去的口号是Talk is cheap. Show me the code.那么今天更应该改成Code is cheap. Show me your constraints.同一个Claude两份代码库输出为什么会分裂上一章讲了一个判断代码生成变便宜了但让代码长期可信、可维护、可演进的约束系统变贵了。我们看一个最小化的对照样例。对照样例我准备了两份功能等价的小项目都是用户注册 登录。两份项目跑起来的行为一模一样注册一个用户、登录、登出没有任何区别。区别只在代码组织方式。版本A的目录结构很简单project_a/ ├── app.py ├── helpers.py └── requirements.txt版本B的目录结构更明确project_b/ ├── AGENTS.md ├── api/ │ └── auth_routes.py ├── application/ │ └── auth_service.py ├── domain/ │ └── user.py ├── infrastructure/ │ ├── password_hasher.py │ └── user_repository.py └── tests/ └── test_auth.py这里要特别说明一点版本A不是烂代码示范。这种项目结构在原型设计和Demo上比版本B更合理因为短平快功能不夸层。版本A的问题不在于代码丑而在于结构太扁平。注册、登录、密码hash、用户存取都混在app.py里helpers.py则承担了一个典型杂物筐的角色什么都可以放进去但没有人能说清楚边界在哪里。版本B的区别也不是目录更多而是它把几个关键约束显式化了路由入口放在 api/业务编排放在 application/领域对象放在 domain/密码hash、用户存储等外部实现放在 infrastructure/测试放在 tests/AGENTS.md 说明项目的分层规则和变更约定然后我把同一个任务丢给Claude Code给注册流程加上忘记密码功能。这时两份代码库给Agent的暗示完全不同。图1.版本A新加一个功能“给注册流程加上忘记密码功能”图2.版本B新加功能“给注册流程加上忘记密码功能。”版本A里Claude Code更容易做什么在版本A里所有东西都堆在一起。app.py既是HTTP入口又包含业务逻辑还直接处理密码hash和用户存储。helpers.py看起来像一个通用工具箱但里面到底应该放什么没有明确边界。这时Claude Code做忘记密码功能最容易出现的是一组局部合理、整体危险的选择。它可能会重新写一份密码hash逻辑。因为现有hash逻辑散落在app.py里没有形成一个明确的唯一入口。Agent能看到那段代码但它未必能判断这是不是团队约定的标准实现能不能复用有没有隐藏副作用如果上下文不够清楚重新写一份看起来正确的实现反而是一个很自然的选择。于是代码库里可能出现第二套密码处理逻辑。单看新代码它也许没错但从系统角度看密码策略开始分叉了。这是一个典型的需要引起警觉的信号单点正确全局错位。它也可能把重置令牌生成塞进helpers.py。因为没有更好的落点。helpers.py本来就像杂物筐多放一个make_reset_token()看起来也合理。但这意味着以后任何人想理解密码重置令牌是怎么生成、怎么过期、怎么校验的都要去杂物筐里翻。它还可能把发送重置邮件直接写在路由函数里。因为在版本A里没有任何结构告诉它外部副作用应该隔离在哪里邮件发送应该通过什么接口注入失败重试应该放在哪一层。最直接的做法就是哪里需要哪里调用。这些选择的问题在于每一个局部看起来都说得通但合在一起会让代码库继续变扁、变散、变难改。功能可能跑得起来测试甚至也可能通过。但这个代码库每经过一次Agent之手边界就更模糊一点。版本B里Claude Code更容易做什么版本B给Agent的提示完全不同。它看到infrastructure/password_hasher.py就更容易判断这个项目里密码hash有一个明确入口。新增忘记密码功能时它更可能复用这个模块而不是重新写一套。它看到application/auth_service.py里已经有register()、login()也更容易延续同样的业务编排方式接收输入、校验用户、调用hasher、调用repository、返回结果。这不是凭空发明而是延续已有形状。它看到AGENTS.md里写着所有产生外部副作用的代码例如发邮件、发短信、调用外部API必须放在 infrastructure/ 下并通过接口或依赖注入传给 application service。那么它在实现邮件发送时就更可能新建infrastructure/mailer.py而不是把发送逻辑直接写进路由函数。它看到tests/test_auth.py也更容易顺手补上忘记密码相关测试。这就是结构和约束的作用。它不是保证Agent永远不犯错但它会把Agent的选择空间缩小密码处理应该去哪里业务编排应该放哪一层外部副作用应该隔离到哪里新增功能应该补哪些测试这些问题版本B已经提前给出了答案。两个代码库给Agent的不是同一份上下文图3.Claude Code看到的两个代码库如图3所示把两个项目的依赖结构画出来差别会更直观。版本A更像一团缠在一起的线球app.py既是入口又是业务又是数据访问helpers.py被到处import新功能来了只能继续往线球上绕一圈。版本B则提供了更清楚的方向api负责入口application负责编排domain放核心概念infrastructure处理外部实现tests承担行为验证。更关键的是版本B不只是目录看起来更专业。它真正提供的是一组约束哪些代码应该放哪里哪些依赖方向是合法的哪些能力应该复用哪些行为需要测试证明。同一个Claude同一份任务面对的其实不是同一个问题。在版本A里它面对的是一个开放空间你看着办放哪都行。在版本B里它面对的是一个被剪枝过的空间这个类型的问题应该沿着这些边界解决。所以最后输出会分裂。不是因为Claude在一个项目里聪明、在另一个项目里变笨而是因为两份代码库给它的约束完全不同。代码库不是Agent的背景板。代码库本身就是Agent的示范、提示词和护栏。结构越清楚Agent越容易顺着结构继续生长结构越混乱Agent越容易把混乱复制并放大。