構(gòu)、判別聯(lián)合與源碼實(shí)現(xiàn))
Metabase Embedding SDK 消息類型詳解MetabotAgentTextMessage 結(jié)構(gòu)、判別聯(lián)合與源碼實(shí)現(xiàn)【免費(fèi)下載鏈接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:項(xiàng)目地址: https://gitcode.com/GitHub_Trending/me/metabase導(dǎo)讀MetabotAgentTextMessage是 Metabase Embedding SDK 中由 AI 助手Metabot返回給宿主應(yīng)用的一種純文本消息類型它描述了對話中Agent 回復(fù)這條消息的完整數(shù)據(jù)結(jié)構(gòu)消息 ID、正文、角色標(biāo)識與消息種類。本文以該類型定義為主線結(jié)合其所屬的MetabotMessage判別聯(lián)合discriminated union、相鄰的MetabotAgentChartMessage圖表消息、useMetabot對話 Hook 以及frontend/src/embedding-sdk-bundle/types/metabot.ts與enterprise/frontend/src/embedding-sdk-ee/metabot/hooks/use-metabot.tsx的真實(shí)實(shí)現(xiàn)幫助你徹底掌握如何在嵌入應(yīng)用里識別、渲染并區(qū)分 Agent 的文本回復(fù)構(gòu)建出類型安全的自定義 AI 問答界面。MetabotAgentTextMessage一段最小的 TypeScript 類型定義關(guān)聯(lián)文檔 MetabotAgentTextMessage.md 給出的核心類型定義非常精煉完整內(nèi)容如下type MetabotAgentTextMessage { id: string; message: string; role: agent; type: text; };這是一條帶字面量標(biāo)記的消息類型。四個(gè)字段各司其職屬性類型語義說明idstring消息的唯一標(biāo)識可用于retryMessage(messageId)重試定位等場景messagestringAgent 回復(fù)的文本正文即要展示給終端用戶的自然語言內(nèi)容roleagent消息發(fā)言方標(biāo)識固定為字面量agent表示消息來自 AI 助手typetext消息種類判別符固定為字面量text表示這是一條純文本消息其中role與type之所以使用字面量類型literal type而非寬泛的string是為了讓 TypeScript 能夠在聯(lián)合類型上進(jìn)行判別收窄type narrowing只要檢查type text且role agent編譯器即可推斷出這條消息的完整結(jié)構(gòu)。在消息類型體系中的位置一條完整的判別聯(lián)合MetabotAgentTextMessage并不是孤立存在的它是 SDK 對話消息類型樹中的一個(gè)葉子節(jié)點(diǎn)。結(jié)合關(guān)聯(lián)的 MetabotMessage.md 與 MetabotAgentMessage.md可以還原出完整的類型層級// 對話中出現(xiàn)的所有消息用戶消息 Agent 消息 type MetabotMessage MetabotUserTextMessage | MetabotAgentMessage; // Agent 產(chǎn)生的消息文本回復(fù) 圖表回復(fù) type MetabotAgentMessage MetabotAgentTextMessage | MetabotAgentChartMessage;展開后MetabotMessage實(shí)際包含三種具體形態(tài)用戶文本消息MetabotUserTextMessage見 MetabotUserTextMessage.md{ id: string; message: string; role: user; type: text }由用戶發(fā)出Agent 文本消息MetabotAgentTextMessage本文主角由 Agent 發(fā)出role為agent、type為textAgent 圖表消息MetabotAgentChartMessage見 MetabotAgentChartMessage.md{ Chart: ComponentTypeMetabotChartProps; id: string; questionPath: string; role: agent; type: chart }Agent 直接產(chǎn)出一張圖表。三種形態(tài)通過type字段構(gòu)成可判別的聯(lián)合。這條定義在開源倉庫的源碼中有完全一致的對應(yīng)實(shí)現(xiàn)見 frontend/src/embedding-sdk-bundle/types/metabot.ts// User messages export type MetabotUserTextMessage { id: string; role: user; type: text; message: string; }; // Agent messages export type MetabotAgentTextMessage { id: string; role: agent; type: text; message: string; }; export type MetabotAgentChartMessage { id: string; role: agent; type: chart; /** URL path to the question, e.g. /question#base64 */ questionPath: string; /** A pre-wired React component that renders the chart. */ Chart: React.ComponentTypeMetabotChartProps; }; export type MetabotAgentMessage | MetabotAgentTextMessage | MetabotAgentChartMessage; export type MetabotMessage MetabotUserTextMessage | MetabotAgentMessage;值得注意的是源碼注釋明確說明 SDK 只對外暴露type text消息與generated_entity圖表卡片這兩類公開消息內(nèi)部還存在tool_call、action、data_part如code_edit、transform_suggestion、todo_list、adhoc_viz、static_viz、state等調(diào)試或內(nèi)部形態(tài)但這些都不會通過 SDK 輸入路徑產(chǎn)生僅用于產(chǎn)品內(nèi)其他界面。這解釋了為什么公開類型體系中只保留文本與圖表兩種 Agent 消息。從內(nèi)部消息到公開類型mapMessage 的映射邏輯MetabotAgentTextMessage并不是后端直接下發(fā)的原始結(jié)構(gòu)而是由 SDK 層從內(nèi)部消息部件message part映射而來。映射邏輯位于 enterprise/frontend/src/embedding-sdk-ee/metabot/hooks/use-metabot.tsx 的mapMessage函數(shù)中const mapMessage ( message: PublicChatMessage, cache: Mapstring, ReturnTypetypeof createChartComponent, authConfig: MetabaseAuthConfig | undefined, ): MetabotMessage match(message) .with( { role: user, type: text }, ({ id, message }) ({ id, role: user, type: text, message }) as const, ) .with( { role: agent, type: text }, ({ id, message }) ({ id, role: agent, type: text, message }) as const, ) .with( { role: agent, type: data_part, part: { type: data-generated_entity, data: { type: card } }, }, ({ id, part }) { const questionPath Urls.generatedCard(part.data); const Chart authConfig ? getCachedChartComponent(questionPath, cache, authConfig) : FallbackChartComponent; return { id, role: agent, type: chart, questionPath, Chart, } as const; }, ) .exhaustive();從這段實(shí)現(xiàn)可以看出當(dāng)內(nèi)部部件匹配{ role: agent, type: text }時(shí)直接原樣映射為公開的MetabotAgentTextMessage保留id與message當(dāng)內(nèi)部部件是data_part且數(shù)據(jù)為generated_entity卡片時(shí)會被轉(zhuǎn)換成語義完全不同的MetabotAgentChartMessage借助Urls.generatedCard(part.data)生成questionPath形如/question#base64的 URL并緩存創(chuàng)建出一個(gè)預(yù)先接線的 React 圖表組件Chart使用ts-pattern的matchexhaustive()保證所有公開消息形態(tài)都被窮盡處理新增類型時(shí)編譯期即可發(fā)現(xiàn)遺漏分支。因此MetabotAgentTextMessage是對話流中Agent 用自然語言回答問題這一場景的標(biāo)準(zhǔn)載體而圖表消息則對應(yīng)Agent 直接給出可視化結(jié)果。消費(fèi)入口useMetabot 與 UseMetabotResultMetabotAgentTextMessage通常不是單獨(dú)使用的而是通過useMetabotHook 從對話狀態(tài)中讀取。關(guān)聯(lián)文檔 useMetabot.md 給出其簽名與基本用法function useMetabot(): UseMetabotResult | null;useMetabot返回 Metabot 對話 API在 SDK bundle 加載完成、MetabaseProvider掛載其內(nèi)部訂閱器之前返回null因此使用前必須做空值守衛(wèi)例如const metabot useMetabot(); if (!metabot) { return Spinner /; } metabot.submitMessage(Show me orders);返回對象UseMetabotResult見 UseMetabotResult.md中包含對話消息數(shù)組與一系列操作函數(shù)屬性類型說明messagesMetabotMessage[]對話中的全部消息圖表消息包含Chart屬性errorMessagesMetabotErrorMessage[]會話級錯(cuò)誤不掛在單條消息上submitMessage(message: string) Promisevoid向?qū)υ捥峤灰粭l新消息retryMessage(messageId: string) Promisevoid回退到messageId之前的用戶消息并重新提交丟棄該 Agent 消息及其之后的內(nèi)容cancelRequest() void取消當(dāng)前進(jìn)行中的請求resetConversation() void清空所有消息、重新開始isProcessingboolean從提交消息到響應(yīng)完成含成功、失敗、取消期間為truecontextWindowPercentUsagenumber對話占用的模型上下文窗口比例取值 0–100isContextWindowFullboolean對話是否已耗盡整個(gè)上下文窗口CurrentChartComponentTypeMetabotChartProps \| null綁定到 Agent 最新產(chǎn)出圖表的預(yù)接線組件未產(chǎn)出圖表時(shí)為nullmessages數(shù)組正是MetabotAgentTextMessage出現(xiàn)的場所。結(jié)合 use-metabot.tsx 的實(shí)現(xiàn)messages由內(nèi)部agent.messages展開所有 parts、過濾出公開部件并逐條mapMessage得到同時(shí)每個(gè) turn 只保留最后一張圖表getFinalChartMessageIdsPerTurn因?yàn)?Agent 在流式輸出過程中可能發(fā)出多張中間圖表。在 Hook 內(nèi)部submitMessage調(diào)用的是agent.submitInput(message, { preventOpenSidebar: true })——即通過 SDK 提交消息時(shí)不會彈出產(chǎn)品內(nèi)邊欄保證行為完全由宿主應(yīng)用控制resetConversation在清空對話的同時(shí)還會清空圖表組件緩存errorMessages來自內(nèi)部消息狀態(tài)status.type errored的展示信息類型為MetabotErrorMessage{ message: string; type: message | alert | locked }alert會以警告圖標(biāo)與錯(cuò)誤色渲染message以純文本渲染。實(shí)戰(zhàn)如何在自定義聊天界面中渲染并區(qū)分 Agent 文本消息借助判別聯(lián)合與字面量類型可以在渲染層用極少的代碼安全區(qū)分消息形態(tài)。以下示例展示了如何基于type字段收窄聯(lián)合類型并分別渲染文本氣泡與圖表卡片import { useMetabot } from metabase/embedding-sdk-react; import type { MetabotMessage } from metabase/embedding-sdk-react; function ChatThread() { const metabot useMetabot(); if (!metabot) { return Spinner /; // SDK 尚未就緒時(shí)的守衛(wèi) } return ( div {metabot.messages.map((msg) ( MessageBubble key{msg.id} message{msg} / ))} /div ); } function MessageBubble({ message }: { message: MetabotMessage }) { // 判別收窄按 type 區(qū)分三種消息形態(tài) if (message.type text message.role agent) { // MetabotAgentTextMessage渲染 Agent 的文本回復(fù) return div classNameagent-bubble{message.message}/div; } if (message.type text message.role user) { // MetabotUserTextMessage渲染用戶提問 return div classNameuser-bubble{message.message}/div; } // MetabotAgentChartMessage渲染 Agent 生成的圖表 return message.Chart /; }這段代碼體現(xiàn)的關(guān)鍵實(shí)踐用type字段收窄聯(lián)合類型下的msg.type只有text與chart兩種取值再配合role即可把text分支進(jìn)一步細(xì)分為用戶消息與 Agent 消息TypeScript 會為每個(gè)分支補(bǔ)全正確的字段類型無需任何類型斷言圖表消息直接渲染組件message.Chart是預(yù)接線組件可直接以 JSX 形式渲染。Chart 組件內(nèi)部按drills屬性決定使用靜態(tài)問題StaticQuestionInternal還是可交互問題InteractiveQuestionInternaldrills{false}默認(rèn)渲染靜態(tài)圖表drills{true}渲染帶下鉆交互的圖表對應(yīng)類型 MetabotChartProps.md 中OmitStaticQuestionProps, ...與OmitInteractiveQuestionProps, ...的聯(lián)合守衛(wèi)nulluseMetabot返回null時(shí)先渲染加載占位避免在訂閱器未掛載時(shí)訪問未就緒的對話狀態(tài)。除消息渲染外還可以組合UseMetabotResult的其他能力實(shí)現(xiàn)完整對話交互用submitMessage發(fā)送用戶輸入、用isProcessing顯示輸入中的加載態(tài)、用isContextWindowFull提示上下文已滿并引導(dǎo)用戶resetConversation、用retryMessage(msg.id)實(shí)現(xiàn)單條回復(fù)的重試該函數(shù)會回退到目標(biāo) Agent 消息之前的用戶消息并重新提交目標(biāo)消息及其之后的內(nèi)容會被丟棄。高級話題上下文窗口、錯(cuò)誤與會話狀態(tài)理解MetabotAgentTextMessage所處的運(yùn)行時(shí)環(huán)境有助于正確設(shè)計(jì) UI上下文窗口管理contextWindowPercentUsage表示當(dāng)前對話占用的模型上下文比例0–100。當(dāng)isContextWindowFull為true時(shí)對話已耗盡上下文繼續(xù)提問可能無法獲得有效回答應(yīng)提示用戶開啟新會話調(diào)用resetConversation。注意所有useMetabot實(shí)例在同一個(gè)應(yīng)用內(nèi)共享對話狀態(tài)都讀取同一份 Redux 狀態(tài)因此在多個(gè)組件中掛載 Hook 不會產(chǎn)生獨(dú)立的會話。會話級錯(cuò)誤模型errorMessages是會話級的不附著在單條消息上。它來自內(nèi)部消息的errored狀態(tài)類型為 MetabotErrorMessage.md 中定義的message | alert | locked三態(tài)alert用于需要醒目警告的錯(cuò)誤message用于普通文本提示。重試語義retryMessage(messageId)的messageId應(yīng)傳入 Agent 消息的id即MetabotAgentTextMessage.id。它會把會話回滾到該 Agent 消息之前的用戶消息并重新提交屬于整輪回退重試而非單條替換。企業(yè)版能力useMetabot的完整實(shí)現(xiàn)掛載在METABOT_SDK_EE_PLUGIN插件上見 use-metabot.tsx源碼位于enterprise/目錄說明 Metabot 對話屬于 Metabase 企業(yè)版/嵌入能力開源OSS版本中該插件未激活時(shí)useMetabot不提供完整功能。如果不想完全自繪聊天界面也可以直接使用 SDK 現(xiàn)成的 MetabotQuestion 組件——它接收 MetabotQuestionProps 并渲染一個(gè)完整的 metabot 問題界面支持layoutauto/sidebar/stacked其中auto在移動端使用stacked、大屏使用sidebar、isSaveEnabled是否顯示保存按鈕、targetCollection保存到指定集合隱藏保存彈窗的集合選擇器等配置而useMetabot面向的是需要完全自定義界面的場景MetabotAgentTextMessage正是這種場景下處理 Agent 文本回復(fù)的類型基石。小結(jié)MetabotAgentTextMessage看似只是一個(gè)四字段的小類型卻是整個(gè) Metabot 對話消息體系的關(guān)鍵一環(huán)它以role: agent與type: text兩個(gè)字面量參與MetabotMessage判別聯(lián)合讓 TypeScript 在渲染層能安全地收窄消息形態(tài)它由 use-metabot.tsx 中的mapMessage從內(nèi)部消息部件映射而來與圖表消息MetabotAgentChartMessage共同構(gòu)成 Agent 的兩類回復(fù)。掌握它的結(jié)構(gòu)、在聯(lián)合類型中的位置以及useMetabot/UseMetabotResult的消費(fèi)方式即可在嵌入應(yīng)用中構(gòu)建類型安全的自定義 AI 聊天體驗(yàn)?!久赓M(fèi)下載鏈接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:項(xiàng)目地址: https://gitcode.com/GitHub_Trending/me/metabase創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考