數(shù)據(jù)平臺:面向Agent的架構與落地實踐)
今年的云棲2026主題是湖生萬物助力AI其中被反復討論的一個核心概念就是面向Agent的全模態(tài)數(shù)據(jù)平臺。做Agent開發(fā)的朋友應該都深有體會模型能力越來越強可肚子里的貨卻常常不夠用。文本、圖片、視頻、表格、日志、API返回值……各種模態(tài)的數(shù)據(jù)散落在后臺、對象存儲、關系庫里Agent想用的時候就像在一片沒有地圖的沼澤里找水看著到處都是數(shù)據(jù)真正能撈上來用的卻少得可憐。全模態(tài)數(shù)據(jù)平臺要解決的就是這件事把所有模態(tài)的數(shù)據(jù)統(tǒng)一收集、統(tǒng)一治理、統(tǒng)一服務讓Agent像擰開水龍頭喝水一樣按需獲得自己想要的任何數(shù)據(jù)。這篇文章我打算從Agent開發(fā)者的視角拆一拆全模態(tài)數(shù)據(jù)平臺的設計思路、底層架構、交互方式以及一套能跑通的最小落地閉環(huán)。最后把我自己在實操中踩過的坑和填坑經(jīng)驗一起交代清楚。1. Agent對數(shù)據(jù)平臺的胃口從單模態(tài)到全模態(tài)的必然轉(zhuǎn)變1.1 Agent的飯量早就不是一兩個接口能喂飽的早些年我們做聊天機器人喂給模型的語料基本就是純文本能加個知識庫檢索就算很高級了。但現(xiàn)在所謂的Agent已經(jīng)不是那個只會聊天的調(diào)包機器人。它要能看圖片、聽語音、分析表格、查詢數(shù)據(jù)庫甚至要實時處理傳感器流、操作瀏覽器和桌面應用。我接觸過的Agent項目里最常見的用法就有用戶傳一張產(chǎn)品設計圖Agent需要同時理解圖像里的物體、標注文字再去檢索對應的技術文檔最后生成一份可執(zhí)行的測試報告。一個數(shù)據(jù)分析Agent需要讀取CSV、Parquet、JSONL等不同格式的數(shù)據(jù)還要能調(diào)用SQL引擎跑聚合查詢再把結果渲染成圖表。智能客服Agent要能處理用戶發(fā)來的語音、截圖還要結合歷史訂單庫和工單系統(tǒng)給出端到端的解決方案。你會發(fā)現(xiàn)這些場景里Agent單靠一個向量數(shù)據(jù)庫或者一個結構化查詢接口根本轉(zhuǎn)不起來。它需要的是一個全能食堂——既有文本、圖片、音視頻這類非結構化食材又有數(shù)據(jù)庫、數(shù)據(jù)倉庫、API返回值這類結構化食材而且食材之間必須建立關聯(lián)讓Agent能一鍋燴出個像樣的菜。1.2 傳統(tǒng)數(shù)據(jù)平臺在哪幾個環(huán)節(jié)卡住了Agent正好最近和幾個團隊交流發(fā)現(xiàn)大家卡住的地方驚人地相似歸納起來無非這么幾類。一類是通道斷數(shù)據(jù)散落在不同的存儲系統(tǒng)比如業(yè)務庫在MySQL日志在Elasticsearch圖片在對象存儲算法特征在HDFS。Agent要拿數(shù)據(jù)得一個個接SDK光寫連接器就得小半年。另一類是字典亂同一個用戶ID訂單表里叫user_id行為日志里叫uid圖片元數(shù)據(jù)里叫userName。Agent自己很難理解這些字段的對應關系更別提跨模態(tài)做關聯(lián)。還有一類是形態(tài)舊傳統(tǒng)數(shù)據(jù)倉庫只認結構化表存不了圖片、視頻和文檔全文向量數(shù)據(jù)庫能存Embedding但又不負責原始數(shù)據(jù)管理和權限控制搜索系統(tǒng)能檢索文本和某些元數(shù)據(jù)但對圖片內(nèi)容、音頻內(nèi)容基本是沒有感知的。Agent被夾在中間成了一個到處拼裝管道的管道工而不是智能體。1.3 全模態(tài)數(shù)據(jù)平臺到底改變了什么全模態(tài)數(shù)據(jù)平臺的核心是讓Agent有一個統(tǒng)一的數(shù)據(jù)入口。數(shù)據(jù)到達平臺后不管原始形態(tài)是什么都會經(jīng)歷一套標準化的采集—清洗—索引—服務流程。平臺對外暴露的不再是散落的API和連接串而是一個帶語義的數(shù)據(jù)目錄和一套統(tǒng)一的訪問協(xié)議。Agent只要知道自己需要什么概念比如銷售額客戶投訴錄音產(chǎn)品截圖就能從數(shù)據(jù)目錄里找到對應資產(chǎn)通過平臺提供的檢索、查詢、訂閱接口把數(shù)據(jù)拿回來。我習慣把它比作一個自來水廠源頭是千家萬戶的溪流、水庫、地下水水質(zhì)和形態(tài)千差萬別但經(jīng)過沉淀、過濾、消毒之后送到你家里就是干凈的、統(tǒng)一標準的自來水。Agent不需要關心水是從哪條河來的只需要打開龍頭就能用。當然做到這一步背后的水廠管道鋪設、水質(zhì)監(jiān)測、應急調(diào)度就是全模態(tài)數(shù)據(jù)平臺真正要啃的硬骨頭。2. 全模態(tài)數(shù)據(jù)平臺的底層架構湖、倉、流一體的設計思路2.1 先說清楚湖和倉在這場變革中的新角色數(shù)據(jù)湖和數(shù)據(jù)倉庫的概念大家都不陌生。傳統(tǒng)做法是結構化數(shù)據(jù)進倉庫非結構化數(shù)據(jù)扔到數(shù)據(jù)湖里躺著。但Agent時代這種割裂扛不住用了因為Agent常常要同時理解一張訂單表和一張產(chǎn)品圖片之間的關系。我的做法是湖倉一體——湖里存原始數(shù)據(jù)倉里存結構化處理后的數(shù)據(jù)再用一套統(tǒng)一的表格式比如Apache Iceberg、Delta Lake、Hudi把兩者串起來。這樣設計的好處非常直接原始數(shù)據(jù)永不丟失湖里的文件可以保存全量歷史滿足模型訓練和調(diào)試追溯的需求。倉里的表可以按業(yè)務概念建模讓Agent直接通過SQL或查詢語法進行結構化訪問。一份數(shù)據(jù)既能跑批處理也能通過增量讀取提供給實時的Agent推理鏈路湖和倉本質(zhì)上是同一份底層文件的不同視圖。我推薦優(yōu)先選Iceberg因為它的快照隔離和時間旅行特性特別適合多模態(tài)數(shù)據(jù)的完整性和回滾。比如Agent凌晨拉了一批圖片元數(shù)據(jù)處理到一半發(fā)現(xiàn)數(shù)據(jù)有問題我們直接用Iceberg的快照回滾到前一版本不需要重新上傳文件非常省事。2.2 多模態(tài)數(shù)據(jù)的統(tǒng)一存儲層怎么搭全模態(tài)平臺的第一步是解決原始文件的統(tǒng)一存儲。我在項目里用的是對象存儲MinIO自建或者云上的OSS/S3所有模態(tài)的文件統(tǒng)一放進去按業(yè)務域和日期分桶。但光存文件沒用關鍵是要有一層讓引擎能讀懂的開關。這里的最佳實踐是給所有文件打上統(tǒng)一的元數(shù)據(jù)標簽比如asset_id資產(chǎn)ID、mode文本/圖片/音頻/視頻/結構化、source_system來源系統(tǒng)、timestamp事件時間等。這些元數(shù)據(jù)一方面可以寫入Iceberg的元數(shù)據(jù)表另一方面也可以同步到Elasticsearch或OpenSearch做全文檢索。實際運行下來先設計好元數(shù)據(jù)規(guī)范再鋪數(shù)據(jù)攝取管道能省掉后面至少三分之二的辯證麻煩。2.3 流批一體的數(shù)據(jù)攝取機制多模態(tài)數(shù)據(jù)形態(tài)各異到達的節(jié)奏也不一樣。交易數(shù)據(jù)可能是實時流水圖片和文檔可能是一批批上傳日志則可能是不間斷的流。為了不讓Agent拿到的是滯后三小時的舊聞平臺需要具備流批一體的攝取能力。我們采用的架構是Apache Flink負責實時流處理處理完的結果既寫入Iceberg做批式分析也把最新的變更推送到一個輕量級的實時索引比如Redis或Kafka同時用Apache Spark定期跑批處理做全量數(shù)據(jù)回填和校驗。這套機制跑了一年多整體穩(wěn)定Agent需要實時數(shù)據(jù)時直接查實時索引需要歷史分析時查Iceberg表兩邊數(shù)據(jù)最終靠asset_id關聯(lián)。2.4 統(tǒng)一語義層把多模態(tài)翻譯成業(yè)務語言這個部分我覺得是整個架構的點睛之筆。原始數(shù)據(jù)是工業(yè)零件但Agent和業(yè)務方需要的是一臺能直接開走的車。語義層的作用就是定義好業(yè)務概念與底層數(shù)據(jù)的映射關系。比如定義產(chǎn)品全景視圖這個概念它背后關聯(lián)了產(chǎn)品主數(shù)據(jù)表結構化、產(chǎn)品圖片集非結構化、說明書PDF文檔、用戶反饋錄音音頻。Agent在數(shù)據(jù)目錄里直接查找產(chǎn)品全景視圖就能拿到一個封裝好的數(shù)據(jù)包里面包含所有模態(tài)的數(shù)據(jù)以及它們之間的關聯(lián)ID。這個語義層可以用一個輕量級圖數(shù)據(jù)庫或元數(shù)據(jù)管理工具比如Apache Atlas、DataHub來實現(xiàn)再配上自定義的語義SQL解析器就能做到讓Agent用大白話問數(shù)。3. 讓Agent用上多模態(tài)數(shù)據(jù)核心API與交互模式拆解3.1 Agent訪問全模態(tài)數(shù)據(jù)的三種姿勢從我的實踐來看Agent和數(shù)據(jù)平臺的交互無非三種姿勢。第一種是投喂Agent在推理前通過數(shù)據(jù)平臺把背景材料統(tǒng)一取出拼裝成上下文。這種適合有明確需求的場景比如寫行業(yè)分析報告前先把所有相關數(shù)據(jù)拉回來。第二種是檢索Agent把當前問題轉(zhuǎn)成向量去平臺里檢索最相關的多模態(tài)片段然后帶著檢索結果去生成回答。這種是RAG的標準玩法適合知識問答、文檔總結這類開放任務。第三種是工具調(diào)用把數(shù)據(jù)平臺封裝成一個個工具ToolAgent根據(jù)用戶的意圖決定調(diào)用哪個工具、傳什么參數(shù)、怎么處理返回結果。比如一個根據(jù)圖片生成產(chǎn)品描述的工具Agent會先調(diào)用圖片檢索工具拿到圖片再調(diào)用大模型生成描述最后調(diào)用圖片存儲工具把結果存回去。三種姿勢可以混合使用。比如做智能導購Agent用戶上傳一張沙發(fā)照片Agent先投喂產(chǎn)品庫里的用戶畫像數(shù)據(jù)再通過檢索找出相似風格產(chǎn)品圖片最后調(diào)用促銷查詢工具獲取價格整個過程數(shù)據(jù)平臺就像一個不停轉(zhuǎn)動的底座。3.2 多模態(tài)數(shù)據(jù)的語義索引是怎么做的要讓Agent能看懂圖片、音頻和視頻單純靠元數(shù)據(jù)標簽是遠遠不夠的。我們需要給非結構化內(nèi)容做語義向量化?,F(xiàn)在比較成熟的做法是使用多模態(tài)Embedding模型比如CLIP、ImageBind或者開源的Chinese-CLIP把圖像、文本映射到同一個向量空間。舉一個實際例子用戶發(fā)給Agent一張北歐風格沙發(fā)的圖片我們需要讓Agent明白這張圖片和文字簡約布藝沙發(fā)淺色系是相關的。做法是先用圖像Encoder把圖片轉(zhuǎn)成一個1024維的向量。同時將產(chǎn)品庫里的每一條描述文本也用同一個文本Encoder轉(zhuǎn)成向量。把這兩個向量都存到向量數(shù)據(jù)庫比如Milvus、Qdrant、或Elasticsearch的dense_vector字段。Agent收到圖片后計算圖片向量和文本向量的余弦相似度找到Top-K最相近的產(chǎn)品描述再結合產(chǎn)品ID去查結構化數(shù)據(jù)。這段邏輯寫起來并不復雜但要注意Embedding模型的語言一致性和領域適配性。之前我們直接套用英文通用模型處理中文商品描述效果慘不忍睹后來換成了在中文電商數(shù)據(jù)上微調(diào)過的模型召回率直接提升了近40%。3.3 統(tǒng)一數(shù)據(jù)服務接口的Design Note要支撐上面三種交互模式平臺對外至少要提供這幾類接口數(shù)據(jù)目錄檢索接口支持模糊查詢、標簽過濾、語義搜索返回數(shù)據(jù)資產(chǎn)和對應的訪問方式。內(nèi)容讀取接口輸入asset_id返回文件的下載地址或二進制流支持限流和臨時憑證。向量檢索接口輸入文本或圖片向量返回Top-K結果及相似度分數(shù)。SQL查詢接口面向結構化表返回JSON結果兼容Agent工具調(diào)用的輸出格式。事件訂閱接口當某個數(shù)據(jù)資產(chǎn)更新時平臺主動推送變更消息給Agent。我設計接口時最看重的就是身份透傳和數(shù)據(jù)權限這兩個點。每一個Agent調(diào)用平臺接口時都會攜帶自身的AppKey和用戶上下文。平臺在返回數(shù)據(jù)前會做一次細粒度的字段過濾比如普通用戶查不到手機號運營人員查不到身份證號。這項能力不是錦上添花而是Agent能規(guī)模化落地的基本前提。4. 從零搭建一個面向Agent的全模態(tài)數(shù)據(jù)平臺最小閉環(huán)實戰(zhàn)4.1 選型清單和整體拓撲這里我給出一個可以直接上手的最小閉環(huán)組合全部用開源組件就能跑起來對象存儲MinIO單機Docker即可表格式Apache Iceberg配合Spark或Flink使用元數(shù)據(jù)與數(shù)據(jù)目錄DataHub開源版或者直接先用自定義MySQL表向量數(shù)據(jù)庫Milvus Lite單機啟動非常簡單語義檢索API自己用FastAPI寫一個輕量服務Agent框架LangChain或ReAct模式自研整體鏈路是數(shù)據(jù)源本地文件/API → Fluentd或Nginx接收 → Spark作業(yè)寫入Iceberg/MinIO → 元數(shù)據(jù)登記到數(shù)據(jù)目錄 → 圖片/文本切片后生成向量存入Milvus → Agent通過統(tǒng)一服務層FastAPI訪問目錄、內(nèi)容、向量和SQL。4.2 第一步搭好原始數(shù)據(jù)層先啟動MinIO和MinIO客戶端創(chuàng)建raw-bucket和processed-bucket兩個存儲桶。原始數(shù)據(jù)一律進raw-bucket處理后的數(shù)據(jù)進processed-bucket。文件命名建議遵循統(tǒng)一規(guī)則{業(yè)務域}/{日期}/{asset_id}.{ext}。比如產(chǎn)品圖片的路徑就是product/2026-03-12/041c9f4e-... .jpg。為了保證文件可校驗我會在攝取時順便計算MD5值寫入元數(shù)據(jù)表。后面Agent拿到文件地址時可以先校驗一下MD5值再決定是否下載能有效避免文件在傳輸過程中被損壞。4.3 第二步做一份多模態(tài)數(shù)據(jù)的血緣和編目等文件進了MinIO就要登記元數(shù)據(jù)。我用一個簡單的MySQL表data_assets來記錄資產(chǎn)信息字段包括asset_id、mode、source_path、processed_path、description、tags、create_time、update_time。同時在asset_relationships表里維護不同資產(chǎn)之間的關系。比如一張產(chǎn)品圖片asset_id img_001它關聯(lián)的產(chǎn)品主數(shù)據(jù)asset_id prod_001它們之間的關系類型是depicts。這樣一來Agent在查產(chǎn)品主數(shù)據(jù)時就可以通過血緣關系自動找到所有相關聯(lián)的圖片、視頻和文檔。這一步不求大而全只要能把關鍵資產(chǎn)和關聯(lián)關系登記好后面Agent的多模態(tài)理解就已經(jīng)有據(jù)可依了。4.3 第三步把多模態(tài)內(nèi)容變成向量向量化是多模態(tài)平臺和傳統(tǒng)數(shù)據(jù)倉庫最不一樣的地方。我們需要一個異步任務定時掃描data_assets表對每一個新出現(xiàn)的圖片生成向量并寫入Milvus。我用的是Swiss-Army式的腳本里面最關鍵的一段邏輯代碼Python偽碼如下from chinese_clip import ChineseCLIPProcessor from milvus import MilvusClient model ChineseCLIPProcessor.from_pretrained(...) client MilvusClient(urihttp://localhost:19530) # 創(chuàng)建集合 client.create_collection( collection_namemultimodal_embedding, dimension1024, metric_typeCOSINE ) def embed_image(image_path, asset_id): vector model.encode_image(image_path) client.insert( collection_namemultimodal_embedding, data[{asset_id: asset_id, vector: vector}] ) def embed_text(text, asset_id): vector model.encode_text(text) client.insert( collection_namemultimodal_embedding, data[{asset_id: asset_id, vector: vector}] )有一個坑必須提醒向量化任務要設置增量檢查點避免每次全量掃描重復編碼浪費GPU。我們會在data_assets表里加一個vectorized字段處理完成后置為1。4.4 第四步封裝Agent可調(diào)用的統(tǒng)一服務現(xiàn)在到了最關鍵的一步——把前面所有能力封裝成一個Agent友好的服務。我這里用FastAPI快速實現(xiàn)一個聚合接口同時支持語義檢索和結構化查詢from fastapi import FastAPI, HTTPException from pydantic import BaseModel app FastAPI() class AgentDataRequest(BaseModel): text: str None image_url: str None top_k: int 5 data_type: str all app.post(/api/agent/data/search) def search_data(request: AgentDataRequest): # 1. 調(diào)用向量檢索拿到Top-K asset_id # 2. 從data_assets表讀取這些資產(chǎn)的分組和路徑 # 3. 根據(jù)data_type字段決定返回內(nèi)容raw文件URL還是結構化結果 # 4. 校驗Agent的權限范圍過濾敏感字段 # 5. 封裝統(tǒng)一返回結構 return { results: [...], query_id: some-uuid, cost_ms: 78 }這個接口的定義需要仔細推敲。我踩過一個坑最初返回的結果直接把MinIO的內(nèi)網(wǎng)地址暴露給Agent導致外部環(huán)境訪問失敗。正確做法是返回一個帶時效的預簽名URL比如有效期5分鐘讓Agent在有效期內(nèi)去下載內(nèi)容。這樣既保安全又避免因權限不足導致的403。4.5 第五步Agent端聯(lián)調(diào)與端到端驗證平臺搭好后還需要驗證Agent真的愿意用這個平臺。最簡單的驗證方式是讓Agent走一遍圖文問答場景。比如用戶問這張圖里的沙發(fā)和哪幾個產(chǎn)品風格最接近Agent應該先調(diào)用/api/agent/data/search接口傳入圖片URL拿到相似產(chǎn)品的asset_id再調(diào)用SQL查詢接口取回產(chǎn)品名稱和價格最后組織語言回答。我在聯(lián)調(diào)時習慣用LangChain的ToolCallingAgent來做from langchain.agents import create_tool_calling_agent from langchain.agents.tools import Tool tools [ Tool(namesearch_multimodal, funcsearch_data, descriptionSearch across text and images), Tool(namequery_product_table, funcquery_product_sql, descriptionQuery product info) ] agent create_tool_calling_agent(llm, tools) result agent.invoke(這張圖里的沙發(fā)和我店里的哪個產(chǎn)品最像)這一步跑通后整個最小閉環(huán)就算成型了。從數(shù)據(jù)進入平臺到Agent能用自然語言調(diào)取多模態(tài)信息鏈路已經(jīng)通了。5. 數(shù)據(jù)治理與性能瓶頸我在實踐中踩過的坑5.1 小文件過多把查詢拖成龜速多模態(tài)數(shù)據(jù)有一個非常典型的毛病——文件散而小。一張產(chǎn)品圖片可能就幾百KB一個文檔片段可能就幾KB但如果每天上百萬個小文件直接落進Iceberg表執(zhí)行查詢時元數(shù)據(jù)目錄會被撐爆。我們有一次審計報表查詢明明只查一天的數(shù)據(jù)居然跑了20分鐘最后定位發(fā)現(xiàn)是Iceberg表里的小文件分區(qū)數(shù)量超過了10萬個。解決辦法有兩個一是數(shù)據(jù)攝取落盤時做文件合并比如用Spark的repartition按asset_id哈希重分區(qū)盡量把碎片文件合并成128MB左右的大文件二是定期用Iceberg RewriteDataFilesAction做Compaction把小文件合并成大文件。這就像把滿抽屜的紐扣按大小顏色分裝到盒子里翻找速度完全不一樣。5.2 向量索引和原始數(shù)據(jù)的一致性向量數(shù)據(jù)庫里存的是Embedding原始文件存在MinIO。如果原始文件被刪了或者更新了向量庫里那條記錄就成了幽靈索引。Agent檢索的時候明明搜索到了點開原始數(shù)據(jù)卻發(fā)現(xiàn)404這種體驗極差。我現(xiàn)在的做法是在刪除原始文件之前先進隊列發(fā)一個delete事件由后臺任務同步刪除對應的向量記錄。如果是更新則先更新對象存儲再重新生成向量并覆蓋寫入。同時做一次全量對賬每天凌晨跑一個腳本把data_assets表和Milvus里的asset_id做差集發(fā)現(xiàn)不一致就自動補償。這個對賬腳本雖然技術含量不高但救了我很多次。5.3 并發(fā)尖峰時的服務降級策略Agent本身是多實例的當用戶量上來之后多個Agent會同時調(diào)用數(shù)據(jù)平臺的接口。最怕的不是QPS高而是某個奇怪的多模態(tài)請求特別重比如用戶上傳一個100MB的視頻文件讓Agent總結內(nèi)容。這種請求如果直接同步處理會拖垮整個服務的Tomcat線程池。我的策略是分三檔處理輕量請求文本、結構化查詢同步處理限制單次響應時間不超過3秒。重量請求圖片向量化、文件抽取異步任務化接口先返回任務IDAgent輪詢獲取結果。超大請求視頻解析、批量數(shù)據(jù)導出直接拒絕只允許通過離線任務中心提交。這套策略再加上每接口的令牌桶限流實測可以把平臺的可用性穩(wěn)定在99.9%以上。5.4 安全合規(guī)的頭疼事兒多模態(tài)數(shù)據(jù)往往比純文本更容易觸碰隱私紅線。一張照片里可能包含人臉、車牌、甚至家里的環(huán)境信息一段語音可能包含聲紋特征。平臺如果不管不顧地全量提供給Agent一旦出事責任不小。我的經(jīng)驗是三層防護數(shù)據(jù)接入時做內(nèi)容安全檢測比如人臉檢測、低俗內(nèi)容識別違規(guī)圖片直接隔離。數(shù)據(jù)訪問時按Agent的用途動態(tài)脫敏。比如客服Agent可以聽到用戶的語音內(nèi)容但不能看到面部畫面那就返回音頻URL時裁剪掉視頻流的畫面軌道。所有Agent調(diào)用數(shù)據(jù)平臺的行為必須留痕包括請求參數(shù)、返回結果摘要、調(diào)用時間方便事后審計和追溯。這套東西做下來確實比普通BI平臺復雜很多但它是面向Agent的數(shù)據(jù)平臺能真正規(guī)模落地的必要條件。寫在最后我在搭建這個全模態(tài)數(shù)據(jù)平臺的過程中最大的體會是技術選型倒在其次真正難的是把數(shù)據(jù)供給這件事想得比Agent的能力還靠前。模型要什么數(shù)據(jù)、以什么形式給、給完怎么溯源這些問題想清楚了平臺才不是一堆組件的堆砌。如果你現(xiàn)在正打算搞自己的Agent數(shù)據(jù)底座我的建議是先別追新框架從最小閉環(huán)起步——一個對象存儲、一張Iceberg表、一個向量庫、一個統(tǒng)一查詢接口已經(jīng)能支撐很多業(yè)務需求。等數(shù)據(jù)量和Agent場景真的跑起來了再逐步迭代治理、安全和性能優(yōu)化。這座湖不是一夜之間挖成的得先讓一股清泉流起來才能慢慢引來魚蝦和萬物。