1. 引言:一次让我重新审视开发方式的转变
过去两年,我的开发工作流经历了两次明显的跃迁:第一次是从「纯手写代码」切换到「Copilot 辅助补全」,第二次则是最近从「补全式助手」走向「Agent 式自主执行」。如果说 Copilot 让我的打字速度变快了,那么 Agent 正在改变我思考问题的方式。这篇文章想记录下这段真实的转变过程,以及它对我日常开发带来的具体影响。
2. 起点:Copilot 时代的工作流
在 Copilot 进入日常开发之前,我的工作流大致是:先想清楚接口和数据结构,再逐行实现,最后靠编译器和测试来兜底。Copilot 出现后,最直观的变化是样板代码和重复逻辑的编写速度大幅提升,但整体流程仍然由我主导——它负责补全,我负责决策。
- 补全式交互:基于上下文给出下一段代码建议,接受或忽略由我决定。
- 局部优化:擅长函数体、单元测试、正则等相对独立的小块代码。
- 心智负担仍在:我需要先想清楚「要什么」,它才能给出「怎么补」。
3. 转折点:从「补全」到「执行」
真正让我感到工作流被颠覆的,是 Agent 类工具开始承担「任务」而不是「片段」。它不再只是等我敲完半个函数再补另一半,而是能理解一个相对完整的目标,自己拆解步骤、调用工具、读取文件、运行命令,并在遇到问题时主动调整策略。
这种变化的核心差异在于:Copilot 补的是代码,Agent 做的是任务。前者把「写」变快,后者把「想」和「做」之间的链路缩短了。
4. 我的开发工作流正在发生哪些具体变化
下面从几个最直观的维度,对比一下我过去和现在的日常开发方式。
| 维度 | Copilot 时代 | Agent 时代 |
|---|---|---|
| 任务粒度 | 函数、代码块 | 功能模块、跨文件改动 |
| 交互方式 | 逐行补全、手动接受 | 描述目标、自主执行 |
| 上下文范围 | 当前文件、附近代码 | 整个仓库、多文件联动 |
| 错误处理 | 由我定位和修复 | Agent 可自行读取报错并迭代 |
| 我的角色 | 编写者 | 审查者、方向决策者 |
5. 一个真实的例子:重构一个老模块
最近我把一个维护了两年的支付回调模块交给 Agent 做重构。过去这种任务我需要先通读代码、梳理状态流转、再手动拆解重写,通常要花掉大半天。这次我只描述了目标:保持对外接口不变、把状态机逻辑抽离、补充边界测试。Agent 自己完成了代码阅读、方案设计、改动落地和测试补充,我主要做的是审查它的改动是否符合预期。
以状态机逻辑为例,重构前这段代码把状态流转散落在回调方法里,靠一堆 if 判断推进,读起来很费劲:
// 重构前:状态流转散落在回调里
public class PaymentCallbackHandler {
private String state = "INIT";
public void onNotify(PaymentNotify notify) {
if ("INIT".equals(state) && "PAID".equals(notify.getStatus())) {
state = "PAID";
// 更新订单、发通知……
} else if ("PAID".equals(state) && "REFUNDED".equals(notify.getStatus())) {
state = "REFUNDED";
// 处理退款……
} else {
// 非法流转,直接忽略
}
}
}
重构后,Agent 把状态流转抽成了独立的枚举和状态机,每个状态只关心自己允许的迁移,新增状态时不再需要改动回调主流程:
// 重构后:状态机逻辑抽离
public enum PaymentState {
INIT {
@Override
public PaymentState on(PaymentNotify notify) {
return "PAID".equals(notify.getStatus()) ? PAID : this;
}
},
PAID {
@Override
public PaymentState on(PaymentNotify notify) {
return "REFUNDED".equals(notify.getStatus()) ? REFUNDED : this;
}
},
REFUNDED {
@Override
public PaymentState on(PaymentNotify notify) {
return this; // 终态,不再流转
}
};
public abstract PaymentState on(PaymentNotify notify);
}
有了这个状态机枚举之后,回调主流程被大幅简化。重构后的 PaymentCallbackHandler 不再关心具体的状态迁移规则,只需要持有当前状态并交给枚举去推进,主流程变得非常薄:
// 重构后:主流程只负责持有状态并交给状态机推进
public class PaymentCallbackHandler {
private PaymentState state = PaymentState.INIT;
public void onNotify(PaymentNotify notify) {
// 状态迁移规则全部收敛到 PaymentState 枚举中
PaymentState next = state.on(notify);
if (next != state) {
state = next;
// 状态变化时再处理副作用:更新订单、发通知、处理退款……
handleSideEffect(state, notify);
}
// 非法流转时 next == state,直接忽略,无需在回调里写 if 判断
}
private void handleSideEffect(PaymentState state, PaymentNotify notify) {
// 按当前状态执行对应的业务副作用
}
}
对比重构前的版本,主流程从「一堆 if 判断 + 状态字符串赋值」变成了「一行状态机推进 + 副作用处理」。新增状态时,只需要在 PaymentState 枚举里加一个枚举值并定义它允许的迁移,回调主流程完全不用动,这正是状态机抽离带来的最大收益。
对比之下,重构后的代码把「每个状态允许什么迁移」收敛到一处,边界更清晰,也更容易补测试。这正是 Agent 帮我完成的核心改动之一。
这个例子让我意识到,我的工作重心正在从「怎么写」转向「怎么描述清楚目标、怎么审查结果」。
6. 被颠覆的不只是写代码
Agent 带来的变化并不局限于编码环节,它正在渗透到整个开发流程中。
- 需求理解:从「把需求翻译成代码」变成「把需求描述清楚,让 Agent 理解并拆解」。
- 代码审查:审查对象从「自己或同事写的代码」扩展到「Agent 生成的代码」,需要更强的判断力。
- 调试排错:Agent 可以自己跑测试、看日志、定位问题,我更多负责确认根因和最终方案。
- 知识管理:沉淀 prompt、任务模板和最佳实践,成为新的「工程资产」。
7. 挑战与边界:哪些事我仍然不放心交给 Agent
尽管 Agent 的能力在快速提升,但我在实践中仍然保留了一些边界。
- 高风险变更:涉及线上数据、资金、权限的改动,我会坚持自己过一遍关键路径。
- 模糊需求:当需求本身存在歧义时,Agent 容易沿着错误方向走很远,需要更早介入。
- 架构决策:技术选型和系统设计这类影响长远的决策,我倾向于自己主导,Agent 作为辅助分析。
- 上下文失控:任务过大时 Agent 可能遗漏约束,需要把大任务拆成更小的、可验证的步骤。
8. 给同样在经历转变的开发者几点建议
如果你也正在从 Copilot 走向 Agent,下面几点是我踩过坑之后总结的经验。
- 先小后大:从单文件、低风险的任务开始尝试,逐步建立对 Agent 的信任边界。
- 把目标写清楚:Agent 的效果很大程度上取决于任务描述的清晰度,值得花时间打磨。
- 保留审查习惯:无论 Agent 多强,代码审查和测试验证都不能省。
- 建立自己的模板库:把常用的任务描述、约束条件和验收标准沉淀下来,复用效率很高。
在「把目标写清楚」这条建议上,我总结了一套可复用的任务描述方法。无论任务大小,我都会尽量把目标、约束、上下文、验收标准这四类要素写进描述里。下面用三个不同粒度的例子来说明。
示例一:修复一个 bug(最小粒度)
目标:修复订单列表页在切换分页时偶发白屏的问题。
上下文:问题出现在 OrderListPage.vue 的 loadOrders 方法,切换页码时会重新请求数据并渲染列表。
约束:不要改动后端接口,保持现有分页交互不变。
验收标准:连续切换 20 次分页不再出现白屏;补充一个针对该场景的回归测试。
这个例子里的关键要素很清晰:目标一句话说清「修什么」,上下文直接定位到文件和函数,约束避免 Agent 顺手改到接口或交互,验收标准则给出了可验证的完成条件。
示例二:添加一个新功能(中等粒度)
目标:为导出功能新增「按日期范围筛选」的能力。
上下文:现有导出入口在 ReportService.export(),目前支持按用户和状态筛选,导出格式为 CSV。
约束:保持现有导出接口签名不变;日期范围使用 UTC 时间;筛选逻辑放在 service 层,不侵入 controller。
验收标准:传入起止日期后,导出的 CSV 只包含该范围内的数据;边界日期(当天 00:00 和 23:59)处理正确;补充对应的单元测试。
中等粒度的任务,上下文和约束要更具体一些。这里明确了改动范围(service 层)、时间处理规则(UTC)和接口兼容性,Agent 就不容易在实现细节上跑偏。
示例三:重构一个模块(较大粒度)
目标:重构支付回调模块,把散落的状态流转逻辑抽离成独立的状态机。
上下文:模块位于 PaymentCallbackHandler,当前状态流转靠 if 判断散落在回调方法里,新增状态需要改动主流程。
约束:对外接口保持不变;不改变现有状态迁移语义;重构后代码风格与项目现有规范一致。
验收标准:所有现有测试通过;新增状态机单元测试覆盖 INIT、PAID、REFUNDED 三条迁移路径;代码评审通过后合入。
大粒度任务最需要把约束和验收标准写透。因为改动范围大、涉及文件多,明确的约束能防止 Agent 顺手重构到无关代码,清晰的验收标准则让「完成」有了可判断的依据。
总结下来,任务描述的质量直接决定了 Agent 的执行质量。目标负责「做什么」,约束负责「不能做什么」,上下文负责「在哪里做」,验收标准负责「做到什么程度算完成」。把这四要素补齐,Agent 的产出会稳定很多。
9. 总结:工具在变,核心能力不变
从 Copilot 到 Agent,变化的表面是工具形态,深层则是开发者与代码之间的关系。补全工具让我写得更快,Agent 让我想得更清楚。但无论工具如何演进,理解业务、拆解问题、判断方案、审查结果这些核心能力,依然是开发者最值得投入的部分。
工具会继续变,工作流也会继续被颠覆,但保持对问题的深刻理解,始终是我们在任何工具时代都不会过时的底气。

476

被折叠的 条评论
为什么被折叠?



