在昨天的文章中,我們拆解了 Context Engineering 的核心
我們知道Agent的上下文不該被動堆疊,而需要透過一套動態機制進行調度
今天我們進入實戰篇:如何將 Write(寫入)、Select(篩選)、Compress(壓縮)、Isolate(隔離)這四大支柱,落實到具體的 Python 程式碼中?
以一個Agent工作流迴圈為例,資料的流轉與處理節點如下:
[環境/用戶輸入]
│
▼
1. Write (寫入) ──> 結構化記錄至狀態儲存庫 (State/Checkpoints)
│
▼
2. Select (篩選) ──> 根據當前任務動態檢索相關記憶與工具 Schema
│
▼
3. Compress (壓縮) ──> 剪裁工具 Raw Output 與摘要過長歷史
│
▼
4. Isolate (隔離) ──> 建立子任務獨立視窗,防止跨節點噪音污染
│
▼
[LLM 決策與執行]
不要將對話單純當作字串拼接,必須使用具備語意結構的狀態物件(State)進行寫入與持久化,明確分離「系統指令」、「使用者意圖」與「工具執行軌跡」
from typing import List, Dict, Any
from dataclasses import dataclass, field
@dataclass
class AgentState:
session_id: str
system_rules: str
user_facts: Dict[str, Any] = field(default_factory=dict) # 長期使用者畫像
messages: List[Dict[str, Any]] = field(default_factory=list) # 對話軌跡
scratchpad: List[Dict[str, Any]] = field(default_factory=list) # 當前任務暫存
# 實作 Write:明確分類寫入,而非混雜堆疊
def write_user_fact(state: AgentState, key: str, value: Any) -> None:
state.user_facts[key] = value
def write_interaction(state: AgentState, role: str, content: str) -> None:
state.messages.append({"role": role, "content": content})
# 範例調用
state = AgentState(session_id="sess_001", system_rules="你是電商客服助理。")
write_user_fact(state, "membership_tier", "VIP")
write_interaction(state, "user", "我想查詢耳機訂單,並辦理換貨。")
當系統掛載了數十個工具時,每一輪把所有工具Schema通通塞進Context會大幅消耗Token並增加模型幻覺
我們應該在執行前依據使用者最新意圖進行 動態工具挑選(Tool Pruning):
# 系統所有的工具池
AVAILABLE_TOOLS = {
"track_order": {"name": "track_order", "desc": "查詢物流與訂單狀態"},
"apply_refund": {"name": "apply_refund", "desc": "辦理訂單退貨退款"},
"apply_exchange": {"name": "apply_exchange", "desc": "辦理商品換貨"},
"reset_password": {"name": "reset_password", "desc": "發送密碼重設信件"},
"query_faq": {"name": "query_faq", "desc": "查詢常見問題知識庫"}
}
def select_relevant_tools(user_query: str) -> List[Dict[str, Any]]:
"""
根據意圖關鍵字或向量檢索,僅挑選與當下任務相關的工具
"""
selected = []
if "訂單" in user_query or "物流" in user_query:
selected.append(AVAILABLE_TOOLS["track_order"])
if "退" in user_query:
selected.append(AVAILABLE_TOOLS["apply_refund"])
if "換" in user_query:
selected.append(AVAILABLE_TOOLS["apply_exchange"])
# 若無特定匹配,默認注入 FAQ 工具
return selected if selected else [AVAILABLE_TOOLS["query_faq"]]
# 根據 "我想查詢耳機訂單,並辦理換貨",僅挑選 track_order 與 apply_exchange
active_tools = select_relevant_tools("我想查詢耳機訂單,並辦理換貨。")
外部API或資料庫回傳的Raw Data動輒數千Token,直接注入會污染Context。我們必須在進入LLM前進行瘦身與提煉
import json
# 模擬外部 API 回傳的肥大資料
raw_tool_payload = {
"status": "success",
"timestamp": 1755678900,
"debug_id": "trace-8899-xyz",
"server_node": "tw-node-03",
"order_data": {
"order_id": "ORD-1001",
"item": "降噪藍牙耳機",
"amount": 3200,
"delivery_status": "DELIVERED",
"warehouse_logs": ["scan_in", "pack_done", "out_for_delivery"]
}
}
def compress_tool_output(payload: Dict[str, Any]) -> str:
"""
僅保留決策必備欄位,移除 trace、log 等系統雜訊
"""
data = payload.get("order_data", {})
compressed = {
"order_id": data.get("order_id"),
"item": data.get("item"),
"status": data.get("delivery_status")
}
return json.dumps(compressed, ensure_ascii=False)
# 壓縮後僅剩 45 字元:{"order_id": "ORD-1001", "item": "降噪藍牙耳機", "status": "DELIVERED"}
cleaned_context = compress_tool_output(raw_tool_payload)
在複雜的多步驟工作流(如「驗證身份 ➔ 查詢訂單 ➔ 產生退換貨單」)中,每個子Agent節點應該擁有獨立純淨的上下文,避免將 A 節點冗長的中間推論過程帶入 B 節點
def run_isolated_subtask(global_state: AgentState, task_name: str, task_input: str) -> str:
"""
建立隔離的 Context 沙盒,執行完畢後只回傳結構化結論給主工作流
"""
# 建立沙盒上下文,不繼承全量歷史對話
sandboxed_context = {
"role": f"你是專門處理【{task_name}】的子節點",
"user_tier": global_state.user_facts.get("membership_tier"),
"task_input": task_input
}
# 模擬子節點執行完畢後的精簡輸出
subtask_result = f"審核通過:{global_state.user_facts.get('membership_tier')} 用戶享有免運換貨權限。"
# 僅將最終結果寫回全域狀態,中間運算過程不污染主對話
global_state.messages.append({"role": "assistant", "content": subtask_result})
return subtask_result
| 支柱 | 核心目標 | 實作策略 | 解決痛點 |
|---|---|---|---|
| Write (寫入) | 結構化分層記錄 | 分離 System Rules、User Facts 與對話軌跡 | 避免狀態混亂與非結構化文字丟失 |
| Select (篩選) | 精準載入最小必要資訊 | 動態挑選 2~3 個相關 Tool Schema,意圖分流 | 防止工具定義吃光 Token 與誤觸發 |
| Compress (壓縮) | 提高單位 Token 資訊密度 | 撰寫 Tool Adapter 清洗 Raw Data、過期對話摘要 | 避免 Context Poisoning 與長文本延遲 |
| Isolate (隔離) | 子任務上下文沙盒化 | 各節點使用獨立視窗,只向主流程傳遞結論 | 阻斷中間除錯訊息與噪音跨節點污染 |
透過 Write ➔ Select ➔ Compress ➔ Isolate 四大工程手段,我們能有效駕馭龐大資料流,確保 Agent 在每一輪決策時都能看見「最純淨、最關鍵」的上下文
然而,即使Context管理得再好,如果LLM輸出的文字依然隨意、無法保證欄位完整性,下游程式碼在解析時就會頻繁遭遇報錯(如 JSON 格式損壞)
明天 【Day 6】甚麼是 Structured Output Engineering,我們將探討如何利用JSON Schema、Pydantic 與Type-safe機制,從根本上強制約束LLM的輸出格式!