Prompt-Chaining-把复杂任务拆成流水线
> **本文适合谁**
Prompt Chaining:把复杂任务拆成流水线
本文适合谁
遇到单个 Prompt 搞不定的复杂任务的开发者。Prompt Chaining 是 Workflow 类 AI 应用的基础设计模式——每个 Prompt 只做一件事,前一步输出是下一步输入。
当一个任务足够复杂,单个 Prompt 就会开始失效。不是模型能力不够,而是让模型同时完成太多事情,本质上违背了注意力机制(模型处理文本时分配计算资源的方式,就像人的专注力有限一样)的工作方式。Prompt Chaining(提示词链,把一个大任务拆成多步)把大任务分解成一系列小 Prompt,每个 Prompt 只做一件事,前一步的输出成为下一步的输入,形成流水线。
为什么单个大 Prompt 会失效
Prompt Chaining 流水线——复杂任务拆分为串联的子任务,每步输出是下步输入
Token 限制:在上下文窗口有限的模型上,把所有指令、所有数据、所有格式要求塞进一个 Prompt,本身就会引发截断问题。即使是支持长上下文的模型,超长的 Prompt 也会导致推理成本急剧上升。
注意力分散:研究表明,当 Prompt 中包含大量不同性质的指令时,模型倾向于对每个子任务都做得"差不多",而不是把任何一个做好。让模型同时完成信息提取、逻辑推理和格式转换,往往不如分三步各做一遍。
调试困难:一个 500 字的 Prompt 输出了错误结果,无法定位是哪个环节出了问题。拆成链之后,在哪一步输出开始偏差,一目了然。
失效场景对比:
| 场景 | 单 Prompt 的问题 | 链式方案 |
|---|---|---|
| 长文档摘要再分析 | 文档太长,摘要质量差 | 先分块摘要,再合并摘要,再分析 |
| 多步骤数据转换 | 中间状态不透明,错误难追踪 | 每步独立验证,失败可重试单步 |
| 条件分支处理 | 复杂 if-else 逻辑写进一个 Prompt,极易混乱 | 先意图识别,再路由到专用 Prompt |
| 多角色协作 | 不同角色的约束相互干扰 | 每个角色独立 Prompt,输出传递 |
三种链的模式
模式一:线性链
最简单的模式,前一步的输出直接作为下一步的输入,形成单向流水线。
LCEL 实现(LangChain Expression Language,LangChain 提供的链式调用语法,用 | 符号把多个步骤串联起来,类似 Unix 管道):
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser, JsonOutputParser
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
# 步骤 1:从用户反馈中提取关键信息
extract_prompt = ChatPromptTemplate.from_template("""
从以下用户反馈中提取关键信息,以 JSON 格式输出:
{{
"product": "提到的产品名",
"issue_type": "问题类型(quality/delivery/service/other)",
"sentiment": "情绪(positive/neutral/negative)",
"key_complaint": "核心诉求一句话总结"
}}
用户反馈:{feedback}
""")
# 步骤 2:根据提取的信息生成回复策略
strategy_prompt = ChatPromptTemplate.from_template("""
根据以下用户反馈分析,制定客服回复策略:
分析结果:{extracted_info}
请输出:
1. 回复的语气(apologetic/neutral/positive)
2. 是否需要补偿(yes/no)
3. 解决方案要点(2-3 条)
""")
# 步骤 3:生成最终回复
reply_prompt = ChatPromptTemplate.from_template("""
根据以下策略,生成专业的客服回复:
策略:{strategy}
原始反馈:{original_feedback}
要求:语气真诚,不超过 150 字,给出明确的解决方案。
""")
# 构建线性链
step1 = extract_prompt | llm | StrOutputParser()
step2 = strategy_prompt | llm | StrOutputParser()
step3 = reply_prompt | llm | StrOutputParser()
# 用 RunnablePassthrough 传递原始数据(RunnablePassthrough 是 LangChain 的工具类,用来在链中传递原始输入数据,不做任何修改)
from langchain_core.runnables import RunnablePassthrough
linear_chain = (
RunnablePassthrough.assign(extracted_info=step1)
| RunnablePassthrough.assign(strategy=step2)
| step3
)
# 调用
result = linear_chain.invoke({"feedback": "收到的手机屏幕有划痕,物流也很慢,很失望"})
print(result)
模式二:条件链(意图识别→路由)
根据中间步骤的输出结果,决定走哪条分支。最典型的场景是意图识别后路由到不同的处理链。
from langchain_core.runnables import RunnableBranch, RunnableLambda
# 意图识别 Prompt
intent_prompt = ChatPromptTemplate.from_template("""
识别用户问题的意图类型,只输出一个词:
- order_query: 订单相关
- product_question: 产品咨询
- complaint: 投诉
- other: 其他
用户问题:{question}
""")
intent_chain = intent_prompt | llm | StrOutputParser()
# 三条专用处理链
order_chain = (
ChatPromptTemplate.from_template("你是订单专家,帮助用户解决:{question}")
| llm | StrOutputParser()
)
product_chain = (
ChatPromptTemplate.from_template("你是产品顾问,详细介绍:{question}")
| llm | StrOutputParser()
)
complaint_chain = (
ChatPromptTemplate.from_template("你是客诉专员,处理此投诉(语气诚恳):{question}")
| llm | StrOutputParser()
)
default_chain = (
ChatPromptTemplate.from_template("你是通用客服,回答:{question}")
| llm | StrOutputParser()
)
# 条件路由链
branch_chain = RunnableBranch(
(lambda x: "order" in x["intent"], order_chain),
(lambda x: "product" in x["intent"], product_chain),
(lambda x: "complaint" in x["intent"], complaint_chain),
default_chain # 默认分支
)
# 组合:先识别意图,再路由
conditional_chain = (
RunnablePassthrough.assign(
intent=lambda x: intent_chain.invoke({"question": x["question"]})
)
| branch_chain
)
result = conditional_chain.invoke({"question": "我的订单三天了还没发货"})
模式三:并行链
多个 Prompt 同时执行,再将结果聚合。适合需要多角度分析同一输入的场景。
from langchain_core.runnables import RunnableParallel
# 三个并行分析维度
security_chain = (
ChatPromptTemplate.from_template("从安全角度分析这段代码的风险:\n{code}")
| llm | StrOutputParser()
)
performance_chain = (
ChatPromptTemplate.from_template("从性能角度分析这段代码的问题:\n{code}")
| llm | StrOutputParser()
)
maintainability_chain = (
ChatPromptTemplate.from_template("从可维护性角度评估这段代码:\n{code}")
| llm | StrOutputParser()
)
# 聚合 Prompt
aggregate_prompt = ChatPromptTemplate.from_template("""
综合以下三个维度的代码分析,给出优先级排序的改进建议:
安全性分析:{security}
性能分析:{performance}
可维护性分析:{maintainability}
请输出按优先级排序的前 5 条改进建议。
""")
# 并行执行 + 聚合
parallel_chain = (
RunnableParallel(
security=security_chain,
performance=performance_chain,
maintainability=maintainability_chain
)
| aggregate_prompt
| llm
| StrOutputParser()
)
code_sample = """
def get_user(user_id):
query = f"SELECT * FROM users WHERE id = {user_id}"
return db.execute(query)
"""
result = parallel_chain.invoke({"code": code_sample})
三种链模式的汇总对比:
链的调试:定位哪一环出了问题
LangChain 内置的 verbose 模式可以打印每个步骤的输入输出:
from langchain.globals import set_verbose, set_debug
# 开启 verbose:打印每步的输入输出摘要
set_verbose(True)
# 开启 debug:打印完整的输入输出内容(更详细)
set_debug(True)
result = linear_chain.invoke({"feedback": "快递很慢"})
输出示例:
> Entering new chain...
[Step 1 - Extract]
Input: {"feedback": "快递很慢"}
Output: {"product": "unknown", "issue_type": "delivery", "sentiment": "negative", "key_complaint": "物流速度慢"}
[Step 2 - Strategy]
Input: {"extracted_info": "..."}
Output: "语气:apologetic;需要补偿:yes;方案:1. 道歉 2. 查询物流 3. 优惠券补偿"
[Step 3 - Reply]
...
当某一步输出明显偏离预期时,可以单独调用该步骤进行诊断,而不必重跑整条链:
# 单步调试
intermediate_output = step1.invoke({"feedback": "快递很慢"})
print("Step 1 输出:", intermediate_output)
# 验证 step2 是否能正确处理 step1 的输出
step2_output = step2.invoke({"extracted_info": intermediate_output})
print("Step 2 输出:", step2_output)
链的成本控制
不同步骤对模型能力的要求不同,可以用差异化的模型降低成本:
from langchain_openai import ChatOpenAI
# 廉价模型:用于简单的分类、提取、格式转换
cheap_llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
# 贵模型:只用于需要深度推理的核心步骤
powerful_llm = ChatOpenAI(model="gpt-4o", temperature=0)
# 成本优化的链:前后步骤用便宜模型,核心步骤用强模型
cost_optimized_chain = (
extract_prompt | cheap_llm | StrOutputParser() # 提取:便宜
| RunnablePassthrough.assign(strategy=
strategy_prompt | powerful_llm | StrOutputParser() # 推理:强模型
)
| reply_prompt | cheap_llm | StrOutputParser() # 格式化:便宜
)
典型成本对比(以 OpenAI 定价为参考):
| 模型 | 每百万 Token 成本(参考,以官网为准) | 适合的链步骤 |
|---|---|---|
| gpt-4o-mini | ~$0.15/$0.60 | 意图识别、格式转换、简单提取 |
| gpt-4o | ~$2.5/$10 | 复杂推理、代码生成、质量评估 |
| claude-haiku-4-5 | ~$0.25/$1.25 | 高并发、批量处理 |
| claude-opus-4-6 | ~$15/$75 | 最复杂的核心推理步骤 |
实战:需求文档→技术方案→代码骨架的三段链
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
cheap_llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.3)
strong_llm = ChatOpenAI(model="gpt-4o", temperature=0.3)
# 步骤 1:需求文档→结构化需求分析
requirements_prompt = ChatPromptTemplate.from_template("""
分析以下需求文档,输出结构化分析:
需求文档:
{requirement_doc}
请提取:
1. 核心功能列表(3-5 条)
2. 非功能需求(性能、安全、可扩展性)
3. 技术约束(语言、框架、已有系统)
4. 主要风险点
""")
# 步骤 2:结构化需求→技术方案
tech_design_prompt = ChatPromptTemplate.from_template("""
根据以下需求分析,设计技术方案:
需求分析:
{requirements_analysis}
请输出:
## 系统架构
(描述整体架构设计)
## 核心模块
(列出主要模块及职责)
## 技术选型
(框架、数据库、中间件选择及理由)
## 接口设计
(主要 API 端点,RESTful 格式)
""")
# 步骤 3:技术方案→代码骨架
code_skeleton_prompt = ChatPromptTemplate.from_template("""
根据以下技术方案,生成 Python 代码骨架(只需类/函数定义和注释,不需要完整实现):
技术方案:
{tech_design}
要求:
- 使用 FastAPI 框架
- 包含完整的类型注解
- 每个函数有 docstring
- 包含 Pydantic 数据模型定义
""")
# 组装三段链
pipeline = (
RunnablePassthrough.assign(
requirements_analysis=(requirements_prompt | strong_llm | StrOutputParser())
)
| RunnablePassthrough.assign(
tech_design=(tech_design_prompt | strong_llm | StrOutputParser())
)
| (code_skeleton_prompt | cheap_llm | StrOutputParser())
)
# 执行
requirement_doc = """
需要开发一个用户积分管理系统:
- 用户消费后自动累积积分
- 积分可以兑换商品或抵扣现金
- 积分有有效期(1年)
- 管理员可以手动调整积分
- 需要支持高并发(日活 10 万)
技术约束:现有系统使用 Python + PostgreSQL
"""
result = pipeline.invoke({"requirement_doc": requirement_doc})
print(result)
三段链的输出流向:
需求文档 (非结构化)
↓ [步骤 1:需求分析 - GPT-4o]
结构化需求分析 (Markdown)
↓ [步骤 2:技术方案 - GPT-4o]
详细技术方案 (Markdown)
↓ [步骤 3:代码骨架 - GPT-4o-mini]
Python 代码骨架 (可运行)
Prompt Chaining 的核心原则是:每个节点只负责一件事,每个节点的输出格式都是下一个节点期望的输入格式。做到这一点,复杂任务就变成了可测试、可替换、可独立优化的流水线。