请提供您需要优化的【原始标题】,我将据此生成一个符合SEO规范的优化标题。
一、一个复杂Prompt引发的执行困境
设想你让大语言模型处理这个任务:
你将300条评论一次性输入,撰写了800字的Prompt指令。结果呢?模型经常遗漏第三个关键痛点;JSON字段的key时而中文时而英文;字数限制形同虚设。
问题不在模型本身——而是你的Prompt在强迫模型“多任务并行”。
Java开发者都深谙一条准则:一个方法如果超过50行还在处理三件事,代码审查绝不会通过。你不会写一个 parseValidatePersistAndNotify() 方法,为什么要求模型在一个Token窗口内同时完成提取、排序、总结、格式化?
这正是**链式提示(Chain Prompting)**要解决的核心痛点。
二、Java类比:从上帝方法到责任链
2.1 反模式:上帝Prompt
// 你绝不会这么写Java代码
public String processReviews(String allReviews) {
// 提取痛点
List<String> painPoints = extractPainPoints(allReviews);
// 排序
painPoints.sort(bySeverity());
// 总结
String summary = summarize(painPoints);
// 格式化JSON
return toJson(summary);
}
如果这四个操作全部塞进一个方法、没有任何清晰的边界、还期望返回值严格符合规范——这就是大多数“超级Prompt”的真实写照。
2.2 正解:链式调用
// 这才是工程化的写法
public ReportJson processReviews(String allReviews) {
List<PainPoint> points = painPointExtractor.extract(allReviews);
List<PainPoint> sorted = severitySorter.sort(points);
String summary = reportSummarizer.summarize(sorted, 200);
return jsonFormatter.format(summary);
}
链式提示的核心思路与此完全一致:将一次大型LLM调用拆解为多次小型调用,每个环节只让模型专注一件事,前一步的输出自然成为后一步的输入。
三、链式提示的三个核心原则
原则1:单一职责
每一步Prompt只描述一个明确任务。避免出现“请提取并总结”——这实际上是两个独立步骤。
错误示例:
请阅读评论,提取痛点并按严重程度排序,然后写总结。
正确示例(第一步):
以下是一批产品评论。请提取每个用户提到的具体痛点。只输出痛点列表,不要排序,不要总结。
格式:每行一个痛点,格式为 "- [严重程度:高/中/低] 痛点描述"
原则2:输出契约
每一步的输出格式必须在Prompt中显式定义。因为下一步的Prompt会直接引用上一步的输出,格式不一致会导致整条链路断裂。
技巧:让模型输出Markdown结构化内容(标题、列表、代码块),比JSON更具备容错性。除非最终步骤确实需要JSON,否则中间环节优先使用Markdown。
原则3:上下文传递
将上一步的输出原封不动注入下一步Prompt。不要手动编辑——一旦引入人工修改,就增加了新的变量,出问题时无法准确定位是哪个环节的偏差。
四、完整代码实现
下面是一个完整的链式提示实现。场景:分析用户对一款SaaS产品的反馈评论,输出结构化分析报告。
"""链式提示完整示例 —— 评论分析流水线
依赖: pip install openai"""
import json
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
MODEL = "qwen-plus"
def call_llm(system_prompt: str, user_prompt: str, temperature: float = 0.3) -> str:
"""单步LLM调用封装。类比Java里的RestTemplate.postForObject()"""
response = client.chat.completions.create(
model=MODEL,
temperature=temperature,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
)
return response.choices[0].message.content
# ---- 步骤1: 提取痛点 ----
def step1_extract_pain_points(reviews: str) -> str:
"""类比Java:PainPointExtractor.extract(String reviews) -> List
运行结果
[Step 1/4] 提取痛点...
提取结果:
- [严重程度:高] 界面太卡,每次点按钮要等3秒,严重影响效率
- [严重程度:高] 如果下个月还不支持批量导出就换产品
- [严重程度:中] 缺少数据导出功能
- [严重程度:中] CSV导入经常乱码
- [严重程度:中] API文档全是英文
...
[Step 2/4] 按严重程度排序...
排序结果:
- [严重程度:高] 界面太卡,每次点按钮要等3秒,严重影响效率
- [严重程度:高] 如果下个月还不支持批量导出就换产品
- [严重程度:中] 缺少数据导出功能
- [严重程度:中] CSV导入经常乱码
...
[Step 3/4] 生成总结...
总结: 用户最不满的是性能卡顿和关键功能缺失,已有流失风险。中等痛点集中在数据导入导出不完善和本地化不足。建议优先优化响应速度并尽快上线批量导出,同时补充中文文档和移动端适配。
[Step 4/4] 格式化输出...
五、什么时候该用链式提示
并非所有场景都需要链式结构。判断标准很直接:
场景 | 是否用链 | 原因 ------ | --------- | ------ 简单问答(“什么是REST”) | ❌ 不用 | 一步就能回答好 翻译+润色 | ⚠️ 可选 | 两步可以提升质量,但一步也够用 提取+分类+排序+总结+格式化 | ✅ 必须用 | 多维度任务,单prompt必丢信息 需要中间结果验证的场景 | ✅ 必须用 | 链式天然支持断点检查 不同步骤需要不同temperature | ✅ 必须用 | 提取要低温(0.1),总结要中温(0.5)
关键判断: 问自己“我写Java会把这些逻辑放在一个方法里吗?”如果答案是不会——就应该拆分。
六、进阶技巧
6.1 分支与条件
链不一定是线性的。你可以根据中间结果决定下一步走向,就像if-else:
pain_points = step1_extract_pain_points(reviews)
high_severity_count = pain_points.count("[严重程度:高]")
if high_severity_count >= 3:
# 走危机处理分支
result = crisis_analysis(pain_points)
else:
# 走常规分析分支
result = routine_analysis(pain_points)
6.2 并行步骤
相互独立的步骤可以并行执行,缩短总耗时:
import concurrent.futures
with concurrent.futures.ThreadPoolExecutor() as executor:
future_sentiment = executor.submit(analyze_sentiment, reviews)
future_pain_points = executor.submit(extract_pain_points, reviews)
future_keywords = executor.submit(extract_keywords, reviews)
sentiment = future_sentiment.result()
pain_points = future_pain_points.result()
keywords = future_keywords.result()
6.3 重试与降级
链式调用中任何一步都可能失败(API超时、输出格式异常)。需要加防护:
def step_with_retry(step_fn, input_data, max_retries=2):
"""类比Java的@Retryable注解"""
for attempt in range(max_retries + 1):
try:
result = step_fn(input_data)
if result and len(result) > 10: # 基本校验
return result
except Exception as e:
if attempt == max_retries:
raise
print(f"步骤失败,重试 {attempt + 1}/{max_retries}: {e}")
raise RuntimeError("所有重试均失败")
七、常见坑与解法
坑1:中间输出格式漂移
模型偶尔会“自作主张”在输出里加一段解释性文字,破坏格式约定。
解法: temperature设为0或0.1,system prompt里加上“不要添加任何解释,只输出指定格式的内容”。
坑2:错误传播放大
步骤2基于步骤1的输出,如果步骤1就错了,后续全错。
解法: 关键链路的步骤1加人工审核断点,或者设一个格式校验器,不符合预期就重试。
坑3:延迟叠加
4步链式调用 = 4次API往返,总延迟是单次调用的4倍。
解法: 用6.2的并行化减少延迟;非关键步骤用更快的模型(如qwen-turbo替代qwen-plus)。
八、总结
链式提示的本质是用工程化思维来组织Prompt。你把一个复杂任务拆成单一职责的小步骤,每步独立测试、独立优化、出错独立重试——这和写Java代码时拆Service、拆方法的思路完全一致。
核心原则就三个:
- 单一职责——每步只干一件事
- 输出契约——每步约定好输出格式
- 上下文传递——上一步输出原样传给下一步
