工作流 — 把大目标拆成可靠的小任务
这一章讲三件事: 为什么对话 agent 干不了复杂的活(拿真实失败演示); 怎么把大目标切成一组小任务、再装配成一条可控的流水线; 以及什么时候才值得把方向盘交回给模型。 主走查贯穿全章:给 Shopify 店铺批量(一次一大批,而非来一家处理一家)写插件推广邮件。
1. 这一章讲什么
第 11 章的 agent 需要人不时拽一把才能不跑偏1。 这一章回答的问题更狠:能不能干脆不拽?
作者的起点是一个权衡图:今天的 LLM 离 AGI(达到并超过人类水平的通用智能) 还很远;在到达之前,能力和通用范围此消彼长—— 纯聊天机器人什么都能聊、什么都办不成; 收窄到具体领域、配上工具的 agent 能办一两步的事; 而要办「一连几十步、中途不许人插手」的事,需要第三种形态: 把大目标拆成一组定义清楚的小任务,交给一条确定性的流水线去跑,这就是工作流2。
主走查就选书里那个听起来很疯狂的活:爬一批 Shopify 网店, 替每家想一个插件点子,再发一封推广邮件过去。作者用真事证明这能成, 也用三次实测失败证明:这件事不能靠对话 agent 直接上。
2. 顶层全景:先拆任务,再拼图
┌─ 爬店铺 HTML(不用 LLM,爬虫就行) ─┐
│ ▼
目标 ─→ 摘要店铺(六问) → 想插件概念 → 写邮件 → 发送
(LLM) (两步,CoT) (三步,CoT) (mock)
图说:这就是全章终局的形状——每个方框是一个任务,箭头是工作项的流向。
上游两家(HTML、摘要)都直接喂给下游三家用,所以这张图不是一条线,
而是有分叉的 DAG(有向无环图:只朝一个方向流、没有回头路的任务网络)。
搭这条线的固定五步3:定目标 → 划任务 → 实现各任务 → 连成工作流 → 优化。 作者强调它的真正卖点是模块化:坏了好定位——哪步出问题查哪个方框4。 顺带一提,串起任务的那位「调度者」并不必然是 LLM——写死的普通程序一样能干5。
3. 核心原理
3.1 反面教材:对话 agent 三连败
同一件活,书里按「越来越用力」试了三轮对话 agent,全部失败,而且败法各异6:
| 尝试 | 配置 | 死法 |
|---|---|---|
| 一 | 无工具 + 「You can do anything—you just have to believe.」 | 它只会复述你的指令,产出一份「假想的计划」 |
| 二 | 加 search_web / browse_site / send_email 三件工具 | 搜索词天真(best Shopify storefronts 2024),邮件是填了 [your_name] 占位符都没替换的信 |
| 三 | 把全部指令塞进系统消息、配专用工具 | 提示词又长又杂,agent 分心;且它没有「工作单元」的概念,几百个店没法排队 |
第三轮的两条死因值得拆开看。 一是系统消息只是「强烈的建议」,别的什么都不是—— 写再多规矩,也不保证服从,出了错也没有自然的恢复点7; 二是没有工作单元,意味着「一次塞进所有店会炸、一家一家来就得自己排队列」, 既然反正要写队列,你已经走进工作流的领地了7。
而这活本身是真能干的:2023 年初一位开 发者真的这么发了几千封营销邮件, 最佳创意来自一家袜子店——网页名叫 Sock-cess Stories8。 工具不用神化,但要放在结构里。
3.2 任务设计:接口先于内容
工作流的第二、三步是划任务、实现任务,第一块硬骨头是先把每件事的 输入输出写成表(模式,schema:字段名、类型、含义的三件套)9。 以「写邮件」这个任务为例:
| 方向 | 字段 | 类型 | 例 |
|---|---|---|---|
| 输入 | name | 文本 | Sock-cess Stories |
| 输入 | concept / rationale | 文本 | 墙面故事墙与自拍角 / 拉互动、塑亲民形象 |
| 输入 | store_id | UUID | 550e8400-e29b-41d4-a716-446655440000 |
| 输出 | subject_line | 文本 | Introducing Sock-cess Stories for your storefront. |
| 输出 | body | 文本 | Your sock store is amazing……9 |
两个讲究。其一,how 不必像接口那么硬:给店写信该是什么腔调 可以边做边调, 改内容容易,改接口伤筋动骨——所以接口先行10; 其二,定了接口,「这个任务到底合不合理」当场就能验出来, 不至于写到一半发现上下游对不上、回去重画图10。
3.3 实现一件 LLM 任务:模板法与工具法
模板法:为任务定制一份提示词模板(LangChain 推崇的做法),
上游数据以 {占位符} 填进去,补全就是输出11。书里的邮件模板妙在一收一放:
前缀写到 Dear {owner_name}, 为止,后缀接 We hope to hear from you soon,
中间整段留白——模型的补全恰好就是可直接寄出的邮件正文,后处理量为零12。
工具法:要从自由文本里抠结构化数据时,反向利用第 10 章的工具调用——
编一个 saveRestaurantDataToDatabase(name, address, phoneNumber) 的假工具,
参数结构即你要的字段,再用 tool_choice 强制调用。数据库 根本不存在,
你只是骗模型把读出来的信息按结构上缴;OpenAI 后来推出的
structured outputs 更进一步保证返回严丝合缝13。
两条失效路径各有验方14:
- 内容太难:连人都抠不出来?先自己读一遍提示词,改到你能读懂为止;
- 结构太复杂:键太多、嵌套太深?把结构拆小,顺手还能对每小块下更细的指令。
3.4 加火力:四招提质量
初版任务不出活时的升级路径15:
- 思维链:在逼答案之前补一句「let's think step-by-step」;
- tool_choice="none" 先想后做:嫌模型上来就抢着调函数? 关掉函数调用让它先推理一轮——工具说明仍要带上, 否则下一轮它面对的是没见过的家伙什。顺带一提: Anthropic 家的 Opus 默认先想,Sonnet/Haiku 要提示才想16;
- Reflexion 自纠:应用层先判卷(格式检查/编译跑测试/请另一个 LLM 当裁判, 即 LLM-as-judge),不合格就把需求原文 + 上次尝试 + 判卷报告 打包成新提示词重来一遍——代价是成倍的计算开销17;
- 专家 + 代理人:干脆造两个对话 agent,一个是任务的「专家」, 另一个替真人当 user proxy 陪聊督办——这就是 AutoGen 库的基本套路18。
3.5 别把锤子当万能钥匙
三条省钱省心的分流19:能用传统软件就不用 LLM(爬店铺用爬虫); 要分类就用 BERT(谷歌早年开源的一个专职判断文字属于哪一类的老牌模型,小、快、稳)这类老练货——更快、更便宜、也更可依赖; 贵且不可逆的动作必须排队等人批准;不同难度的任务配不同的模型 (便宜的自己托管,难的用头条上那台贵的,特化的用微调款)20。 评估也从任务级做起,别等全流程拼完才发现第 3 格是坏的21。
3.6 装配拓扑:三种连法,三种代价
状态机(把每个任务看成一个状态、活儿在状态之间流转的模型)也好、发布-订阅(一方发布活儿、订阅了的任务认领)也好、总调度器也好,本质都是「任务怎么互连」22:
| 拓扑 | 形状 | 得 | 失 |
|---|---|---|---|
| pipeline 流水线 | 排成一列,一手交一手 | 最简单 | 信息被截留:店铺详情帮得上「想插件」,却到不了「写邮件」;硬传等于把两任务焊死,得不偿失23 |
| DAG 有向无环图 | 可分叉不可回流(Airflow/Luigi 一脉的标配) | 上游全部完成即可跑,好推理好管理;详情直达两个下游24 | 回不了头 |
| cyclic 含环的图 | 允许工作项折返(如质检不过退回上游) | 能自我修复 | 复杂度暴涨:失败信息要与原物料重新会合;每个任务都要学会处理失败批注;还得数重试次数防死循环——能藏进任务内部就把递归藏在里面,别抬到流程层25 |
此外还要二选一:批处理(一次喂一批已知的活)还是流式(来一件处理一件); 前者好维护,后者适合实时,Shopify 例两者皆可26。
3.7 主走查:Fly By Jing 的那封邮件
主走查开始。 五个任务落成图上的形状,书里逐格交代了实现,再把 川菜调料品牌 Fly By Jing 的店铺 HTML 从入口灌进去27:
① emit storefront html(mock):吐出预存的 HTML
② summarize storefront:LLM 按六个问题摘要——卖什么?基调?
在乎什么价值?主题元素?有没有值得夸的?(第 5 问原话挑明:
是在为「到邮件里捧店主的 ego」做准备)还有什么值得一提?
③ generate plug-in concept(两步):先发散脑暴多个选项、选出最好的,
再单独出一份详报——刻意把思维链和成品分开,只保留成品往外传
④ generate email(三步):先用 CoT 定推广策略 → 再写主题行 → 最后写正文
⑤ send email(mock):打印到屏幕
图说:五个格子、两种 mock、三次 CoT。最终产出的主题行是
「Ignite Your Culinary Adventure with Our Recipe Integration Plug-in」,
正文夸完匠心再谈变现,落款——Albert Berryman, Director of Innovation。
落款是作者埋的彩蛋:两人的姓 Berryman 和名 Albert 各取一半拼出的化名—— 一家并不存在的 JivePlug-ins 公司的「创新总监」28。 这个例子的价值在于它是能跑通的全量小样本:mock 两端,把设计力气全花在中段, 正是起步期的正确姿势。
随后是优化清单,每一条都对应可观察的毛病29: 创意同质化(满屏 virtual try-on 和公益积分榜)→ 强化脑暴步骤避开俗手; 点子没法落地 → 追加可行性评估子流程;质量不稳 → 任务级或流程级挂 Reflexion; 以及从第一天就开始攒输入输出样本——离线上 harness 测试(下一章的主角)靠它, DSPy、TextGrad 这类自动优化框架也吃这份口粮;上线后采真实流量抽样,用 A/B 对比着持续改进30。
3.8 高级玩法:把方向盘还给模型的三个档位
基础工作流的缺点是死板。作者给了三个加自治程度的档位,并提前警告: 自主性越高,系统越不稳定、越难推理31:
- 让 LLM 给工作流派单:保持任务集合不变,把「派单」本身做成一个带工具的 会话 agent;再进一步,连任务自身也是 agent——所谓 agent of agents, 用 finish 工具交付(ReAct 论文的 Finish 即此意);最激进的是现场造任务: 工作流 agent 现写系统消息、现挑工具,组一个临时 agent;外加一份不断重新排序优先级的任务清单32;
- 有状态的任务 agent:不再「事项流转、任务干完就忘」,而是每个工件绑定一个常驻 agent—— 网页文件配一个代码 agent,UI 改了它会收到消息、改自己的文件、再把消息传给下游。 依赖图要先立好规矩防循环引用;好处是用户可以直接找「管这个文件的 agent」当面谈33;
- 角色与委派:AutoGen 的 Assistant/UserProxy 二人转,或多角色的 group chat manager 圆桌;CrewAI 则给每个 agent 配 role/goal/backstory/tools, 支持 sequential/hierarchical 两种流程(consensual 协作模式写作时还在规划中)34。
书末的练习题透着作者的顽皮:让你亲手搓 CodeAssistant + UserProxy, 然后围观它们会不会陷入无限互道再见——"Goodbye! Thanks again." / "You bet, thank you too!"35
4. 作者的判断与证据
有出处的事实:
- Umar 的批量邮件是真事(书引了社交媒体串与图),Sock-cess Stories 是 GPT-4 真实产出的最佳创意8;
- Airflow/Luigi 以 DAG 为骨架是业界现状,非作者杜撰24;
- AutoGen/CrewAI 的机制描述忠于当时版本,CrewAI 的 consensual 模式注明未上线34。
作者的立场(工程判断,非测量结论):
- 三次对话 agent 失败的演示是作者自己构造的对照实验,细节(搜索词、占位符) 取自他们的实际运行;结论「系统消息只是强烈建议」与第 10 章「描述里写『先问』没用」一脉相承7;
- 全章末句给出的总律:simpler is almost always better——能用传统软件就不用 LLM, 必须用时也要把 LLM 锁在任务里、外面用确定性图串联;高阶形态留给确实需要的场景36。
判断(我们的,不是书里的): 「通用性-强度」这条轴不只能解释工具选择, 还能预测故障模式:越靠近通用端的系统(agent),故障表现为「随机跑偏」, 修复手段是人拉一把;越靠近强度端的系统(工作流),故障表现为「某格坏了」, 修复手段是修那一格。运维策略应该跟着自己在轴上的位置走。 如果错,会错在: 如果模型能力跃迁让 agent 在宽域上 也稳定, 「位置决定故障形态」的分界会模糊——但截至本书出版, 作者实测的 Shopify 三连败仍是反例。
5. 边界与局限
- 全书刻意不绑框架:LangChain/Semantic Kernel/AutoGen/DSPy 只点名不展开, 学到的是套路而非 API;框架演进快,实践时要回官方文档对齐37;
- 主干例子规模很小(五个任务、两端 mock),真实生产里的同时大量请求、重试策略、 多租户隔离不在射程内;
- 高阶三档都在前沿地带,作者自认不够稳定,当思路读,别当施工图抄31;
- 「将来也许真能随手起一个工作流」式的展望属于作者的期许,不是当下能力36。
6. 可带走的
主走查一行回顾:HTML 进 → 六问摘要 → 脑暴选优 → CoT 定策略再写邮件 → 落款 Albert Berryman 的成品出——没有一个格子试图一次做完五件事。
- AGI 未至之前,通用性 买不来可靠性;大目标一律切块;
- 接口先行:输入输出的 schema 定死,how 可以慢慢磨;
- 要结构就上工具法(假工具 + tool_choice 强制);要文本就模板法(prefix/suffix 夹住正文);
- 任务失灵先分诊:人都做不出来?改料。人做得出来它做不出来?上 CoT 或 Reflexion;
- 能不上 LLM 就不上;不同难度配不同价位的模型;不可逆动作必有人审;
- 默认 DAG,环形是止血手段不是架构偏好,且要把递归藏进单个任务;
- 攒 I/O 样本从第一天开始——评估(下一章)和自动优化(DSPy/TextGrad)都吃它;
- 自治度是个旋钮,拧一格多一分不稳;每拧一格前先问这格里的人还剩多少作用;
- 高阶组合术(agent of agents、有状态任务 agent、AutoGen/CrewAI)记名字就好, 动手时再看文档。
7. 原文地图
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 通用性换强度 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:14(搜「marked deficiencies in reasoning」) · :30(搜「rigid structure to guide」) |
| Shopify 任务清单与真事 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:56(搜「website HTMLs」) · :67(搜「definitive yes」) · :72(搜「Sock-cess Stories」) |
| 三连败实录 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:80(搜「You can do anything」) · :96(搜「best Shopify storefronts 2024」) · :98(搜「your_name」) · :118(搜「strong suggestion and nothing more」) |
| 无工作单元之痛 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:113(搜「units of work」) |
| 五步法与模块化 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:133(搜「Define goal」) · :146(搜「because it is modular」) |
| schema 两张表 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:186(搜「550e8400」) · :193(搜「subject_line」) |
| how 可以软 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:203(搜「rigidly defined」) |
| 模板法夹住正文 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:219(搜「LangChain encourages」) · :250(搜「We hope to hear from you soon」) |
| 工具法骗结构 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:280(搜「saveRestaurantDataToDatabase」) · :308(搜「tool_choice parameter」) · :315(搜「structured outputs」) |
| 两类失效 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:320(搜「tried to do it yourself」) · :323(搜「overly complex」) |
| 四招提质量 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:341(搜「think step-by-step」) · :350(搜「on the Opus」) · :365(搜「referred to as」) · :372(搜「new prompt that will include the task requirements」) |
| 别滥用 LLM | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:393(搜「BERT-based classifier」) · :401(搜「lightweight, cheap, self-hosted」) |
| 拓扑三分 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:426(搜「all the same thing」) · :435(搜「email composer」) · :451(搜「Airflow and Luigi」) · :479(搜「number of attempts」) |
| 批 vs 流 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:486(搜「known and finite」) |
| 主走查实现细目 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:518(搜「praiseworthy」) · :524(搜「two-step process that first brainstorms」) · :530(搜「devise a strategy」) |
| Fly By Jing 成品 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:545(搜「Recipe Integration Plug-in」) · :572(搜「Albert Berryman」) |
| 优化清单 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:580(搜「virtual try-on」) · :585(搜「selected concepts are feasible」) · :597(搜「DSPy and TextGrad」) · :601(搜「live-traffic A/B tests」) |
| 高阶三档 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:619(搜「inherently less stable」) · :642(搜「finish tool」) · :654(搜「work list algorithm」) · :666(搜「code-writing agent」) · :683(搜「circular dependencies」) |
| AutoGen/CrewAI | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:718(搜「group chat manager」) · :720(搜「still in planning」) |
| 练习与总结 | Chapter 9 | text/12-ch09-chapter-9-llm-workflows.txt:737(搜「endless, back-and-forth series」) · :752(搜「simpler is almost」) |