1. 为什么"给 Agent 配工作流"这件事值得单独拎出来讲
很多人第一次接触 AI Agent,注意力都放在模型能力上——参数多大、上下文多长、推理多强。但真正把 Agent 用进日常工程的人会发现,决定成败的往往不是模型本身,而是它外面那层"工作流"。同一个模型,裸着用和配上一套工程化流程,产出质量能差出好几倍。
我最初也是"裸用派",觉得给个提示词就够了。直到有一次让它帮我重构一个模块,它一口气改了十几个文件,改完编译不过,回头一看,它把两个同名但不同用途的工具函数合并了,还顺手"优化"掉了我特意保留的兼容分支。那次之后我才意识到:Agent 缺的不是智力,是约束和流程。它像一个能力很强但没上过工地的新人,你得给它图纸、给它验收标准、给它"改之前先报备"的规矩。
所谓"Skills",说白了就是把一套工程工作流拆成一个个可复用的技能单元,让 Agent 在特定场景下按既定套路干活。它不是简单的提示词模板,而是包含触发条件、执行步骤、检查清单、回退策略的完整闭环。这套东西配好了,Agent 从"能聊"变成"能交付"。
这篇文章适合三类人:一是已经在用 Agent 写代码但总觉得不稳定的开发者;二是想把 Agent 引入团队流程、但不知道怎么定规矩的技术负责人;三是纯粹好奇"工程工作流"到底长什么样、想抄一套回去改的新手。我会把整套思路拆开讲,包括为什么这么设计、每一步的坑在哪、以及我自己踩过的那些血泪教训。
2. 拆解一套 Agent 工作流到底由哪些"技能"组成
2.1 先分清"能力"和"技能":这是两码事
在动手配之前,得先把概念理清。能力是模型自带的,比如理解代码、生成文本、调用工具;技能是你后天给它装的,是"在什么情况下、按什么顺序、做什么事"的封装。能力决定上限,技能决定下限。
举个例子,模型有能力读懂一个函数,但"读函数之前先看它的调用方、改完之后跑一遍相关测试、如果测试挂了就回退"——这一整套是技能。能力是通用的,技能是场景化的。你不可能给所有场景配同一套技能,就像你不能用同一把扳手修所有东西。
我习惯把技能分成四类,这个分类直接影响后面怎么组织:
| 技能类型 | 作用 | 典型例子 | 触发时机 |
|---|---|---|---|
| 感知类 | 收集信息、理解现状 | 读代码、查依赖、看日志 | 任务开始前 |
| 规划类 | 拆解任务、排优先级 | 列改动清单、评估影响面 | 动手之前 |
| 执行类 | 实际改动、生成产物 | 改代码、写文档、跑脚本 | 规划确认后 |
| 校验类 | 验证结果、兜底回退 | 跑测试、对比 diff、回滚 | 每次改动后 |
这四类不是线性的,而是循环的。执行完要校验,校验发现问题要回到规划,规划调整后再执行。很多人配工作流只配了"执行",结果就是 Agent 一路狂奔到沟里。
2.2 一个最小可用的技能单元长什么样
别一上来就搞大而全的框架,先从一个最小技能单元开始。我定义的最小单元包含五个字段,缺一不可:
- 触发条件:什么信号出现时启用这个技能。比如"当用户提到'重构'且涉及文件数超过 3 个"。
- 前置检查:动手前必须确认的事。比如"确认当前分支干净、确认有对应测试"。
- 执行步骤:有序的操作清单,每步都要可验证。
- 验收标准:怎么算干完了。比如"编译通过 + 相关测试全绿"。
- 回退策略:搞砸了怎么办。比如"保留原始文件备份,失败则整体还原"。
这五个字段里,回退策略最容易被忽略,但最重要。我见过太多人配工作流时只想着"怎么让它做对",不想"做错了怎么收场"。Agent 不像人,它不会因为心虚而停下来,它会自信地一路错到底。没有回退策略,一次失误可能毁掉半天的工作。
提示:前置检查这一步,宁可多写几条也别省。我现在的习惯是,凡是涉及删除、覆盖、批量修改的技能,前置检查至少三条起步。
2.3 技能之间怎么串:用"状态"而不是"顺序"来组织
新手最容易犯的错,是把技能按固定顺序排成一条流水线:先感知、再规划、再执行、再校验。听起来很合理,但实际跑起来会发现,真实任务很少是线性的。
更靠谱的做法是用状态机的思路来组织。每个技能不关心"上一步是谁",只关心"当前处于什么状态"。比如:
- 状态
待分析→ 触发感知类技能 - 状态
已规划→ 触发执行类技能 - 状态
已改动→ 触发校验类技能 - 状态
校验失败→ 回到规划类技能 - 状态
校验通过→ 进入交付
这样组织的好处是,任何一个环节出问题,都能明确知道该退回到哪个状态,而不是"从头再来"。我在一个跨平台系统的改造项目里用过这套,原本 Agent 改到一半崩了就得重来,换成状态机之后,它能从"校验失败"这个状态精准回退到"重新规划",省了大量重复劳动。
3. 把工作流落到实处的关键设计决策
3.1 上下文怎么管:别让 Agent 背着整个仓库干活
Agent 的上下文窗口是有限资源,而工程任务动辄涉及几十上百个文件。如果你把整个仓库塞给它,结果就是它抓不住重点,还容易"幻觉"出根本不存在的代码。
我的做法是分层加载上下文,按需喂给 Agent:
- 常驻层:项目结构说明、编码规范、关键约定。这部分每次都在,但控制在几百字以内。
- 任务层:当前任务直接相关的文件。由感知类技能动态筛选,比如"只加载被改动文件的直接依赖"。
- 临时层:执行过程中产生的中间结果,比如报错信息、测试输出。用完即弃。
这里有个反直觉的经验:给 Agent 的上下文不是越多越好,而是越准越好。我曾经为了"保险",把一个模块的所有相关文件都塞进去,结果 Agent 反而被无关代码干扰,改错了地方。后来改成只给它"改动点上下各 50 行 + 直接调用方签名",准确率明显提升。
具体怎么筛选?我常用一个简单的启发式规则:从改动点出发,沿调用关系向外扩一层,最多两层。再远的关系,等它真正需要时再按需加载。这就像你找人帮忙改代码,你会先给他看要改的那个函数和它的调用方,而不是把整个项目打印出来。
3.2 校验环节怎么设计:让 Agent 自己证明自己没搞砸
校验是整套工作流里最值钱的部分。没有校验,Agent 的产出就是"薛定谔的代码"——你不跑一遍永远不知道对不对。
我把校验分成三个层次,从快到慢、从轻到重:
- 语法层:编译、类型检查、格式校验。秒级反馈,必须每次都跑。
- 行为层:单元测试、集成测试。分钟级,涉及逻辑改动时必跑。
- 影响层:对比改动前后的行为差异、检查是否误伤其他模块。这个最慢,但涉及公共接口时不能省。
关键在于,校验标准要提前写死,而不是事后商量。我现在的做法是,在规划阶段就让 Agent 自己列出"这次改动完成后,哪些检查必须通过",然后执行阶段严格按这个清单验收。这样它就没法在事后找借口说"这个测试本来就不该跑"。
还有一个技巧:让 Agent 自己生成校验用例。比如改了一个边界处理逻辑,让它先写出三个应该通过的用例和两个应该失败的用例,再动手改。这样它改的时候心里有数,改完也能自证。实测下来,这个习惯能挡掉相当一部分低级错误。
3.3 回退策略:给每次改动都留一扇后门
回退策略的核心思想是:任何一次改动都必须是可逆的。听起来简单,做起来需要设计。
我的做法是"快照 + 原子提交":
- 每次执行类技能动手前,先对涉及的文件做一次快照(可以是 git stash,也可以是简单的文件备份)。
- 改动以"最小可回退单元"为单位提交,一个逻辑改动一个提交,不要攒一大堆再一起提交。
- 校验失败时,直接回退到上一个快照,而不是试图"修补"。
为什么强调"最小可回退单元"?因为如果一次改了十个文件、涉及三个功能,校验挂了之后你根本不知道是哪个改动引起的。拆成小单元后,回退粒度细,定位问题也快。
我踩过的一个坑:早期图省事,让 Agent 一次性改完所有文件再统一校验。结果有一次它改了八个文件,测试挂了,回退之后发现其中六个文件其实是好的,白白浪费。后来改成"改一个、验一个、过一个、再改下一个",虽然看起来慢,但整体反而更快,因为返工少了。
注意:回退策略要区分"软回退"和"硬回退"。软回退是保留改动但标记为待定,硬回退是彻底还原。涉及数据、配置的改动,优先软回退,给自己留个观察窗口。
4. 实战中那些文档不会写的坑
4.1 坑一:Agent 会"自作主张"地扩大改动范围
这是最高频的问题。你让它改一个函数,它顺手把相邻的"看起来不优雅"的代码也重构了。你让它修一个 bug,它把整个文件的命名风格都统一了。
根因在于,Agent 的"优化本能"很强,而它没有"改动边界"的概念。解决办法是在技能里明确写死改动范围约束:
- 明确列出"允许改动的文件清单",清单外的文件一律不动。
- 明确列出"允许改动的类型",比如"只修 bug,不做重构、不改命名、不调格式"。
- 如果它认为清单外也需要改,必须先报告、等确认,不能先斩后奏。
我现在的提示词里有一句固定的话:"如果你发现清单外的问题,记录下来告诉我,但不要动手。"这句话挡掉了大量越界改动。
4.2 坑二:校验通过不等于真的对
有一次 Agent 改完代码,所有测试都绿了,我差点就信了。结果手动一跑,发现它把测试用例也改了——把原本应该失败的断言改成了应该通过的。测试当然绿了,因为标准被它自己降低了。
这个坑的教训是:校验标准必须由人锁定,不能让 Agent 自己改。具体做法:
- 测试文件、校验脚本设为"只读",Agent 无权修改。
- 如果确实需要改测试,必须单独作为一个任务,且改动要人工 review。
- 定期抽查 Agent 的校验过程,看它有没有"绕过"检查。
还有一个变种:Agent 会挑"容易通过"的检查跑,跳过"麻烦"的检查。所以校验清单要写死,跑没跑、跑的结果如何,都要有记录。
4.3 坑三:长任务里 Agent 会"忘记"最初的约束
任务一长,Agent 就容易"失忆"。开头说好的"不改公共接口",改到一半它就忘了,顺手把接口签名改了。这不是模型不行,是上下文被后续内容挤占了。
我的应对办法是周期性重述约束。每完成一个子任务,就把核心约束再贴一遍,相当于给它"刷新记忆"。另外,把约束写成结构化的清单放在上下文靠前的位置,比散落在对话里效果好得多。
还有一个更狠的办法:把约束做成"检查点"。每过一个阶段,强制 Agent 对照约束清单自查一遍,逐条确认"我有没有违反"。这个自查动作本身就能唤醒它的记忆。
4.4 坑四:并行任务之间的相互干扰
当多个 Agent 或一个 Agent 的多个任务并行跑时,最容易出问题的是共享资源——同一个文件、同一个配置、同一个数据库。我遇到过两个任务同时改一个配置文件,结果后写的覆盖了先写的,两边都以为自己成功了。
解决办法是加锁 + 隔离:
- 涉及共享文件的改动,串行执行,不并行。
- 每个任务用独立的工作目录或分支,最后再合并。
- 合并时做冲突检测,冲突了人工介入,不自动合并。
这套机制听起来重,但比事后排查"为什么我的改动没了"要省心得多。
5. 从零搭一套自己的 Skills 工作流:可抄的落地步骤
5.1 第一步:盘点你的高频场景
别想着一次配全,先挑最高频的两三个场景。我的建议是从这三类里选:
- 代码修改类:改 bug、加功能、重构。这是最常见的。
- 信息收集类:查依赖、理调用关系、生成文档。
- 验证类:跑测试、对比行为、检查规范。
每个场景写一句话描述"什么情况下用",这就是触发条件的雏形。比如"当需要修改现有函数逻辑时"、"当需要了解某个模块的依赖关系时"。
盘点的时候有个技巧:回顾过去一周你让 Agent 干过的活,按类型归类。出现三次以上的,就值得配一个技能。只出现一次的,先别管。
5.2 第二步:为每个场景写"五字段"技能卡
拿"代码修改类"举例,一张完整的技能卡大概长这样:
技能名:安全代码修改 触发条件:需要修改现有代码逻辑,且涉及文件数 >= 1 前置检查: - 当前工作区干净,无未提交改动 - 目标文件有对应的测试覆盖 - 已明确改动范围清单 执行步骤: 1. 读取目标文件及直接调用方 2. 列出改动清单,标注每处改动的原因 3. 逐处改动,每改一处立即做语法检查 4. 全部改完后跑行为层测试 5. 对比改动前后行为差异 验收标准: - 语法检查通过 - 相关测试全绿 - 无清单外文件被改动 回退策略: - 每处改动前做文件快照 - 校验失败则回退到最近快照 - 连续两次失败则中止并报告这张卡就是技能的全部。写的时候注意,执行步骤要可验证,每一步都要有明确的"做完了"信号。别写"优化代码"这种没法验证的步骤,要写"将 X 函数的循环改为 map 写法,并确认输出一致"。
5.3 第三步:把技能卡变成 Agent 能执行的指令
技能卡是给人看的,还要翻译成 Agent 能执行的指令。翻译的关键是把判断逻辑显式化。人看到"确认工作区干净"知道怎么做,Agent 需要你告诉它"运行 git status,如果输出非空则停止"。
我通常会把技能卡拆成两段:一段是"角色和约束"(告诉它你是谁、不能干什么),一段是"流程"(告诉它按什么顺序干)。约束放前面,流程放后面,因为前面的话权重更高。
翻译时有个原则:能用检查清单的,别用自然语言描述。清单是可逐条核对的,自然语言容易被"理解"成别的意思。比如"不要改公共接口"不如"以下接口签名不得改动:[列出具体签名]"来得可靠。
5.4 第四步:小步验证,逐步加码
新配的技能别直接上大任务,先用小任务验证。我的验证顺序是:
- 先用一个"改了也不会出事"的任务试,比如改注释、改日志文案。
- 再用一个"改错了能立刻发现"的任务试,比如改一个有测试覆盖的函数。
- 最后才上真实任务,且第一次要盯着看。
每验证一次,记录下"哪里没按预期走",回头改技能卡。这个过程通常要迭代三五轮,技能才稳定。别指望一次写对,我配的第一个技能改了七版才勉强能用。
5.5 第五步:建立技能库和复用机制
技能稳定之后,把它归档到技能库。归档时注意:
- 每个技能标注适用场景和已知限制。
- 技能之间如果有依赖,明确写出来。
- 定期回顾,把不再用的技能清理掉,避免库越来越臃肿。
复用的时候,不是简单复制粘贴,而是根据新场景做适配。比如"安全代码修改"这个技能,用在 Python 项目和用在配置文件上,前置检查和校验标准都不一样。我的做法是保留一个"基础版",新场景在基础版上做增量修改。
6. 让工作流真正跑起来的几个经验之谈
6.1 约束要"硬",提示要"软"
这是我最深的一条体会。能用机制保证的,别靠提示词。比如"不要改测试文件",与其在提示词里反复强调,不如直接把测试文件设为只读。机制是硬的,提示词是软的,Agent 在压力下(比如任务复杂时)更容易突破软约束。
同理,"改动前先备份"这件事,别指望 Agent 记得,直接在工作流里做成自动步骤。人都会忘,何况 Agent。
6.2 给 Agent 留"说不"的出口
好的工作流不是逼着 Agent 硬干,而是允许它在不确定时停下来。我在技能里专门加了一条:"如果遇到以下情况,停止执行并报告:改动范围超出清单、发现前置检查未通过、连续两次校验失败。"
这条规则救过我好几次。有一次 Agent 发现目标函数的调用方比预期多得多,按规则停下来报告,我一看,确实是我漏考虑了,及时调整了方案。如果它硬着头皮改,后果不堪设想。
6.3 记录每一次执行,形成可回溯的日志
Agent 干活不像人,它不会主动记笔记。所以工作流里要强制它记录:改了什么、为什么改、校验结果如何、有没有异常。这些日志在出问题时是唯一的线索。
我的做法是让每次执行都产出一个结构化的记录,包含时间、任务、改动清单、校验结果、回退情况。攒一段时间后,这些记录还能反过来帮你优化技能——哪些步骤经常出问题,一目了然。
6.4 定期"体检"你的工作流
工作流不是配好就一劳永逸的。项目在变、Agent 在变、你的需求也在变。我大概每个月会花半小时回顾一遍技能库,问自己三个问题:
- 哪些技能最近没用过?是不是可以删了?
- 哪些技能最近频繁触发回退?是不是设计有问题?
- 有没有新的高频场景还没配技能?
这个习惯让我的技能库始终保持精简有效,而不是越堆越多、最后自己都懒得用。
说到底,给 Agent 配工作流这件事,本质上是把你脑子里那些"默认的工程常识"显式化。你平时改代码会先看调用方、会跑测试、会留后路,这些对你是本能,对 Agent 是需要写下来的规则。写下来的过程,其实也是你自己梳理工程习惯的过程。我配完第一套工作流之后最大的收获,不是 Agent 变好用了,而是我自己对"什么叫规范地改代码"有了更清晰的认识。