LLM上下文工程實戰:Prompt組裝、Token預算與RAG上下文設計

AI与大数据

摘要

  • Context Engineering(上下文工程)是2026年LLM應用落地的核心能力,比Prompt Engineering覆蓋面更廣、更貼近生產
  • Token預算是硬約束:系統提示詞、工具定義、RAG檢索、對話歷史必須分層分配,否則要么超窗截斷、要么成本失控
  • Prompt組裝不是字串拼接,而是有優先級的上下文管道(Context Pipeline),每一層都有明確的預算和淘汰策略
  • RAG上下文注入的3大坑:檢索噪聲淹沒關鍵資訊、Chunk邊界切斷語義、重複內容浪費Token
  • 本文提供從原理到Python實作的完整方案,含Token預算計算器與生產級Context Manager

目錄


為什麼Prompt Engineering不夠用了

2024年大家還在討論「怎麼寫好Prompt」,到了2026年,企業落地LLM應用時真正卡脖子的不是「一句話怎麼寫」,而是整個上下文怎麼組織

一個真實的生產故障

某電商客服AI上線第一週,用戶投訴率飆升。排查發現:

現象 根因 影響
AI回答與訂單無關 RAG檢索了10條歷史工單,淹沒了當前訂單上下文 答非所問
多輪對話後響應變慢 對話歷史無限累積,Token超窗後觸發截斷 丟失用戶意圖
月API帳單超預算3倍 系統提示詞重複發送,未利用Prompt Caching 成本失控

這三個問題,沒有一個靠「優化Prompt措辭」能解決。它們都屬於Context Engineering的範疇。

Prompt Engineering vs Context Engineering

維度 Prompt Engineering Context Engineering
關注點 單條提示詞的措辭和格式 整個上下文的組織、預算和生命週期
適用範圍 簡單問答、一次性任務 多輪對話、RAG、Agent、工具呼叫
核心技能 角色設定、Few-shot、CoT Token預算、上下文分層、壓縮淘汰
生產複雜度 高(涉及快取、檢索、狀態管理)
2026面試權重 基礎題 高頻架構題

簡單說:Prompt Engineering管「說什麼」,Context Engineering管「給模型看什麼」


Context Engineering核心概念

上下文的4個層次

把發給LLM的完整輸入想像成一個「資訊三明治」:

┌─────────────────────────────────────────────┐
│  Layer 1: 系統層 (System Context)            │
│  角色定義、行為約束、輸出格式、安全策略        │
├─────────────────────────────────────────────┤
│  Layer 2: 工具層 (Tool Context)              │
│  Function Calling定義、MCP工具描述、Schema    │
├─────────────────────────────────────────────┤
│  Layer 3: 知識層 (Knowledge Context)         │
│  RAG檢索結果、知識圖譜、業務規則文件           │
├─────────────────────────────────────────────┤
│  Layer 4: 對話層 (Conversation Context)      │
│  多輪歷史、用戶當前輸入、中間推理步驟          │
└─────────────────────────────────────────────┘

每一層都有獨立的Token預算,層與層之間還有優先級關係。當總Token接近視窗上限時,從低優先級層開始淘汰

上下文的生命週期

Context不是一次性組裝的,它在一次完整互動中會經歷多個階段:

  1. 組裝(Assembly):按優先級合併各層上下文
  2. 驗證(Validation):檢查Token總量、格式合規、敏感資訊過濾
  3. 發送(Dispatch):呼叫LLM API,利用Prompt Caching減少重複Token
  4. 更新(Update):將模型響應追加到對話層,觸發下一輪組裝
  5. 壓縮(Compaction):對話過長時,摘要或淘汰低價值歷史

Token預算:上下文視窗的「財務規劃」

為什麼要做Token預算

假設你用的是128K上下文視窗的模型,看起來很大,但生產環境中:

  • 系統提示詞 + 工具定義:通常佔 2K-8K Token
  • RAG檢索10條文件:每條500 Token = 5K Token
  • 50輪對話歷史:每輪200 Token = 10K Token
  • 模型輸出預留:4K Token

合計已經 21K-27K Token。如果業務複雜(多工具Agent、長文件RAG),輕鬆突破50K。沒有預算管理,就是在裸奔

推薦預算分配表(128K視窗)

層級 預算比例 Token上限 淘汰策略
系統層 固定 4K 不淘汰,利用Prompt Caching
工具層 固定 6K 按使用頻率動態載入
知識層 彈性 20K 按相關性分數截斷
對話層 彈性 30K 滑動視窗 + 摘要壓縮
輸出預留 固定 8K
安全緩衝 固定 10K 防止估算誤差超窗

Token計數器的3種實作

方案1:tiktoken精確計數(推薦)

import tiktoken

def count_tokens(text: str, model: str = "gpt-4o") -> int:
    encoding = tiktoken.encoding_for_model(model)
    return len(encoding.encode(text))

def budget_check(layers: dict[str, str], max_tokens: int = 128000) -> dict:
    usage = {name: count_tokens(content) for name, content in layers.items()}
    total = sum(usage.values())
    return {
        "usage": usage,
        "total": total,
        "remaining": max_tokens - total,
        "overflow": total > max_tokens,
    }

方案2:字元估算法(快速預檢)

中文約 1.5-2 字元/Token,英文約 4 字元/Token。用於組裝前的快速預檢,最終發送前再用tiktoken精確校驗。

方案3:API返回的實際用量

呼叫後從 response.usage 取得真實消耗,用於監控和動態調整預算。


Prompt組裝流水線設計

流水線架構

用戶輸入 ──→ [意圖識別] ──→ [知識檢索] ──→ [上下文組裝] ──→ [預算校驗] ──→ LLM API
                  │                │                │                │
                  ▼                ▼                ▼                ▼
            決定載入哪些工具    Top-K文件篩選     按優先級合併      超限則壓縮

組裝優先級規則

當Token預算不足時,按以下順序裁剪:

  1. 先裁對話層最舊的訊息(保留最近N輪 + 首輪系統互動)
  2. 再裁知識層低分文件(按Rerank分數從低到高移除)
  3. 再裁工具層未使用的工具定義(只保留本輪可能呼叫的工具)
  4. 最後才動系統層(系統層應盡量固定,利用Prompt Caching)

生產級組裝器實作

from dataclasses import dataclass, field
from typing import Optional

@dataclass
class ContextLayer:
    name: str
    content: str
    priority: int
    max_tokens: int
    cacheable: bool = False

@dataclass
class ContextBudget:
    total_limit: int = 128000
    output_reserve: int = 8000
    safety_buffer: int = 10000

    @property
    def available(self) -> int:
        return self.total_limit - self.output_reserve - self.safety_buffer

class ContextAssembler:
    def __init__(self, budget: ContextBudget):
        self.budget = budget
        self.layers: list[ContextLayer] = []

    def add_layer(self, layer: ContextLayer) -> None:
        self.layers.append(layer)
        self.layers.sort(key=lambda l: l.priority)

    def assemble(self) -> str:
        available = self.budget.available
        parts: list[str] = []

        for layer in self.layers:
            tokens = count_tokens(layer.content)
            if tokens <= layer.max_tokens and tokens <= available:
                parts.append(layer.content)
                available -= tokens
            elif tokens > layer.max_tokens:
                truncated = self._truncate(layer.content, layer.max_tokens)
                parts.append(truncated)
                available -= layer.max_tokens

        return "\n\n---\n\n".join(parts)

    def _truncate(self, text: str, max_tokens: int) -> str:
        encoding = tiktoken.encoding_for_model("gpt-4o")
        tokens = encoding.encode(text)
        if len(tokens) <= max_tokens:
            return text
        return encoding.decode(tokens[:max_tokens])

RAG上下文注入最佳實踐

RAG是Context Engineering中最容易踩坑的環節。檢索到的文件如何「餵」給模型,直接決定回答品質。

文件注入的3種格式

格式1:XML標籤包裹(推薦,Claude/GPT均友好)

<retrieved_documents>
  <document source="product_manual_v3.pdf" score="0.92">
    產品保固期為購買之日起12個月,人為損壞不在保固範圍內...
  </document>
  <document source="faq_returns.md" score="0.87">
    7天無理由退貨需保持商品完好,運費由買家承擔...
  </document>
</retrieved_documents>

格式2:編號引用(適合需要溯源的場景)

[1] 產品保固期為購買之日起12個月...(來源:product_manual_v3.pdf)
[2] 7天無理由退貨需保持商品完好...(來源:faq_returns.md)

請基於以上參考資料回答用戶問題,並在回答中標註引用編號。

RAG上下文的5條鐵律

規則 說明 違反後果
相關性閾值過濾 低於0.7分的文件不注入 噪聲干擾,幻覺增加
去重 同一文件的不同Chunk合併 Token浪費
元資料保留 標註來源、時間、版本 無法溯源,合規風險
位置優先 最相關的文件放最前面 模型注意力衰減(Lost in the Middle)
動態Top-K 根據剩餘預算調整K值 預算不足時硬截斷

Lost in the Middle問題

2023年史丹佛大學的研究發現:當相關資訊放在上下文中间位置時,模型的召回準確率顯著下降。生產中的應對策略:

  • 最相關的2條文件放在最前面
  • 次相關的放在最後面
  • 中間位置放系統提示詞或工具定義等「固定內容」

上下文壓縮與淘汰策略

策略1:滑動視窗

保留最近N輪對話,最簡單也最有效。推薦 N=10-20(視單輪Token量而定)。

策略2:摘要壓縮

當對話超過閾值時,用一個小模型(或同模型)對早期對話做摘要:

SUMMARIZE_PROMPT = """請將以下對話歷史壓縮為一段摘要,保留:
1. 用戶的核心訴求和約束條件
2. 已確認的關鍵事實(訂單號、產品型號等)
3. 尚未解決的問題

對話歷史:
{history}

摘要(不超過200字):"""

策略3:結構化狀態提取

對於Agent場景,不保留完整對話,而是維護一個結構化的「會話狀態」:

{
  "user_intent": "查詢訂單物流",
  "entities": {"order_id": "ORD-20260703-8842"},
  "resolved": ["已確認訂單存在", "物流承運商為順豐"],
  "pending": ["預計送達時間"]
}

每輪只把狀態JSON注入上下文,Token消耗從O(輪數)降到O(1)。


Python生產級Context Manager實作

class ProductionContextManager:
    def __init__(
        self,
        model: str = "gpt-4o",
        budget: ContextBudget = ContextBudget(),
    ):
        self.model = model
        self.budget = budget
        self.assembler = ContextAssembler(budget)
        self.conversation_history: list[dict] = []

    def build_context(
        self,
        user_input: str,
        system_prompt: str,
        retrieved_docs: Optional[list[dict]] = None,
        tools: Optional[list[dict]] = None,
    ) -> str:
        self.assembler.layers.clear()

        self.assembler.add_layer(ContextLayer(
            name="system", content=system_prompt,
            priority=0, max_tokens=4000, cacheable=True,
        ))

        if tools:
            tools_text = self._format_tools(tools)
            self.assembler.add_layer(ContextLayer(
                name="tools", content=tools_text,
                priority=1, max_tokens=6000,
            ))

        if retrieved_docs:
            docs_text = self._format_rag_docs(retrieved_docs)
            self.assembler.add_layer(ContextLayer(
                name="knowledge", content=docs_text,
                priority=2, max_tokens=20000,
            ))

        history_text = self._format_history()
        self.assembler.add_layer(ContextLayer(
            name="conversation", content=history_text,
            priority=3, max_tokens=30000,
        ))

        user_layer = f"<user_query>\n{user_input}\n</user_query>"
        self.assembler.add_layer(ContextLayer(
            name="current_input", content=user_layer,
            priority=4, max_tokens=4000,
        ))

        return self.assembler.assemble()

    def _format_rag_docs(self, docs: list[dict]) -> str:
        filtered = [d for d in docs if d.get("score", 0) >= 0.7]
        filtered.sort(key=lambda d: d["score"], reverse=True)
        parts = ["<retrieved_documents>"]
        for doc in filtered:
            parts.append(
                f'  <document source="{doc["source"]}" score="{doc["score"]:.2f}">\n'
                f'    {doc["content"]}\n'
                f'  </document>'
            )
        parts.append("</retrieved_documents>")
        return "\n".join(parts)

    def update_history(self, role: str, content: str) -> None:
        self.conversation_history.append({"role": role, "content": content})
        if len(self.conversation_history) > 40:
            self._compact_history()

    def _compact_history(self) -> None:
        old = self.conversation_history[:20]
        self.conversation_history = self.conversation_history[20:]
        summary = f"[Earlier conversation summary: {len(old)} messages condensed]"
        self.conversation_history.insert(0, {"role": "system", "content": summary})

面試高頻考點與避坑指南

面試常問的5個問題

Q1:Context Engineering和Prompt Engineering有什麼區別?

Context Engineering關注整個輸入上下文的組織、預算和生命週期管理,是系統級設計;Prompt Engineering關注單條提示詞的措辭優化,是技巧級優化。生產環境中前者決定系統能不能跑、跑多少錢,後者決定回答品質好多少。

Q2:128K上下文是不是可以不做壓縮了?

不能。128K是理論上限,實際中要考慮:成本(按Token計費)、延遲(上下文越長推理越慢)、注意力衰減(Lost in the Middle)、以及多使用者並發時的資源競爭。生產環境必須做預算管理。

Q3:RAG檢索10條文件全部注入好不好?

不好。檢索結果必須經過相關性過濾(閾值)、去重、Rerank重排,並按預算動態調整Top-K。噪聲文件會顯著增加幻覺率。

Q4:Prompt Caching和Context Engineering什麼關係?

Prompt Caching是成本優化手段,Context Engineering決定哪些內容適合快取。系統提示詞和工具定義等固定內容應標記為cacheable,對話層和RAG結果不適合快取。

Q5:多Agent系統中上下文怎麼管理?

每個Agent維護獨立的Context Manager,透過結構化狀態(而非完整對話歷史)在Agent間傳遞資訊。避免把Agent A的完整上下文傳給Agent B,Token會指數級膨脹。

生產避坑清單

表現 解法
無限累積對話歷史 多輪後響應變慢、超窗截斷 滑動視窗 + 摘要壓縮
RAG噪聲注入 回答偏離用戶問題 相關性閾值 + Rerank
系統提示詞重複計費 API成本居高不下 Prompt Caching
工具定義全量載入 8K+ Token浪費在無用工具上 按意圖動態載入工具
缺少Token監控 成本失控後才發現 每次呼叫記錄 usage 指標

多模型上下文的差異化管理

生產環境抽象 TokenCounter 介面,絕不用 GPT 的 tiktoken 估算 Claude 用量。

Prompt Caching 生產實踐

系統提示詞和工具定義標記為可快取,90% 快取命中率可降低約 80% API 成本。

企業客服系統改造案例

平均輸入 Token 從 45K 降至 12K,月 API 成本從 ¥28 萬降至 ¥9 萬,答非所問率從 23% 降至 6%。

上下文工程 vs 微調 vs 長上下文

80% 的「模型效果不好」是上下文組織問題,不是模型能力問題。先優化 Context Engineering,再考慮微調。

2026 年趨勢

上下文感知 Reranker、自適應 Token 預算、跨會話長期記憶、多模態上下文管理、上下文安全。


總結與延伸閱讀

Context Engineering是2026年LLM應用從Demo走向生產的分水嶺。核心就三件事:分層管理上下文、嚴格Token預算、智慧壓縮淘汰

設計要點回顧

  1. 上下文分4層:系統層、工具層、知識層、對話層,各有獨立預算
  2. Token預算是硬約束,128K視窗不等於可以揮霍
  3. RAG注入必須過濾、去重、排序,避免Lost in the Middle
  4. 對話壓縮三策略:滑動視窗、摘要壓縮、結構化狀態提取
  5. Prompt Caching + Context Pipeline是成本優化的組合拳

相關閱讀

權威參考

本站提供瀏覽器本地工具,免註冊即可試用 →

#Context Engineering#LLM上下文工程#Prompt设计#RAG上下文#长上下文优化#2026