agentic_huge_data_base / wiki
页面 Open WebUI · 5.5 多模型响应展示·DeepWiki 中文全文译文

5.5 · 多模型响应展示(Multi-Model Response Display)

多模型对话工作台与知识应用入口 · 本章是 Open WebUI DeepWiki 中文译文的独立章节页,保留原始链接、源码锚点、模块标签和章节层级。

项目Open WebUI 章节5.5 状态全文译文 模块系统架构、界面与交互、频道、笔记与协作、工具、记忆与模型调用
源码线索
  • src/lib/apis/streaming/index.ts
  • src/lib/components/chat/Chat.svelte
  • src/lib/components/chat/MessageInput.svelte
  • src/lib/components/chat/Messages.svelte
  • src/lib/components/chat/Messages/Message.svelte
  • src/lib/components/chat/Messages/MultiResponseMessages.svelte
  • src/lib/components/chat/Messages/RateComment.svelte
  • src/lib/components/chat/Messages/ResponseMessage.svelte
  • src/lib/components/chat/Messages/ResponseMessage/TaskList.svelte
  • src/lib/components/chat/Messages/UserMessage.svelte
模块标签
  • 系统架构
  • 界面与交互
  • 频道、笔记与协作
  • 工具、记忆与模型调用
  • 接口与服务契约

中文译文

多模型响应展示(中文译文)

原始 DeepWiki 页面:https://deepwiki.com/open-webui/open-webui/5.5-multi-model-response-display
翻译时间:2026-06-09T16:08:37.793Z
翻译模型:deepseek-chat
原文字符数:11679
项目:Open WebUI (open-webui)

---

多模型响应展示

相关源文件

以下文件为本 wiki 页面的生成提供了上下文:

  • src/lib/apis/streaming/index.ts
  • src/lib/components/chat/Chat.svelte
  • src/lib/components/chat/MessageInput.svelte
  • src/lib/components/chat/Messages.svelte
  • src/lib/components/chat/Messages/Message.svelte
  • src/lib/components/chat/Messages/MultiResponseMessages.svelte
  • src/lib/components/chat/Messages/RateComment.svelte
  • src/lib/components/chat/Messages/ResponseMessage.svelte
  • src/lib/components/chat/Messages/ResponseMessage/TaskList.svelte
  • src/lib/components/chat/Messages/UserMessage.svelte
  • src/lib/components/chat/ModelSelector.svelte
  • src/lib/components/chat/ModelSelector/ModelItem.svelte
  • src/lib/components/chat/ModelSelector/ModelItemMenu.svelte
  • src/lib/components/chat/ModelSelector/Selector.svelte
  • src/lib/components/icons/Label.svelte
  • src/lib/components/icons/Tag.svelte
  • src/lib/utils/index.ts

目的与范围

多模型响应展示系统允许用户同时查询多个 AI 模型,并以对比布局查看它们的响应。当用户一次性向多个模型发送消息时,系统会以标签页界面或并排卡片的形式展示每个模型的响应,方便用户比较不同模型对同一提示的回答。

本文档涵盖实现多模型响应渲染的前端组件和数据结构。关于生成这些响应的后端聊天补全管道,请参阅聊天中间件与请求流程。关于父消息容器组件,请参阅消息渲染

---

架构概览

当用户消息的 selectedModels 数组中包含多个模型时,多模型响应展示系统被触发。系统检测到该条件后,会通过 MultiResponseMessages.svelte 进行渲染,而非标准的单响应渲染器。

组件层级

标题:多模型展示的组件层级

graph TB
    Chat["Chat.svelte<br/>主聊天编排器"]
    Messages["Messages.svelte<br/>消息列表容器"]
    Message["Message.svelte<br/>单条消息包装器"]
    UserMsg["UserMessage.svelte<br/>用户消息渲染器"]
    MultiResp["MultiResponseMessages.svelte<br/>多模型响应协调器"]
    RespMsg["ResponseMessage.svelte<br/>单模型响应渲染器"]

    Chat --> Messages
    Messages --> Message
    Message --> UserMsg
    Message --> MultiResp
    Message --> RespMsg

    MultiResp --> RespMsg
    MultiResp -.->|"N 个实例"| RespMsg

    Note1["决策点:<br/>parentMessage.models.length > 1"]
    Message --> Note1
    Note1 -.-> MultiResp
    Note1 -.-> RespMsg

来源:src/lib/components/chat/Messages/Message.svelte:76-128

Message.svelte 中的路由逻辑通过检查父消息(用户提示)上 models 数组的长度来决定使用哪个渲染器:

{#if history.messages[messageId].role === 'user'}
    <UserMessage ... />
{:else if (history.messages[history.messages[messageId].parentId]?.models?.length ?? 1) === 1}
    <ResponseMessage ... />
{:else}
    <MultiResponseMessages ... />
{/if}

来源:src/lib/components/chat/Messages/Message.svelte:55-128

---

消息历史数据结构

多模型响应采用基于树的消息历史组织方式,每个用户消息可以有多个子响应,每个模型对应一个。

历史模式

标题:多模型消息树结构

graph TB
    subgraph "history 对象"
        messages["messages: Object&lt;messageId, Message&gt;"]
        currentId["currentId: string | null"]
    end

    subgraph "消息结构"
        id["id: string (UUID)"]
        parentId["parentId: string | null"]
        childrenIds["childrenIds: string[]"]
        role["role: 'user' | 'assistant'"]
        content["content: string"]
        model["model: string"]
        modelIdx["modelIdx: number"]
        models["models: string[]<br/>(仅用户消息包含)"]
    end

    subgraph "多模型组织"
        userMsg["用户消息<br/>models: ['gpt-4o', 'claude-3-5-sonnet']"]
        resp1["响应 1<br/>model: 'gpt-4o'<br/>modelIdx: 0"]
        resp2["响应 2<br/>model: 'claude-3-5-sonnet'<br/>modelIdx: 1"]

        userMsg --> resp1
        userMsg --> resp2
    end

来源:src/lib/components/chat/Messages/MultiResponseMessages.svelte:64-74src/lib/utils/index.ts:195-226

分组消息 ID 结构

MultiResponseMessages 按模型索引组织消息,以实现高效导航:

变量类型用途
groupedMessageIdsObject<number, {messageIds: string[]}>将所有响应 ID 按对应的模型索引分组。
groupedMessageIdsIdxObject<number, number>跟踪每个模型当前可见的响应索引。

这种组织方式支持独立导航每个模型的响应历史,因为多次重新生成或编辑可能为每个模型创建多个响应版本。

来源:src/lib/components/chat/Messages/MultiResponseMessages.svelte:59-60src/lib/components/chat/Messages/MultiResponseMessages.svelte:157-197

---

初始化与消息分组

初始化流程

标题:多模型初始化序列

sequenceDiagram
    participant Mount as "onMount"
    participant Init as "initHandler"
    participant History as "history.messages"
    participant Groups as "groupedMessageIds"

    Mount->>Init: 触发初始化
    Init->>History: 获取 parentMessage
    Init->>History: 读取 parentMessage.models

    loop 每个模型
        Init->>History: 查找匹配 modelIdx 的 childrenIds
        Init->>Groups: 按 modelIdx 存储 messageIds
    end

    Init->>Groups: 计算每个模型的当前索引
    Init->>Init: 设置 selectedModelIdx

来源:src/lib/components/chat/Messages/MultiResponseMessages.svelte:148-204src/lib/components/chat/Messages/MultiResponseMessages.svelte:233-235

initHandler 函数执行按模型分组消息的关键任务:

groupedMessageIds = parentMessage?.models.reduce((a, model, modelIdx) => {
    // 查找所有属于父消息子节点且具有相同 modelIdx 的消息
    let modelMessageIds = parentMessage?.childrenIds
        .map((id) => history.messages[id])
        .filter((m) => m?.modelIdx === modelIdx)
        .map((m) => m.id);

    // 对没有 modelIdx 的消息提供向后兼容支持
    if (modelMessageIds.length === 0) {
        let modelMessages = parentMessage?.childrenIds
            .map((id) => history.messages[id])
            .filter((m) => m?.model === model);

        modelMessages.forEach((m) => {
            m.modelIdx = modelIdx;
        });

        modelMessageIds = modelMessages.map((m) => m.id);
    }

    return {
        ...a,
        [modelIdx]: { messageIds: modelMessageIds }
    };
}, {});

来源:src/lib/components/chat/Messages/MultiResponseMessages.svelte:157-182

---

展示模式

系统支持两种展示模式,由 $settings?.displayMultiModelResponsesInTabs 设置控制。

标签页展示

displayMultiModelResponsesInTabstrue 时,响应以标签页界面展示。仅渲染所选模型的响应,在选中多个模型时有助于提升性能。

来源:src/lib/components/chat/Messages/MultiResponseMessages.svelte:253-326

卡片展示

displayMultiModelResponsesInTabsfalse 时,响应以并排卡片形式展示。选中的卡片使用实线边框(border-2),未选中的使用虚线边框。容器使用 CSS 滚动吸附(scroll snap),在移动设备上实现流畅导航。

来源:src/lib/components/chat/Messages/MultiResponseMessages.svelte:329-385

---

响应导航

用户可以使用上一步/下一步控件浏览每个模型的多个响应版本。

导航逻辑

导航函数实现了边界限制以防止越界访问,并向下钻取到所选分支的最深层子节点:

const showPreviousMessage = async (modelIdx) => {
    groupedMessageIdsIdx[modelIdx] = Math.max(0, groupedMessageIdsIdx[modelIdx] - 1);

    let messageId = groupedMessageIds[modelIdx].messageIds[groupedMessageIdsIdx[modelIdx]];
    let messageChildrenIds = history.messages[messageId].childrenIds;

    while (messageChildrenIds.length !== 0) {
        messageId = messageChildrenIds.at(-1);
        messageChildrenIds = history.messages[messageId].childrenIds;
    }

    history.currentId = messageId;

    await tick();
    await updateChat();
    triggerScroll();
};

来源:src/lib/components/chat/Messages/MultiResponseMessages.svelte:105-123

---

响应合并(混合代理)

系统提供了“合并响应”功能,使用混合代理(Mixture of Agents,MoA)技术将多个模型输出合并为单个统一响应。

合并处理器

合并处理器收集每个模型当前显示的响应,并触发 MoA 补全:

const mergeResponsesHandler = async () => {
    const responses = Object.keys(groupedMessageIds).map((modelIdx) => {
        const { messageIds } = groupedMessageIds[modelIdx];
        const messageId = messageIds[groupedMessageIdsIdx[modelIdx]];

        return history.messages[messageId].content;
    });
    mergeResponses(messageId, responses, chatId);
};

来源:src/lib/components/chat/Messages/MultiResponseMessages.svelte:223-231

合并后的响应在通过 generateMoACompletion 触发生成后,显示在各个模型响应下方。

来源:src/lib/components/chat/Chat.svelte:87src/lib/components/chat/Messages/MultiResponseMessages.svelte:397-421

---

集成总结

MultiResponseMessages 组件充当并行消息分支的高级协调器:

  1. 状态同步:使用 history.currentId 在模型选择过程中保持全局聊天状态与用户焦点同步。
  2. 性能:使用 {#key messageId}{#key history.currentId} 确保 ResponseMessage 等组件在导航过程中正确重新初始化。
  3. 响应式:根据 $mobile 存储适配布局,在卡片展示中切换 min-w-fullmin-w-80

来源:src/lib/components/chat/Messages/MultiResponseMessages.svelte:104-146src/lib/components/chat/Messages/MultiResponseMessages.svelte:339-340