基於文件系統的上下文工程
將文件系統用作代理上下文的主要溢出層,因為上下文窗口有限,而任務通常需要比單一窗口所能容納的更多資訊。檔案讓代理能夠透過單一介面儲存、檢索和更新幾乎無限量的上下文。
偏好動態上下文發現——按需提取相關上下文——而非靜態包含,因為靜態上下文無論相關性如何都會消耗令牌,並排擠任務特定資訊的空間。
何時啟用
在以下情況啟用此技能:
- 工具輸出導致上下文窗口膨脹
- 代理需要跨長期軌跡持久化狀態
- 子代理必須在沒有直接訊息傳遞的情況下共享資訊
- 任務需要比窗口能容納的更多上下文
- 建構能夠學習和更新自身指令的代理
- 為中間結果實作草稿板
- 需要讓代理能夠存取終端機輸出或日誌
請勿為其他技能負責的相鄰工作啟用此技能:
- 跨會話的語義記憶、實體追蹤或時序知識圖譜:
memory-systems。 - 對話摘要、壓縮或持久交接措辭:
context-compression。 - 不需要檔案儲存的令牌效率策略:
context-optimization。 - 多代理拓撲或交接協定設計:
multi-agent-patterns。 - 從活動窗口本身逐出內容的模型編輯:
self-managed-context。
核心概念
根據以下四種模式診斷上下文失敗,因為每種都需要不同的檔案系統補救措施:
- 遺失上下文——總可用上下文中缺少所需資訊。透過將工具輸出和中間結果持久化到檔案中進行修復,確保沒有任何遺失。
- 檢索不足的上下文——檢索到的內容未能涵蓋代理所需的內容。透過將檔案結構化以進行目標檢索(對 grep 友善的格式、清晰的章節標題)進行修復。
- 檢索過多的上下文——檢索到的內容遠遠超過所需,浪費令牌並降低注意力。透過將大量內容卸載到檔案並返回簡潔的參考來進行修復。
- 隱藏的上下文——專業資訊隱藏在許多檔案中。透過結合 glob 和 grep 進行結構搜尋以及語義搜尋進行概念查詢來進行修復。
將文件系統用作解決所有四個問題的持久層:寫入一次,持久儲存,選擇性檢索。
詳細主題
靜態與動態上下文的權衡
將靜態上下文(系統指令、工具定義、關鍵規則)視為昂貴的不動產——無論相關性如何,它在每次輪換中都會消耗令牌。隨著代理累積能力,靜態上下文會增長並排擠動態資訊。
改用動態上下文發現:只包含最小的靜態指標(名稱、一行描述、檔案路徑),並在相關時使用搜尋工具載入完整內容。這更節省令牌,並且通常透過減少窗口中的矛盾或不相關資訊來提高回應品質。
接受權衡:動態發現要求模型能辨識何時需要更多上下文。目前的前沿模型處理得很好,但能力較差的模型可能無法觸發載入。如有疑問,寧可靜態包含關鍵的安全或正確性約束。
模式 1:文件系統作為草稿板
將大型工具輸出重新導向至檔案,而不是直接返回到上下文中,因為單次網路搜尋或資料庫查詢就可以將數千個令牌傾倒入訊息歷史記錄中,並在整個對話過程中持續存在。
將輸出寫入草稿檔案,提取簡潔摘要,並返回檔案參考。然後,代理使用目標檢索(grep 尋找模式,read_file 搭配行範圍)來僅存取它需要的內容。
def handle_tool_output(output: str, threshold: int = 2000) -> str:
if len(output) < threshold:
return output
file_path = f"scratch/{tool_name}_{timestamp}.txt"
write_file(file_path, output)
key_summary = extract_summary(output, max_tokens=200)
return f"[Output written to {file_path}. Summary: {key_summary}]"
使用 grep 搜尋卸載的檔案,並使用 read_file 搭配行範圍來檢索目標區段,因為這保留了完整的輸出以供後續參考,同時只在活動上下文中保留約 100 個令牌。
模式 2:計劃持久化
將計劃寫入文件系統,因為長期任務在計劃脫離注意力或被摘要掉時會失去連貫性。代理可以在任何時候重新讀取其計劃,恢復對目標和進度的認知。
以結構化格式儲存計劃,使其既可讀又可由機器解析:
# scratch/current_plan.yaml
objective: "重構認證模組"
status: in_progress
steps:
- id: 1
description: "審計目前認證端點"
status: completed
- id: 2
description: "設計新的令牌驗證流程"
status: in_progress
- id: 3
description: "實作並測試變更"
status: pending
在每次輪換開始或任何上下文刷新後重新讀取計劃以重新定位,因為這起到了「透過複述來操控注意力」的作用。
模式 3:透過文件系統進行子代理通訊
將子代理的發現結果透過文件系統路由,而不是透過訊息傳遞,因為多跳訊息鏈會在每次跳躍中因摘要而降低資訊品質(「電話遊戲」)。
讓每個子代理直接寫入自己的工作目錄。協調器直接讀取這些檔案,保持完整保真度:
workspace/
agents/
research_agent/
findings.md
sources.jsonl
code_agent/
changes.md
test_results.txt
coordinator/
synthesis.md
實施每個代理的目錄隔離,以防止寫入衝突並保持每個輸出工件(artifact)的清晰所有權。
模式 4:動態技能載入
將技能儲存為檔案,並僅在靜態上下文中包含技能名稱和簡短描述,因為將所有指令塞入系統提示會浪費令牌,並可能以相互矛盾的指導混淆模型。
可用的技能(在相關時使用 read_file 載入):
- database-optimization:查詢調優和索引策略
- api-design:REST/GraphQL 最佳實踐
- testing-strategies:單元、整合和端到端測試模式
僅在目前任務需要時才載入完整的技能檔案(例如 skills/database-optimization/SKILL.md)。這將 O(n) 的靜態令牌成本轉換為每個任務的 O(1)。
模式 5:終端機和日誌持久化
自動將終端機輸出持久化到檔案,並使用 grep 進行選擇性檢索,因為來自長時間運行程序的終端機輸出會快速累積,而手動複製貼上容易出錯。
terminals/
1.txt # 終端機會話 1 的輸出
2.txt # 終端機會話 2 的輸出
使用目標化的 grep 進行查詢(grep -A 5 "error" terminals/1.txt),而不是將整個終端機歷史記錄載入到上下文中。
模式 6:透過自我修改學習
讓代理將學習到的偏好和模式寫入自己的指令檔案,以便後續會話自動載入此上下文,這無需手動更新系統提示。
def remember_preference(key: str, value: str):
preferences_file = "agent/user_preferences.yaml"
prefs = load_yaml(preferences_file)
prefs[key] = value
write_yaml(preferences_file, prefs)
使用驗證來保護此模式,因為自我修改可能會隨著時間累積不正確或矛盾的指令。將其視為實驗性——定期檢閱持久化的偏好設定。
文件系統搜尋技術
結合 ls/list_dir、glob、grep 和 read_file 搭配行範圍進行上下文發現,因為模型專門針對文件系統遍歷進行訓練,並且這種組合在結構模式清晰的技術內容上通常優於語義搜尋。
ls/list_dir:發現目錄結構glob:尋找符合模式的檔案(例如**/*.py)grep:搜尋檔案內容,返回匹配行及其上下文read_file搭配範圍:讀取特定區段而不載入整個檔案
將文件系統搜尋用於結構化和精確匹配查詢,並將語義搜尋用於概念查詢。結合兩者以實現全面發現。
實用指導
何時使用文件系統上下文
當情況符合以下標準時應用文件系統模式,因為它們會增加 I/O 開銷,只有透過節省令牌或持久化需求才能證明其合理性:
使用時機:
- 工具輸出超過約 2000 個令牌
- 任務跨越多個對話輪次
- 多個代理需要共享狀態
- 技能或指令超過舒適的系統提示大小
- 需要選擇性查詢日誌或終端機輸出
應避免時機:
- 任務在單一輪次內完成(開銷不合理)
- 上下文可舒適地容納在窗口內(沒有需要解決的問題)
- 延遲至關重要(檔案 I/O 會增加可衡量的延遲)
- 模型缺乏文件系統工具功能
檔案組織
為了代理的可發現性組織檔案,因為代理透過列出和讀取目錄名稱進行導航:
project/
scratch/ # 暫存工作檔案
tool_outputs/ # 大型工具結果
plans/ # 活動計劃和檢查清單
memory/ # 持久化的學習資訊
preferences.yaml # 使用者偏好
patterns.md # 學習到的模式
skills/ # 可載入的技能定義
agents/ # 子代理工作空間
使用一致的命名慣例,並在暫存檔案中包含時間戳或 ID 以進行區分。
對於自主研究循環,將原始檢索到的證據儲存在消耗它的執行(run)下,例如 researcher/runs/<run-id>/sources/evidence/raw/。不要將原始研究轉儲留在儲存庫根目錄中;根級別的工件(artifact)難以審計且易於在沒有出處的情況下被引用。
令牌核算
在應用文件系統模式前後測量令牌的來源,因為沒有測量的最佳化會導致徒勞:
- 追蹤靜態與動態上下文的比例
- 監控卸載前後的工具輸出大小
- 測量動態載入的上下文實際被使用的頻率
範例
範例 1:工具輸出卸載
輸入:網路搜尋返回 8000 個令牌
之前:8000 個令牌被加入訊息歷史記錄
之後:
- 寫入 scratch/search_results_001.txt
- 返回:"[Results in scratch/search_results_001.txt. Key finding: API rate limit is 1000 req/min]"
- 代理在需要具體細節時 grep 檔案
結果:約 100 個令牌在上下文中,8000 個令牌可按需存取
範例 2:動態技能載入
輸入:使用者詢問資料庫索引
靜態上下文:"database-optimization: Query tuning and indexing"
代理動作:read_file("skills/database-optimization/SKILL.md")
結果:僅在相關時載入完整技能
範例 3:作為檔案參考的聊天歷史
觸發條件:達到上下文窗口限制,需要摘要
動作:
1. 將完整歷史寫入 history/session_001.txt
2. 為新的上下文窗口產生摘要
3. 包含參考:"Full history in history/session_001.txt"
結果:代理可以搜尋歷史檔案以恢復在摘要中遺失的細節
指引
- 將大型輸出寫入檔案;將摘要和參考返回到上下文
- 以結構化檔案儲存計劃和狀態以便重新讀取
- 使用子代理檔案工作空間而非訊息鏈
- 動態載入技能,而不是將所有內容塞入系統提示
- 將終端機和日誌輸出持久化為可搜尋的檔案
- 結合 grep/glob 與語義搜尋以實現全面發現
- 為代理的可發現性組織檔案,使用清晰的名稱
- 測量令牌節省量以驗證文件系統模式是否有效
- 實作暫存檔案的清理以防止無界增長
- 使用驗證保護自我修改模式
- 將原始證據保留在消耗它的執行、評估和提案旁邊
陷阱
- 暫存目錄無界增長:代理建立的暫存檔案沒有清理,最終耗盡磁碟空間並使目錄清單變得嘈雜。實作保留政策(基於時間或計數)並在會話邊界執行清理。
- 多代理檔案存取的競態條件:對同一檔案的並發寫入會悄悄地損毀狀態。實施每個代理的目錄隔離或使用帶有代理前綴條目的僅附加檔案。
- 移動/重新命名後的過期檔案參考:代理持有來自先前輪次的路徑,這些路徑在重構或檔案重新組織後不再存在。在讀取快取路徑之前,始終驗證檔案是否存在;如果檢查失敗,則使用 glob 重新發現。
- glob 模式假匹配:過於寬泛的模式(例如
**/*)會將不相關的檔案拉入上下文,浪費令牌並混淆模型。將 glob 範圍限定到特定目錄和副檔名。 - 檔案大小假設:不檢查大小就讀取檔案可能會在單一工具呼叫中將 10 萬個令牌傾倒入上下文。在讀取前檢查檔案大小;對大型檔案使用行範圍讀取。
- 缺少檔案存在性檢查:代理假定檔案存在於先前的輪次,但它們可能已被刪除或移動。始終使用存在性檢查保護讀取,並優雅地處理遺失檔案的錯誤。
- 草稿板格式漂移:無結構的草稿板在多次寫入後變得不可解析,因為格式慣例在連續附加中會侵蝕。從第一次寫入就定義並實施一個架構(YAML、JSON 或結構化 Markdown)。
- 硬編碼的絕對路徑:當儲存庫在不同位置被檢出或在容器中執行時會中斷。使用從專案根目錄的相對路徑或動態解析路徑。
整合
此技能擁有檔案備份上下文儲存
…[翻譯時已截斷]