☰
Agent时代:从写代码到做东西,开发者如何转型与搭建工作流
2026/10/31 4:17:41 网站建设 项目流程

1. 从“手写代码结束”这句话说起

“手写代码结束了,做东西的人刚开始。”这句话第一次看到的时候,我盯着它想了很久。它不是在说程序员要失业了,也不是在鼓吹什么工具万能论。它说的是一件更朴素、也更扎心的事:当代码的产出成本被压到接近于零,真正稀缺的东西就不再是“能不能写出来”,而是“到底要做什么”。

过去十几年,我们这行的手艺很大程度上体现在“实现”上。一个需求过来,你要拆解、要设计数据结构、要选框架、要处理边界、要调性能。这些活儿有门槛,也有成就感。但现在情况变了——AI agent 能在几秒钟内吐出一个能跑的 CRUD,能帮你把一段 Rust 的所有权报错解释得明明白白,能根据一句自然语言描述生成整个项目骨架。写代码这件事本身,正在从“核心技能”退化成“基础素养”。

那什么变得更重要了?是判断力。是知道该做什么、不该做什么、先做什么、后做什么。是把一个模糊的想法,翻译成 agent 能理解、能执行、能验证的任务序列。是当 agent 给你吐出 500 行代码时,你能一眼看出哪一行会在并发场景下炸掉。

这篇东西,我想结合 Ruby on Rails、Rust、Claude Opus 4.5 这些关键词,聊聊在这个“agent 时代”,一个真正做东西的人应该怎么定位自己、怎么搭工具链、怎么把 agent 用出价值而不是被它带偏。不管你是刚入门的新手,还是写了十年代码的老兵,这里面的很多坑我都亲自踩过,希望能帮你少走点弯路。

2. Agent 到底改变了什么:从“写”到“编排”的范式转移

2.1 写代码的成本曲线被彻底压平了

先看一个很直观的对比。以前我要做一个带用户认证、数据库、REST API 的后端服务,用 Rails 的话大概是这样的流程:rails new建项目,配 Gemfile,写 migration,写 model,写 controller,配路由,写测试,调 bug。熟练工大概一两天能出一个能用的版本。用 Rust 加 Axum 或者 Actix,时间只会更长,因为类型系统会逼着你想清楚每一个数据流。

现在呢?你把需求描述清楚,Claude Opus 4.5 这类模型能在几分钟内给你一个结构完整的项目。Rails 的约定优于配置它门儿清,Rust 的 trait 和生命周期它也能处理。写代码这件事的边际成本,正在快速趋近于零。

但这里有个反直觉的点:成本降低不等于价值降低。恰恰相反,当所有人都能快速产出代码时,代码本身的质量差异会被放大。一个架构混乱、边界不清的项目,在 agent 加持下会以更快的速度变成技术债。所以“做东西的人”的价值,从“写得快”转移到了“想得清”。

2.2 Agent 不是自动补全,它是任务执行者

很多人对 agent 的理解还停留在“高级版代码补全”。这是个危险的误解。自动补全解决的是“这一行怎么写”,agent 解决的是“这件事怎么做”。

举个我自己的例子。我最近在做一个 Rust 写的桌面小工具,用 Tauri 做壳。我需要一个功能:读取本地某个目录下的所有 Markdown 文件,解析出其中的待办事项,汇总成一个列表。如果用传统方式,我得自己写文件遍历、写 Markdown 解析、写数据结构、写 UI 绑定。但用 agent 的方式,我是这样拆的:

  1. 先让 agent 理解我的目录结构和文件格式
  2. 让它生成一个独立的 Rust 模块,只负责扫描和解析
  3. 单独验证这个模块的输出
  4. 再让它接入 Tauri 的命令系统
  5. 最后处理前端调用

每一步都是一个可验证的小任务。Agent 的核心价值不是替你写代码,而是替你执行“任务序列”。你负责定义任务边界和验收标准,它负责填充实现细节。

2.3 为什么 Ruby on Rails 和 Rust 在这个时代反而更值得关注

有意思的是,agent 时代并没有让框架变得不重要,反而让某些框架的价值更突出了。

Rails 的“约定优于配置”在 agent 场景下是个巨大优势。因为约定明确,agent 生成的代码更容易符合预期,你 review 起来也更快。一个 Rails 项目的目录结构、命名规范、分层逻辑都是高度标准化的,agent 不需要猜。相比之下,一个高度自由、什么都能塞的框架,agent 生成的东西往往需要你花更多时间整理。

Rust 则是另一个极端。它的类型系统和所有权模型,本质上是一套“编译期的验收标准”。Agent 生成的 Rust 代码,如果编译不过,那就是真的有问题。这比动态语言里“跑起来看着对但暗藏 bug”要安全得多。Rust 的严格性,恰好成了 agent 输出质量的天然过滤器。这也是为什么最近基于 Rust 的 agent 工具链越来越多——不是赶时髦,是类型安全在自动化场景下真的省心。

3. 搭一套能扛事的 Agent 工作流:我的实际配置

3.1 任务拆解比提示词技巧重要一百倍

网上有很多“提示词工程”的教程,教你用什么魔法句式让模型输出更好。我试过不少,结论是:在 agent 场景下,任务拆解的能力远比提示词技巧重要。

一个模糊的指令,比如“帮我做一个用户管理系统”,agent 会给你一堆看起来能用但处处是坑的东西。但如果你把它拆成:

  • 第一步:设计数据库 schema,包含用户表、角色表、权限表,给出字段和关系
  • 第二步:基于 schema 生成 migration 和 model
  • 第三步:生成认证相关的 controller 和路由
  • 第四步:为每个接口写测试用例
  • 第五步:跑测试,修复失败项

每一步都有明确的输入和输出,agent 的执行质量会高出一个数量级。这不是提示词的功劳,是任务分解的功劳。

我自己的习惯是,在让 agent 动手之前,先用纸或者文档把任务树画出来。每个叶子节点必须是一个“可独立验证”的单元。如果一个任务没法验证,那就说明它拆得还不够细。

3.2 用 Rust 做 agent 的“执行沙盒”

这是我踩过坑之后总结出来的一个关键实践。Agent 生成的代码,尤其是涉及文件操作、网络请求、系统调用的部分,绝对不能直接在你的主环境里跑。你需要一个沙盒。

我的做法是用 Rust 写一个轻量的执行器,把 agent 生成的代码放在隔离环境里跑。Rust 的std::process::Command配合资源限制,可以很好地控制子进程的行为。为什么用 Rust 而不是 Python 或者 Node?因为 Rust 编译出来的二进制没有运行时依赖,启动快,资源占用低,而且类型安全让我在写执行器本身的时候少犯错误。

具体来说,这个执行器做几件事:

  • 限制 CPU 时间和内存使用
  • 限制可访问的文件路径
  • 捕获标准输出和错误输出
  • 设置超时,防止死循环
use std::process::{Command, Stdio}; use std::time::Duration; fn run_in_sandbox(code_path: &str) -> Result<String, String> { let output = Command::new("timeout") .arg("10s") .arg("cargo") .arg("run") .arg("--manifest-path") .arg(code_path) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .output() .map_err(|e| e.to_string())?; if output.status.success() { Ok(String::from_utf8_lossy(&output.stdout).to_string()) } else { Err(String::from_utf8_lossy(&output.stderr).to_string()) } }

这段代码很简单,但思路很重要:永远不要信任 agent 生成的代码,先让它在一个受控环境里证明自己能跑。这个习惯帮我避免了好几次因为 agent 生成的代码里有无限循环或者意外文件删除而导致的灾难。

3.3 版本控制是 agent 时代的生命线

Agent 会改代码,而且改得很快。如果你没有严格的版本控制习惯,很快就会陷入“不知道哪次改动引入了 bug”的困境。

我的做法是:每一次 agent 的改动,都必须是一个独立的 commit。不管改动多小,都要提交。commit message 写清楚这次改动的意图和验证结果。这样一来,如果某个改动出了问题,回滚成本极低。

更进一步,我会用 git 的 branch 来隔离实验性的 agent 任务。让 agent 在一个独立分支上折腾,验证通过了再合并。这听起来很基础,但我见过太多人让 agent 直接在 main 分支上改,出了问题手忙脚乱。

提示:给 agent 的每一个任务都配一个独立的 git 分支,任务完成后用 squash merge 合并。这样历史记录干净,回滚也方便。

4. 当 Agent 开始“做东西”:几个真实的场景拆解

4.1 场景一:用 Rails 快速验证一个想法

假设你有个想法:做一个内部用的书签管理工具,支持标签、搜索、导入导出。以前你可能要犹豫一下“值不值得花两天做”。现在不用犹豫了,直接让 agent 上。

我的流程是这样的:

  1. 先用自然语言把需求写清楚,包括数据模型、页面、交互
  2. 让 agent 生成 Rails 项目骨架和 migration
  3. 本地跑起来,看数据库结构对不对
  4. 让 agent 生成 controller 和 view
  5. 手动调 UI 细节,这部分 agent 做得不够好
  6. 让 agent 补测试

整个过程大概两三个小时,其中大部分时间花在“想清楚要什么”和“调 UI”上。写代码的时间被压缩到了很小一部分。这就是“做东西的人刚开始”的真实含义——你的时间从实现转移到了定义和验收。

这里有个坑要注意:Rails 的 agent 生成代码很容易过度使用 gem。Agent 看到“搜索”就给你装 Elasticsearch,看到“导入导出”就给你装一堆解析库。我的经验是,在让 agent 动手之前,先明确告诉它“只用标准库和 Rails 自带功能,不要引入新 gem”。这一句话能省掉后面大量的依赖管理麻烦。

4.2 场景二:Rust 写一个高性能的 agent 调度器

如果你要做的不是 CRUD,而是需要处理并发、需要高性能的东西,Rust 的优势就出来了。我最近在做一个多 agent 协作的小系统,核心是一个调度器,负责把任务分发给不同的 agent 实例,收集结果,处理失败重试。

这个调度器用 Rust 写,核心逻辑大概两百行。为什么不用 Python?因为 Python 的 GIL 在高并发场景下是个硬伤,而 agent 调度天然是 IO 密集加并发密集的。Rust 的 async/await 配合 tokio,能轻松处理几千个并发任务。

关键设计点:

  • 用tokio::sync::mpsc做任务队列
  • 每个 agent 实例是一个独立的 task
  • 用Arc<Mutex<>>管理共享状态
  • 失败任务自动重试,最多三次
use tokio::sync::mpsc; use std::sync::Arc; use tokio::sync::Mutex; async fn dispatch_tasks( tasks: Vec<String>, agent_count: usize, ) -> Vec<String> { let (tx, rx) = mpsc::channel::<String>(100); let rx = Arc::new(Mutex::new(rx)); let mut handles = vec![]; for _ in 0..agent_count { let rx = rx.clone(); let handle = tokio::spawn(async move { loop { let task = { let mut rx = rx.lock().await; match rx.recv().await { Some(t) => t, None => break, } }; // 执行任务 let result = execute_task(task).await; // 处理结果 } }); handles.push(handle); } for task in tasks { tx.send(task).await.unwrap(); } drop(tx); for handle in handles { handle.await.unwrap(); } vec![] }

这段代码的价值不在于它多复杂,而在于它展示了Rust 在 agent 基础设施层面的适用性。当你的 agent 系统需要扛并发、需要低延迟、需要长时间稳定运行时,Rust 几乎是当前最好的选择。

4.3 场景三:Claude Opus 4.5 在代码审查中的实际表现

Claude Opus 4.5 在代码理解和生成上的能力,我用下来的感受是:它像一个非常勤奋但偶尔会过度自信的初级工程师。它能发现很多你忽略的边界情况,能给出合理的重构建议,但它也会在某些时候“编造”一些不存在的 API 或者给出看似合理实则错误的方案。

我的用法是:让 agent 做第一轮审查,把它发现的问题列出来,然后我自己判断哪些是真问题、哪些是误报。这个流程能帮我抓住大概 70% 的明显问题,剩下的 30% 需要我自己看。

一个具体的例子:我有一段 Rust 代码处理文件读取,agent 指出我没有处理文件不存在的情况。这是对的,我确实漏了。但它同时建议我用一个我根本没引入的 crate 里的函数,这就是典型的“幻觉”。所以 agent 审查的结果,必须经过人工过滤,不能直接采纳。

5. 那些没人告诉你但一定会踩的坑

5.1 Agent 的“上下文遗忘”比你想的严重

Agent 在多轮对话中会遗忘早期的约定。比如你在第一轮告诉它“所有 API 返回都用 snake_case”,到第五轮它可能就给你返回 camelCase 了。这不是模型不行,是上下文窗口的物理限制。

我的应对方法是:把关键约定写成一个“项目宪法”文件,每次让 agent 干活之前,先把这个文件的内容贴给它。这个文件不用长,一页纸就够,包含命名规范、目录结构、依赖限制、错误处理约定这些。每次任务开始前重新注入,能极大减少不一致。

5.2 不要用 agent 做“架构决策”

Agent 很擅长在给定架构下填充实现,但它不擅长做架构决策。你让它“设计一个用户系统”,它会给你一个能用的方案,但往往不是最适合你场景的方案。它不知道你的团队规模、不知道你的部署环境、不知道你未来半年的规划。

架构决策必须由人来做。Agent 可以给你提供选项和利弊分析,但拍板的是你。我见过有人让 agent 全权决定技术选型,结果选了一个社区很小、文档很差的库,后面维护起来苦不堪言。

5.3 测试是 agent 时代的“安全带”

Agent 生成的代码,如果没有测试,你根本不知道它是不是真的能用。而且 agent 很容易生成“看起来对”的代码——语法正确、逻辑通顺,但边界情况全错。

我的做法是:让 agent 先写测试,再写实现。测试用例由我来定义,agent 负责把测试写出来。然后让 agent 写实现,跑测试,直到全绿。这个流程能过滤掉大部分低级错误。

注意:Agent 写的测试本身也可能有问题。我遇到过 agent 写的测试断言写反了,导致错误的实现也能通过。所以测试写完,我会快速扫一遍断言逻辑,确认它测的是对的东西。

5.4 性能问题往往藏在“能跑”之后

Agent 生成的代码,第一优先级是“能跑”,性能通常不在它的考虑范围内。一个在本地跑得好好的功能,上了生产环境可能因为一个 N+1 查询就崩了。

我的经验是:在 agent 完成功能实现后,专门让它做一轮性能审查。告诉它关注数据库查询、循环内的 IO、不必要的内存分配这些点。Rust 的话,还可以让它检查有没有不必要的 clone。这一轮审查往往能发现不少问题。

6. 做东西的人,到底该把时间花在哪

6.1 定义问题比解决问题更难

Agent 让“解决问题”变得便宜了,于是“定义问题”的价值就凸显出来了。一个清晰的问题定义,包含:目标是什么、约束是什么、验收标准是什么、不做什么。这四件事想清楚,agent 才能干得好。

我现在的习惯是,在打开编辑器之前,先花 20 分钟把问题写下来。写不清楚就说明还没想清楚,这时候让 agent 动手只会浪费双方的时间。

6.2 判断力来自“做过”

Agent 可以给你建议,但它不能替你承担判断的后果。而判断力这个东西,没有捷径,只能来自大量的实践。你做过足够多的项目,踩过足够多的坑,才能在 agent 给你三个方案时,一眼看出哪个会在三个月后出问题。

所以我的建议是:不要因为 agent 能写代码就跳过动手的环节。该自己写的核心逻辑还是要自己写,该自己调的 bug 还是要自己调。Agent 是杠杆,但杠杆需要支点,你的经验就是那个支点。

6.3 保持对“手艺”的敬畏

最后说点感性的。写代码这件事,哪怕 agent 能做得又快又好,它依然是一门手艺。手艺的价值不只在于产出,还在于过程中对细节的打磨、对美的追求、对“这样做对不对”的反复追问。

Agent 可以帮你写一个能用的函数,但它不会因为变量命名不够优雅而纠结,不会因为一个边界情况没处理好而睡不着觉。这些“纠结”和“睡不着”,恰恰是区分“能跑的东西”和“好东西”的关键。

“手写代码结束了,做东西的人刚开始。”这句话我越琢磨越觉得对。代码会越来越便宜,但把东西做好、做对、做得让人愿意用,这件事永远不会便宜。Agent 把我们从重复劳动里解放出来,不是让我们躺平,而是让我们有机会去做那些真正需要人的判断和品味的事。

我在实际使用 agent 的过程中最大的体会是:它放大了我的能力,也放大了我的懒惰。当我认真定义问题、严格验收结果时,它让我效率翻倍;当我偷懒把模糊的需求丢给它时,它给我一堆需要返工的垃圾。所以最终决定产出质量的,还是我自己。工具再好,用工具的人得先想清楚自己要什么。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询