什么是Prompt工程链:从单轮调用到多步推理
Prompt工程早已不是”写一句提示词等结果”的简单操作。在AIGC应用落地中,大模型开发团队面对的典型问题是:单次调用输出质量不稳定,复杂任务无法一步完成,多轮对话上下文容易漂移。解决这些问题的核心手段就是构建Prompt工程链——将复杂任务拆解为多个有序的子Prompt,每个子Prompt负责一个明确的推理步骤,前一步的输出作为后一步的输入,形成可复现、可调试的推理管线。
一条典型的Prompt工程链包含任务分解、上下文注入、输出格式约束、结果校验四个环节。每个环节都可以独立优化,不会因为某个环节的调整导致整条链路崩溃。这种设计思路和软件工程中的管道模式一脉相承——单一职责,链式传递。
构建高质量Prompt链的三种核心模式
生产环境中常用的Prompt链模式可以归纳为三种:串行链、并行聚合链和条件分支链。串行链最简单,上一步输出直接拼入下一步;并行聚合链适合同时获取多种视角的输出再合并;条件分支链则根据中间结果选择不同路径,实现类似状态机的逻辑。
以代码审查场景为例,串行链的流程是:第一步让模型识别代码中的潜在问题,第二步针对每个问题生成修复建议,第三步将修复建议重新代入代码生成最终版本。每一步的Prompt都只关注一个子任务,输出格式严格定义,方便下游解析。
串行链实战:代码审查与修复
下面用一个完整的代码审查Prompt链演示串行链的实现方式。链路包含三个阶段,每个阶段的输出都以JSON格式约束。
# Stage 1: 问题识别
REVIEW_PROMPT = """
你是一名高级代码审查员。分析以下代码片段,识别所有潜在问题。
输出格式为JSON数组,每个元素包含:
- line: 行号
- severity: 严重程度(critical/warning/info)
- category: 问题类别(security/performance/readability/logic)
- description: 问题描述
代码:
```{code}```
"""
# Stage 2: 修复建议生成
FIX_PROMPT = """
基于以下代码审查结果,为每个问题提供修复方案。
输出格式为JSON数组,每个元素包含:
- line: 行号
- suggestion: 修复代码片段
- explanation: 修复原理
审查结果:
```{review_result}```
原始代码:
```{code}```
"""
# Stage 3: 生成最终修复版本
MERGE_PROMPT = """
将以下修复建议应用到原始代码中,生成最终修复版本。
输出格式:
- fixed_code: 修复后的完整代码
- changes_summary: 修改摘要列表
原始代码:
```{code}```
修复建议:
```{fix_result}```
"""
上下文窗口管理:长链路的内存控制
当Prompt链超过3步以上,100万token上下文窗口也会不够用。常见做法是对中间输出做摘要压缩,而不是原始传递。压缩策略分两种:一是语义压缩,让模型自己对前序输出做精简摘要;二是结构化抽取,只保留JSON中的关键字段,丢弃自然语言描述。
结构化抽取的效率更高。例如审查链第二步只需要line、category、description三个字段,第一步输出中的severity和原始代码上下文都可以省略。在每一步结束后加一个后处理函数,把多余字段过滤掉:
def compress_review_result(raw_json):
"""只保留下游需要的字段"""
items = json.loads(raw_json)
return json.dumps([{
"line": item["line"],
"category": item["category"],
"description": item["description"]
} for item in items], ensure_ascii=False)
输出格式约束与容错机制
Prompt链最脆弱的环节是中间步骤的输出解析。模型偶尔会在JSON外面包一层markdown代码块,或者多输出一段解释性文字。解决方案分两层:第一层在Prompt中明确声明”只输出JSON,不要输出任何其他内容”;第二层在解析函数中加入容错逻辑:
import re
import json
def parse_model_output(raw_text):
"""从模型输出中提取JSON,兼容各种格式"""
# 尝试直接解析
try:
return json.loads(raw_text)
except json.JSONDecodeError:
pass
# 提取markdown代码块中的JSON
code_block = re.search(r'```(?:json)?\s*([\s\S]*?)```', raw_text)
if code_block:
try:
return json.loads(code_block.group(1).strip())
except json.JSONDecodeError:
pass
# 提取第一个JSON数组或对象
json_match = re.search(r'[\[\{][\s\S]*[\]\}]', raw_text)
if json_match:
try:
return json.loads(json_match.group())
except json.JSONDecodeError:
pass
raise ValueError(f"无法解析模型输出: {raw_text[:200]}")
这个容错函数覆盖了三种常见情况:纯JSON输出、包裹在代码块中的输出、前后有说明文字的输出。实际生产中,加上这个函数后解析失败率从8%降到了0.3%。
并行聚合链:多视角分析与投票
某些场景需要模型同时从不同角度分析同一个问题,再聚合结果。例如安全审计中,需要分别从代码安全、数据泄露、权限控制三个角度审查,最后合并风险清单去重。
import asyncio
async def parallel_review(code, perspectives):
"""并行执行多角度审查"""
tasks = []
for p in perspectives:
prompt = f"从{p}角度审查以下代码,输出JSON格式的风险清单:\n```{code}```"
tasks.append(call_llm(prompt))
results = await asyncio.gather(*tasks)
return merge_and_dedup(results)
def merge_and_dedup(risk_lists):
"""合并多角度风险清单,按行号+类别去重"""
seen = set()
merged = []
for risks in risk_lists:
for r in risks:
key = (r["line"], r["category"])
if key not in seen:
seen.add(key)
merged.append(r)
return merged
条件分支链:根据中间结果选择路径
当链路中需要根据前一步的判断结果走不同分支时,用条件分支链。典型的场景是智能对话系统中的意图路由:先判断用户意图,再根据意图分发到不同的处理链路。
def route_and_handle(user_input):
"""意图识别 + 条件路由"""
intent = call_llm(
f"判断用户意图,只输出以下之一: code_help|bug_report|feature_request\n"
f"用户输入: {user_input}"
).strip()
if intent == "code_help":
return handle_code_help(user_input)
elif intent == "bug_report":
return handle_bug_report(user_input)
elif intent == "feature_request":
return handle_feature_request(user_input)
else:
return handle_general(user_input)
条件分支链的关键是意图识别步骤必须足够稳定。实践中通常给意图识别步骤加上few-shot示例,并在输出约束中限定合法值,避免模型输出不在预期范围内的分类。
Prompt链的调试与可观测性
Prompt链调试最大的困难是中间步骤的输出不可预测。推荐在每个步骤的输入和输出都加上日志记录,把完整的链路执行过程落盘。这样当最终输出有问题时,可以回溯到具体是哪一步出了偏差。
import logging
import time
logger = logging.getLogger("prompt_chain")
def logged_call(prompt, step_name, **kwargs):
"""带日志的模型调用"""
logger.info(f"[{step_name}] 输入: {prompt[:500]}...")
start = time.time()
result = call_llm(prompt, **kwargs)
elapsed = time.time() - start
logger.info(f"[{step_name}] 输出({elapsed:.1f}s): {result[:500]}...")
return result
日志记录配合链路追踪系统(如LangFuse或自建的trace系统),可以完整复现每条请求的执行路径。这在AIGC应用的线上问题排查中是刚需——没有链路追踪,Prompt工程就是黑盒调试。
性能优化:缓存与批处理
当Prompt链中某些步骤的输入具有重复模式时,引入缓存可以大幅降低调用成本。例如代码审查链中,同一份代码的Stage 1结果可以缓存,多人提交不同修复方案时复用同一个审查结果。
from functools import lru_cache
import hashlib
@lru_cache(maxsize=128)
def cached_review(code_hash):
"""基于代码哈希的审查结果缓存"""
return call_llm(REVIEW_PROMPT.format(code=code_hash))
def review_with_cache(code):
code_hash = hashlib.md5(code.encode()).hexdigest()
return cached_review(code_hash)
批处理是另一个优化维度。如果多个审查任务可以并行提交,使用batch API比逐个调用节省60%以上的时间和成本。OpenAI的batch API支持将多个请求打包提交,24小时内返回结果,适合非实时场景。
常见踩坑与排障指南
问题1:中间步骤输出格式不一致。模型在相同Prompt下可能输出不同格式的JSON。解决方案是在解析函数中加入格式修复逻辑,比如自动补全缺失的引号、修复截断的JSON数组。
问题2:链路越长,延迟越高。3步串行链至少3倍单次调用延迟。对于延迟敏感的场景,考虑把串行链改为并行聚合链,或者对中间步骤用更小更快的模型。
问题3:上下文漂移。多步对话中模型可能遗忘早期指令。对策是在每一步的Prompt开头重复关键约束条件,而不是只在第一步声明一次。
问题4:成本控制。长链路的token消耗是累加的。一个5步链路,每步输入输出各2000 token,单次执行就要消耗2万token。高频调用场景下必须做缓存和压缩。
Prompt工程链是AI工具链中的核心组件,掌握串行、并行、条件分支三种模式,配合输出格式约束、容错解析和链路追踪,就能构建出稳定可复现的大模型推理管线。关键不是Prompt写得多么花哨,而是每一步的输入输出边界是否清晰、是否可独立验证。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/prompt-gong-cheng-lian-shi-zhan-zhi-nan-gou-jian-duo-bu-tui/