wulibaibao

© 2026 wulibaibao.com

LLMContextRAGToken

LLM Context Engineering:上下文工程化实践

Wwulibaibao📅 2026年4月12日👁️ 30 次阅读⏱️ 4 分钟阅读

LLM Context Engineering:上下文工程化实践

前言

用过大模型的人都知道,同样的模型,不同的 prompt,效果天差地别。但很多人没意识到的是,上下文的管理本身就是一门工程

本文讨论的是:如何在真实项目中系统性地管理大模型的上下文,控制 Token 成本,提高输出质量。这不是 prompt 技巧,而是工程实践。

Token 的成本账

以 MiniMax M2.7 为例,思考一个实际场景:

你的应用每次请求向大模型发送用户最近 20 条对话历史(平均每条 100 Token)+ 知识库检索结果(2000 Token)+ 系统提示(500 Token)+ 用户问题(200 Token)= 4900 Token

如果你的应用每天处理 10000 次请求,每天消耗的 Token 量是 4900 × 10000 = 4900 万 Token

单 Token 成本哪怕只有 0.0001 元,日成本就是 4900 元,月成本接近 15 万。上下文膨胀不加控制,Token 成本会以你想象不到的速度侵蚀利润

上下文分层架构

好的上下文工程,第一步是分层。不是把所有信息一股脑塞进 context window,而是分层管理,按需注入。

┌─────────────────────────────────┐
│  System Prompt(500 Token)      │  ← 固定不变,全局指令
├─────────────────────────────────┤
│  Domain Knowledge(2000 Token) │  ← 知识库切片,按需检索
├─────────────────────────────────┤
│  Conversation History(variable)│  ← 动态截断,保留最近 N 条
├─────────────────────────────────┤
│  Task Context(variable)       │  ← 本次任务特定信息
├─────────────────────────────────┤
│  User Query(~200 Token)       │  ← 用户当前输入
└─────────────────────────────────┘

System Prompt 的最佳实践

System Prompt 决定模型行为上限,但很多人写得很随意。几个关键原则:

角色要具体,不要泛泛。差的做法是"你是一个 AI 助手,请帮助用户"。好的做法是具体描述角色的专业领域、擅长技术、回答风格。

规则要靠前,越重要的规则位置越靠前。大模型对 prompt 开头和结尾的信息记忆最强,中间的容易被"遗忘"。

用 XML 标签分隔不同部分

<role>你是 React 性能专家</role>
<constraints>
- 不推荐用 useMemo 的场景要明确指出
- 每次回答必须包含可运行的代码示例
</constraints>
<output-format>JSON: { "verdict": "...", "reason": "...", "code": "..." }</output-format>

对话历史的智能管理

对话历史是上下文膨胀的最大来源。聊天应用每轮对话,上下文都在增长,不加控制很快就会触及 context window 上限。

策略一:固定窗口截断

最简单,保留最近 N 条消息:

function getTruncatedHistory(
  messages: Message[],
  maxTokens: number = 4000
): Message[] {
  const reversed = [...messages].reverse();
  let tokenCount = 0;
  const result: Message[] = [];

  for (const msg of reversed) {
    const msgTokens = estimateTokens(msg.content);
    if (tokenCount + msgTokens > maxTokens) break;
    result.unshift(msg);
    tokenCount += msgTokens;
  }

  return result;
}

优点:实现简单,可预测。缺点:可能截断关键历史信息。

策略二:Summarization(摘要压缩)

当对话超过阈值时,用模型自身生成摘要,将详细历史替换为摘要:

async function compressHistory(
  messages: Message[],
  model: ModelClient
): Promise<Message[]> {
  if (messages.length < 10) return messages;

  const recentHistory = messages.slice(0, -5);
  const olderMessages = messages.slice(0, -5);

  const summary = await model.complete(
    `请简要总结以下对话的核心内容,保留关键信息,控制在 200 字以内:\n
    ${olderMessages.map(m => `${m.role}: ${m.content}`).join('\n')}`
  );

  return [
    { role: "system", content: `【对话摘要】${summary}` },
    ...recentHistory
  ];
}

策略三:Semantic Chunking(语义分块)

不是按时间截断,而是按语义相关度选择历史消息。向量数据库存储历史,检索时只召回与当前问题语义相关的信息:

async function retrieveRelevantHistory(
  currentQuery: string,
  history: Message[],
  topK: number = 5
): Promise<Message[]> {
  const queryEmbedding = await embed(currentQuery);

  const similarities = history.map(msg => ({
    msg,
    score: cosineSimilarity(queryEmbedding, msg.embedding)
  }));

  return similarities
    .filter(s => s.score > 0.7)
    .sort((a, b) => b.score - a.score)
    .slice(0, topK)
    .map(s => s.msg);
}

知识库检索的工程实践

RAG(Retrieval Augmented Generation)是当前最主流的知识库增强方案,但实操中有很多坑。

Chunk Size 不是越大越好

常见误区:以为 chunk 越大,上下文信息越完整,效果越好。实际上:

  • 过大的 chunk(> 2000 Token):包含过多无关信息,噪声稀释了有效信号,检索精度下降
  • 过小的 chunk(< 200 Token):丢失上下文,模型无法理解完整语义

以代码库为例,一个函数块 + 它的注释 + 调用上下文 = 最佳单元,而不是按行分割。

推荐策略:重叠分块,每个 chunk 保留与下一个 chunk 的重叠部分,保证上下文连续性。

function chunkWithOverlap(
  text: string,
  chunkSize: number = 500,
  overlap: number = 100
): string[] {
  const chunks: string[] = [];
  let start = 0;

  while (start < text.length) {
    const end = start + chunkSize;
    chunks.push(text.slice(start, end));
    start += chunkSize - overlap;
  }

  return chunks;
}

混合检索优于纯向量检索

纯向量检索对关键词不敏感(比如搜索 "React useEffect",可能召回的是语义相似但关键词不匹配的内容)。

混合检索:向量相似度 + BM25 关键词权重结合

async function hybridSearch(
  query: string,
  vectorDB: PineconeClient,
  topK: number = 5
) {
  const vector = await embed(query);
  const keywords = extractKeywords(query);

  const [vectorResults, bm25Results] = await Promise.all([
    vectorDB.search(vector, topK * 2),
    bm25Index.search(keywords, topK * 2)
  ]);

  const fused = rrfMerge([
    { results: vectorResults, weight: 0.7 },
    { results: bm25Results, weight: 0.3 }
  ], topK);

  return fused;
}

Prompt 缓存:降低成本的关键

2024 年下半年,各主要大模型厂商陆续推出了 Prompt 缓存功能(Prompt Caching / Context Caching)。这个功能允许在多次请求间复用相同的上下文前缀,只需为变化的部分付费。

MiniMax 的实现思路

const cache = new Map<string, string>();

async function completeWithCache(
  sessionId: string,
  systemPrompt: string,
  context: string,
  query: string
): Promise<string> {
  const cacheKey = hash(systemPrompt + context);

  if (cache.has(cacheKey)) {
    return model.complete({
      cacheKey,
      query,
      useCache: true
    });
  }

  return model.complete({
    systemPrompt,
    context,
    query,
    cacheWindow: true
  });
}

成本对比(假设每天 10000 次请求,system + context = 5000 Token,query = 200 Token):

模式 每日 Token 消耗 相对成本
无缓存 (5000 + 200) × 10000 = 5200万 100%
上下文缓存 5000(首请求) + 200 × 10000 = 700万 ~13%

缓存失效策略

缓存虽好,但有 TTL(Time To Live)限制。常见策略:

  • 时间过期:30 分钟 / 1 小时后失效
  • 版本控制:知识库更新时主动失效旧缓存
  • 容量淘汰:LRU 淘汰最少使用的缓存
  • 强制刷新:用户明确交互(如切换话题)时清空上下文

输出质量的工程保障

结构化输出

在生产环境中,非结构化的文本输出难以可靠解析。要求模型输出 JSON 结构,然后用 JSON Schema 验证:

const response = await model.complete({
  prompt,
  outputFormat: {
    type: "json",
    schema: {
      type: "object",
      properties: {
        verdict: { type: "string", enum: ["APPROVE", "REJECT", "REVIEW"] },
        reason: { type: "string", maxLength: 200 },
        confidence: { type: "number", minimum: 0, maximum: 1 }
      },
      required: ["verdict", "reason"]
    }
  }
});

const parsed = JSON.parse(response);
const valid = validate(parsed, schema);
if (!valid) {
  // 重试或降级
}

幂等性处理

大模型输出有随机性,同样的输入可能得到略有不同的结果。关键业务场景需要:

  1. 多次采样:相同输入请求 3 次,选择多数一致的答案
  2. 一致性校验:输出结果应该有内部一致性
  3. 回退机制:结构化解析失败时,降级为文本输出 + 人工确认

总结

LLM Context Engineering 的本质是:在质量、成本、可维护性之间找平衡

核心工程实践:

  • 分层:System / Knowledge / History / Task / Query 各司其职
  • 压缩:Summarization + Semantic Chunking 控制历史膨胀
  • 缓存:Prompt Caching 将重复上下文成本降低 80%+
  • 结构化:Schema 验证 + 幂等处理保证输出可靠

上下文工程不是一次性配置完就完事的,它是持续优化的过程——监控 Token 消耗、分析截断对质量的影响、定期调整 chunk size 和检索策略。

W
wulibaibao
全栈开发 / 创业实践者,分享技术踩坑、工具链搭建和产品化过程中的思考。关注 AI 辅助编程与电商实战。

📚相关文章

💬评论

加载评论...