复杂任务怎么拆成多步 Prompt?
一句话回答
把复杂任务拆成几个简单的步骤,每一步用一个专门的 Prompt,上一步的输出作为下一步的输入,由代码串起来,这就是 Prompt 链。常见模式有顺序链、路由、并行后汇总、生成后校验。好处是每一步任务单一、更容易写好,还能单独测试、观测和更换模型;代价是调用次数多,延迟和成本增加。执行路径由开发者在代码里确定,这是它和 Agent 的根本区别。
详细解析
为什么要拆
一个 Prompt 里塞进太多要求,模型容易顾此失彼;出了问题,也很难判断是哪个环节没做好。拆开之后:
- 每一步只做一件事,指令更短、更清晰
- 每一步可以选不同的模型和参数:分类用便宜的小模型,生成用更强的模型
- 步骤之间可以插入代码:校验、查数据库、执行业务规则
- 中间结果可见,出问题时能定位到具体的步骤
不需要拆的情况:任务本身简单,一次调用就能做好;步骤之间要共享大量上下文,拆开反而丢信息;对延迟非常敏感。
常见模式
| 模式 | 做法 | 例子 |
|---|---|---|
| 顺序链 | 上一步的输出作为下一步的输入 | 提取要点 → 写初稿 → 润色 |
| 路由 | 先分类,再交给对应的专用 Prompt | 客服问题先分成退款、技术、其他,再分别处理 |
| 并行后汇总 | 互不依赖的子任务并发执行,最后合并 | 代码审查分别检查安全、性能、可读性,再汇总成报告 |
| 生成后校验 | 生成者产出结果,评审者按标准检查,不通过就带着意见重写 | 生成客服回复后,检查是否承诺了政策以外的内容 |
设计要点
- 步骤之间传结构化数据:每一步输出 JSON 并校验,相当于定义了步骤之间的接口,见 怎么让大模型稳定地输出 JSON
- 在关键步骤之间加检查:不合格就提前结束或走兜底,不要让第一步的错误一路传到最后
- 只传下一步需要的信息,不要把所有中间结果都塞给每一步
- 每一步单独评测:给每个步骤准备小的测试集,效果变差时能定位到具体的步骤
- 记录每一步的输入、输出、耗时和 token,便于排查,见 链路追踪
- 评审要有明确的标准:能用规则检查的(长度、必含字段、禁用词)用代码检查;需要模型评审时给出检查清单,重写循环要设最大次数
和 Agent 的区别
Prompt 链的每一步、每个分支都是开发者预先写好的,路由也只是在几条预定的路径里选一条;Agent 则由模型在运行时决定下一步调用什么工具、做什么。步骤能预先确定时,优先用 Prompt 链,更可控,也更容易测试,见 工作流和 Agent 怎么选。
代码示例
客服工单处理:路由 → 专用 Prompt 生成回复 → 评审,不通过就带着意见重写。chatJson 是自己封装的函数:调用模型并用 zod 校验返回的 JSON;generateReply 用指定的 System Prompt 生成回复,有评审意见时附在消息里。
import { z } from 'zod'
const Category = z.object({ category: z.enum(['refund', 'bug', 'other']) })
const Review = z.object({ pass: z.boolean(), issues: z.array(z.string()) })
const REPLY_PROMPTS = {
refund: '你是退款专员。根据退款政策回答,不要承诺政策以外的金额和时间……',
bug: '你是技术支持。先确认问题现象和复现步骤,再给出排查建议……',
other: '你是客服助手。礼貌、简短地回答用户的问题……',
}
async function handleTicket(ticket: string) {
// 第 1 步:分类。任务简单,用小模型,temperature 设为 0
const { category } = await chatJson(Category, {
model: 'small-model',
temperature: 0,
prompt: `把工单分为 refund、bug、other 之一,输出 {"category": "..."}。\n<ticket>\n${ticket}\n</ticket>`,
})
// 第 2 步:用对应类别的专用 Prompt 生成回复
let reply = await generateReply(REPLY_PROMPTS[category], ticket)
// 第 3 步:评审,不通过就带着意见重写,最多重写 2 次
for (let round = 0; ; round++) {
const review = await chatJson(Review, {
temperature: 0,
prompt: `检查客服回复:是否回答了用户的问题、是否承诺了政策以外的内容、语气是否礼貌。输出 {"pass": true 或 false, "issues": ["问题描述"]}。\n<ticket>\n${ticket}\n</ticket>\n<reply>\n${reply}\n</reply>`,
})
if (review.pass) return { category, reply }
if (round === 2) return { category, reply: null } // 仍然不合格,转人工处理
reply = await generateReply(REPLY_PROMPTS[category], ticket, review.issues)
}
}
面试官可能追问
链条是不是越长越好?
不是。每一步都有出错的可能,错误会沿着链条累积:假设每一步的成功率是 95%,串联 5 步后,端到端的成功率只有约 77%。步骤越多,延迟和成本也越高。能合并的步骤就合并,以端到端的评测结果为准。
生成后校验时,评审者能用同一个模型吗?
可以,但同一个模型有相同的盲区,还可能偏向自己生成的内容。能用规则检查的尽量用代码;必须让模型评审时,给出明确的检查清单,重要场景可以换一个模型来评审,见 LLM-as-a-Judge。
多步调用延迟太高,怎么优化?
互不依赖的步骤并发执行;简单的步骤用小模型;固定的前缀利用提示缓存;最后一步用流式输出,让用户尽早看到内容;按条件跳过步骤,比如只对高风险的回复做评审。
中间某一步失败了怎么办?
超时、限流这类可重试的错误,做有限次重试;校验不通过时,带上错误信息让模型修正;仍然失败就走兜底路径,比如返回默认结果或转人工。长流程要保存中间结果,失败后从断点继续,而不是从头再来。
易错点
- 步骤之间传自由文本,下一步解析不稳定
- 没有中间检查,第一步的错误一路传到最后
- 为了拆而拆,简单任务拆成多步,反而更慢、更贵
- 评审和重写的循环不设上限,模型反复修改停不下来
AI 模拟面试官
用自己的话回答,AI 对照参考答案打分、指出遗漏,再追问,最多 3 轮
这道题你掌握了吗?
选一个最接近的状态,没掌握的题会出现在"我的进度 · 待复习"里。
学习记录暂存在本机浏览器。登录后自动同步到账号,换设备也能看到。