
在實際 AI Agent 開發里長任務“跑著跑著就丟了上下文”是最高頻的坑之一。所謂長任務是指需要多輪調用模型才能完成的執行過程比如批量處理文檔、按步驟重構代碼模塊、生成報告后再逐項校驗任務通常持續幾分鐘到幾十分鐘。問題在于模型本身沒有記憶上下文只來自你本次請求傳入的內容任務一旦超過窗口長度或者進程重啟、會話切換早期結論、用戶約束、已完成列表就會丟失后續步驟開始“失憶”。prime-agent 正是圍繞這個問題設計的上下文管理方案它把模型層無狀態的對話補齊為有狀態的長任務執行上下文讓 Agent 在 token 受限的前提下仍然能引用早期信息。這篇文章會沿著一條完整鏈路展開先講清楚上下文為什么會丟再拆解 prime-agent 這類方案的核心機制然后給出一套最小可運行的工程示例說明環境準備、關鍵參數、驗證方法和排查路徑。適合正在開發 Agent 應用、做 LLM 應用工程化或者被長任務輸出不穩定困擾的開發者閱讀。1. 長任務為什么會“跑著跑著就丟了上下文”1.1 上下文窗口不是無限的token 上限與截斷機制大語言模型的上下文窗口是一個有限資源。常見模型從幾萬 token 到幾十萬 token 不等但不管窗口多大長任務只要持續產出中間結果就有可能在某一輪把窗口占滿。窗口占滿后發生什么取決于調用方式平臺側靜默截斷中間內容只保留開頭和結尾。請求直接報錯提示上下文長度超出限制。框架自動做滑動窗口丟棄最早的消息。這三種情況都會讓 Agent“失憶”。更隱蔽的是靜默截斷程序沒有報錯后面步驟還在繼續但關鍵約束已經被裁掉了最終結果看似正常實際已經偏離目標。1.2 上下文丟失的三種典型形態把丟上下文的問題歸納成三種形態排查時會更快定位形態表現典型觸發場景靜默截斷程序正常執行但早期約束失效循環內不斷追加歷史消息中間內容被裁剪會話重置狀態完全清空重新從“零”開始進程重啟、會話超時、任務被調度系統重新拉起引用漂移信息還在但后續步驟引用錯誤把多段內容壓縮后丟失時間順序或歸屬關系1.3 普通對話補全為什么不能直接用于長任務普通對話補全的 API 是無狀態的。你發一條請求模型返回一條響應服務端不會替你保存這次對話。所謂“多輪對話”本質上是客戶端把歷史消息逐條拼進下一次請求再發出去。這種模式在短對話里夠用但放到長任務里會出現兩個問題每次請求都攜帶全部歷史token 消耗線性增長很快觸頂。任務執行到一半需要暫停或恢復時歷史消息存在哪里、如何加載、如何保證不丟都需要自己設計。prime-agent 這類上下文管理組件解決的正是這兩個問題它把“歷史消息”升級為“執行上下文”并給上下文加上持久化、壓縮、檢索和恢復能力。2. prime-agent 的核心思路把無狀態對話變成有狀態執行2.1 它在任務鏈路中的位置可以把 prime-agent 理解成 Agent 和模型之間的一層上下文管理層。任務開始時它負責初始化上下文每執行完一個步驟它負責把關鍵信息寫回存儲后續步驟需要信息時它負責把最相關的內容組裝進新的模型請求。這種設計讓“模型沒有記憶”這個底層限制不再直接暴露給業務代碼。業務側只關心當前任務的目標和結果不關心上一輪到底傳了多少歷史消息。2.2 四個核心機制機制作用解決什么上下文快照把當前任務的關鍵狀態持久化到外部存儲會話重置、進程重啟后的恢復摘要壓縮把冗長歷史壓縮成結構化摘要長文本超過窗口上限關鍵信息抽取從步驟結果中提取約束、結論、待辦項中間結果信息過載按需檢索當前請求只組裝最相關的片段token 浪費和信息漂移2.3 和“把上下文全部塞進 Prompt”的本質區別很多人遇到丟上下文第一反應是把所有歷史都塞進 Prompt。這個做法在任務短的時候有效任務一長就會撞上窗口上限而且會引入大量無關信息干擾模型輸出。prime-agent 的思路是“有所取舍”把必須記住的信息抽出來保存把不需要的細節丟棄把臨時需要的信息按需檢索回來。本質上是拿“存儲 檢索”換“上下文窗口”讓長任務不再被窗口大小鎖死。3. 環境與項目結構學習環境和生產環境先分開下面示例用于說明工程思路實際實現要結合自己的語言、框架和模型服務調整。如果原始材料沒有給出明確版本落地前先確認你的模型 SDK、向量庫和運行環境版本。3.1 最小運行環境組件建議說明語言Python 3.10示例代碼基于 Python其他語言同理模型服務任意外部 LLM API 或本地模型關注請求接口和返回結構存儲本地文件或 SQLite 即可先跑通再換 Redis、PostgreSQL可選向量數據庫只有用到按需檢索時才需要學習環境可以用本地文件存儲快照省去中間件部署。生產環境至少要換成具備高可用和事務能力的外部存儲。3.2 推薦的項目結構agent_app/ ├── main.py # 任務入口 ├── context/ │ ├── store.py # 快照持久化 │ ├── compress.py # 摘要壓縮 │ └── retrieve.py # 按需檢索 ├── steps/ │ ├── plan.py # 任務步驟定義 │ └── executor.py # 步驟執行循環 └── llm/ └── client.py # 模型調用封裝這個結構把上下文管理、任務執行、模型調用拆成三層。實際項目可以根據規模調整但“上下文管理獨立成模塊”這一點不要省否則后期排查會非常痛苦。3.3 核心數據模型一個長任務上下文至少需要保存以下信息# 示意數據模型實際字段按任務擴展 dataclass class TaskContext: task_id: str # 任務唯一標識 goal: str # 初始目標壓縮時不可丟棄 constraints: list[str] # 用戶約束逐條保留 completed_steps: list[str] # 已完成步驟 pending_steps: list[str] # 待執行步驟 latest_summary: str # 當前壓縮摘要 raw_events: list[dict] # 原始步驟記錄可被壓縮設計這個模型時要記住壓縮可以丟細節但目標、約束、已完成/待辦狀態是任務能否繼續的關鍵必須單獨列出不能混在長摘要里。4. 最小案例從樸素循環升級到帶上下文管理的 Agent4.1 場景假設假設要執行一個三步任務設定目標為產品寫一篇技術文檔。生成文檔初稿。根據約束校驗并修改。這個任務只有三步看似不需要上下文管理但把它循環執行 10 次、20 次時問題就暴露出來了。下面先用樸素實現演示問題再給出改進版。4.2 樸素實現為什么普通循環會丟上下文# 樸素實現每次請求都攜帶全部歷史 def naive_run(llm, steps, user_goal): messages [{role: user, content: user_goal}] for step in steps: # 把所有歷史消息都發給模型 content step.execute(llm, messages) messages.append({role: assistant, content: content}) # 問題messages 無限增長窗口遲早占滿這里的錯誤在于歷史消息只增不減也沒有任何持久化。任務在第 15 步時前面 14 步的完整輸出都堆在請求里中間步驟很容易被截斷。4.3 prime-agent 風格的上下文管理實現# 帶上下文管理的執行循環 def context_aware_run(llm, context_store, task_id, steps, user_goal): ctx context_store.load(task_id) if ctx is None: ctx TaskContext( task_idtask_id, goaluser_goal, constraintsextract_constraints(user_goal), completed_steps[], pending_stepssteps, latest_summary, raw_events[] ) for step in steps: if step.name in ctx.completed_steps: continue # 恢復時跳過已完成步驟 # 組裝當前請求目標 約束 摘要 當前步驟輸入 prompt build_prompt( goalctx.goal, constraintsctx.constraints, summaryctx.latest_summary, stepstep.input ) result llm.call(prompt) # 執行后把關鍵信息寫回上下文 ctx.completed_steps.append(step.name) ctx.raw_events.append({step: step.name, result: result}) # 超過閾值時做壓縮而不是無限擴展 if estimate_tokens(ctx.raw_events) COMPRESS_THRESHOLD: ctx.latest_summary compress_summary(llm, ctx.latest_summary, ctx.raw_events) ctx.raw_events [] # 壓縮后釋放原始事件 context_store.save(ctx) # 每步都落盤保證可恢復 return ctx.latest_summary關鍵點有三個每步完成后立刻保存上下文進程崩潰后可以從最后一步繼續。請求里只放“目標 約束 摘要 當前步驟”不塞全部歷史。原始事件超過閾值就壓縮壓縮后清空避免 token 增長失控。4.4 為什么這樣能保住上下文模型側看到的上下文變小了但任務最關鍵的信息沒有丟目標、約束、摘要都穩定存在。中間過程的完整文本被扔掉代價是“細節丟失”收益是“關鍵信息始終可引用”。長任務真正需要的不是全部歷史而是“夠用的歷史”。5. 關鍵參數與壓縮策略選型5.1 關鍵參數說明參數含義常見值調大影響調小影響COMPRESS_THRESHOLD原始事件觸發壓縮的 token 閾值窗口上限的 30%-50%保留更多細節token 消耗更高壓縮更頻繁細節丟失更多SNAPSHOT_INTERVAL快照保存頻率每步一次恢復粒度更細寫入開銷高恢復時可能丟失最近幾步RETRIEVE_TOP_K按需檢索返回片段數3-5上下文更充分可能引入噪音信息不足模型重復提問SUMMARY_MAX_TOKENS壓縮摘要長度上限窗口的 10%-20%摘要信息更全占用更多空間摘要過短丟失細節參數沒有絕對的最優值要結合任務類型調整。步驟產出很長、關鍵信息少的任務閾值可以調低盡早壓縮步驟之間強依賴、經常引用早期結論的任務摘要要留足空間。5.2 壓縮策略怎么選策略做法適合場景風險全量摘要把全部歷史壓縮成一段摘要階段性結論明確、步驟線性早期細節丟失滑動窗口只保留最近 N 輪完整消息近鄰步驟強依賴早期約束失效分層摘要按步驟或主題分塊壓縮可檢索長文檔、多子任務實現復雜度高混合策略關鍵信息單獨保存非關鍵信息壓縮大多數生產場景需要定義“關鍵”規則推薦組合是目標、約束、待辦單獨保存步驟結果做分層摘要模型請求時再通過檢索把相關片段拉回來。這是目前長任務工程里最常見的做法。6. 運行驗證怎么確認上下文真的保住了6.1 驗證步驟代碼跑通不代表上下文保住。建議按以下順序驗證檢查快照文件是否按預期生成內容是否包含目標、約束、已完成步驟。讓任務執行到第 N 步后手動中斷再重新啟動確認能從第 N 步繼續。在第 1 步設置一個明確約束比如“禁止使用某個術語”到第 20 步時觀察輸出是否仍遵守。查看每次請求實際發送的 token 數確認沒有隨步驟數線性增長。對比樸素實現和改進版在相同任務上的最終結果質量。6.2 預期日志輸出INFO tasktask_001 stepwrite_draft done INFO tasktask_001 raw_events_tokens12800 compress_triggeredTrue INFO tasktask_001 snapshot_saved offset6 INFO tasktask_001 stepreview_draft prompt_tokens3210看到compress_triggeredTrue和snapshot_saved交替出現說明壓縮和持久化都在正常工作。如果只有執行日志沒有快照日志就要懷疑上下文根本沒有被保存。6.3 驗證指標指標關注點請求 token 數是否被控制在穩定區間而不是隨步驟增長中斷恢復成功率重啟后能否從斷點繼續約束保持率早期約束在后續步驟的執行率最終結果一致性同輸入兩次執行結果是否穩定7. 常見問題與排查鏈路7.1 常見問題速查表問題現象常見原因檢查方式處理建議所有歷史塞進 Prompt窗口很快滿沒有做壓縮或檢索觀察請求 token 數引入摘要壓縮和按需檢索任務重啟后從開頭重新執行快照未保存或加載失敗檢查快照文件和日志每步落盤增加恢復邏輯壓縮后早期約束失效摘要只寫了結論沒寫約束查看 latest_summary 內容約束單獨字段保存檢索回來的片段不對片段缺少時間和順序信息檢查檢索返回結果給片段加時間戳、步驟號快照保存失敗但沒有報錯異常被吞掉關閉異常吞沒查看日志保存失敗要告警不能靜默7.2 標準排查鏈路按順序排查不要跳步先確認上下文存儲有沒有寫入檢查快照文件、數據庫記錄。再確認加載邏輯重啟后是否讀到了正確的 task_id。接著看壓縮摘要里是否包含約束和待辦。然后看檢索召回片段是否為當前步驟真正需要的內容。最后看請求組裝實際發給模型的 Prompt 里到底有什么。7.3 三個必須避開的坑坑一把所有歷史都塞回 Prompt。這是最常見的錯誤。以為自己做了上下文管理實際只是每次把 raw_events 全量拼進請求token 照樣爆炸。正確做法是只保留摘要、約束、待辦和當前步驟。坑二摘要只寫“做了什么”不寫“決定了什么”。壓縮時模型傾向于復述過程忽略結論和約束。建議壓縮 Prompt 里明確要求必須保留所有用戶約束、目標、未完成事項。坑三快照保存失敗被吞掉異常。很多 Agent 框架里上下文保存失敗只是 catch 后打一行日志任務繼續跑結果所有狀態都沒落盤。生產環境必須把保存失敗當成嚴重錯誤處理寧可暫停任務也不能讓狀態丟失。8. 最佳實踐與擴展方向8.1 長任務上下文管理檢查清單目標是否單獨保存不參與壓縮丟棄。用戶約束是否逐條保存并在每次請求內重復注入。已完成任務列表是否持久化重啟后能跳過。原始事件是否設置了 token 閾值并觸發壓縮。快照是否每步或每隔固定步數落盤。模型請求是否只包含目標、約束、摘要、當前步驟。保存失敗是否有告警是否阻斷任務繼續。測試用例是否包含“中斷后恢復”場景。8.2 生產環境還要額外做什么學習環境跑通后進入生產環境至少要補齊使用 Redis、PostgreSQL 等外部存儲替代本地文件避免多實例任務狀態不一致。給上下文管理增加監控指標請求 token 數、壓縮次數、快照耗時、恢復成功率。對模型調用增加重試和熔斷避免單次超時導致整個任務失敗。敏感信息要在寫入快照前脫敏防止上下文落盤帶來數據泄露風險。保留每個任務版本的歷史快照方便回溯和分析。8.3 下一步擴展方向如果長任務場景更復雜可以在 prime-agent 的思路上繼續擴展把摘要升級為向量索引任務規模大時用相似度檢索替代關鍵詞匹配。對超長任務做多級記憶分層工作記憶、任務記憶、長期記憶。在關鍵節點插入人工確認點由人來確認進度后再繼續。讓壓縮策略可配置不同任務類型使用不同閾值和摘要模板。長任務丟上下文不是模型能力問題而是工程架構問題。只要把“模型無狀態”這個事實接受下來圍繞持久化、壓縮、檢索幾個方向設計好上下文管理層任務跑得再久也能保持關鍵信息在線。對新手來說從這個最小案例開始改造自己的 Agent 循環比直接上復雜框架更值得先做。