
最近程序员圈子里最热的话题绕不开DHH那句“手写代码时代落幕”。DHH是谁Ruby on Rails的创始人也是长期活跃在技术争议一线的老炮他这次直接把矛头指向了传统编码方式说AI Agent正在重塑软件工程。我常年在一线写代码、带项目刚看到这句话时第一反应是“又来放炮”但冷静下来复盘了最近几个月的真实开发流程却发现手写代码的工作量确实在肉眼可见地减少。这篇文章不想讨论口号只聊Agent到底怎么嵌入软件工程的日常哪些环节真的被重构了以及我自己踩过的坑和值得抄的作业。无论你是写过几年代码的老手还是刚入行还在焦虑AI替代自己的新人都能从中找到一些能直接用的东西。1. 先看懂DHH的判断手写代码落幕背后的技术逻辑1.1 从工具到智能体开发角色的本质变化早些年我们用的IDE插件、代码补全、代码片段生成器本质上都还是“静态工具”。它们基于规则或模板工作你写一个字母它帮你补完剩下的单词最多再预测一下下一行。这种工具没有理解能力它的输出质量取决于你输入了什么而整个过程依然由人脑驱动。Agent和这些工具的本质差别在于它不再是“听指令的锤子”而是“能自己看图纸的施工队”。一个现代AI Agent底层通常是一个大语言模型但它被赋予了三样传统工具没有的东西目标拆解能力、环境感知能力、工具调用能力。目标拆解让它能把你的一句话需求分解成若干子任务环境感知让它能读取当前项目的代码结构、依赖关系、已有约定工具调用让它能真正执行命令、读写文件、调用API、跑测试用例。我打个比方之前的代码补全就像一个打字员你口述一句它跟一句而Agent像是一个外包初级工程师你把需求丢给它它会自己规划方案、写代码、跑测试、发现问题再改最后给你一个可运行的交付物。打字员永远需要你思考而Agent开始承担“思考”的一部分工作量。DHH说手写代码落幕本质上指的是从“人逐字敲键盘”向“人定义边界和意图”的转变而不是说程序员这个职业没了它只是换了一种形态。1.2 Agent正在替换的不是“打字”而是“决策链路”很多人一听“手写代码落幕”就慌觉得程序员要失业了。其实往前翻二十年C语言时代我们用汇编后来用高级语言再后来用Github的成熟库每一步都在减少“手写”的字数。DHH这句话的核心不是消灭代码而是消灭“从需求到代码”之间的那层低效决策链路。传统软件开发中一个功能从需求到上线中间要经历需求分析、概要设计、详细设计、编码、自测、联调、评审、发布。编码只是整个流程里的一个环节而这个环节里又有大量决策这个接口参数应该怎么设计这个逻辑是放服务端还是客户端这个异常要怎么处理过去这些决策基本靠经验丰富的工程师拍脑袋然后再手写进代码里。Agent的出现让这些决策可以被“预演”和“自动化试错”。举个例子我需要在项目里加一个用户登录功能。以往我是打开编辑器新建文件手写一个包含密码加密、Token签发、会话管理、异常处理的后端接口大概几百行代码。现在我可以告诉Agent“用现有项目的风格新增一个登录接口基于JWT”它能直接读取项目结构和已有工具类生成接口代码还会自动补上项目里已有的校验逻辑。我做的不是“写代码”而是“描述边界”和“审查结果”。决策链路里相当大一部分被下沉到了Agent内部它先给出一个方案我再判断方案对不对。手写代码退出了主舞台但作为“决策者”的角色反而更重要了。2. Agent落地开发全流程四个典型场景的实战解读2.1 需求分析与接口设计让Agent替你兜住混乱真正接手过复杂项目的人都清楚开发最耗神不是敲代码而是跟产品对需求、跟后端扯接口、跟设计抠字段。Agent在这块能帮大忙但前提是你得学会给它喂“结构化信息”。我现在的习惯是在启动一个开发任务前把零散需求扔给Agent让Agent先整理成一份需求文档草案。比如我会给它一段很口语化的描述“用户想在小程序里查看历史订单支持按时间筛选也能看到订单状态还要能一键催单。”Agent接收到这种话它不会直接甩给我代码而是会输出包含功能列表、优先级、边界条件、接口草案的文档。这一步看起来不起眼实际上省掉了很多来回确认的时间因为它强制你把模糊词语变成具体字段和逻辑。到了接口设计阶段Agent更是一个好帮手。如果你已经有了一套OpenAPI或Swagger定义直接把定义文件丢给它让它按照现有风格生成新接口的请求响应模型它通常不会跑偏。如果项目里没有既有规范让它先跟着主流的RESTful风格走再根据你自己环境的约定做调整也比从零手写规范快得多。我踩过的坑是一开始没给Agent足够多关于项目背景的信息导致它设计出的接口跟现有的错误码体系、日志规范对不上。现在我会先让它扫描一下项目里的公共模块和配置类再让它干活。这个前置步骤很值得花时间。不过有一点要特别提醒Agent生成的接口设计在“边界情况”上经常会有漏洞。比如用户并发下单、库存不足、网络超时这类分支它有时会默认忽略。我团队里的做法是让Agent生成之后我自己快速画一个状态机或分支清单专门盯着边界条件去检查。这个动作千万别省。2.2 代码生成与重构从补全到整段交付代码生成是Agent最被广泛吹捧的能力实际用下来也确实是提效最直观的环节。但它的使用方式已经跟我们印象里的“AI补全一行”完全不同。Github Copilot刚出来的时候大家是在函数内部补全几行逻辑到了Agent时代它可以跨文件感知上下文做模块级甚至服务级的生成。我在最近一个Python项目中需要写一个对接第三方支付的回调处理器。原来的流程是读第三方文档、看回调协议、找SDK封装、写验签逻辑、处理重复通知、写异步任务。这个环节我至少要花半天时间。用Agent之后我把第三方文档的PDF链接和现有项目的目录结构告诉它它自己分析出回调参数、验签算法、幂等处理方案然后生成了完整的控制器代码和配套的DTO类。我甚至不用复制粘贴它是直接命令式地创建了文件。重构场景就更高效了。有一次我需要把一个老旧的单体函数拆成三个独立服务涉及十几个文件的改动。如果手写改动我最怕的就是漏掉某个调用方。Agent可以自动搜索所有引用位置生成重构脚本并逐个检查改完后的文件是否还有语法错误或缺失导入。当然这种大规模重构我不会完全盲信改完后必须跑一遍全量测试。但即使加上我的审查时间也比人工逐文件改要快一倍以上。这就是DHH说的“手写代码落幕”的实感——我不再写代码我变成了一个代码验收员。但这里有个重要前提Agent生成的代码质量极大程度上取决于你项目的基础建设。如果项目本身没有单元测试、没有类型注解、没有统一的代码规范Agent就会学坏生成出一堆风格混乱、没有类型提示的代码。想要用好Agent先把工程地基打好。2.3 自动化测试与持续集成Agent跑腿把活干测试用例是软件开发里最反人类的劳动几乎人人都承认它重要但主动写的意愿极低。Agent在这块解决了我一个很大的痛点它能基于现有代码自动生成覆盖主要路径的单元测试甚至会补一些边界值测试。我之前维护一个订单服务里面有大量分散在各模块的条件逻辑。以前写单元测试我得自己翻代码逻辑、造数据、模拟依赖光一个咖喱函数就能磨一小时。Agent的做法是先读函数源码然后生成一张输入输出表再按照这个表生成pytest和unittest风格的用例文件并直接跑起来把失败结果反馈出来。我只需要关注那些失败用例是需求真的bug还是Agent生成了错误的预期。这个流程把所有机械劳动全包了。持续集成的改动就更有意思了。Agent可以接入CI流水线在代码提交后自动分析diff判断这个改动会影响哪些模块然后选择性地跑相关测试而不是每一次都全量回归。这相当于让Agent替代了以前由专家手工配置或凭经验勾选的测试范围。另外当测试失败时Agent能自己查看失败日志、定位到具体代码行甚至尝试生成修复补丁提交MR。我已经遇到了几次修复正确率超过百分之八十的场景最终只要我确认一下逻辑符合业务语义就可以合入。不过自动化测试场景的“信任边界”一定要划好。我会让Agent自动跑测试但绝不让它自动部署到生产环境。测试可以容忍它犯蠢生产不能。2.4 代码评审与文档维护隐性成本最高的环节很多团队只知道写代码耗时却忽略了CR和文档这两个吞时间的黑洞。一个中型项目的Code Review往往要在MR里反复讨论几十条评论Reviewer要人肉理解改动的背景、影响面和风格兼容性这比写代码还费脑子。Agent能充当一个“第一轮评审员”提前把明显的问题找出来逻辑死角、空指针风险、并发安全问题、不规范的命名、中间大对象泄漏等。我自己在使用时会先让Agent跑一轮全量审查输出问题清单和严重级别然后再人工重点看那些它标成高危的问题普通的代码排列问题就交给它了。文档维护以前是项目经理的噩梦现在Agent可以把整个流程自动化。在代码提交阶段Agent根据MR描述生成变更日志在关键模块加载时Agent读取函数签名和注释生成在线API文档。今年我发现最省心的部分是让Agent每周跑一次扫描代码里新增的todo、fixme、XXX然后把它们按风险分组整理成周报开周会时直接就能用。以前这种活要实习生做到半夜现在只需要跑一条命令。3. 从零搭一个能用的Python Agent核心步骤与关键代码3.1 选择Agent框架LangChain、AutoGen还是自研网上关于Agent框架的信息现在铺天盖地但真正决定用哪个还是要看你自己的使用场景和团队基础。LangChain是老牌框架生态最全支持大量对话模型、向量库、工具链的接入适合需要复杂编排的项目。缺点是抽象层次多学习曲线比较陡而且版本升级频繁上个月写的代码下个月可能就废弃了。AutoGen是微软开源的主打多Agent会话适合做“多个角色互相协作”的团队仿真比如一个项目经理Agent、一个开发Agent、一个测试Agent一起开会解决任务这个框架在模拟工作流方面很有想象力。另外还有比较轻量的自研方案如果你的需求只是“读代码调LLM执行命令”其实用几十行Python封装一个规律化流程就够了不需要硬上重型框架。我自己在真实项目里的选择是如果只是给项目加一个“智能助手”界面用LangChain快速搭建如果要做多角色协作的复杂流程试过AutoGen但大部分工程化任务我更倾向封装一个最小可用的工具类直接调用LLM接口完成任务。道理很简单框架越重出问题时要排查的层数就越多不如Leave simple起来让Agent老老实实地当一个“可调用的函数”。3.2 最小Agent的骨架代码我用一个最简单的例子说明Agent基本结构。这个Agent要实现在指定的Python文件目录中自动查找所有遗留代码并生成重构方案。核心逻辑如下import os import json import requests class SimpleAgent: def __init__(self, api_key, model_namedeepseek-chat): self.api_key api_key self.model_name model_name self.messages [{role: system, content: 你是一名有着十年经验的Python架构师}] def send(self, prompt): self.messages.append({role: user, content: prompt}) payload { model: self.model_name, messages: self.messages, temperature: 0.2 } headers {Authorization: fBearer {self.api_key}, Content-Type: application/json} response requests.post(https://api.openai.com/v1/chat/completions, jsonpayload, headersheaders) r response.json() reply r[choices][0][message][content] self.messages.append({role: assistant, content: reply}) return reply def scan_and_refactor(self, directory): # 1. 收集目录下所有的 .py 文件 files [] for root, dirs, filenames in os.walk(directory): for f in filenames: if f.endswith(.py): files.append(os.path.join(root, f)) # 2. 逐个读取内容传送给LLM分析 for f in files[:5]: # 限制数量防止请求过大 with open(f, r, encodingutf-8) as fh: code fh.read() prompt f请分析下面的代码给出重构建议和潜在风险点\n{code} advice self.send(prompt) print(f\n 对 {f} 的建议 ) print(advice)这个骨架展示了一个Agent最核心的三个部件系统提示词约束角色、对话历史保持状态、工具调用这里是文件读取。你可以扩展它让它调用终端、运行测试命令、抓取接口数据。工程化没有神秘的东西就是把“循环思考—决策—执行—反馈”变成程序。3.3 接入真实LLM与工具调用直接可复用的配置上面的例子中我只用了requests调用一个通用接口。实际写生产级Agent时要注意几个参数细节。第一messages是累积式的代表着Agent的记忆。每次请求都会带上整个历史记录这意味着项目代码如果很长很容易超出上下文窗口。处理办法是使用“摘要化”比如只保留关键结论或把代码内容截断到可用的窗口大小。第二temperature直接决定生成风格。写代码建议调低到0.2左右太高的温度会产生大量没必要的随机性写创意文案时可以调到0.8以上。第三工具调用要有明确的安全边界。我给Agent配置执行Shell命令时会用whitelist白名单只允许ls、cat、pytest等命令绝不开放rm -rf这类危险动作。这是我整理的一个工具函数配置表配置项推荐值使用场景temperature0.2-0.3代码生成、重构建议max_tokens1024-2048单次输出长度控制top_p0.9避免采样过于发散重试次数3次避免网络或限流波动超时时间30秒长时间生成时需要调大如果你有自己的Agent框架也一定要校验延迟。我在多个模型中对比过代码生成响应最快的往往是较长上下文的模型但长上下文模型在大型项目内容注入时会因为参数增多而变慢。我自己实际项目中更倾向先把项目裁剪成多个与当前任务相关的片段再用RAG或向量检索拉取上下文这样延迟更可控。4. 常见问题与排查速查表Agent落地时我踩过的坑4.1 模型幻觉与代码质量的不确定性Agent最大的坑就是它会“一本正经地胡说八道”。它可能在重构代码时给一个变量起一个不存在的库导入也可能在写测试用例时断言了一个根本不存在的方法。最初我踩过不少这种坑最尴尬的是让Agent处理一个项目里的时间工具类它把三个不同的时间格式混着写最后跑测试时全挂。解决这个问题我的经验是一定要把“验证闭环”做进流程里。不要让Agent直接生成一个“看上去不错”的文件而是让它生成后立刻执行项目里已有的静态检查、类型检查或单测。把错误结果反馈给它逼它自我修正。我还发现当你在提示词里明确要求“请严格按照项目中已有的日志规范和错误码体系编写代码”时产生幻觉的概率会大幅下降。另外对生成结果保持最基本的怀疑是所有用Agent的程序员必备的职业素养。4.2 上下文窗口和长任务断片长任务场景里Agent经常会干着干着就忘了最初的需求。比如它在处理一个复杂重构任务时刚开始还按着你的边界条件来后面就开始自由发挥。这通常是因为项目文件太多把对话历史撑爆了早期的约束被截断了。我习惯的做法是把大任务拆成“子Agent”每个子Agent只负责一个垂直域。比如“文件解析Agent”只管读取文件“代码生成Agent”只管生成代码“测试执行Agent”只管跑测试。我需要一个协作者来统筹它们的结果但每个单独Agent的上下文都是干净的。如果不用多Agent也要学会给Agent做“关键信息提示”借着对话压缩机制把最重要的指令比如“不要修改数据库连接池配置”固化到系统提示词中让它只带记忆核心不背大量原文。4.3 权限与安全检查让Agent跑起来之前必须先绑住手脚安全是Agent落地最高最厚的墙。团队里常有同事图方便给Agent开放了整个服务器的sudo权限结果它运行一个删除测试数据的命令时发现当前目录的连接信息不对它在自动纠错过程中直接把部署脚本改了。我亲身经历过这种事故之后就把Agent的执行权限锁得非常死。我给出的建议是无论内部还是外部Agent都通过沙箱化容器来完成任务。如果你跑的是代码就让它在Docker容器中跑这个容器没有宿主机网络和文件系统读写权限。如果你想让它调用线上接口给它分配一个独立的服务账号这个账号只有“读”权限没有任何“写”和“删”权限。更为保险的是Agent每次尝试执行危险命令时强制进入人工审批流。别嫌烦必要时候这是救命的防线。4.4 团队协作与流程适配不是每个人都能接受AgentAgent改造的不只是代码还有团队里每个人的工作习惯。年轻开发者经常一上来就开开开心心地让Agent代写大量代码最后连自己都不理解代码逻辑出了问题完全排查不了资深开发者则容易出于“代码洁癖”而产生强烈抵触情绪宁愿自己手写也不愿意用Agent。这两种极端在短期内都无法硬推。我的经验是先在非核心流程中试点比如让Agent帮忙生成测试用例、写周报、整理文档让团队习惯它的输出形式。再把Agent引入代码生成场景但要求必须经过人工CR和测试。最后形成一套团队内部使用的“提示词模板库”和“代码生成规范”尤其是那些经常性重复的代码录入工作全部约束在模板内。一旦你发现某一类代码是Agent能稳定生成且不出错的你再把它推广到全员。这种方式能减少很多摩擦。关于Agent落地的一些真实感受把Agent引入到软件工程流程后一个很直观的变化是我把更多精力留在了真正创造价值的部分理解业务痛点、设计复杂系统的边界、做技术选型决策。代码本身正在变成一种可以外包给Agent的标准化劳动这跟当年从汇编转到高级语言没什么两样。但我也看到很多团队容易走偏一上来就指望Agent接管所有开发工作结果被模型的幻觉、上下文断片和权限问题拖垮。我个人体会是要想用好Agent先扎扎实实把项目的基础设施补全让单测、类型检查、代码规范这些底盘稳定Agent才会像漂亮的舞伴一样带你跳得顺利。如果你正打算把Agent引入团队我建议从测试用例和文档维护这两个低风险高回报的场景开始等人员普遍适应了再逐步走向核心编码环节。未来可预见的趋势是软件工程师的核心竞争力不再是“写代码”而是“定义问题和验收结果”。早点想明白这个转变不管是个人还是团队都会走得稳很多。