大模型上下文工程(Context Engineering)决定了一个模型在真实业务链路中的上限。上下文窗口越放越大,瓶颈早已不是“装得下”,而是检索不到关键内容、上下文相互污染、推理成本随 token 线性上涨。本文围绕长上下文管理、Lost in the Middle 现象与 KV Cache 优化展开,并给出一个可直接复用的上下文封装示例。
大模型上下文工程的三个环节:检索、组装、压缩
上下文工程可以拆成三个环节:检索决定放什么,组装决定怎么放,压缩决定放不下怎么办。多数项目里暴露出来的问题,最终都能归到这三个环节之一。
- 检索:从向量库、关键词库或业务数据库中召回与当前问题相关的片段。单路检索命中率通常不稳定,混合召回再叠加相关性过滤更稳。
- 组装:按系统提示词、历史消息、检索片段、当前问题的顺序拼接上下文。核心约束在系统层和用户层各出现一次,模型提取效率明显更高。
- 压缩:窗口超限时用滑动窗口或结构化摘要折叠旧内容,把 token 预算留给关键信息。
三个环节里,检索决定信息质量,组装决定模型利用效率,压缩决定成本上限。长上下文场景的调优顺序一般是先修组装,再补检索,最后才考虑压缩策略。
Lost in the Middle:长上下文中段信息利用率下降
多项评测都观察到同一现象:模型对输入头部和尾部信息的命中率明显高于中段,处于中间位置的关键事实容易被遗漏。工程上的缓解手段有几类:
- 核心指令前移,放在系统提示词头部。
- 关键事实在系统层与用户层重复出现,重复的成本远低于遗漏的代价。
- 背景性资料放中段,决定流程走向的内容放尾部附近。
长上下文评测时也要注意:如果把关键信息全放在中段,评测结果会明显低于真实水平,测试集设计本身就会引入偏差。
KV Cache 与 Prefix Caching:长上下文推理成本优化
生成阶段每个新 token 都要与历史全部 token 的 Key-Value 向量做注意力计算,KV Cache 随输入长度线性增长,显存和延迟随之上升。工程上常用的优化路线有三条:
- Prefix Caching:对相同的系统提示词与固定前缀做缓存复用,多轮对话和批量请求场景收益最明显。
- KV Cache 量化:从 FP16 降到 INT8,显存占用大约下降一半,多数业务场景精度损失可接受。
- 滑动窗口:无状态场景只保留最近 N 轮对话,更早的历史折叠成摘要,token 成本大幅下降。
多轮对话、报表分析这类长会话场景,Prefix Caching 叠加历史折叠,通常能把单次调用成本压到原来的三分之一以下。
Python 示例:可复用的上下文组装与压缩
class ContextManager:
def __init__(self, system_prompt, max_tokens=32000):
self.system_prompt = system_prompt
self.max_tokens = max_tokens
self.history = []
def add_message(self, role, content):
self.history.append({"role": role, "content": content})
def _estimate(self, text):
# 中英文混合的粗略估算,上线前替换为真实 tokenizer 计算
return int(len(text) * 1.3)
def _fold(self, messages):
# 把最旧的一批消息折叠成摘要,防止长会话无限膨胀
items = [m["content"][:40] for m in messages]
return {"role": "system", "content": "历史摘要:" + ";".join(items)}
def build(self, query, retrieved=None):
parts = [{"role": "system", "content": self.system_prompt}]
budget = self.max_tokens - self._estimate(query)
if retrieved:
budget -= self._estimate(str(retrieved))
parts.append({"role": "user", "content": "检索片段:\n" + str(retrieved)})
pending = list(self.history)
while pending and budget > 0:
msg = pending.pop()
cost = self._estimate(msg["content"])
if cost <= budget:
parts.insert(1, msg)
budget -= cost
else:
parts.insert(1, self._fold(pending))
break
parts.append({"role": "user", "content": query})
return parts
调用方只需维护一个 ContextManager 实例,多轮对话中反复调用 build 即可拿到裁剪后的上下文。接入真实业务时,把 _estimate 替换为官方 tokenizer 的长度计算,_fold 改为摘要模型调用,就能直接上线。
用评测集验证上下文工程收益
上线前固定一组评测集:多轮任务的关键信息命中率、首 token 延迟、单次 token 成本。改造前后各跑一遍,对比结果,上下文工程的收益就一目了然。目标是用最少的 token 拿到最高的任务完成率,而不是把窗口塞满。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/da-mo-xing-shang-xia-wen-gong-cheng-shi-zhan-zhang-shang/