写在前面
你有没有遇到过这样的情况:
给ChatGPT一个超长的需求,罗列了七八条要求,结果它要么漏掉某些要求,要么生成的内容质量参差不齐,让你不得不反复修改提示词。
你: 请阅读这篇5000字的技术文档,提取核心观点, 总结成3条要点,每条不超过50字, 语气要专业但不失幽默, 最后给出实践建议... AI: [生成了一堆内容,但要点太啰嗦,语气不对,还漏了实践建议] 你: (╯°□°)╯︵ ┻━┻问题出在哪?你把太多子任务塞进了一个Prompt!
今天要讲的**链式提示(Prompt Chaining)**就是解决这个问题的利器。它的核心思想很简单:
把复杂任务拆解成多个子任务,每个子任务用一个独立的Prompt,前一个任务的输出作为后一个任务的输入,形成一条"提示链"。
就像工厂流水线一样——每个工位专注做好一件事,最终产品质量反而更高。
这篇文章会带你搞懂:
- 什么是链式提示,为什么要用它
- 链式提示 vs 单一复杂Prompt的对比
- 文档问答的完整实战案例
- 链式提示的最佳实践和常见陷阱
- 如何在实际项目中应用链式提示
什么是链式提示?
核心定义
**链式提示(Prompt Chaining)**是一种将复杂任务分解为多个子任务的提示工程技术。每个子任务对应一个独立的Prompt,子任务的输出结果作为下一个Prompt的输入,形成一条处理链条。
一个形象的类比
想象你要制作一份复杂的年度报告:
方法A(单一Prompt): 给实习生一个超长的任务清单,期望他一次性完成所有工作
- 收集数据 + 清洗数据 + 分析数据 + 可视化 + 撰写报告 + 排版美化
- 结果: 实习生手忙脚乱,质量难以保证,出错难以定位
方法B(链式Prompt): 将任务分配给多个专人,形成流水线
- 数据分析师 → 清洗好的数据
- 统计专家 → 分析结果
- 设计师 → 图表可视化
- 撰稿人 → 最终报告
- 结果: 每个环节专业可控,质量有保障,出错容易定位
链式提示就是方法B——让AI在每个环节只专注做好一件事。
流程示意
复杂任务 ↓ [任务分解] ↓ 子任务1(Prompt 1) → 输出1 ↓ 子任务2(Prompt 2 + 输出1) → 输出2 ↓ 子任务3(Prompt 3 + 输出2) → 输出3 ↓ 最终结果为什么需要链式提示?
问题1: 单一Prompt的复杂度上限
当你把太多要求塞进一个Prompt时会发生什么?
❌ 超载的Prompt: 请阅读这篇论文,提取关键发现,评估方法的创新性, 指出潜在局限性,对比已有研究,总结实践价值, 用学术语气撰写,格式化为Markdown表格... 问题: - AI容易遗漏某些要求 - 无法保证每个子任务的质量 - 出错后难以定位问题环节 - 难以调整某个环节的处理逻辑问题2: 长上下文的"模糊中间"问题
即使模型支持128K的上下文窗口,也不意味着它能准确"记住"所有细节。把多个任务混在一起,容易导致:
- 前面的指令被后面的覆盖
- 中间的要求被"遗忘"
- 输出质量参差不齐
链式提示的优势
| 维度 | 单一复杂Prompt | 链式提示 |
|---|---|---|
| 可靠性 | ⭐⭐ 容易遗漏要求 | ⭐⭐⭐⭐⭐ 每步可验证 |
| 可控性 | ⭐⭐ 难以调整 | ⭐⭐⭐⭐⭐ 每步可独立优化 |
| 透明度 | ⭐ 黑盒处理 | ⭐⭐⭐⭐⭐ 过程可见 |
| 可调试性 | ⭐ 出错难定位 | ⭐⭐⭐⭐⭐ 精准定位问题环节 |
| 质量稳定性 | ⭐⭐ 波动大 | ⭐⭐⭐⭐ 更稳定 |
| 开发复杂度 | ⭐⭐⭐⭐⭐ 简单 | ⭐⭐ 需要设计链条 |
核心价值:
- 提高可靠性- 每个子任务独立处理,降低出错概率
- 增强透明度- 看到每一步的中间结果
- 便于调试- 精准定位问题环节
- 提升灵活性- 可以随时调整某个环节的逻辑
- 改善用户体验- 构建更智能的对话助手
实战案例:文档问答系统
让我们通过一个真实案例来理解链式提示的威力。
场景描述
任务: 根据一篇长文档回答用户问题
这是一个典型的RAG(检索增强生成)场景,但我们用链式提示来实现。
传统方法的问题
❌ 单一Prompt方法: 将整篇文档和问题一起扔给AI,让它直接回答 问题: 1. 文档太长,AI容易"迷失" 2. 无关内容干扰答案质量 3. 难以验证答案的来源 4. 成本高(处理整个文档)链式提示方案
我们将任务分解为两个步骤:
步骤1: 从文档中提取相关引文 ↓ 步骤2: 基于引文生成答案步骤1: 提取相关引文
设计思路: 先让AI从大文档中找出与问题相关的片段,缩小处理范围。
Prompt 1:
你是一个很有帮助的助手。你的任务是根据文档回答问题。 第一步是从文档中提取与问题相关的引文,由####分隔。 请使用<quotes></quotes>输出引文列表。 如果没有找到相关引文,请回应"未找到相关引文!"。 #### {{文档内容}} #### 用户问题: {{问题}}输入示例:
文档: [关于Prompt Engineering的维基百科文章] 问题: What are the prompting techniques mentioned in the document?输出1 (提取的引文):
<quotes>- Chain-of-thought (CoT) prompting[27] - Generated knowledge prompting[37] - Least-to-most prompting[38] - Self-consistency decoding[39] - Complexity-based prompting[41] - Self-refine[42] - Tree-of-thought prompting[43] - Maieutic prompting[45] - Directional-stimulus prompting[46] - Textual inversion and embeddings[59] - Using gradient descent to search for prompts[61][62][63][64] - Prompt injection[65][66][67]</quotes>关键设计点:
- ✅单一职责- 只负责提取引文,不负责回答
- ✅格式化输出- 使用XML标签包裹,便于后续处理
- ✅边界情况处理- 明确说明找不到时如何回应
- ✅分隔符使用- 用
####清晰分隔文档和指令
步骤2: 基于引文生成答案
设计思路: 使用第一步提取的精准引文,结合原始文档,生成高质量答案。
Prompt 2:
根据从文档中提取的相关引文(由<quotes></quotes>分隔) 和原始文档(由####分隔),请构建对问题的回答。 请确保答案准确、语气友好且有帮助。 #### {{文档内容}} #### <quotes> {{步骤1的输出}} </quotes> 用户问题: {{问题}}输出2 (最终答案):
文档中提到的提示技术包括: 1. Chain-of-thought (CoT) prompting - 思维链提示 2. Generated knowledge prompting - 生成知识提示 3. Least-to-most prompting - 从简到难提示 4. Self-consistency decoding - 自我一致性解码 5. Complexity-based prompting - 基于复杂度的提示 6. Self-refine - 自我精炼 7. Tree-of-thought prompting - 思维树提示 8. Maieutic prompting - 苏格拉底式提示 9. Directional-stimulus prompting - 定向刺激提示 10. Textual inversion and embeddings - 文本反转和嵌入 11. Using gradient descent to search for prompts - 使用梯度下降搜索提示 12. Prompt injection - 提示注入 每一种技术都采用独特的策略来增强或明确与大型语言模型的互动, 以产生期望的结果。关键设计点:
- ✅聚焦处理- 主要基于精选的引文,避免被无关内容干扰
- ✅保留上下文- 仍然提供原始文档,以防引文不够完整
- ✅明确要求- 指定答案的语气和特征
- ✅结构清晰- 清楚标识引文和文档的边界
对比分析
| 维度 | 单一Prompt | 链式Prompt |
|---|---|---|
| 准确率 | 中等,易遗漏 | 高,基于精确引文 |
| 成本 | 高(处理全文) | 低(聚焦相关部分) |
| 可验证性 | 低,无法追溯 | 高,可查看引文来源 |
| 调试难度 | 难,黑盒处理 | 易,每步可检查 |
| 响应速度 | 慢(处理量大) | 快(分步处理) |
链式提示的设计原则
原则1: 单一职责
每个Prompt只负责一个明确的子任务。
❌ 职责混乱: 提取引文 + 评估相关性 + 生成答案 + 格式化输出 ✅ 职责清晰: Prompt 1: 提取引文 Prompt 2: 评估相关性 Prompt 3: 生成答案 Prompt 4: 格式化输出原则2: 明确的输入输出格式
每个环节的输出格式要标准化,便于下一环节处理。
推荐格式: - JSON: {"key": "value"} - XML: <tag>content</tag> - Markdown: ## 标题\n内容 - 自定义分隔符: ####内容####示例:
// Prompt 1 输出(JSON格式){"relevant_quotes":["引文1","引文2"],"confidence":0.85}// Prompt 2 可以直接解析使用原则3: 错误处理和边界情况
每个环节都要考虑异常情况。
✅ 完善的Prompt: 你的任务是提取相关引文。 正常情况: 输出<quotes>引文列表</quotes> 找不到引文: 输出"未找到相关引文" 文档为空: 输出"文档为空,无法处理" 格式错误: 输出"文档格式错误"原则4: 可观测性
在链条中插入检查点,记录中间结果。
# 伪代码示例defprompt_chain(document,question):# 步骤1: 提取引文quotes=extract_quotes(document,question)log("Step 1 - Quotes extracted:",quotes)# 记录中间结果ifnotquotes:return"未找到相关信息"# 步骤2: 生成答案answer=generate_answer(document,quotes,question)log("Step 2 - Answer generated:",answer)# 记录结果returnanswer原则5: 适度拆分
不是拆得越细越好,要平衡复杂度和效率。
❌ 过度拆分: 步骤1: 分词 步骤2: 去停用词 步骤3: 提取关键词 步骤4: 计算相关性 步骤5: 排序 步骤6: 提取引文 → 太繁琐,效率低 ✅ 适度拆分: 步骤1: 提取相关引文(包含上述所有操作) 步骤2: 生成答案 → 简洁高效链式提示的典型场景
场景1: 内容生成流水线
用户需求 ↓ [需求分析] → 提取关键要素 ↓ [大纲生成] → 生成内容结构 ↓ [内容撰写] → 逐节撰写 ↓ [润色优化] → 改善表达 ↓ [格式化] → 最终输出实际应用: 自动化博客写作、报告生成
场景2: 代码审查助手
代码提交 ↓ [语法检查] → 发现语法问题 ↓ [逻辑分析] → 识别逻辑缺陷 ↓ [性能评估] → 标注性能瓶颈 ↓ [安全扫描] → 发现安全漏洞 ↓ [建议汇总] → 生成审查报告实际应用: Code Review机器人、PR助手
场景3: 客服对话系统
用户问题 ↓ [意图识别] → 判断问题类型 ↓ [知识检索] → 查找相关知识 ↓ [答案生成] → 生成初步答案 ↓ [情感优化] → 调整语气风格 ↓ [个性化] → 根据用户画像定制 ↓ 最终回复实际应用: 智能客服、产品咨询机器人
场景4: 数据分析流程
原始数据 ↓ [数据清洗] → 去除异常值 ↓ [特征提取] → 识别关键特征 ↓ [趋势分析] → 发现数据趋势 ↓ [可视化建议] → 推荐图表类型 ↓ [洞察总结] → 生成分析报告实际应用: 商业智能助手、数据报告生成器
实现链式提示的技术方案
方案1: 顺序链(Sequential Chain)
最简单的形式,线性执行。
defsequential_chain(prompts,initial_input):current_input=initial_inputforprompt_templateinprompts:# 填充当前输入到Prompt模板prompt=prompt_template.format(input=current_input)# 调用LLMcurrent_input=llm.generate(prompt)# 记录中间结果log_step(prompt,current_input)returncurrent_input使用示例:
prompts=["提取这段文本的关键词: {input}","基于这些关键词,生成3个相关问题: {input}","为每个问题提供简短答案: {input}"]result=sequential_chain(prompts,"人工智能正在改变世界...")方案2: 条件链(Conditional Chain)
根据中间结果决定下一步。
defconditional_chain(document,question):# 步骤1: 提取引文quotes=extract_quotes_prompt(document,question)# 条件判断if"未找到"inquotes:return"抱歉,文档中没有相关信息"# 步骤2: 评估引文质量quality=evaluate_quotes_prompt(quotes)ifquality<0.5:# 质量不够,尝试扩大搜索范围quotes=extract_quotes_with_relaxed_criteria(document,question)# 步骤3: 生成答案answer=generate_answer_prompt(document,quotes,question)returnanswer方案3: 并行链(Parallel Chain)
多个子任务并行执行后汇总。
importasyncioasyncdefparallel_chain(text):# 并行执行多个分析任务tasks=[analyze_sentiment(text),# 情感分析extract_entities(text),# 实体提取summarize_text(text),# 文本摘要detect_language(text)# 语言检测]# 等待所有任务完成results=awaitasyncio.gather(*tasks)# 汇总结果final_result=merge_results(results)returnfinal_result方案4: 使用LangChain框架
LangChain提供了现成的链式提示工具。
fromlangchain.chainsimportSequentialChainfromlangchain.promptsimportPromptTemplatefromlangchain.llmsimportOpenAI# 定义子链chain1=LLMChain(llm=OpenAI(),prompt=PromptTemplate(input_variables=["document","question"],template="从文档中提取与问题相关的引文:\n文档:{document}\n问题:{question}"),output_key="quotes")chain2=LLMChain(llm=OpenAI(),prompt=PromptTemplate(input_variables=["document","quotes","question"],template="基于引文回答问题:\n引文:{quotes}\n问题:{question}"),output_key="answer")# 组合成顺序链overall_chain=SequentialChain(chains=[chain1,chain2],input_variables=["document","question"],output_variables=["answer"])# 执行result=overall_chain({"document":doc,"question":q})print(result["answer"])最佳实践与常见陷阱
最佳实践
1. 设计可复用的Prompt模块
# 创建Prompt模块库classPromptModules:@staticmethoddefextract_quotes(document,question):returnf""" 从文档中提取与问题相关的引文。 文档:{document}问题:{question}输出格式: <quotes>引文列表</quotes> """@staticmethoddefgenerate_answer(document,quotes,question):returnf""" 基于引文生成答案。 引文:{quotes}问题:{question}要求: 准确、简洁、友好 """# 复用模块quotes=llm.generate(PromptModules.extract_quotes(doc,q))answer=llm.generate(PromptModules.generate_answer(doc,quotes,q))2. 添加验证步骤
defvalidated_chain(document,question):# 步骤1: 提取引文quotes=extract_quotes(document,question)# 验证: 检查引文格式ifnotis_valid_xml(quotes):quotes=fix_xml_format(quotes)# 验证: 检查引文相关性relevance=check_relevance(quotes,question)ifrelevance<0.6:log_warning("引文相关性较低")# 步骤2: 生成答案answer=generate_answer(document,quotes,question)# 验证: 检查答案完整性iflen(answer)<50:answer=regenerate_with_more_details(document,quotes,question)returnanswer3. 实现重试机制
defchain_with_retry(prompt,max_retries=3):forattemptinrange(max_retries):try:result=llm.generate(prompt)# 验证结果ifis_valid_result(result):returnresult log(f"结果验证失败,重试{attempt+1}/{max_retries}")exceptExceptionase:log(f"生成失败:{e}, 重试{attempt+1}/{max_retries}")return"处理失败,请稍后重试"常见陷阱
陷阱1: 信息丢失
❌ 问题: 步骤1: 从长文档提取摘要(200字) 步骤2: 基于摘要回答细节问题 → 摘要可能丢失了回答所需的关键细节 ✅ 解决: 步骤1: 提取相关段落(保留完整信息) 步骤2: 基于完整段落回答问题陷阱2: 过度依赖中间结果
❌ 问题: 步骤1提取的引文有误 → 步骤2基于错误引文生成答案 → 最终答案错误 ✅ 解决: - 在关键步骤添加验证 - 保留原始输入,让后续步骤可以"回头看" - 实现降级策略(如果中间结果质量差,回退到更保守的方法)陷阱3: 链条过长导致成本激增
❌ 问题: 10个步骤,每步调用一次GPT-4 → 成本是单次调用的10倍 ✅ 解决: - 合并不必要的步骤 - 非关键步骤使用更便宜的模型(如GPT-3.5) - 缓存重复调用的结果陷阱4: 忽略错误传播
❌ 问题: 步骤1的小错误 → 步骤2放大 → 步骤3继续放大 → 最终结果完全错误 ✅ 解决: - 在每个关键步骤进行结果验证 - 设置质量阈值,低于阈值则中止链条 - 实现"熔断机制",检测到异常立即停止进阶技巧
技巧1: 自适应链条
根据输入复杂度动态调整链条长度。
defadaptive_chain(text,question):# 评估复杂度complexity=assess_complexity(text,question)ifcomplexity<0.3:# 简单任务,单步处理returnsimple_answer(text,question)elifcomplexity<0.7:# 中等任务,两步处理quotes=extract_quotes(text,question)returngenerate_answer(text,quotes,question)else:# 复杂任务,完整链条quotes=extract_quotes(text,question)refined_quotes=refine_quotes(quotes,question)answer=generate_detailed_answer(text,refined_quotes,question)returnpolish_answer(answer)技巧2: 反馈循环
让后续步骤可以"回头"调整前面的结果。
defchain_with_feedback(document,question):# 第一轮: 提取引文quotes=extract_quotes(document,question)# 第二轮: 尝试生成答案answer=generate_answer(document,quotes,question)# 检查答案质量quality=evaluate_answer_quality(answer,question)ifquality<0.6:# 质量不够,反馈给第一步,重新提取更多引文quotes=extract_more_quotes(document,question,current_quotes=quotes)answer=generate_answer(document,quotes,question)returnanswer技巧3: 人机协作链
在关键节点引入人工确认。
defhuman_in_the_loop_chain(document,question):# 步骤1: AI提取引文quotes=extract_quotes(document,question)# 人工检查点ifrequire_human_review(quotes):quotes=human_review_and_edit(quotes)# 步骤2: 基于人工确认的引文生成答案answer=generate_answer(document,quotes,question)returnanswer实战:构建一个完整的文档问答系统
让我们把所有技巧整合起来,构建一个生产级的系统。
系统架构
classDocumentQASystem:def__init__(self,llm):self.llm=llm self.cache={}defanswer_question(self,document,question):"""主流程"""try:# 步骤1: 提取引文quotes=self._extract_quotes(document,question)# 验证引文质量ifnotself._validate_quotes(quotes):return"无法找到相关信息"# 步骤2: 生成答案answer=self._generate_answer(document,quotes,question)# 验证答案质量ifnotself._validate_answer(answer):# 重试一次answer=self._generate_answer(document,quotes,question)# 步骤3(可选): 润色答案final_answer=self._polish_answer(answer)returnfinal_answerexceptExceptionase:self._log_error(e)return"处理出错,请稍后重试"def_extract_quotes(self,document,question):"""步骤1: 提取引文"""cache_key=f"quotes_{hash(document)}_{hash(question)}"ifcache_keyinself.cache:returnself.cache[cache_key]prompt=f""" 你是一个很有帮助的助手。从文档中提取与问题相关的引文。 文档: ####{document}#### 问题:{question}输出格式: <quotes>引文列表</quotes> 如果没有相关引文,输出: 未找到相关引文 """quotes=self.llm.generate(prompt)self.cache[cache_key]=quotesreturnquotesdef_validate_quotes(self,quotes):"""验证引文质量"""if"未找到"inquotes:returnFalseifnotquotes.strip():returnFalse# 检查格式ifnot("<quotes>"inquotesand"</quotes>"inquotes):returnFalsereturnTruedef_generate_answer(self,document,quotes,question):"""步骤2: 生成答案"""prompt=f""" 根据引文回答问题。要求准确、简洁、友好。 引文:{quotes}问题:{question}请生成答案: """returnself.llm.generate(prompt)def_validate_answer(self,answer):"""验证答案质量"""iflen(answer)<20:returnFalseif"不知道"inansweror"无法回答"inanswer:returnFalsereturnTruedef_polish_answer(self,answer):"""步骤3: 润色答案(可选)"""# 简单处理,实际可以更复杂returnanswer.strip()def_log_error(self,error):"""错误日志"""print(f"Error:{error}")# 使用示例system=DocumentQASystem(llm=my_llm)answer=system.answer_question(document=long_document,question="What are the main findings?")print(answer)总结:链式提示的核心要点
关键概念
- 任务分解- 复杂任务拆解为子任务链条
- 流水线处理- 前一步输出作为后一步输入
- 单一职责- 每个Prompt专注一个子任务
- 可观测性- 记录每步中间结果,便于调试
适用场景
✅ 适合使用链式提示: - 多步骤处理任务(数据清洗 → 分析 → 可视化) - 需要中间验证的任务(提取 → 验证 → 使用) - 复杂的内容生成(大纲 → 撰写 → 润色) - 对话系统(意图识别 → 检索 → 生成回复) ❌ 不适合使用: - 简单的单步任务(如文本翻译) - 对延迟要求极高的场景(多次调用增加延迟) - 预算非常有限的场景(多次调用增加成本)实施清单
✅ 设计阶段: - [ ] 明确任务目标和约束条件 - [ ] 识别可拆解的子任务 - [ ] 设计每个子任务的输入输出格式 - [ ] 确定子任务之间的依赖关系 - [ ] 考虑异常情况和降级策略 ✅ 实现阶段: - [ ] 为每个子任务编写独立的Prompt - [ ] 实现链条编排逻辑 - [ ] 添加日志和监控 - [ ] 实现重试和错误处理机制 - [ ] 添加缓存优化性能 ✅ 验证阶段: - [ ] 测试每个子任务的独立功能 - [ ] 测试完整链条的端到端流程 - [ ] 验证异常情况的处理 - [ ] 评估性能和成本 - [ ] 收集用户反馈并迭代优化建议
| 优化目标 | 策略 |
|---|---|
| 降低成本 | 使用更便宜的模型处理简单步骤;缓存重复请求 |
| 提升速度 | 并行执行独立步骤;减少不必要的步骤 |
| 提高准确率 | 添加验证步骤;实现反馈循环;引入人工检查点 |
| 增强可靠性 | 实现重试机制;设置降级策略;完善错误处理 |
| 改善可维护性 | 模块化Prompt设计;统一输入输出格式;完善文档和注释 |
下一步行动
今天就试试:
- 找一个你当前使用的复杂Prompt
- 分析它可以拆解成几个子任务
- 为每个子任务设计独立的Prompt
- 实现简单的顺序链
- 对比链式提示前后的效果差异
本周目标:
- 在3个不同场景尝试链式提示
- 记录每个环节的中间结果
- 分析哪些环节可以进一步优化
- 总结自己的最佳实践
长期习惯:
- 遇到复杂任务先想:能否拆解成链条?
- 建立自己的Prompt模块库
- 持续优化常用的链条设计
- 关注链式提示的新模式和工具
记住:链式提示不是把简单问题复杂化,而是把复杂问题结构化。就像优秀的软件架构一样——模块清晰、职责明确、易于维护、便于扩展。
下次再遇到"一个Prompt搞不定"的复杂任务,别硬塞了,试试拆成链条,让AI在流水线上"专业分工"吧! 🔗✨
延伸阅读
- LangChain官方文档:Chains
- Anthropic: Prompt Chaining最佳实践
- OpenAI Cookbook: 复杂任务的分解策略
这篇文章对你有帮助吗?分享你的链式提示实践经验!