核心命題: 當 AI Agent 在單一 session 中連續分析多隻股票,上下文線性增長到 50K+ tokens 時,早期股票的財務數據會殘留在 LLM 的注意力窗口中——它無法區分哪些數據屬於 00653,哪些屬於 00928。子代理隔離是如何解決這個問題的?
事故數據: 00653 的 CR 基金(HK$3.68億)混入 00928 報告 · 00928 實際沒有 CR 基金 · 發現後立即修復
方法論: 事故記錄 → 根因追蹤 → 隔離架構設計 → sessions_spawn 實現 → 效果驗證 → 通用原則提煉
前言:一次不該發生的數據污染
2026 年 6 月,我們在使用 AK-SDD(港股信息搜索調查系統)連續調研兩間公司時,遇到了一個看似微小卻極具破壞性的問題。
調研目標:
- 00653 卓悅控股(Bonjour Holdings)——美容零售、物業投資
- 00928 帝王國際投資(King International Investment)——白酒銷售、保健產品、放債
兩間公司的業務完全不同。但當我們收到 00928 的調研報告時,發現了一段令人困惑的描述:
「公司持有 CR Business Innovation Investment Fund,賬面值約 HK$3.68億,其中約 HK$1.54億已進行減值處理...」
這不屬於 00928。00928 的業務是白酒(帝王池系列)、保健產品(男性健康產品)、以及放債。它根本沒有 CR Business Innovation Investment Fund。
這段數據來自 00653。
這不是 LLM 的幻覺。這是上下文污染的系統性問題。
一、問題場景:連續多股調研中的上下文洩漏
1.1 AK-SDD 的工作流程
AK-SDD 是君澤智庫的港股信息搜索調查系統,具有以下結構:
| 階段 | 內容 | Token 消耗 |
|---|---|---|
| 公司基本信息 | 名稱、股票代碼、行業分類 | ~500 |
| 業務描述 | 主營業務、收入結構 | ~2,000 |
| 財務分析 | 收入、利潤、資產負債 | ~5,000 |
| 股權結構 | 主要股東、持股比例 | ~3,000 |
| 新聞與風險 | 近期公告、訴訟、監管 | ~4,000-8,000 |
| 合計(單隻股票) | ~15,000-20,000 tokens |
問題不在於單隻股票的分析。問題在於——當你在同一個 session 中連續分析兩隻股票時,第一隻股票的 15,000-20,000 tokens 全部殘留在上下文中。
1.2 複現事故的具體過程
Step 1: 分析 00653 卓悅控股
→ Agent 搜索業務、財務、物業投資
→ 發現 CR Business Innovation Investment Fund
→ 詳細分析基金規模(HK$3.68億)、減值(HK$1.54億)
→ Session tokens: ~18,000
Step 2: 開始分析 00928 帝王國際投資
→ Session tokens: 18,000 + 新搜索 ~15,000 = ~33,000
→ LLM 的注意力窗口中有兩組完全獨立的財務數據
→ 沒有任何結構化機制標記「哪些數據屬於哪隻股票」
→ 風險:LLM 在生成報告時可能混合數據
Step 3: 生成 00928 報告
→ LLM 輸出中包含 CR 基金描述
→ 原因:00653 的基金數據仍在上下文中,且 00928 的資產部分沒有足夠強的信號來區分
→ 結果:數據污染
1.3 為什麼 LLM 分不清
這不是 LLM「不夠聰明」——這是注意力機制的內在限制。
當上下文中有多段相似的結構化數據(財務報表、基金描述、資產負債),LLM 的注意力權重會基於語義相似性而非來源分離來分配。說人話就是:
如果你在同一段對話中給了 LLM 兩家公司的財務數據,它可能把第一家的資產當作第二家的資產來引用——因為它們在語義空間中「長得很像」。
更關鍵的是,LLM 沒有內建的「數據隔離」概念。它把整個上下文視為一個連續的資訊流。除非你在 prompt 中明確標記了邊界(而我們當時沒有),否則它不會自動區分。
二、具體案例:CR 基金從 00653 到 00928 的遷移路徑
2.1 兩家公司的真實對比
| 維度 | 00653 卓悅控股 | 00928 帝王國際投資 |
|---|---|---|
| 行業 | 美容產品零售 + 物業投資 | 白酒銷售 + 保健產品 + 放債 |
| 主要資產 | 零售網絡、物業組合、CR 基金 | 白酒存貨、放債應收款 |
| CR 基金 | ✅ 持有,HK$3.68億 | ❌ 根本沒有 |
| 收入結構 | 零售店收入 + 租金收入 | 白酒銷售 + 利息收入 |
| 近期新聞 | 沽空報告爭議 | 白酒品牌推廣 |
兩間公司的唯一相似點是:都是港股小型上市公司,名字裡都有「國際」或「控股」。在業務、資產、收入結構上,它們沒有任何交集。
2.2 數據污染的具體表現
在污染後的 00928 報告中,CR 基金的描述被插入到了「資產結構」章節:
## 資產結構
公司持有 CR Business Innovation Investment Fund,賬面值約 HK$3.68億。
該基金主要投資於亞太區商業物業,受近年商業地產市場調整影響,
其中約 HK$1.54億已進行減值處理。管理層表示將持續監控...
此外,公司主要資產還包括:
- 白酒存貨(帝王池系列)
- 放債應收款項
- 保健產品庫存
這段描述在數據上和 00653 完全一致,但在語境上完全錯誤——它被無縫地編織進了 00928 的報告中,沒有任何明顯的「嫁接」痕跡。
2.3 為什麼這個事故特別危險
傳統的 LLM 幻覺是憑空捏造數據——它至少看起來像假的。但上下文污染產生的錯誤是引用真實數據但張冠李戴——每一個數字都是真實存在的,只是它們屬於錯誤的公司。
這種錯誤的危險性在於:
- 表面可信度極高——數字都「對得上」
- 需要領域知識才能發現——必須知道 00928 沒有 CR 基金
- 常規 QA 無法捕捉——格式正確、數據真實、邏輯自洽
- 在金融決策中可能導致嚴重後果——投資者可能基於錯誤的資產結構做出判斷
三、根因分析:LLM 上下文窗口中的數據邊界模糊
3.1 OpenClaw 的 Session 上下文模型
OpenClaw 的 session 採用線性對話模型:
Session Context (tokens 隨對話長度線性增長)
│
├─ Message 1: System prompt
├─ Message 2: User: "分析 00653"
├─ Message 3: Agent: [搜索 00653 業務]
├─ Message 4: Agent: [獲取 00653 財務數據]
├─ Message 5: Agent: [分析 CR 基金,HK$3.68億]
│ ... (15,000 tokens)
├─ Message 20: Agent: [00653 報告完成]
├─ Message 21: User: "分析 00928" ← 此時上下文 ~18,000 tokens
├─ Message 22: Agent: [搜索 00928 業務]
├─ Message 23: Agent: [獲取 00928 財務數據]
│ ... (新增 15,000 tokens)
├─ Message 40: Agent: [生成 00928 報告] ← 上下文 ~33,000 tokens
│ ↑
│ 00653 的所有數據仍然在此
│ 沒有任何機制隔離
關鍵問題:Message 21 開始時,00653 的全部調研數據(15,000+ tokens)仍在上下文中。LLM 在生成 00928 報告時,這些數據是可見的、可引用的。
3.2 為什麼簡單的 Prompt 指令不夠
我們最初嘗試通過在 prompt 中添加指令來解決:
「請只使用當前查詢公司的數據,不要引用之前分析過的公司的資訊。」
這個指令在大多數情況下有效——但不是 100%。當上下文變得足夠長(30K+ tokens),LLM 的指令遵循能力會衰減。在我們的測試中:
| 上下文長度 | Prompt 指令成功率 |
|---|---|
| < 10K tokens | 99%+ |
| 10K-20K tokens | ~95% |
| 20K-35K tokens | ~85-90% |
| > 35K tokens | ~75-80% |
對於金融分析來說,80% 的成功率意味著每五次分析就有一次可能出錯——這在需要精確數據的金融場景中是完全不可接受的。
3.3 真正的原因:數據缺乏結構化歸屬標記
更深層的問題是:在傳統的 session 模型中,所有數據都是平鋪的。沒有層級結構,沒有 namespace,沒有數據歸屬標記。
平鋪模型(現狀):
["00653 持有 CR 基金 HK$3.68億", ← 歸屬:未標記
"00653 營收 HK$5.2億", ← 歸屬:未標記
"00928 白酒銷售收入 HK$1.2億", ← 歸屬:未標記
"00928 放債利息收入 HK$0.3億"] ← 歸屬:未標記
隔離模型(目標):
[Namespace: 00653] [Namespace: 00928]
├─ CR 基金 HK$3.68億 ├─ 白酒收入 HK$1.2億
├─ 營收 HK$5.2億 ├─ 放債利息 HK$0.3億
└─ 美容零售業務 └─ 保健產品業務
在第一種模型中,LLM 需要自己推斷數據歸屬——而當數據量足夠大、相似度足夠高時,這個推斷可能出錯。在第二種模型中,數據歸屬是結構化強制執行的,LLM 無法跨越 namespace 引用數據。
四、解決方案:子代理隔離架構的設計與實現
4.1 核心設計理念
解決方案的本質非常簡單:
不要在同一段對話中分析兩隻股票。為每隻股票創建一個全新的、完全隔離的 session。
技術實現上,使用 OpenClaw 的 sessions_spawn 機制——為每次股票調研創建一個獨立的子代理 session:
主 Session(協調層)
│
├─ sessions_spawn: 分析 00653
│ └─ 子代理 Session 00653
│ ├─ 搜索 00653 業務
│ ├─ 獲取 00653 財務
│ ├─ 生成 00653 報告
│ └─ 返回報告到主 session
│ ✅ 上下文:只包含 00653 數據
│ ✅ 無其他股票數據干擾
│
├─ sessions_spawn: 分析 00928
│ └─ 子代理 Session 00928
│ ├─ 搜索 00928 業務
│ ├─ 獲取 00928 財務
│ ├─ 生成 00928 報告
│ └─ 返回報告到主 session
│ ✅ 上下文:只包含 00928 數據
│ ✅ 完全隔離,00653 數據不可見
│
└─ 匯總報告
4.2 隔離架構的三層設計
┌──────────────────────────────────────────────┐
│ 主 Agent(調度層) │
│ 職責:任務分配、結果匯總、質量檢查 │
│ 上下文:只包含每隻股票的摘要結果 │
└─────┬────────────────────┬───────────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 子代理 00653 │ │ 子代理 00928 │
│ 獨立 Session │ │ 獨立 Session │
├──────────────┤ ├──────────────┤
│ 上下文: │ │ 上下文: │
│ • 00653 業務 │ │ • 00928 業務 │
│ • 00653 財務 │ │ • 00928 財務 │
│ • 00653 新聞 │ │ • 00928 新聞 │
│ │ │ │
│ ❌ 看不到: │ │ ❌ 看不到: │
│ 00928 的任何 │ │ 00653 的任何 │
│ 數據 │ │ 數據 │
└──────────────┘ └──────────────┘
第一層:主 Agent 調度
- 接收用戶的調研請求
- 為每隻股票創建獨立的子代理
- 匯總子代理返回的報告
- 執行最終的質量檢查
第二層:子代理執行
- 每個子代理擁有完全乾淨的新 session
- 只接收一個任務描述和當前股票的數據
- 不受其他股票數據干擾
- 完成後返回結構化報告
第三層:數據邊界強制
- 子代理的上下文僅限於傳入的任務描述
- 不能訪問主 session 的歷史消息
- 不能訪問其他子代理的數據
- session 結束後自動清理
4.3 實現代碼
在 AK-SDD 中,子代理調用被封装為一個函數:
async def analyze_stock_in_subagent(
stock_code: str,
stock_name: str,
query_params: dict
) -> dict:
"""
在隔離的子代理 session 中分析單隻股票。
每個子代理擁有完全乾淨的上下文,
不會被其他股票的數據污染。
"""
task_prompt = f"""
對 {stock_code} {stock_name} 進行港股信息搜索調查。
【隔離規則 - 必須遵守】
1. 你只能使用本次搜索獲取的數據
2. 不要引用任何外部資訊或記憶中的數據
3. 只分析 {stock_code} 的相關信息
4. 所有數值必須標註來源和日期
【調查範疇】
- 公司基本信息:行業、主營業務
- 財務分析:最近三年收入、利潤、資產負債
- 股權結構:主要股東及持股比例
- 風險因素:近期重大事件、訴訟、監管
- 資產詳情:物業、投資、無形資產
【輸出格式】
返回結構化的 JSON 或 Markdown 報告,
包含所有調查結果的來源引用。
"""
# 創建隔離的子代理 session
result = await sessions_spawn(
task=task_prompt,
context="isolated", # 關鍵:完全隔離的上下文
tools=["web_search", "web_fetch", "tavily_search"],
timeout=300 # 5 分鐘超時
)
return result
對於批量調研,採用並行模式(多隻股票同時進行):
async def batch_analyze_stocks(
stocks: list[tuple[str, str]] # [(code, name), ...]
) -> dict[str, dict]:
"""
並行分析多隻股票,每隻股票在隔離的子代理中執行。
並行模式下的優勢:
1. 每隻股票獨立 session → 無數據污染
2. 多隻股票同時執行 → 總耗時 = 最慢的一隻
3. 任一子代理失敗不影響其他
"""
tasks = [
analyze_stock_in_subagent(code, name, params)
for code, name in stocks
]
# 並行執行所有子代理
results = await asyncio.gather(*tasks, return_exceptions=True)
# 處理結果,隔離失敗的
output = {}
for (code, name), result in zip(stocks, results):
if isinstance(result, Exception):
output[code] = {
"status": "error",
"error": str(result),
"stock_name": name
}
else:
output[code] = {
"status": "success",
"report": result,
"stock_name": name
}
return output
4.4 隔離保證的技術細節
子代理的隔離不是「建議性的」——它是強制性的:
| 隔離維度 | 實現方式 | 保證級別 |
|---|---|---|
| Session 上下文 | 每個子代理創建獨立 session,context="isolated" |
✅ 強制 |
| 記憶/持久化 | 子代理不加載 MEMORY.md 或 daily notes | ✅ 強制 |
| 向量記憶 | 子代理不訪問 Qdrant(或限制為只讀預設切片) | ✅ 強制 |
| 文件系統 | 子代理限制在臨時工作目錄 | ✅ 可配置 |
| 工具訪問 | 只授予搜索和提取工具,無寫入權限 | ✅ 強制 |
| 生命週期 | session 結束後自動清理,不留殘留 | ✅ 自動 |
最關鍵的是第一個維度——Session 上下文隔離。這確保了子代理完全看不到其他股票的數據,從根本上杜絕了數據污染的可能性。
五、效果驗證:子代理隔離後的數據準確性
5.1 修復後的測試結果
我們對修復後的系統進行了嚴格的測試,包含 20 組不同股票組合的連續分析:
| 測試組 | 股票組合 | 隔離前錯誤率 | 隔離後錯誤率 |
|---|---|---|---|
| 組 1 | 00653 → 00928 | 🟡 1 次數據污染 | ✅ 0 錯誤 |
| 組 2 | 00005 → 00011 | 🟢 0 錯誤 | ✅ 0 錯誤 |
| 組 3 | 00700 → 09988 | 🟡 1 次(PE 數據混用) | ✅ 0 錯誤 |
| 組 4 | 00175 → 02333 | 🟢 0 錯誤 | ✅ 0 錯誤 |
| 組 5 | 01928 → 06862 | 🟡 1 次(營收數據混用) | ✅ 0 錯誤 |
| ... | (共 20 組) | 總計 3 次污染 | 總計 0 次污染 |
隔離前:20 組中有 3 組出現數據污染(15% 污染率)
隔離後:20 組中 0 組出現數據污染(0% 污染率)
5.2 更重要的發現:報告質量反而提升了
子代理隔離不僅消除了數據污染,還帶來了意外的質量提升:
隔離前(共享 session):
├─ 平均報告長度:~2,500 字
├─ 引用來源數量:8-12 個
├─ 分析深度:中等
└─ 原因:上下文擁擠,LLM 傾向於簡化輸出
隔離後(獨立 session):
├─ 平均報告長度:~4,000 字
├─ 引用來源數量:15-22 個
├─ 分析深度:顯著提升
└─ 原因:上下文乾淨,LLM 可以充分展開分析
結論:隔離不僅防止了錯誤,還讓 LLM 能更好地「專注」於當前任務。
5.3 並行執行的性能優勢
子代理隔離還帶來了另一個好處——天然支持並行執行:
| 執行模式 | 3 隻股票總耗時 | 說明 |
|---|---|---|
| 串行(共享 session) | ~18 分鐘 | 依次執行,每隻 ~6 分鐘 |
| 並行(子代理隔離) | ~7 分鐘 | 三隻同時執行,等待最慢的一隻 |
| 性能提升 | 2.6x | 股票越多,優勢越明顯 |
六、通用啟示:金融 AI 應用的可靠性設計原則
從這次事故和修復過程中,我們提煉出了金融 AI 應用的五條可靠性設計原則:
🔴 原則一:數據歸屬強制標記
永遠不要讓 LLM 自己推斷數據的歸屬。
❌ 錯誤做法:
在同一個 prompt 中列出多個實體的數據,
依靠 LLM 自己區分
✅ 正確做法:
每個實體的數據在獨立的 namespace/session 中處理,
數據歸屬由架構強制執行,而非 LLM 推理
實戰檢查點: 你的系統中,是否存在同一 session 處理多個獨立實體的情況?如果有,立即重構為隔離模式。
🔴 原則二:Session 上下文最小化
金融分析的 session 不應該包含不相關的歷史數據。
❌ 錯誤做法:
Session 上下文隨著對話線性增長,
所有歷史數據都在注意力窗口中
✅ 正確做法:
每次獨立分析任務使用乾淨的 session,
只在必要時傳遞摘要結果
實戰檢查點: 檢查你的 session token 消耗。如果有 30% 以上的 tokens 與當前任務無關,你的上下文過大了。
🟡 原則三:子任務強隔離
任何涉及不同數據源的子任務都應該隔離執行。
🔴 高風險場景(必須隔離):
- 連續分析多隻股票
- 對比多家公司的財務數據
- 處理多個法律文件
- 審查多份合同
🟡 中風險場景(建議隔離):
- 並行搜索多個主題
- 多步驟數據轉換
- 跨領域分析
🟢 低風險場景(可共享 session):
- 單一主題的深度討論
- 同一數據源的多次查詢
- 交互式問答
🟡 原則四:獨立驗證層
即使使用了子代理隔離,仍然需要獨立的驗證步驟。
驗證策略:
1. 檢查報告中的關鍵數據是否與原始來源一致
2. 交叉對比:同一數據點是否在正確公司的報告中
3. 業務邏輯檢查:報告中的業務描述是否與公司已知業務匹配
4. 異常檢測:報告中是否出現了不屬於當前公司的數據項
🟢 原則五:失敗模式設計
金融 AI 系統必須預設會出錯,並設計好失敗模式。
出錯場景 → 系統響應
───────────────────────────────────
數據污染 → 隔離 + 重新生成
幻覺(捏造數據) → 來源驗證 + 拒絕輸出
搜索失敗 → 降級為已知數據 + 標記不完整
超時 → 返回部分結果 + 標記未完成
API 錯誤 → 重試 3 次 + 最終降級
關鍵: 永遠返回「有標記的部分結果」而非「看似完整的錯誤結果」。不完整的報告可以被識別和補充;錯誤的報告可能誤導決策。
七、教訓與反思
7.1 這次事故教會我們什麼
-
LLM 不是數據庫。 不要期望它像數據庫一樣保持數據隔離。上下文中的任何數據都可能被引用——無論是否應該。
-
Prompt 指令不是安全邊界。 在 prompt 中說「不要引用之前的數據」是軟約束,不是硬隔離。當上下文足夠大時,軟約束會失效。
-
架構層的隔離比行為層的指令更可靠。 子代理 session 隔離是架構層的解決方案,它從根本上消除了數據污染的可能性,而不只是降低了概率。
-
金融場景的可靠性要求遠高於一般應用。 在一般聊天中,15% 的數據污染率可能只是「不完美」;在金融分析中,這是「不可接受的」。
7.2 與 Claw Code 的 Smart Compaction 對比
我們之前在研究 Claw Code 時,深入分析了它的 Smart Session Compaction 機制——通過把舊消息壓縮成結構化摘要來控制上下文長度。
但這次事故說明:壓縮不能解決數據歸屬問題。 即使你把 00653 的全部數據壓縮成一段摘要,這段摘要仍然在上下文中,仍然可能被 00928 的報告引用。
壓縮解決的是「token 上限」問題;隔離解決的是「數據污染」問題。兩者互補但不互相替代。
7.3 未來方向
基於這次經驗,我們計劃在 AK-SDD 和更廣泛的金融分析工具鏈中引入以下改進:
- 自動隔離路由 — 系統自動識別「需要隔離」的場景,無需手動配置
- 跨 session 結果校驗 — 子代理結果返回後,自動觸發獨立的驗證子代理
- 隔離級別分級 — 輕量隔離(只隔離上下文)、標準隔離(上下文+工具)、嚴格隔離(上下文+工具+文件系統)
- 子代理執行審計日誌 — 完整記錄每個子代理的輸入、輸出、工具調用,用於事後審計
八、結語
這次數據污染事故是一個經典的「看起來很小,實際上很嚴重」的問題。
表面上,它只是一次 AI 輸出的錯誤——把 A 公司的數據放在了 B 公司的報告裡。但深挖下去,它暴露了 LLM 應用在金融場景中缺乏數據歸屬強制的系統性缺陷。
解決方案不是讓 prompt 寫得更好,不是讓模型參數更多,而是從架構層面強制數據隔離。子代理隔離架構——為每個獨立分析任務創建完全乾淨的 session——是一個簡單、有效、可複用的模式。
在金融 AI 中,可靠性不是一個功能,而是一個基礎要求。一個 1% 的錯誤率,可能導致 100% 的信任損失。 Clean Context 設計模式不是可選的優化——它是金融 AI 應用的最低標準。
本文基於 2026-06-08 AK-SDD 系統的真實生產事故與修復過程。
受影響股票: 00653.HK(卓悅控股)、00928.HK(帝王國際投資)
修復方案: sessions_spawn 子代理隔離架構
驗證結果: 20 組測試,0% 數據污染率
相關系統: OpenClaw Agent Platform · AK-SDD 港股信息搜索調查系統