一化:從雙端點走向類型感知的單一路由)
Civitai Orchestrator 工作流查詢統(tǒng)一化從雙端點走向類型感知的單一路由【免費下載鏈接】civitaiA repository of models, textual inversions, and more項目地址: https://gitcode.com/GitHub_Trending/ci/civitai導(dǎo)讀本文圍繞 Civitai 主站當(dāng)前倉庫src/目錄下的 Next.js 應(yīng)用中的一份架構(gòu)演進(jìn)文檔 docs/unified-workflow-query.md 展開剖析其提出的統(tǒng)一工作流查詢端點Unified Workflow Query Endpoint方案將圖片生成查詢與提示詞增強(qiáng)查詢合并為單一 tRPC 端點并讓服務(wù)端格式化層具備類型感知能力。讀完本文你將理解當(dāng)前雙端點架構(gòu)的分歧點、統(tǒng)一方案的四個實施步驟、其中涉及的四個關(guān)鍵挑戰(zhàn)以及源碼中已有的部分統(tǒng)一化進(jìn)展queryWorkflowsByTags可以直接將該方案應(yīng)用于自己的 orchestrator 集成或同類多類型查詢場景。一、現(xiàn)狀兩條并行的查詢路徑文檔首先指出當(dāng)前存在兩個彼此獨立的查詢端點它們調(diào)用的是同一個底層 orchestrator API分歧完全發(fā)生在服務(wù)端格式化層端點Tag 過濾服務(wù)端處理客戶端消費方queryGeneratedImagesgenerationformatGenerationResponse2約 150200 行資源富化、遺留元數(shù)據(jù)歸一化、圖片 blob 格式化Queue.tsx、Feed.tsx經(jīng)useGetTextToImageRequestsqueryPromptEnhancementsprompt-enhancement無queryWorkflows原始透傳HistoryTab.tsx經(jīng)useGetPromptEnhancementHistory在源碼中可以完整印證這張表。路由定義位于 src/server/routers/orchestrator.router.tsqueryGeneratedImages第 331 行起通過queryGeneratedImageWorkflows2處理并在 green 域名下追加greentag、開啟cache: true通用按 tag 查詢queryWorkflowsByTags第 211 行起是提示詞增強(qiáng)歷史的實際落點其注釋明確寫著Generic workflow query by tags — used for prompt enhancement history, future text workflows, etc.即該端點從設(shè)計上就是類型無關(guān)的。客戶端兩側(cè)的消費方式也各不相同圖片側(cè)useGetTextToImageRequestssrc/components/ImageGeneration/utils/generationRequestHooks.ts會registerSignalGroup(generation)把WORKFLOW_TAGS.GENERATION實際常量值為gen見 src/shared/constants/generation.constants.ts與篩選器 tag 拼接后調(diào)用useInfiniteQuery隨后把每條 workflow 包成new WorkflowData(workflow, { domain, nsfwEnabled })提示詞側(cè)useGetPromptEnhancementHistorysrc/components/Generation/PromptEnhance/promptEnhanceHooks.ts直接以{ tags: [prompt-enhancement] }調(diào)用queryWorkflowsByTags.useInfiniteQuery再經(jīng)mapWorkflowToRecord映射為PromptEnhancementRecord包含 originalPrompt、enhancedPrompt、issues、recommendations、temperature 等字段供 HistoryTab.tsx 渲染。二、共享底座類型無關(guān)的queryWorkflows兩條路徑之所以能統(tǒng)一關(guān)鍵在于它們最終都匯入同一個底層函數(shù)queryWorkflows。該函數(shù)位于 src/server/services/orchestrator/workflows.ts本身不關(guān)心 workflow 的具體類型它承擔(dān)了三件公共職責(zé)強(qiáng)制注入civitaitagtags: [civitai, ...(query.tags ?? [])]確保查詢始終限定在 civitai 域內(nèi)讀取超時兜底AbortSignal.timeout(ORCHESTRATOR_QUERY_TIMEOUT_MS)常量值為 20 秒workflows.ts防止 orchestrator 掛起時無限阻塞并占死 api 連接池觸發(fā)后會被識別為可重試的 503統(tǒng)一文案ORCHESTRATOR_UNAVAILABLE_MESSAGE錯誤分類映射400 → BadRequest、401 → Authorization、403 → InsufficientFunds、429 → RateLimit、404 → NotFound其余 4xx 歸為 BadRequest上游 5xx/網(wǎng)絡(luò)故障歸為可重試 503未知錯誤原樣拋出保持真實 bug 可見。同時單條讀取getWorkflow也有獨立的 20 秒兜底ORCHESTRATOR_GET_TIMEOUT_MS服務(wù)于statusUpdate輪詢熱路徑??梢酝茢嗉热坏讓硬樵兲烊活愋蜔o關(guān)統(tǒng)一化的工作重心確實如文檔所說全部集中在服務(wù)端格式化層 客戶端消費層。三、分歧點formatGenerationResponse2的圖片假設(shè)queryGeneratedImages之所以需要專門的服務(wù)端處理是因為formatGenerationResponse2src/server/services/orchestrator/orchestration-new.service.ts假定每個 workflow 都包含圖片/視頻步驟。它的處理流水線包括資源富化從workflow.metadata.resources和每個 step 的getResourceRefsFromStep中收集資源 ID按(id, epoch)去重保證同一版本的不同 epoch 不被合并然后批量調(diào)用getResourceData命中數(shù)據(jù)庫把模型名、版本、epoch 號等信息補(bǔ)全到響應(yīng)中Raw-AIR 負(fù) ID 資源跳過富化新格式歸一化workflow.metadata.paramsworkflow.metadata.resources其中normalizedWfMeta是顯式白名單而非展開——每個暴露給調(diào)用方的 key 都必須被命名例如remixOfId、isPrivateGeneration、modelSubstitutions都是逐項挑選的遺留格式回退無 workflow 級 metadata 時回退到steps[0].metadata標(biāo)準(zhǔn)生成或step.metadata.transformations[last]遺留增強(qiáng)格式步驟格式化formatStep再對每個 step 做輸出歸一化。formatStepOutputs內(nèi)部已經(jīng)是一個按step.$type分發(fā)的 switchorchestration-new.service.ts覆蓋comfy、imageGen/textToImage、model3DPreview、imageUpscaler、preprocessImage、videoGen含 LTX 2.3 的additionalVideos多視頻批處理、videoUpscaler/videoEnhancement/videoInterpolation、preprocessVideo、aceStepAudio、miniMaxMusic3、polyGen合并 rigged/animated 變體等類型default返回空數(shù)組。問題在于提示詞增強(qiáng) workflow 的 input/output 是自包含的沒有資源、沒有圖片 blob這套流水線對它要么空轉(zhuǎn)、要么產(chǎn)生垃圾數(shù)據(jù)。這正是文檔強(qiáng)調(diào)必須讓formatGenerationResponse2類型感知的根本原因。四、統(tǒng)一方案四個實施步驟文檔給出的方案分四步以下是完整設(shè)計及與源碼的對應(yīng)關(guān)系。1. 單一 tRPC 端點將queryGeneratedImages重命名/替換為統(tǒng)一的queryWorkflows端點去掉硬編碼的generationtag 過濾讓客戶端按需傳 tag。從源碼看這一思路的雛形其實已經(jīng)落地為queryWorkflowsByTags——它接收的正是workflowQuerySchema且沒有任何類型假設(shè)。2. 類型感知的服務(wù)端格式化器把formatGenerationResponse2從假定全圖/視頻改為按步驟類型分發(fā)switch (step.$type) { case textToImage: case videoGen: // 現(xiàn)有 image/video 格式化資源富化、blob 處理、遺留兼容 break; case promptEnhancement: // 透傳或輕量歸一化input/output 自包含 break; default: // 未知類型的通用透傳 break; }這里的 switch 結(jié)構(gòu)與源碼中formatStepOutputs的switch (step.$type)完全同構(gòu)差異在于前者目前是輸出歸一化層而統(tǒng)一方案要求把資源富化 元數(shù)據(jù)歸一化也納入類型分派。3. 判別聯(lián)合Discriminated Union響應(yīng)每個 workflow 攜帶一個type判別字段讓客戶端無需猜測 payload 形狀type NormalizedWorkflow | { type: generation; /* 現(xiàn)有 image/video 字段 */ } | { type: promptEnhancement; /* input/output/issues/recommendations */ } | { type: unknown; /* 原始 step 數(shù)據(jù) */ };可以推斷promptEnhancement分支的字段應(yīng)與PromptEnhancementRecordpromptEnhanceHooks.ts對齊即 workflowId、createdAt、originalPrompt、enhancedPrompt、issues、recommendations、instruction、preserveTriggerWords、temperature、status。4. 客戶端過濾Queue/Feed過濾type generation歷史頁過濾type promptEnhancement或者干脆渲染混合內(nèi)容為不同類型配各自的卡片組件。對應(yīng)的客戶端改造面包括useGetTextToImageRequests目前直接對全部條目執(zhí)行new WorkflowData(...)generationRequestHooks.ts統(tǒng)一后需要先按type分流useGetPromptEnhancementHistory的mapWorkflowToRecord按$type promptEnhancement或name prompt-enhancement查找 step則可以退化為簡單的類型斷言。五、關(guān)鍵挑戰(zhàn)詳解5.1 遺留格式處理formatGenerationResponse2同時處理三種元數(shù)據(jù)格式統(tǒng)一時必須保證新格式workflow.metadata.paramsworkflow.metadata.resourcesorchestration-new.service.ts遺留格式step.metadata.paramsstep.metadata.resources第 3115-3124 行遺留增強(qiáng)格式step.metadata.transformations[last]第 3098-3114 行。這些邏輯必須對圖片 workflow 保留但絕不能對提示詞增強(qiáng) workflow 執(zhí)行——否則會失敗或產(chǎn)生垃圾數(shù)據(jù)。文檔給出的約束是類型分發(fā)發(fā)生在格式化入口遺留兼容邏輯只掛在generation分支下。5.2 資源富化的條件化圖片 workflow 需要把資源 ID 富化為模型名、版本、epoch 號這一步要命中數(shù)據(jù)庫getResourceData。提示詞增強(qiáng) workflow 沒有資源富化步驟必須條件化否則每次歷史查詢都會產(chǎn)生無謂的數(shù)據(jù)庫開銷。文檔同時點出一個細(xì)節(jié)formatGenerationResponse2的資源收集橫跨 workflow 級與 step 級兩處第 3010-3026 行條件化時要同時覆蓋這兩處入口。5.3 Signal 更新通道useTextToImageSignalUpdatesrc/components/ImageGeneration/utils/useGenerationSignalUpdate.ts訂閱SignalMessages.TextToImageUpdate常量值orchestrator:text-to-image-update見 src/server/common/enums.ts經(jīng) 100ms 防抖后把 statusUpdate 結(jié)果 patch 進(jìn)trpc.orchestrator.queryGeneratedImages的 React Query 緩存updateWorkflowsStatus用getQueryKey(trpc.orchestrator.queryGeneratedImages)定位緩存。而提示詞側(cè)走的是另一條通道useWorkflowUpdateSignal訂閱SignalMessages.WorkflowUpdateorchestrator:workflow-update通過onWorkflowSignal監(jiān)聽器注冊表把事件分發(fā)給useGetPromptEnhancementHistory后者再以updateWorkflowInTagCache(workflowItem, PROMPT_ENHANCEMENT_TAGS)更新queryWorkflowsByTags的緩存src/components/Orchestrator/workflowHooks.ts。統(tǒng)一后需要二選一要么建立統(tǒng)一的 Signal 通道要么維護(hù)多個訂閱共同更新同一個緩存。注意updateWorkflowInTagCache/addWorkflowToTagCache已經(jīng)是按 tag 匹配查詢鍵的通用實現(xiàn)matchesTagQuery檢查 query key 的 input.tags 是否包含目標(biāo) tag可以推斷這套機(jī)制天然適合遷移到統(tǒng)一端點。5.4WorkflowData/BlobData包裝器圖片側(cè)把 workflow 包進(jìn)WorkflowDatasrc/shared/orchestrator/workflow-data.ts它會把原始輸出包裝成BlobData子類ImageBlob、VideoBlob、AudioBlob、Model3DBlob抽象基類見 workflow-data.ts承擔(dān) NSFW 攔截與父引用BlobData.step、StepData.workflow接線。這套機(jī)制與圖片輸出強(qiáng)耦合統(tǒng)一查詢需要多態(tài)包裝器或?qū)Ψ菆D片類型跳過包裝。從源碼看WorkflowData的構(gòu)造選項domain、nsfwEnabled、allowMatureContent都與圖片的 NSFW 策略相關(guān)提示詞增強(qiáng)記錄不需要也不應(yīng)走這套包裝。六、統(tǒng)一化不可忽視的緩存維度文檔未展開、但源碼中必須納入統(tǒng)一化評估的是queryGeneratedImages專屬的短 TTL 緩存體系orchestration-new.service.tsQUERIED_WORKFLOWS_CACHE_TTL 3秒用于折疊 SignalR 重連風(fēng)暴——每次重連所有標(biāo)簽頁會同時 invalidatequeryGeneratedImages導(dǎo)致毫秒級的大量相同首頁查詢緩存鍵getQueriedWorkflowsCacheKey必須覆蓋所有影響響應(yīng)的參數(shù)take、cursor、tags、ascending、fromDate、toDate、excludeFailed、hideMatureContent并刻意排除 token以允許同一用戶的多標(biāo)簽頁共享條目失效采用每用戶索引集合SMEMBERS→DELdeleteWorkflow、cancelWorkflow、updateWorkflow、patch四個變更端點都會調(diào)用bustQueriedWorkflowsCache主動清緩存orchestrator.router.ts且只緩存第一頁無 cursor深翻頁直接穿透。而queryWorkflowsByTags提示詞增強(qiáng)歷史目前沒有這層緩存。統(tǒng)一端點后3 秒短 TTL 變更即失效的語義是否要覆蓋全部類型需要單獨決策如果對提示詞增強(qiáng)歷史也啟用會讓歷史記錄的增刪改如刪除一條增強(qiáng)記錄同樣依賴失效鏈路如果維持現(xiàn)狀則統(tǒng)一端點內(nèi)部將出現(xiàn)同端點不同緩存策略的分叉這本身也是一種復(fù)雜度。七、工作量評估與落地建議文檔給出的評估為23 天拆解如下讓formatGenerationResponse2類型感知且不破壞現(xiàn)有圖片 workflow約 1 天更新客戶端 hooks 與組件以處理判別聯(lián)合約 1 天回歸驗證遺留 workflow 格式仍能正確渲染約 0.5 天。建議是作為后續(xù)項推進(jìn)而不是提示詞增強(qiáng)功能的一部分——當(dāng)前雙端點方案已可用且足夠清晰當(dāng)出現(xiàn)第三種 orchestrator workflow 類型時統(tǒng)一化才真正值得做因為屆時每新增一種類型就新增一個端點的模式會開始顯得冗余。從當(dāng)前倉庫的實際狀態(tài)可以印證這一演進(jìn)方向已經(jīng)部分發(fā)生queryWorkflowsByTags的存在本身就是通用端點先行的落地orchestrator.router.ts提示詞增強(qiáng)已不再需要專屬端點而圖片側(cè)的queryGeneratedImages仍保留著強(qiáng)圖片假設(shè)與專屬緩存。可以推斷后續(xù)真正需要做的是讓formatGenerationResponse2的類型分發(fā)與queryWorkflowsByTags的通用查詢能力合流再統(tǒng)一客戶端判別與 Signal 通道即可完成文檔描述的整體收斂。相關(guān)查詢類型定義可在 src/types/router.ts 的QueryGeneratedImages中追根溯源。參考路徑速查設(shè)計文檔docs/unified-workflow-query.md路由層src/server/routers/orchestrator.router.tsqueryGeneratedImagesL331、queryWorkflowsByTagsL211底層查詢src/server/services/orchestrator/workflows.tsqueryWorkflowsL127、超時兜底 L64-L88格式化與緩存src/server/services/orchestrator/orchestration-new.service.tsformatGenerationResponse2L3003、queryGeneratedImageWorkflows2L3277、緩存 TTL L3177查詢?nèi)雲(yún)?schemasrc/server/schema/orchestrator/workflows.schema.ts圖片側(cè) hookssrc/components/ImageGeneration/utils/generationRequestHooks.ts、Signal 更新useGenerationSignalUpdate.ts提示詞側(cè) hookssrc/components/Generation/PromptEnhance/promptEnhanceHooks.ts通用緩存輔助src/components/Orchestrator/workflowHooks.ts客戶端包裝器src/shared/orchestrator/workflow-data.tsTag 與 Signal 常量src/shared/constants/generation.constants.ts、src/server/common/enums.ts【免費下載鏈接】civitaiA repository of models, textual inversions, and more項目地址: https://gitcode.com/GitHub_Trending/ci/civitai創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考