1. 从 DHH 的发言说起为什么“手写代码落幕”这个判断值得认真对待DHH 这个名字在 Web 开发圈子里不需要太多介绍。Rails 框架的缔造者Basecamp 的联合创始人多年来一直以“反潮流”著称——当整个行业都在往微服务、前后端分离、复杂构建链上狂奔的时候他坚持“一人全栈”“约定优于配置”“Majestic Monolith”。所以当他抛出“手写代码时代落幕Agent 正在重塑软件工程”这样的观点时我的第一反应不是“又一个蹭 AI 热度的”而是“这个人又在别人没注意的时候看到了什么”。我自己的开发经历大概能分成三个阶段。第一阶段是纯手写从变量命名到每一行 SQL 都自己敲那时候觉得“代码量”就是生产力。第二阶段是“半自动”用代码生成器、脚手架、ORM 自动迁移省掉大量重复劳动但核心逻辑还是自己写。第三阶段就是现在——我开始把越来越多的任务交给 Agent 去执行自己退到“定义问题、审查结果、做关键决策”的位置上。这个转变不是一夜之间发生的但回头看它确实在重塑我理解“软件工程”的方式。这篇文章想聊的不是“AI 会不会取代程序员”这种已经被聊烂的话题而是更具体的东西Agent 到底在软件工程的哪些环节产生了实质影响它的能力边界在哪里一个普通的开发者现在应该怎么把 Agent 纳入自己的工作流以及DHH 说的“手写代码时代落幕”到底意味着什么、不意味着什么。我会结合 Rails 生态、CLI 工具链、Agent 框架选型、并发与安全这些实际话题把这件事拆开来讲。如果你是一个正在写代码的开发者不管你是做 Web 后端、写 Python 脚本、还是搞课程设计的学生这篇文章里的思路和操作方案都能直接参考。我不会只讲概念会给出具体的工具选型、配置方法、踩坑记录和排查技巧。2. Agent 到底改变了软件工程的哪些环节2.1 从“写代码”到“描述意图”编程抽象层级的又一次跃迁软件工程的历史本质上就是一部“抽象层级不断上移”的历史。从打孔纸带到汇编语言从汇编到 C从 C 到 Java/Python从手写 SQL 到 ORM每一次跃迁都意味着开发者不再需要关心底层细节而是用更接近人类思维的方式描述意图让工具去完成翻译和实现。Agent 带来的变化我认为是同一逻辑的延续但跨度更大。以前的抽象工具编译器、框架、ORM是“被动”的——你写什么它执行什么它不会帮你做决策。Agent 是“主动”的——你描述一个目标它会自己规划步骤、选择工具、执行操作、检查结果甚至在遇到错误时自己调整策略。举个具体的例子。以前我要给 Rails 项目加一个“用户可以通过邮箱或用户名登录”的功能我需要写 migration 加字段、改 model 加验证、写 controller 处理两种登录路径、改 view 加表单、写测试用例、跑测试、修 bug。现在我可以对 Agent 说“给 User 模型加上用户名登录支持保持邮箱登录不变需要相应的测试覆盖。”Agent 会自己去读现有代码结构、生成 migration、修改 model 和 controller、写测试、跑测试、根据失败信息修复。我做的事情变成了确认需求描述是否准确、审查生成的代码是否符合项目规范、决定是否合并。这个变化的核心不在于“Agent 能写代码”而在于开发者的核心产出从“代码”变成了“意图描述 质量判断”。这跟 DHH 说的“手写代码时代落幕”是一回事——不是说没人写代码了而是说“手写”不再是主要的价值来源。2.2 Rails 生态为什么是观察 Agent 落地的好样本Rails 社区对 Agent 的态度很有意思。一方面Rails 本身就是“约定优于配置”的典范大量脚手架和生成器早就在做“自动化”的事情另一方面Rails 社区又特别强调“开发者体验”和“代码可读性”这两点和 Agent 生成代码的理念天然契合。我观察到的一个现象是在 Rails 项目里使用 Agent 的门槛比在其他框架里低很多。原因有几个。第一Rails 的目录结构和命名约定非常固定Agent 不需要花大量精力去“理解项目结构”它可以直接按照约定生成正确的文件路径和类名。第二Rails 的测试生态Minitest/RSpec非常成熟Agent 生成代码后可以立即跑测试验证形成“生成-验证-修复”的闭环。第三Rails 的“胖模型瘦控制器”哲学让业务逻辑集中在少数几个文件里Agent 需要理解和修改的代码面比较小。我试过在一个中等规模的 Rails 项目大概 200 多个 Ruby 文件里用 Agent 做几类任务新增 CRUD 接口、重构重复的查询逻辑、补充缺失的测试、修复 N1 查询问题。实测下来CRUD 接口和测试补充这两类任务的完成度最高基本一次通过率在 70% 以上重构类任务需要更多人工审查因为 Agent 有时候会“过度重构”把一些有意为之的代码也改掉。2.3 CLIAgent 与软件工程之间的“手”聊 Agent 在软件工程里的落地绕不开 CLI。为什么因为 Agent 要真正“做事”它需要能操作文件系统、执行命令、运行测试、查看输出。这些能力最直接的接口就是命令行。你可以把 Agent 想象成一个刚入职的远程同事。你不可能让他直接操作你的 IDE 界面但你可以给他一个终端让他通过命令来完成工作。git管理版本、rails生成代码、bundle管理依赖、rspec跑测试、rubocop检查风格——这些 CLI 工具就是 Agent 的“手”。这也是为什么最近各种 CLI 形态的 Agent 工具密集出现。它们的基本模式都差不多一个终端界面你输入自然语言指令Agent 解析后调用相应的 CLI 命令读取输出决定下一步操作。区别主要在于支持哪些工具调用、上下文管理能力如何、安全沙盒怎么做、并发处理能力怎么样。我自己的使用习惯是把 Agent 的 CLI 工具和项目本身的 CLI 工具链分开。Agent 的 CLI 负责“理解和规划”项目的 CLI 负责“执行和验证”。这样职责清晰出问题的时候也容易定位——是 Agent 理解错了还是项目工具本身有问题。3. 主流 Agent 工具链的选型与实操对比3.1 代码生成类 Agent 的三种形态目前市面上能用于软件工程的 Agent 工具大致可以分成三类。第一类是编辑器内嵌型代表是各种 IDE 插件形态的 Agent。它们的优势是上下文获取方便——能直接读取当前打开的文件、光标位置、项目结构。劣势是操作范围受限一般只能在编辑器能触及的范围内工作对终端命令的执行能力有限。第二类是终端原生型代表是各种 CLI Agent 工具。它们直接跑在终端里能执行任意命令操作范围最大。劣势是上下文需要自己管理你得告诉它项目在哪里、用什么技术栈、有哪些约束。第三类是平台托管型代表是各种云端 Agent 平台。你把项目托管上去Agent 在云端执行任务。优势是环境隔离好、并发能力强劣势是数据安全顾虑、网络依赖、调试不便。对于个人开发者和小团队我的建议是优先选终端原生型。原因很简单——软件工程的绝大部分操作最终都要落到命令行上终端原生型 Agent 的“操作半径”最大能覆盖从代码生成到部署验证的完整链路。编辑器内嵌型适合做辅助平台托管型适合做 CI/CD 环节的自动化。3.2 安装与配置以 CLI Agent 为例的完整流程这里以我实际使用的一套 CLI Agent 工作流为例讲一下从零开始的配置过程。不同工具的具体命令可能不同但整体思路是通用的。第一步确认运行环境。大部分 CLI Agent 工具需要 Node.js 或 Python 运行时。先检查版本node --version python3 --version我遇到过最常见的问题就是运行时版本不兼容。比如某些工具要求 Node 18 以上而你系统里是 Node 16安装后运行会报“不兼容”或者直接崩溃。建议用nvm或pyenv管理多版本运行时避免全局升级影响其他项目。第二步安装 CLI 工具。通常通过包管理器安装npm install -g agent-cli-name # 或者 pip install agent-cli-name安装完成后验证agent-cli-name --version如果报“unable to locate the binary or required runtime components”这类错误九成是 PATH 没配好或者运行时版本不对。先which agent-cli-name看看能不能找到可执行文件找不到就检查 npm/pip 的全局 bin 目录是否在 PATH 里。第三步配置项目上下文。这是最关键的一步。Agent 需要知道你的项目是什么、用什么技术栈、有哪些约定。大部分工具支持一个配置文件类似.agentrc或agent.config.json你可以在里面声明{ projectType: rails, testCommand: bundle exec rspec, lintCommand: bundle exec rubocop, excludePaths: [node_modules, tmp, log], conventions: { rubyStyle: rubocop, commitFormat: conventional } }这个配置文件的作用是给 Agent 一个“项目说明书”。没有它Agent 会花大量时间自己探索项目结构而且容易做出不符合项目规范的决策。有了它Agent 的首次任务完成率能提升不少。第四步设置安全边界。这一步很多人会忽略但非常重要。Agent 能执行任意命令意味着它也可能执行危险命令。我建议至少做三件事一是限制 Agent 的工作目录不让它跑到项目目录外面去二是对破坏性命令rm -rf、git reset --hard、数据库迁移回滚等设置人工确认三是用 Git 做版本控制Agent 的每次修改都先提交或 stash出问题可以回滚。注意不要在没有版本控制的情况下让 Agent 直接修改代码。我踩过这个坑——Agent 重构了一个文件改坏了逻辑而我没有及时提交导致丢失了半小时的工作。3.3 工具选型对比表维度编辑器内嵌型终端原生型平台托管型上下文获取自动范围有限需手动配置范围大需上传范围最大命令执行能力有限完整完整沙盒内并发处理一般取决于工具强数据安全本地本地需评估调试便利性好好一般适合场景日常编码辅助全流程自动化CI/CD、批量任务上手难度低中中高选型的时候不要追求“一个工具解决所有问题”。我现在的做法是编辑器内嵌型做实时补全和小范围重构终端原生型做功能开发和测试修复平台托管型做代码审查和依赖更新这类批量任务。三者配合效率比单用一个工具高很多。4. Agent 在真实项目中的落地流程与关键细节4.1 任务拆解什么样的任务适合交给 Agent不是所有任务都适合交给 Agent。我总结了一个简单的判断标准任务是否有明确的验证方式。如果一个任务做完之后你能用自动化手段测试、lint、类型检查判断它对不对那它就适合交给 Agent。如果一个任务的好坏需要大量主观判断那 Agent 做完你还是得花大量时间审查省不了多少事。适合交给 Agent 的任务类型新增符合现有模式的 CRUD 接口有测试验证补充缺失的单元测试有覆盖率验证修复明确的 bug有复现测试验证重构重复代码有测试保证行为不变更新依赖版本并修复兼容性问题有测试验证生成文档和注释有格式检查不太适合交给 Agent 的任务类型架构设计决策需要权衡多种因素性能优化需要 profiling 和业务理解涉及第三方服务集成的复杂逻辑验证成本高安全相关的代码审查成本高我自己的经验是把大任务拆成小任务每个小任务都有明确的验证方式然后逐个交给 Agent。比如“给项目加一个评论功能”这个大任务可以拆成加 Comment 模型和 migration、加 Comment 控制器和路由、加 Comment 的视图、写 Comment 的测试。每个小任务 Agent 都能独立完成并验证。4.2 实操记录用 Agent 完成一个 Rails 功能模块下面是我最近用 Agent 完成的一个实际任务记录。任务是给一个已有的 Rails 项目加“文章标签”功能要求支持多标签、标签筛选、标签云展示。任务一数据模型。我给 Agent 的指令是“创建 Tag 模型和 ArticleTag 关联模型Tag 有 name 字段唯一索引ArticleTag 是 Article 和 Tag 的 join 模型。生成相应的 migration 和模型测试。”Agent 的执行过程读取现有 Article 模型 → 生成 migration 文件 → 生成 Tag 和 ArticleTag 模型 → 在 Article 模型里加has_many :tags, through: :article_tags→ 生成模型测试 → 跑测试 → 测试通过。我审查了生成的代码发现一个问题Agent 没有给name字段加唯一索引。我在指令里说了“唯一索引”但 Agent 可能理解成了“唯一验证”。这是一个典型的“指令歧义”问题。我补充指令后Agent 生成了新的 migration 加索引。实操心得给 Agent 的指令要尽量具体避免“唯一”“合理”“适当”这类模糊词汇。能说“加数据库唯一索引”就不要说“保证唯一”。任务二控制器和路由。指令“给 ArticlesController 加上按标签筛选的功能路由支持/articles?tagxxx同时加一个/tags页面展示标签云。”Agent 完成了控制器修改、路由添加、视图生成。测试跑过后我发现标签云的排序逻辑不对——Agent 按标签名字母序排了但产品需求是按文章数量降序排。这个需求我在指令里没写清楚属于我的问题。补充指令后修复。任务三测试补充。指令“给标签功能补充集成测试覆盖创建带标签的文章、按标签筛选、标签云页面渲染。”Agent 生成了测试文件跑测试有两个失败。Agent 自己读取失败信息发现是 fixture 数据的问题自动修复后测试通过。这个过程基本不需要我介入。整个任务从开始到完成大概花了 40 分钟其中我介入修改指令 3 次审查代码 2 次。如果纯手写我估计需要 2-3 小时。效率提升是明显的但也不是“完全不用管”。4.3 并发场景下 Agent 的表现与限制“AI Agent 怎么扛并发”是最近被问得很多的问题。我的实测结论是单个 Agent 实例不适合处理高并发任务但多个 Agent 实例可以通过任务队列实现并发。单个 Agent 的工作模式是“思考-执行-观察-再思考”的串行循环。它同一时间只能处理一个任务因为它的上下文窗口是有限的同时处理多个任务会导致上下文混乱。我试过让一个 Agent 同时处理三个文件的重构结果它把三个文件的修改混在一起产生了大量冲突。正确的做法是用任务队列把并发任务拆开每个 Agent 实例从队列里取一个任务处理完再取下一个。这样虽然单个 Agent 是串行的但多个 Agent 并行工作整体吞吐量上去了。# 简化的任务队列示例 from queue import Queue from threading import Thread task_queue Queue() def agent_worker(agent_id): while not task_queue.empty(): task task_queue.get() print(fAgent {agent_id} 开始处理: {task[name]}) # 这里调用 Agent 执行任务 result run_agent_task(task) print(fAgent {agent_id} 完成: {task[name]}, 结果: {result}) task_queue.task_done() # 启动 3 个 Agent 并行工作 for i in range(3): t Thread(targetagent_worker, args(i,)) t.start()这个模式的关键是任务之间必须相互独立。如果两个任务修改同一个文件并发执行会产生冲突。所以拆任务的时候要注意文件级别的隔离。4.4 Agent 安全不能忽视的边界问题Agent 能执行命令、读写文件、访问网络这意味着它的安全边界必须明确。我见过有人让 Agent 直接在生产环境的服务器上操作这是非常危险的。我的安全实践包括几条。第一Agent 只在开发环境的容器里运行容器有独立的文件系统和网络策略不能访问生产数据库和敏感配置。第二Agent 执行的每条命令都记录日志方便事后审计。第三对敏感操作删除文件、修改数据库 schema、推送代码到远程仓库设置人工确认。第四定期检查 Agent 的上下文里有没有混入敏感信息API key、密码等如果有及时清理。关于 Agent 记忆的安全最近有一些研究比如 a-memguard 这类主动防御框架在探讨如何防止 Agent 的记忆被污染或泄露。核心思路是对 Agent 写入记忆的内容做过滤和脱敏对读取记忆的操作做权限控制。这个方向值得关注尤其是当 Agent 开始长期运行、积累大量项目上下文的时候。5. 常见问题与排查技巧实录5.1 Agent 执行失败的高频原因与解决方案在实际使用中Agent 执行失败的原因五花八门。我整理了一个速查表覆盖了我遇到的大部分情况。问题现象可能原因排查方法解决方案命令找不到PATH 未配置which cmd把工具 bin 目录加入 PATH运行时版本不兼容Node/Python 版本过低node --version用 nvm/pyenv 切换版本网络请求失败代理配置问题检查环境变量配置正确的网络访问方式上下文超限项目太大或对话太长查看 token 使用量拆分任务、清理对话历史生成代码不符合规范缺少项目配置检查 agent 配置文件补充 conventions 配置测试跑不过环境依赖缺失手动跑测试复现安装缺失依赖、修复环境Agent 卡住不响应任务太复杂或指令模糊查看 Agent 日志拆解任务、细化指令修改了不该改的文件工作目录配置错误检查 excludePaths限制工作目录、加确认机制5.2 几个我踩过的坑和对应的解决思路坑一Agent 把测试文件也“重构”了。有一次我让 Agent 重构一个 service 对象它顺手把对应的测试文件也改了把测试断言改成了匹配它新写的代码。这导致测试虽然通过了但测试本身已经失去了验证意义。解决方法是在指令里明确说“只修改 lib/ 目录下的文件不要动 spec/ 目录”或者在配置里把测试目录设为只读。坑二Agent 在修复一个 bug 的时候引入了新 bug。这是最让人头疼的情况。Agent 看到测试失败就改代码让测试通过但它没有理解测试背后的业务逻辑改出来的代码虽然让测试绿了但行为是错的。解决方法是对 Agent 的修改做 code review尤其是涉及业务逻辑的修改。不要因为测试通过了就盲目合并。坑三Agent 的上下文里混入了过时的信息。当对话很长的时候Agent 可能会引用很早之前讨论过的、但已经被推翻的方案。解决方法是定期清理对话历史或者在关键决策点重新明确约束条件。我现在的习惯是每完成一个子任务就开一个新的对话把必要的上下文重新贴一遍。坑四CLI 工具在 Windows 上的兼容性问题。我遇到过node_modules\opencode\cli\bin\opencode.exe 与你运行的 Windows 版本不兼容这类错误。这通常是 Node 版本和工具编译目标不匹配导致的。解决方法是用 WSL2 跑 CLI Agent或者确保 Node 版本和工具要求的版本一致。Windows 原生环境的兼容性问题比 Linux/macOS 多不少如果条件允许建议在 WSL2 或容器里跑 Agent。5.3 Agent 开发的学习路线建议如果你是一个想深入 Agent 开发的开发者我建议的学习路线是这样的。第一阶段用起来。先选一个 CLI Agent 工具在自己的项目里用起来。不要一上来就研究原理先感受一下 Agent 能做什么、不能做什么、在哪些环节能帮到你。这个阶段的重点是建立直觉。第二阶段理解 Agent 的基本架构。一个典型的 Agent 包含几个核心组件LLM负责理解和生成、工具调用层负责执行操作、记忆系统负责保存上下文、规划模块负责拆解任务。理解这些组件怎么配合能帮你更好地设计 Agent 工作流。第三阶段自己搭一个简单的 Agent。不需要从零训练模型用现成的 LLM API 加上工具调用就能搭一个。Python 生态里有很多 Agent 框架可以用选一个上手快的照着文档搭一个能执行简单任务的 Agent。这个阶段的重点是理解“工具调用”和“上下文管理”这两个核心机制。第四阶段深入特定方向。比如你想做代码生成方向的 Agent就深入研究代码理解、代码生成、测试验证这些环节你想做运维方向的 Agent就深入研究命令执行、日志分析、故障排查。这个阶段没有标准路线取决于你的实际需求。吴恩达的 Agent 教程是一个不错的入门材料它把 Agent 的核心概念讲得很清楚而且有配套的代码示例。但教程毕竟是教程真正的理解还是得靠实际项目。6. 我对“手写代码时代落幕”的理解回到 DHH 的那个判断。我的理解是他说的“落幕”不是指“没人写代码了”而是指“手写代码不再是软件工程的核心瓶颈”。以前软件工程的瓶颈在于“把想法翻译成代码”这个过程太慢、太容易出错。现在Agent 正在把这个瓶颈往后推——翻译过程越来越自动化瓶颈变成了“定义正确的问题”和“判断结果的质量”。这对开发者的能力结构提出了新的要求。以前你只要会写代码就能找到工作现在你还需要会描述意图、会设计验证方案、会审查 Agent 的输出。这些能力以前也有用但以前不是核心竞争力因为写代码本身就消耗了大部分精力。现在写代码的精力省下来了这些能力就变成了区分优秀和普通的关键。我自己的感受是用 Agent 之后我花在“敲键盘”上的时间少了大概一半但花在“想清楚要做什么”和“检查做得对不对”上的时间多了。整体产出是提升的但提升的来源不是“写得更快”而是“想得更清楚”。还有一个变化是我对代码的“所有权”感觉变淡了。以前我写的每一行代码我都记得为什么这么写现在很多代码是 Agent 生成的我需要通过测试和审查来建立信心。这有好有坏——好处是我不用再纠结于代码风格这种细节坏处是我对代码的理解可能不如以前深入。我的应对方式是对关键路径的代码坚持自己写或者至少自己重写一遍对边缘代码接受 Agent 生成 测试验证的模式。这个转变还在进行中远没有到稳定的状态。但有一点我比较确定Agent 不会让软件工程变得简单它只会让软件工程的难点发生转移。以前难在“写”现在难在“想”和“判断”。对于习惯了“写”的开发者来说这个转变需要时间适应。但适应之后你会发现你能做的事情比以前多得多。