
CopilotKit A2UI 錯誤恢復實戰Google ADK 的 validate→retry 恢復循環與硬失敗降級【免費下載鏈接】CopilotKitThe Frontend Stack for Agents Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol項目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit導讀本文基于 CopilotKit 倉庫中 Google ADK 集成的 A2UI Error Recovery 演示a2ui-recovery系統講解生成式 UIA2UI在模型產出畸形渲染結果時的完整容錯機制中間件如何通過parse_and_fix在單次嘗試內治愈松散參數如何通過 validate→retry 恢復循環在達到嘗試上限后返回a2ui_recovery_exhausted硬失敗信封以及前端ag-ui/a2ui-middleware如何以building → retrying → failed → painted的生命周期狀態優雅呈現全過程。讀完本文你將掌握這套后端中間件恢復 前端生命周期渲染的 A2UI 容錯架構并能夠復現其 QA 驗證流程。一、為什么生成式 UI 需要錯誤恢復A2UIAgent-to-UI讓 Agent 直接生成 UI 描述而非傳統地逐個調用工具。模型生成的 UI 描述天然存在不確定性——它可能把 components 與 data 序列化成 JSON 字符串而非結構化數組松散參數也可能引用一個不存在的子節點結構性錯誤。在 CopilotKit 的 v2 React Core 中A2UI 中間件驅動整個生成式 UI 生命周期于單個a2ui-surfaceactivity 上一個穩定的 messageIdreplace: true見 A2UIMessageRenderer.tsxbuilding動畫骨架屏 Building interface可選實時 token 計數retrying同一骨架屏當重試可感知后副標題變為 Retrying generation… (N/M attempts)failed干凈的錯誤卡片替換骨架屏絕不出現半渲染的壞 surfacepaintedsurface 渲染器接管 UI上述狀態不再渲染任何內容這一生命周期的狀態機、時序與調試信息曝光均定義在 A2UIRecoveryStates.tsx。本演示OSS-158的價值在于把這些內部機制顯式暴露出來通過兩個建議按鈕分別驗證可治愈與不可治愈兩條路徑。二、Demo 概覽ADK-only 的架構定位本演示是ADK-only的恢復循環recovery loop存在于 Google ADK 的ag_ui_adk中間件中而 langgraph-python 運行時路徑沒有等價實現因此該 demo 沒有 langgraph-python 的 parity 對照在 LP e2e-parity 對比中豁免原文檔 Notes 部分OSS-375 跟蹤 LP parity。與 declarative-gen-ui 演示不同本 demo 采用**后端擁有backend-owned**的 A2UI 接線組件配置說明運行時路由injectA2UITool: false防止運行時再注入一份工具雙重綁定ADK Agentget_a2ui_tool({ recovery: { maxAttempts: 3 } })后端 Agent 自己擁有generate_a2ui工具目錄defaultCatalogId: declarative-gen-ui-catalog復用 declarative-gen-ui 目錄不引入新組件主題Vantage Threads 銷售上下文復用銷售數據集讓修復后的 surface 有真實數字可渲染只有 backend-owned 路徑會顯式暴露恢復循環與a2ui_recovery_exhausted硬失敗declarative-gen-ui 演示采用的是運行時自動注入不暴露該循環。三、前置條件復現與驗證本演示前需滿足以下條件完整繼承自 原文檔Demo 已部署可在 dashboard 主機上通過/demos/a2ui-recovery訪問Agent 后端健康/api/healthGOOGLE_API_KEY已設置AGENT_URL指向暴露a2ui_recoveryagent 路徑的 ADK agent serveragent 注冊名為a2ui-recovery見 copilotkit-a2ui-recovery/route.ts依賴版本要求ag-ui-adk 0.7.0提供 validate→retry 恢復循環 a2ui_recovery_exhausted硬失敗信封ag-ui/a2ui-middleware 0.0.10提供building/retrying/failed生命周期渲染后端擁有式接線路由設置injectA2UITool: falseAgent 通過get_a2ui_tool({ recovery: { maxAttempts: 3 } })擁有generate_a2ui見 recovery_agent.py復用declarative-gen-ui目錄catalogId: declarative-gen-ui-catalog與 Vantage Threads 銷售上下文無新增組件本演示為ADK-only無 langgraph-python parity 參照3.1 運行時路由backend-owned 接線實現route.ts 的核心邏輯const AGENT_URL process.env.AGENT_URL || http://localhost:8000; const recoveryAgent new HttpAgent({ url: ${AGENT_URL}/a2ui_recovery, headers, // 轉發入站 x-aimock-context 頭 }); const runtime new CopilotRuntime({ agents: { a2ui-recovery: recoveryAgent }, a2ui: { injectA2UITool: false, // 關鍵后端已擁有工具運行時不得再注入 defaultCatalogId: declarative-gen-ui-catalog, }, });injectA2UITool: false是承重墻配置——CopilotKit#5611 之后 provider catalog 默認將injectA2UITool置為 true若此處不顯式關閉運行時會再注入一份generate_a2ui造成雙重綁定。3.2 ADK Agent把恢復循環參數顯式釘死recovery_agent.py 中Agent 以LlmAgent形式注冊recovery_agent LlmAgent( nameA2uiRecoveryAgent, modelget_model(), instruction_INSTRUCTION, tools[ get_a2ui_tool({ model: get_a2ui_model(), default_catalog_id: declarative-gen-ui-catalog, recovery: {maxAttempts: 3}, on_a2ui_attempt: _log_attempt, }) ], after_model_callbackstop_on_terminal_text, )要點解析recovery: {maxAttempts: 3}恢復與恢復耗盡硬失敗本是 toolkit 默認行為此處為演示顯式釘死上限使渲染器的 Retrying… (N/M) 標簽與適配器上限一致on_a2ui_attempt: _log_attempt開發可觀測性鉤子每次嘗試含被拒絕的都會記錄[a2ui recovery] attempt N: valid/invalid errors見 recovery_agent.pyget_a2ui_model()A2UI 子 Agent 需要具體的Gemini模型對象而非字符串因為在強制render_a2ui調用中模型被直接調用同時該函數會按GOOGLE_GEMINI_BASE_URL接入 aimock 代理并安裝 x-header 鉤子使子 Agent 的調用與主 Agent 走同一代理、匹配同一批 aimock fixtures見 shared_chat.pystop_on_terminal_textafter_model_callbackGemini 3.1 Flash-Lite 在成功工具調用后不會自然結束 agentic 循環該回調在含文本且無 pending function_call且finish_reasonSTOP時設置_invocation_context.end_invocation True終止循環防止無限重復調用工具四、測試步驟4.1 基礎功能導航到/demos/a2ui-recovery驗證頁面在 3 秒內渲染且單個CopilotChat面板居中max-width ~896px、rounded-2xl、全高。前端實現見 page.tsx它使用CopilotKit組件并指定runtimeUrl/api/copilotkit-a2ui-recovery、agenta2ui-recovery、a2ui{{ catalog: myCatalog }}驗證聊天已接線到runtimeUrl/api/copilotkit-a2ui-recovery與agenta2ui-recoveryDevTools → Network發送消息命中該端點而非/api/copilotkit驗證兩個建議按鈕suggestion pills以逐字標題可見Recover a bad renderShow an unrecoverable failure兩個按鈕的定義見 suggestions.ts通過useConfigureSuggestions注冊。前端聊天面板在 chat.tsx 中通過CopilotChat agentIda2ui-recovery classNameh-full rounded-2xl /渲染并復用 declarative-gen-ui 的銷售上下文。4.2 治愈路徑Healing path點擊 Recover a bad render消息Render my Q2 sales dashboard, recovering if the first attempt is malformed.內層render_a2ui返回free-form / 松散sloppyA2UI 參數components 與 data 以 JSON 字符串而非結構化數組形式存在。驗證中間件通過parse_and_fix**治愈heals**這些參數為有效 surface 并完成渲染——無壞 surface、無錯誤橫幅驗證渲染出的surface 有效包含declarative-metric行Quarterly Revenue $4.2M、Win Rate 31%——即松散渲染被修復并正常呈現DevTools → Network驗證最終工具結果攜帶a2ui_operations容器無a2ui_recovery_exhausted驗證聊天回復為一句話簡述治愈結果aimock fixture 中 HEAL 分支的內層render_a2ui參數即為典型松散形態a2ui-recovery.json{ id: call_d6_recover_heal_design, name: render_a2ui, arguments: {\surfaceId\: \recovery-demo\, \catalogId\: \declarative-gen-ui-catalog\, \components\: \[{\\\id\\\: \\\root\\\, ...}]\, \data\: \{}\} }注意components與data都是字符串而非數組——這正是模型常產出的松散形態。治愈本身由 ADK 中間件實時執行parse_and_fix單次通過而非 fixture 預先修復。對應的 Playwright 斷言a2ui-recovery.spec.ts確認declarative-metric元素數量 ≥ 2且頁面上不出現Couldnt generate the UI、Catalog not found、Cannot create component ... without a type 等錯誤文本。4.3 硬失敗路徑Hard-fail / recovery exhausted點擊 Show an unrecoverable failure消息Render a dashboard that keeps failing validation so I can see the fallback.驗證生命周期以得體的failed狀態結束既不是壞/半渲染 surface也不是靜默丟棄DevTools → Network驗證render_a2ui被嘗試至上限3 次嘗試全部無效工具返回a2ui_recovery_exhausted信封無a2ui_operations渲染驗證聊天回復用一句話優雅解釋降級行為EXHAUST 分支的 fixture 結構性無效root 引用了未定義的子節點never-defineda2ui-recovery.json因此每次嘗試都校驗失敗循環必然觸頂。對應斷言a2ui-recovery.spec.tsCouldnt generate the UI 可見超時 90sdeclarative-metric數量恒為 0壞 surface 永不渲染——中間件門控 適配器恢復循環共同保證的 no-wipe 語義且聊天輸入框仍可用對話在硬失敗后可繼續使用。4.4 回歸與隔離驗證恢復演示不影響 declarative-gen-ui 或 beautiful-chat 演示各自獨立的路由與 Agent每個按鈕再次運行驗證產生相同的生命周期五、雙按鈕的 fixture 選擇機制per-pill 區分兩個按鈕跑的是同一個內層render_a2ui工具但它們之所以能分別命中可治愈與恒無效的 fixture依賴一個精妙機制原文檔 Per-pill fixture selection 小節ag_ui_adk 0.7.0會把運行時的對話轉發進內層render_a2ui調用因此 aimock 匹配的最后一個用戶回合就是按鈕提示語本身通用的 A2UI 渲染指引作為 system prompt 攜帶不參與用戶消息匹配。由此每個按鈕按userMessage命中自己的內層 fixtureHEAL → free-form/可治愈 fixtureEXHAUST → 恒無效 fixture。經 aimock journal 驗證HEAL →call_d6_recover_heal_designEXHAUST →call_d6_recover_exhaust_design被調用 3 次對應重試循環。三個 e2e 測試頁面加載、heal、exhaust在 aimock 下全部通過。六、前端生命周期渲染的源碼級細節ag-ui/a2ui-middleware 0.0.10負責把中間件狀態渲染為可見 UI。其狀態字段由中間件蓋印在a2ui-surfaceactivity 內容上A2UIRecoveryStates.tsxstatus: building | retrying | failed可選 attempt / maxAttempts / progressTokens / error / errors / attempts可選 debugExposure: hidden | collapsed | verbose可選服務端可覆蓋客戶端選項可調項客戶端a2ui.recovery選項見 CopilotKitProvider.tsx選項默認值作用showAfterMs2000Retrying… 副標簽在延遲多少毫秒后可見showAfterAttempts2一旦attempt達到該值立即顯示 Retrying… 副標簽debugExposurecollapsed調試細節曝光程度hidden/collapsed/verbose關鍵實現行為A2URetryingState快速/瞬態重試不會閃爍只有重試可感知后超過showAfterMs或attempt越過showAfterAttempts副標簽才顯示Retrying generation… (N/M attempts)否則與正常 building 狀態無異debugExposure ! hidden且有校驗錯誤時骨架屏下方出現可折疊的 validation issues 調試面板失敗態A2UIRecoveryFailure以琥珀色卡片替換骨架屏標題 Couldnt generate the UI副文案提示可繼續聊天并重試開發細節折疊在debugExposure門控的 expander 內。渲染器的狀態分派邏輯在 A2UIMessageRenderer.tsxstatus failed→ 失敗卡片status retrying→ 重試態默認building→ 宿主提供的 loader 優先否則內建骨架屏。surface 掛載完成后以a2ui_operations鍵進行最終渲染A2UI_OPERATIONS_KEY a2ui_operations見 A2UIMessageRenderer.tsx。七、注意事項與已知限制畸形渲染由 aimock fixtures 強制產生showcase/aimock/d6/google-adk/a2ui-recovery.json內層render_a2ui調用按userMessagetoolNamerender_a2ui匹配。治愈healing本身由 ADK 中間件實時執行而非 fixture 完成因此運行驗證需要以 aimock 啟動整套棧GOOGLE_GEMINI_BASE_URL指向 aimock 代理畸形渲染才能確定性觸發對接真實 LLM 時demo 無法可靠地產出無效嘗試本演示為ADK-only恢復循環位于ag_ui_adk中間件langgraph-python 的運行時 A2UI 路徑無等價實現OSS-375 跟蹤 LP parity測試刻意不斷言瞬態的 Retrying generation… (N/M) 標簽——該標簽是閾值門控 時序依賴的見copilotkit/react-core/v2的A2UIRecoveryStates斷言它會引入 flaky 測試a2ui-recovery.spec.ts八、總結A2UI Error Recovery 演示展示了 CopilotKit A2UI 生態中一條完整的容錯鏈路后端ag_ui_adk中間件通過parse_and_fix單次治愈松散參數、通過 validate→retry 循環在嘗試上限后返回a2ui_recovery_exhausted硬失敗信封前端ag-ui/a2ui-middleware以building → retrying → failed → painted生命周期狀態在不渲染壞 surface的前提下優雅呈現全過程aimock 則通過轉發對話到內層調用 userMessage 匹配保證兩條路徑的確定性復現。這套后端恢復 前端生命周期 fixture 驅動驗證的組合可直接遷移到其他接入 A2UI 協議的后端集成中。【免費下載鏈接】CopilotKitThe Frontend Stack for Agents Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol項目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考