上下文工程为什么比Prompt工程更值得关注
大模型开发中,上下文工程(Context Engineering)正在成为比Prompt工程更高维度的技术方向。当模型支持的上下文窗口从4K扩展到128K乃至百万Token级别,核心挑战不再是”怎么写提示词”,而是”在有限窗口内放什么内容、按什么顺序放、如何压缩冗余信息”。上下文工程直接决定大模型的推理质量、成本和延迟,尤其在AI工具链和智能对话系统场景中,无效Token的累积会显著拉低响应准确率。
上下文窗口的Token管理涉及三个层面:输入侧的上下文裁剪与优先级排序、处理过程中的上下文压缩与摘要、输出侧的上下文窗口溢出处理。实际工程中,很多团队只关注Prompt模板设计,却忽略了系统消息、对话历史、工具调用结果、检索增强内容叠加后的Token总量控制。
Token预算分配与上下文优先级模型
在智能对话系统中,一个完整的上下文由多个部分组成:系统指令、用户画像、对话历史、检索文档、工具调用结果。每个部分对模型推理的贡献度不同,需要建立Token预算分配机制。
以下是一个上下文Token预算分配的Python实现:
import tiktoken
class ContextManager:
def __init__(self, model_name, max_tokens=128000):
self.encoder = tiktoken.encoding_for_model(model_name)
self.max_tokens = max_tokens
self.budget = {
'system': 2000,
'profile': 1000,
'history': 8000,
'retrieval': 60000,
'tools': 3000,
'response': 15000,
'buffer': 5000
}
def count_tokens(self, text):
return len(self.encoder.encode(text))
def allocate(self, context_parts):
# 按优先级分配Token预算,超出部分截断
priority = ['system', 'profile', 'tools', 'history', 'retrieval']
allocated = {}
remaining = self.max_tokens - self.budget['response'] - self.budget['buffer']
for key in priority:
budget = min(self.budget[key], remaining)
text = context_parts.get(key, '')
token_count = self.count_tokens(text)
if token_count <= budget:
allocated[key] = text
remaining -= token_count
else:
if key == 'history':
allocated[key] = self._truncate_history(text, budget)
elif key == 'retrieval':
allocated[key] = self._truncate_retrieval(text, budget)
else:
allocated[key] = self._truncate_tail(text, budget)
remaining -= budget
return allocated
def _truncate_history(self, text, budget):
# 对话历史截断:保留最近的对话轮次
messages = text.split('\n---\n')
result = []
token_sum = 0
for msg in reversed(messages):
tokens = self.count_tokens(msg)
if token_sum + tokens > budget:
break
result.insert(0, msg)
token_sum += tokens
return '\n---\n'.join(result)
def _truncate_retrieval(self, text, budget):
# 检索文档截断:按相关性分数保留高分片段
chunks = text.split('\n[CHUNK]\n')
result = []
token_sum = 0
for chunk in chunks:
tokens = self.count_tokens(chunk)
if token_sum + tokens > budget:
break
result.append(chunk)
token_sum += tokens
return '\n[CHUNK]\n'.join(result)
def _truncate_tail(self, text, budget):
# 尾部截断:保留前N个Token
tokens = self.encoder.encode(text)
truncated = tokens[:budget]
return self.encoder.decode(truncated)
这个实现的核心思路是给不同上下文来源设定Token预算上限,按优先级分配。系统指令和用户画像优先级最高,因为它们影响全局行为;检索文档预算最大但优先级最低,因为可以被裁剪而不影响基础对话能力。
对话历史压缩:滑动窗口与摘要链
长对话场景中,对话历史会持续增长。简单的滑动窗口截断会丢失早期关键信息。更有效的方案是摘要链(Summary Chain):将超出窗口的历史对话压缩为摘要,再将摘要纳入上下文。
class HistoryCompressor:
def __init__(self, llm_client, max_turns=10, summary_threshold=5):
self.llm = llm_client
self.max_turns = max_turns
self.summary_threshold = summary_threshold
def compress(self, messages):
# 将旧对话轮次压缩为摘要
if len(messages) <= self.max_turns:
return messages
recent = messages[-self.max_turns:]
old = messages[:-self.max_turns]
summaries = []
batch_size = self.summary_threshold
for i in range(0, len(old), batch_size):
batch = old[i:i+batch_size]
summary = self._summarize_batch(batch)
summaries.append(summary)
compressed = [
{'role': 'system', 'content': '以下是之前对话的摘要:\n' + '\n'.join(summaries)},
] + recent
return compressed
def _summarize_batch(self, batch):
# 调用模型生成对话摘要
transcript = '\n'.join([f'{m["role"]}: {m["content"]}' for m in batch])
prompt = f'请用2-3句话概括以下对话的关键信息,保留重要的事实和决策:\n{transcript}'
return self.llm.complete(prompt)
摘要链的代价是额外的LLM调用开销。工程上需要权衡:对话轮次较少时用滑动窗口即可,超过20轮的长对话场景才有必要引入摘要压缩。一个实践经验是将摘要阈值设定在对话历史Token占用超过总预算30%时触发。
检索增强生成中的上下文注入策略
RAG场景下,检索返回的文档片段如何注入上下文直接影响模型回答质量。常见做法是将所有片段拼接后放在系统提示中,但更精细的做法是按片段相关性分数动态调整注入位置和数量。
def build_rag_context(query, retriever, max_chunks=5, min_score=0.65):
# 构建RAG上下文,按分数过滤和排序
results = retriever.search(query, top_k=max_chunks * 2)
filtered = [r for r in results if r['score'] >= min_score]
selected = filtered[:max_chunks]
context_parts = []
for idx, chunk in enumerate(selected):
context_parts.append(
f'[片段{idx+1} | 相关度: {chunk["score"]:.2f}]\n{chunk["text"]}'
)
return '\n\n'.join(context_parts)
片段间的分隔符和编号不是装饰,而是帮助模型区分不同信息来源。实测中,使用明确分隔标记的上下文注入方式,比纯文本拼接的回答准确率提升约15%。
上下文溢出的降级处理
当所有压缩策略都无法将Token降到窗口限制以内时,需要设计降级策略。优先保留系统指令和当前用户输入,逐步丢弃历史对话和检索文档,确保模型至少能基于当前输入给出基本响应。在生产环境中,应该对上下文Token总量做实时监控,超过80%阈值时触发告警,避免因窗口溢出导致服务异常。Prompt工程中常用的思维链(CoT)也会占用上下文空间,在设计时需要将推理链长度纳入Token预算考量。自然语言处理领域的最新研究也表明,上下文中信息的排列顺序对模型理解效果有显著影响,将最相关的信息放在上下文的开头和结尾位置(”中间遗忘”效应),可以进一步提升模型对关键信息的利用率。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/da-mo-xing-shang-xia-wen-gong-cheng-shi-zhan-zhang-shang/