作者:Yancheng He, Weixun Wang, and Xiaoyang Li | 專案負責人:Weixun Wang
本文英文名稱:The Bitter Lesson Behind Building Agentic RL in Terminal Environments
兩個 RLers 的故事
Alex 是一名二年級博士生,過去幾個月一直在做 RLVR(Reinforcement Learning with Verifiable Rewards)。訓練 LLM 解數學題、寫程式的過程幾乎都很立竿見影——模型生成回答,獲得獎勵,然後變得更好。乾淨、簡單。
「RLVR 本質上就是一個單步驟的 bandit 問題。」Alex 常常這樣和實驗室同學開玩笑。
有一天,指導教授突然建議他去探索 agentic 任務:網頁導航、工具調用、在真實環境中的多步推理。
「未來是 Agent。」指導教授意味深長地說。
Alex 信心滿滿地投入其中:「能有多難?我都懂 PPO 了,GRPO 論文也看過,RLVR pipeline 也上線過。」
兩週後,Alex 盯著一條毫無起色的訓練曲線發呆。
「怎麼了?」正在偷偷做 agent 系統的高年級學生 Morgan 問。
「什麼都不對!」Alex 抱怨道。「我的模型行為總是很怪異,環境還總是出現各種問題,結果什麼都學不到。信用分配根本無從下手。訓練速度賊慢。還有軌跡儲存的問題——光是存 KV cache 就把 GPU 顯存耗光了。」
Morgan 點了點頭:「歡迎來到 agentic RL。它已經不是 bandit 了。」
「可我讀過所有長時序 RL 的論文啊……」
「論文給你的是演算法。它不會告訴你,軌跡跑到一半環境崩了該怎麼辦;每個 episode 長度不同怎麼 batch rollout;或者怎麼在訓練時高效回放 50 步長的軌跡。」
Alex 無力地靠在椅背上:「那我該怎麼辦?」
Morgan 笑了笑:「幸運的是,我們把這些都記錄下來了——基礎設施、技巧、失敗案例。稍顯雜亂,但都是真實發生的。」
那一天,Alex 終於意識到:
RLVR 訓練的是一個「會回答」的模型。而 Agentic RL 訓練的是一個「會行動」的模型——跨時間、跨狀態、跨不確定性地行動。
而這,改變了一切。
RLVR 在數學、程式碼與通用推理任務上帶來了顯著提升。但在其成功背後,也隱藏著一種結構上的簡化:傳統的 RLVR 更像是一種 in-context bandit 問題——模型生成一次完整回答,獲得獎勵,然後更新參數。過程中不存在多步互動式決策與環境狀態轉移。
Agentic RL 則更接近多步互動式 MDP 的設定:模型需要採取行動、觀察環境回饋,並在稀疏且延遲的獎勵訊號下,對長程軌跡進行最佳化。
這意味著模型不再只是「給出一個答案」,而是要在不斷變化的環境中持續決策和修正行為,並為最終結果負責。這也讓應用場景從封閉、可驗證的任務,擴展到諸如旅遊規劃、複雜資料分析等更為複雜的真實任務。
這種轉變也對基礎設施和演算法設計提出了更高的要求:包括端到端非同步的訓練管線、更穩定的長時序信用分配機制、與真實環境的深度整合,以及能夠支撐持續擴展的工程基礎設施。本文記錄了我們在這一方向上的探索經驗。
我們將首先介紹我們如何建構的訓練環境,隨後分享我們如何篩選 RL 訓練實例,最後討論我們在訓練 Agentic RL 過程中累積的一系列實務經驗。
對演算法部分更感興趣的讀者,可以直接跳轉至訓練部分。
Why this matters ? Agentic RL is not just about algorithms — it requires co-designing environments, infrastructure, and algorithms.
環境管理器:從 0 到 1
為了在終端環境中使用強化學習訓練智慧代理,我們首先在 ROLL 中建構了一套環境管理器,並清晰地劃分了三個核心組件之間的互動邊界:ROLL(訓練框架)、iFlow CLI(Agent 框架) 和 ROCK(沙盒管理器)。
在實務中,我們支援了兩種互補的模式:
Roll-Managed Mode:由 ROLL 負責上下文管理與軌跡建構;主要透過工具調用介面與 iFlow CLI 互動。
CLI-Native Mode:上下文、會話與歷史資訊完全由 iFlow CLI 維護;ROLL 僅作為調用方,不負責軌跡拼接。
在不同的訓練階段,我們會根據當前的優先目標在這兩種模式之間切換。
Roll-Managed Mode
在這種模式下,終端環境以輕量級、step 粒度的方式運行,而 ROLL 負責整個 rollout 迴圈、軌跡建構與上下文管理。
主要組件包括:
TrajEnvManagerTB:驅動完整的 rollout 流程(重置→ 決策 → 執行 → 終止),並儲存訓練所需的軌跡資料。
TerminalBenchEnv:載入終端任務資料,向沙盒提交執行請求,收集執行結果,並根據測試結果計算獎勵。
SandboxManager:管理沙盒會話的生命週期(建立會話、執行命令、上傳檔案等)。
IFlowCLITool:解析工具調用格式及回傳結果,並構造符合 iFlow CLI 協定的可執行命令。
這種模式的主要優勢在於訓練側的高度彈性:可以根據訓練需求彈性組織上下文,引入更豐富的 prompt 模板和互動機制以提升穩健性(重要)。
但其缺點就是需要在 ROLL 內部維護額外的上下文處理邏輯,這不可避免地會與真實 iFlow CLI Agent 的行為存在一定差距。
CLI-Native Mode
在許多 Agentic RL 訓練管線中,訓練階段的 prompt 設計與上下文管理往往與生產環境中的真實 Agent 框架不同,這通常會導致部署後的模型能力下降。為了更好地與 Agent 側的最佳化保持一致,我們也同時開發了 CLI-Native Mode。
在 CLI-Native 模式下,我們相當於是直接在「iFlow CLI 上訓練模型」。
在 RL 過程中,ROLL 直接調用 iFlow CLI api 獲取最新上下文,而不是手動拼接 prompt 或重新實作 Agent 邏輯。
iFlow CLI 負責管理所有上下文、會話與歷史資訊,確保模型在訓練時看到的輸入分佈與真實使用場景一致(包括動態上下文、工具列表、系統提示詞、內部狀態等),並將更新後的上下文回傳給 ROLL。
iFlow CLI 與 ROLL 透過一個輕量級的 ModelProxy Service 通訊,該服務提供基於佇列的非同步訊息機制,用於交換 LLM 請求與回應,支援高併發與非阻塞執行。
這種模式確保訓練、評估與部署都完全一致,最大程度減少行為不一致的問題,但在訓練側上下文定製方面的彈性相對較低。
在實務中,我們會在不同階段使用這兩種模式,它們相互補充。
一些實作細節
非同步訓練管線
Agentic RL 具有明顯的長尾延遲特性:大多數 rollout 能夠快速完成,但少數 rollout 由於生成文字較長或緩慢的環境互動而耗時較長。
在同步、批次式 rollout 管線中,這些長耗時任務極易成為拖尾瓶頸,導致 GPU 利用率下降、端到端延遲增加。
為了解決這一問題,我們在 ROLL 中建構了一套完全非同步的訓練管線。具體包括:
環境級非同步 rollout:將 rollout 中的 LLM 生成、環境互動與獎勵計算拆解獨立,互不阻塞,實現更細粒度的執行調度。
冗餘並行環境:透過增加環境組數量與組大小,避免 fail-slow 或 fail-stop 環境成為系統瓶頸。
非同步訓練機制:在不同裝置上解耦 rollout 與訓練階段,使其並行推進。
Train–rollout 復用機制:透過時間分片動態劃分 GPU 資源,使裝置可以在 infer 與 train 之間彈性切換。
這一設計使系統在面對各種長尾現象時依然保持穩健,並在高延遲波動下維持穩定吞吐。
如果你對底層設計與更多實作細節感興趣,可以參考我們的 ROLL Flash 論文和 ROLLART 論文。
保持環境「乾淨」
在終端 RL 訓練中,初始環境狀態直接決定了 Agent 能夠觀察與利用的內容。即使是極小的殘留痕跡——例如暫存檔、快取連結、未完成安裝、或洩漏的測試腳本——都可能會影響學習訊號。
在早期實驗中,我們發現了兩個相關問題:
環境初始化與 Agent 安裝過程往往會留下中間產物(如暫存檔、快取套件、部分安裝結果),這些資訊可能間接提示模型。
在少量合成環境中,測試檔案儘管經過目錄隔離與權限控制,模型仍可能透過某些路徑或命令被模型間接存取到。
尤其是第二種情況,模型會非常迅速地「偷懶」:與其認真推理任務,不如直接讀取甚至修改測試腳本。圖中展示了早期訓練中最常見命令的分佈情況。測試腳本調用次數(紅色標註)顯著上升,說明模型越來越依賴這種捷徑,最終大量 rollout 退化為直接執行測試檔案。
為防止此類洩漏與污染,我們會進行嚴格的環境清理:
在 rollout 前主動清理環境初始化或 Agent 安裝過程中產生的中間檔案。
測試檔案僅在最終評估階段上傳,與訓練階段嚴格隔離。
簡而言之,我們確保環境保持乾淨,並嚴格隔離所有測試相關的檔案,讓 Agent 真正在沙盒中學習解決問題,而不是利用殘留線索或測試腳本漏洞。
RL 訓練實例
RL 訓練實例的品質對於 agentic RL 至關重要。同時並非所有「高品質」的實例都適合用於 RL 訓練。在我們的訓練管線中,RL 實例主要來自兩個來源:
大規模合成的實例:按照難度與標籤採樣,並由多個外部供應方進一步標註與篩選。
專家編寫的實例:通常難度更高、構造更精細。
關於合成流程的詳細介紹,可參考我們的技術報告:Let It Flow,這裡就不重點介紹了。
下面主要總結幾個在實務中比較關鍵的問題。
偽陽性問題
在早期階段,我們發現大量合成實例存在 false positive(偽陽性) 問題:自動生成的測試案例要麼不完整,要麼本身存在問題。
當然這是自動化單元測試生成中的普遍存在的問題,但在 agentic RL 中尤為致命,因為模型可能會有各種辦法「鑽漏洞」。在我們早期的合成資料中,false positive 比例一度高達約 40%。
一個典型的例子:
Task Description
Configure a git server so that I can run on my computer
git clone user@server:/git/server
echo "hello world" > hello.html
git add index.html
git commit -m "add index"
git push origin webserver
And have this data then be pushed to a webserver running on port 8080 so if I run
curl <https://server:8080/hello.html>
then I see the output "hello world"但測試腳本只檢查:curl <http://localhost:8080/hello.html> 是否回傳 "hello world"。
因此,Agent 完全可以在不真正建構 git → push → deploy 整個流水線的情況下通過測試——例如直接將 hello.html 寫入 web 根目錄。最終輸出結果看似正確,但底層系統行為並不符合預期。
為了解決這個問題,我們在資料合成流程中引入了一個完備的 LLM-as-judge 驗證模組。多個 LLM 協同審查每一組「指令–測試」對,識別具有高 false-positive 風險的實例。對於這些高風險樣本,我們會強化測試案例或調整任務描述。只有通過驗證的實例,才會進入 RL 訓練池。
Ground-Truth 與 No-Op 驗證
在將實例加入 RL 訓練池之前,我們都會進行兩個基礎檢查:
Ground-truth 驗證:如果 golden solution 無法通過全部測試,則捨棄該實例。
No-op 驗證:如果在不執行任何有效操作的情況下也能通過測試,則捨棄該實例。
這兩個檢查可以有效避免引入會產生誤導性訓練訊號的實例。
環境多樣性與穩健性
藉助 Roll-Managed Mode 的彈性,我們會有意在初始環境中引入多樣性,例如:
不同版本的軟體套件;
不同的映像檔來源;
不同的環境配置細節。
這樣做的目標是防止 Agent 過度擬合於某一種「理想化」的環境配置,使其能應對更多樣的環境。
除了上面提到的隨機化之外,我們有時還會進一步有意擾動甚至部分破壞環境——例如移除某個預裝相依套件或切換到不可用的映像檔來源。這迫使模型學會檢查、診斷與恢復,而不是預設一切環境條件都已準備就緒。
在實務中,這些操作相當於一種環境增強:它們幫助 Agent 處理不確定性,促使其在行動前主動檢查環境狀態,並提升其對不同環境配置的適應能力。
如何保證終端環境中 Agentic RL 的穩定性
在真實終端環境中進行 agentic RL 訓練,與在靜態資料集上訓練有很大的不同。訓練的不穩定性不僅來自策略最佳化本身,還來自於實例品質、環境雜訊、框架約束以及長程信用分配等多方面因素。
下面我們分享一些我們認為在實務中比較關鍵的技巧和經驗。
Mask and Filter
終端環境不可避免地會出現:
瞬時的網路故障;
沙盒啟動失敗;
工具調用偶發超時等問題。
如果將這些異常訊號直接納入策略更新,會向最佳化過程引入雜訊。為此,我們採用了較為通用的 mask & filter 策略,就遵循一個簡單原則:
當前對訓練有害或無法提供有效學習訊號的樣本都可以採用 mask 或是 filter
在高雜訊、強環境依賴的 agentic RL 訓練中,這往往是維持訓練穩定性的基礎保障。基於這一思路,我們將失敗顯式劃分為兩類:
不可恢復或大規模的錯誤(例如環境啟動失敗、沙盒不可用):這類樣本會被完全 mask 掉,並用佔位樣本替換,以保證能有 batch size 大小的資料。
def handle_rollout_with_mask(rollout, failure_type):
"""
rollout: one trajectory (episode-level)
failure_type: describes what went wrong during rollout
"""
# Unrecoverable or large-scale failures
# e.g. env init failed, sandbox unavailable, reward computation broken
if failure_type in {
"env_init_failed",
"sandbox_unavailable",
"env_reset_failed",
"reward_calculation_failed",
}:
# Create a placeholder rollout to keep batch shape stable
placeholder = create_placeholder_rollout()
# Mask all tokens so this sample contributes zero gradient
placeholder.response_mask[:] = 0
placeholder.advantages[:] = 0
placeholder.rewards[:] = 0
placeholder.meta["masked"] = True
return placeholder
# Normal rollout: keep as-is
return rollout偶發且可恢復錯誤(例如工具超時、網速延緩等):這類樣本會被 filter 掉,並在全局控制比例(例如 ≤50%)下捨棄,避免過度重試。
class GroupFilterTB:
def __init__(self, config: AgenticConfig, env_manager_config: EnvManagerConfig, mode: str):
self.config = config
self.env_manager_config = env_manager_config
self.mode = mode
self.global_filter_stats = {"total": 0, "filtered": 0}
def filter(self, group_id: int, episode_id: int, group: list[DataProto]):
"""
Decide whether to filter out an entire group of rollouts.
"""
self.global_filter_stats["total"] += 1
# Step 1: Check whether this group contains any rollout
# that explicitly requests to be dropped
# (e.g., due to tool timeout, transient execution error)
should_drop = False
for data in group:
if data.meta_info.get("drop_flag", False):
should_drop = True
break
# If no rollout indicates a drop condition, keep the group
if not should_drop:
return False
# Step 2: Compute the current global filter ratio
# This guards against pathological cases where
# too many groups are dropped and training stalls
current_global_filter_ratio = (
self.global_filter_stats["filtered"] / self.global_filter_stats["total"]
if self.global_filter_stats["total"] > 0 else 0.0
)
# If we already filtered too much globally, stop filtering
if current_global_filter_ratio >= 0.5:
return False
# Also prevent the *next* filter from exceeding the limit
if (self.global_filter_stats["filtered"] + 1) / self.global_filter_stats["total"] > 0.5:
return False
# Step 3: Drop this group and update global stats
self.global_filter_stats["filtered"] += 1
return True此外,我們在訓練過程中還會根據需要引入其他類型的 mask 操作,例如 max-turn mask 等,以進一步約束異常軌跡對最佳化的影響。
如下圖所示,不使用 mask & filter 時訓練波動較大、準確率不穩定;而採用該策略後,訓練曲線更加平滑,並收斂到顯著更優的效能。
保守起步:先從正樣本軌跡學習
在早期階段,RL 往往受限於資料品質,而不是最佳化演算法本身(當資料品質較差時,再好的最佳化方法也難以奏效)。
我們的觀察是:
在資料尚未完全可靠時,僅使用正樣本軌跡進行訓練明顯更穩定。
當然也存在共識:資料足夠可靠時,同時利用正負軌跡能夠帶來更好的泛化能力。
我們對兩種訓練策略進行了直接對比。在大規模合成資料上,同時使用正負軌跡進行更新往往頻繁崩潰,而僅用正軌跡訓練在各種設定下都保持穩定。
當切換到小規模、高品質、經過專家驗證的資料後,趨勢發生變化:兩種方法都能穩定訓練,但加入負軌跡後,下游測試集上的效能提升更顯著。
基於此,我們採用了一種簡單的課程式策略:
早期階段,僅使用正樣本軌跡更新策略,利用大規模實例資料建構穩定的策略流形。
後期階段,當擁有小規模但高品質的實例(通常為專家建構並多輪驗證)後,才開始同時考慮正負軌跡訓練。
這種課程式方法既避免了早期發散,又保留了後期效能提升空間。
與 RFT 的區別:乍看之下,僅使用正樣本進行更新可能類似 Reinforcement Fine-Tuning(RFT),但兩者在形式與訓練動力學上存在明顯的差異:
前者損失函數仍然是標準的 RL 目標函數,而非完全的行為克隆式目標,因此通常具備更強的泛化能力。
前者策略更新仍遵循標準 RL 流程,包括 masking、clipping、normalization 等穩定機制,從而可以自然整合樣本過濾、細粒度獎勵以及訓推不一致控制等策略——這些在雜訊較大的終端環境中尤為重要。需要強調的是,positive-only RL 並不是 RFT 的替代,而是一種更為保守的 RL 訓練方式。
Chunked MDP
多輪 agentic 任務中:
大多數 token 並不會改變環境狀態;
一條軌跡中可能包含多個決策節點;
在大多數情況下,每一次互動步驟都對應一個具體的決策或狀態轉移。
因此我們重新思考了 agentic RL 的最佳最佳化單元。
核心思路
我們提出在 interaction chunk(互動片段) 層面建模多輪 agentic 互動。所謂 interaction chunk,是指從一次環境互動到下一次環境互動之間的一段連續片段,通常以一次工具調用結束,構成一個完整的功能單元。
與其對單個 token 或整條軌跡進行最佳化,我們將每個 chunk 視為一個語義上的「動作單元」。
在此基礎上,我們提出了 Interaction-Perceptive Agentic Policy Optimization(IPA),其核心包括:
在 chunk 層級 而非 token 層級計算回報與重要性採樣;
當推理策略與訓練策略的偏差過大時,對 整個 chunk 進行 masking,而不是逐 token masking,從而更契合以結果為導向的粗粒度獎勵結構;
引入 chunk 初始化重採樣,以及 imitation learning + RL 的混合訓混合訓練方式,擴大模型在困難任務上的有效學習範圍。
總體而言,IPA 將信用分配、重要性採樣與學習訊號重新錨定在「interaction chunk」這一統一的互動單元上。
收益
這種設計帶來了兩個實際收益:
在長程軌跡上獲得更穩定的梯度;
提升模型可學習能力的上限。
從實驗結果來看,IPA 在困難的長程任務上始終表現出更平滑的梯度與更強的效能表現。下圖展示了 token 級最佳化與 chunk 級最佳化的直接對比:
關於 Chunked MDP 的完整公式、masking 策略以及 chunk 初始化重採樣方法,我們已在技術報告中進行了系統整理。對完整技術細節感興趣的讀者,可參考我們的技術報告。
下面展示的是採用最終 IPA 演算法訓練得到的模型訓練曲線:
自適應地應用 RL 技巧
Agentic RL 為什麼更難?
在訓練 agentic model 時,有以下幾個突出的問題:
重尾分佈與極端負回報
少數失敗軌跡可能異常長(例如無限重試、長迴圈、重複工具調用),從而產生極大幅度的負回報。這些重尾樣本容易主導梯度,導致策略分佈向次優區域偏移,引發訓練不穩定。
帶正向結果的淺層策略模式
模型可能並未真正理解任務,而是依賴重複試錯、某些固定命令序列或某些捷徑。由於 outcome reward 只檢查最終結果,這類淺層模式可能被強化,逐漸收縮策略空間並形成固化的模板。
雜訊型失敗
失敗往往多樣且不明確,未必都由模型本身引起,可能是由環境隨機性或系統級干擾引起。負樣本的信心度通常低於正樣本。
從宏觀角度看,agentic RL 面臨的問題與 RLVR 在 outcome reward 下的問題類似:信用分配、負樣本不可靠、訓練不平衡。但在終端環境中,這些問題更為嚴重:時序更長;工具互動更離散;改變環境的 token 占比極小;失敗模式更多樣,負樣本變異數更大等。
在 agentic 設定下,訓練訊號的訊噪比顯著下降,使得信用分配與樣本可靠性問題更加敏感。
我們通常會根據當前的主導因素採取不同緩解策略,例如:
selective trajectory masking
selective token masking
trajectory-level reweighting
retry-loop penalties
other light behavior shaping rewards or penalties, …
這些策略的核心目標一致:
控制哪些軌跡、軌跡的哪些部分,以及以何種權重參與策略梯度更新。
需要強調的是,沒有通用解法。不同資料條件下,同一策略可能產生相反效果。
如下圖所示,在兩種不同的資料設定下,我們觀察到了截然相反的現象:在一種情況下,移除標準差會迅速導致訓練崩潰;而在另一種情況下,同樣的操作卻反而使訓練更加穩定(這裡主要是資料分佈的差異導致)。
這一現象與我們此前在 RLVR 任務中對各類 RL 技巧的分析結果是一致的。感興趣的讀者可以參考我們的論文以了解更多細節:RL Tricks
Crash 是常態,關鍵是如何 Resume
由於上述各種不穩定因素的存在,agentic RL 在訓練過程中會更容易發生崩潰。因此,我們首先需要建立一個簡單的心態:
在大規模終端 RL 訓練中,崩潰是常態。
訓練樣例
如下圖所示(紅色曲線),訓練分數在大約 step ~80 時開始急劇下降。但如果回顧更早階段,我們可以看到在開始崩潰之前,優勢的平均值已經出現了明顯的持續下滑趨勢。
進一步分析發現:
從大約 step ~50 開始,失敗軌跡的最大回覆長度迅速上升;
但是失敗軌跡的樣本數基本保持不變。
這表明問題並非源於整體失敗數量的增加,而主要是少量極端失敗軌跡的影響。
為緩解這一問題,我們首先對回應長度超過 20k 的失敗軌跡進行 masking 來消除這些極端負樣本的影響(以及其他目標一致的策略,例如降低權重)。從灰色曲線可以看到,優勢的平均值開始回升,訓練過程趨於穩定。
但在大約 40 個 step 之後,不穩定再次出現。這一次,最早的訊號是負樣本數量逐漸增加。針對這一現象,我們對負樣本進行全局重加權,降低其在策略更新中的整體貢獻。結果如橙色曲線所示。
透過這一步調整,訓練再次恢復穩定。這只是一個簡單的範例——在整個訓練過程中,我們經歷了許多類似的時刻。
當訓練出現不穩定時,我們通常優先檢查以下幾個訊號:
是否有少量極端軌跡正在主導更新?(典型特徵:異常長的失敗軌跡,伴隨重尾分佈的負回報)→ 採用 masking,降低這些軌跡的權重,並收緊 clipping。
負樣本是否在整體上佔據主導?→ 降低負樣本權重,過濾低信心度失敗樣本,或採用課程式訓練策略。
模型是否在學習「壞模式」?→ 引入行為懲罰、更多維度的獎勵設計等。
……
另外有兩條經驗性原則:
優先針對極端軌跡進行定向處理(如果極端軌跡能被某些特徵定位到,例如 mask 掉超長負樣本),如果仍然不穩定,再採用全局重加權。
RL 梯度通常比監督學習雜訊更大,因此更小的學習率,配合更強的約束、退火或自適應機制,往往更穩定。
細粒度行為監控與懲罰
在 Agentic RL 中,reward hacking 往往更加隱蔽。由於智慧代理與真實環境互動,它們常常可以以「看似合理」的方式通過測試案例。
在實務中,我們觀察到一些反覆出現的模式:
修改既定環境:智慧代理不是解決任務本身,而是直接修改初始環境設定。
工具過度使用:反覆調用工具完成一些簡單或瑣碎的操作,本質上是在進行暴力重試。
濫用搜尋:透過大量重複調用搜尋引擎來彌補內部推理能力不足。
不安全或破壞性操作:執行高風險命令,例如刪除所有檔案或終止所有行程。
隱蔽的捷徑:利用測試腳本或環境預設配置中的漏洞,在未真正解決任務的情況下通過測試。
這些現象主要是兩點啟示。
第一,測試案例的品質與穩健性至關重要——薄弱或描述不充分的測試可能在無意中獎勵錯誤行為。
第二,並非所有實例都適合用於 RL 訓練:某些任務本身難以透過測試準確評估,反而更容易誘導模型尋找捷徑或形成不良模式,而不是學習真正的解決方案。
值得一提,我們在訓練過程中對模型行為進行了很細粒度的監控。比如會追蹤如下訊號:
不同任務的成功率趨勢;
不同工具的成功 / 失敗率;
重複或迴圈的工具調用模式;
不同工具使用頻率;
不同命令使用頻率。
透過這些訊號,我們可以快速發現行為異常的任務,例如某個工具調用突然激增、出現大量重試迴圈,或頻繁執行「kill process」類命令等等。一旦檢測到類似模式,我們會回滾訓練,或定位並移除引發問題的實例。
根據我們的經驗,這種持續、細粒度的監控與動態調整,也是保證長期 agentic RL 訓練穩定且有效運行的關鍵(尤其是在防止隱蔽 reward hacking 行為方面)。
環境服務的可觀測性
這裡額外提一點沙盒環境服務的視覺化觀測也非常重要。
下面這張圖,是我們某次大規模訓練期間的沙盒併發監控。不同顏色代表不同環境組,在高峰階段系統會同時維持數千級別的併發會話,圖中的尖刺往往對應某些環境組瞬時的負載激增或回收延遲。
事實上,我們在多個階段都遇到過因環境併發抖動導致的訓練異常,這些問題在沒有系統級服務觀測的情況下會很難定位。
我們的訓練離不開 ROCK 工程團隊的長期支援。所使用的沙盒管理系統 ROCK 已經開源,歡迎了解。
總結
Agentic RL 本身就是細節很多,這本質上也是一套高度耦合的系統:資料、環境、獎勵、調度、最佳化……任何一個小環節出問題,都可能在幾十個 step 之後放大成一次 crash。
所以早期階段不可避免地會經歷大量排查:看曲線、翻日誌、做視覺化、定位異常軌跡、回滾實驗(我們的家常便飯了)。
但當這些關鍵環節被一一理順、視覺化監控體系搭起來之後,後面的訓練都會順利起來,訓練曲線基本都很穩定,異常模式可以被提前發現,crash 也基本可溯源。
前期那些看似繁瑣的檢查,其實是在為後面的大規模穩定訓練打基礎。
而一旦把這些基礎打牢,很多事情就會自然展開。
Looking Forward
從建模角度看,終端環境其實更接近 部分可觀測馬可夫決策過程(POMDP)。
Agent 通常無法直接觀察到完整的環境狀態:例如完整的檔案系統結構、已安裝軟體版本、先前修改過的配置以及過去的失敗嘗試,都很難完整呈現。
很多我們在訓練中遇到的問題,本質上都可以歸結為兩個老問題:部分可觀測性 與 長期信用分配。
這些問題並不新,但在 agentic 場景下會被進一步放大。我們認為 agentic RL 還有若干值得探索的方向:
挖掘更複雜的長時序任務與有效的 agentic 模式
一方面,我們確實需要更複雜、更貼近真實世界的長時序任務(現在 terminal-bench 裡的大多任務並非真正的長序任務)。
另一方面,我們認為:有些 agent 能力,至少在當前階段,很難僅靠 RL 自發湧現(網路上有大量記錄「人如何思考」的文字,但很少有系統性記錄「人如何完成複雜任務」的完整執行過程——因為這些任務往往跨平台、跨裝置、跨時段展開,完整軌跡難以被收集)。
主動地挖掘並強化有效的 agentic 行為模式是一個值得思考的地方。
更真實的 Agent–Environment–Human 閉環最佳化
在真實應用中,Agent 面對的並不是靜態環境與固定工具介面,而是一個持續演化的包含 Agent,Environment,Human 的系統。使用者可能隨時補充資訊、修改需求、糾正錯誤,甚至直接改變環境本身。
面對這種動態場景,Agent 不能只是一味執行指令,而要學會主動獲取資訊、在不確定時及時確認,並在收到回饋後更新自己的判斷,並將這些「提問—回饋—更新信念」的過程納入訓練與評估,從而建立更接近 human-in-the-loop 與 online RL 的最佳化框架。
更強大的基建與更開放的環境
Agentic RL 其實非常吃工程能力,需要高併發、低阻塞、可擴展的環境執行能力;需要足夠穩定且高度非同步的訓練框架來降低時間開銷;更需要能夠支撐模型持續 scaling 的工程基礎。
與此同時,當前許多終端環境仍然高度依賴人工配置——例如固定的映像檔來源、權限邊界控制、預安裝軟體,以及被限制在單機或 Docker 容器中的執行空間。
這些都會無形中限制模型的探索空間。如果我們希望 Agent 具備更強的泛化能力,很可能需要 更高層次、更開放、更可演化的環境體系,並結合依賴環境動態變化的獎勵設計(而非靜態獎勵規則)。
更細粒度的信用分配與獎勵建模
相較於 RLVR,agentic RL 有更多可被利用的中間訊號,例如工具執行成功與否、子任務完成情況、環境狀態一致性檢查等。但我們並不認為依賴複雜的獎勵規則設計(例如對工具失敗固定施加 −0.5 懲罰)是一種可持續的解決方案。
其他有趣的發現
並行函數調用
下圖對比了 qwen3-coder-plus、glm-4.6、claude-sonnet-4.5 以及 ROME 在同一批任務上的軌跡表現,展示了在單個 assistant step 內進行 並行函數調用 的頻率與分佈情況。
我們觀察到,claude-sonnet-4.5 的並行度顯著更高,無論是在進行並行工具調用的頻率上,還是在單步內同時調用的工具數量上,都明顯領先。
進一步的分析發現,claude-sonnet-4.5 往往更擅長在執行具體操作前識別當前真正需要的資訊。它通常不會立刻進入執行階段,而是先識別環境中的關鍵不確定性,並在同一步驟中透過多個並行的「檢查類調用」獲取資訊。
例如,當給出任務「Install Anaconda for me」時,claude-sonnet-4.5 會在單一步驟中進行多項檢查,包括但不限於:
使用
pwd、ls、cat、grep等命令檢查目錄結構與配置狀態;使用
python -V和pip list識別現有 Python 環境與相依套件情況;使用
read_file與search查找可行的安裝方法及相關約束(如網路連通性、映像檔可用性)。
從經驗上看,這種並行調用主要集中在檢查類工具上,而不是直接修改環境的執行或編輯類操作。
這種模式為 Agent 設計與訓練提供了一個有價值的啟示:在進行狀態改變之前,顯式鼓勵一個「前置的、並行的資訊收集階段」可能是有益的。
常見失敗模式
在對一些軌跡分析中我們發現終端類 agentic 任務中最常見的兩類失敗模式是:無效迴圈 與 超時。
智慧代理往往在已有明確失敗訊號的情況下,仍然重複同一種策略,而不懂切換思路或重新審視假設,從而形成冗長而無效的互動鏈。
另一方面,超時也是一個重要失敗來源:歸結到模型上往往是缺乏對長時間運行命令執行時長的可靠感知,容易被預設超時機制誤導,從而產生誤判或反覆重試。
除了這兩類主導模式之外,我們還觀察到其他問題,例如幻覺、不恰當的工具選擇,以及違反任務約束等。
下圖展示了多個模型在 Terminal Bench 上的錯誤類型分佈:
總結
我們所遇到的核心挑戰——長時序信用分配、部分可觀測性、雜訊失敗以及脆弱的環境——在強化學習領域並非新問題。
真正的難點在於,如何建構穩定可靠的整個系統(訓練框架、沙盒環境和 agent 框架等)。
當然 Agentic RL 仍處於早期階段,本文中提到的許多技術,可能並非最佳實務或最終方案,主要都是我們在實際實驗過程中總結出的經驗教訓。
展望未來,隨著環境更加開放、任務更加複雜,我們相信真正的進步將來自於最佳化目標、環境、訓練框架之間更加緊密的協同設計和整合。
我們希望這篇部落格以及此前的技術報告,能夠為那些在真實環境中訓練 agentic model 的研究者與工程師提供幫助,或許也能讓他們少走一些我們曾經踩過的冤枉路。
English Version:https://www.notion.so/The-Bitter-Lesson-Behind-Building-Agentic-RL-in-Terminal-Environments-2eaddd45837f80c9ad2ed6a15ef3c1a1?pvs=21
🚀ROLL TEAM:https://wwxfromtju.github.io/roll_team.html
📄 技術報告:https://arxiv.org/pdf/2512.24873
🧠 模型:https://huggingface.co/FutureLivingLab/iFlow-ROME
🧩 框架:
RL訓練框架: https://github.com/alibaba/ROLL
沙盒環境管理: https://github.com/alibaba/ROCK
Agent框架:https://github.com/iflow-ai/iflow-cli
📊 Benchmarks: https://github.com/alibaba/terminal-bench-pro引用連結
[1] ROLL Flash: https://arxiv.org/pdf/2510.11345
[2] ROLLART: https://www.arxiv.org/pdf/2512.22560
[3] Let It Flow: https://arxiv.org/pdf/2512.24873
[4] RL Tricks: https://arxiv.org/abs/2508.08221
[5] ROCK: https://github.com/alibaba/ROCK