频道架构(中文译文)
原始 DeepWiki 页面:https://deepwiki.com/open-webui/open-webui/10.1-channel-architecture
翻译时间:2026-06-09T16:10:19.033Z
翻译模型:deepseek-chat
原文字符数:16769
项目:Open WebUI (open-webui)
---
频道架构
相关源文件
本 Wiki 页面基于以下源文件生成:
backend/open_webui/models/channels.pybackend/open_webui/models/messages.pybackend/open_webui/routers/channels.pysrc/lib/apis/channels/index.tssrc/lib/components/channel/Channel.sveltesrc/lib/components/channel/ChannelInfoModal.sveltesrc/lib/components/channel/ChannelInfoModal/AddMembersModal.sveltesrc/lib/components/channel/ChannelInfoModal/UserList.sveltesrc/lib/components/channel/MessageInput.sveltesrc/lib/components/channel/MessageInput/InputMenu.sveltesrc/lib/components/channel/Messages.sveltesrc/lib/components/channel/Messages/Message.sveltesrc/lib/components/channel/Thread.sveltesrc/lib/components/layout/Sidebar/ChannelItem.sveltesrc/lib/components/layout/Sidebar/ChannelModal.sveltesrc/lib/components/workspace/common/AddAccessModal.sveltesrc/lib/components/workspace/common/MemberSelector.svelte
目的与范围
本文档描述 Open WebUI 中的频道系统,该系统提供群组消息和直接消息功能。频道支持用户间的实时通信,并具备线程、反应、文件附件和 AI 模型交互能力。
关于实时 Socket.IO 事件处理的信息,请参见实时通信架构 (2.5)。关于消息渲染和显示的详细信息,请参见消息渲染 (5)。
---
频道类型与数据模型
频道系统支持三种不同的频道类型,每种类型具有不同的访问控制模型和用例:
频道类型概览
| 类型 | 代码值 | 访问控制 | 用例 |
|---|---|---|---|
| 标准频道 | None 或 "" | access_grants(基于组/用户的权限) | 组织范围的讨论,具有细粒度权限 |
| 群组频道 | "group" | 成员列表 + is_private 标志 | 团队协作,支持成员加入 |
| 直接消息 | "dm" | 仅成员列表 | 私密的一对一或小群组对话 |
核心数据模型
erDiagram
"Channel (Base)" ||--o{ "ChannelMember (Base)" : "拥有成员"
"Channel (Base)" ||--o{ "Message (Base)" : "包含"
"Channel (Base)" ||--o{ "AccessGrant (Base)" : "拥有授权"
"Channel (Base)" ||--o{ "ChannelWebhook (Base)" : "拥有 Webhook"
"Channel (Base)" ||--o{ "ChannelFile (Base)" : "拥有文件"
"Message (Base)" ||--o{ "MessageReaction (Base)" : "拥有反应"
"Message (Base)" ||--o{ "Message (Base)" : "父/回复(线程)"
"Channel (Base)" {
text id PK
text user_id
text type
text name
text description
boolean is_private
json data
json meta
bigint created_at
bigint updated_at
}
"ChannelMember (Base)" {
text id PK
text channel_id FK
text user_id FK
text role
text status
boolean is_active
boolean is_channel_muted
boolean is_channel_pinned
bigint joined_at
bigint last_read_at
}
"Message (Base)" {
text id PK
text user_id
text channel_id FK
text reply_to_id FK
text parent_id FK
boolean is_pinned
text content
json data
json meta
bigint created_at
}
"AccessGrant (Base)" {
text principal_type
text principal_id
text permission
}
来源:
backend/open_webui/models/channels.py:36-62backend/open_webui/models/channels.py:93-121backend/open_webui/models/messages.py:24-30backend/open_webui/models/messages.py:43-63
频道模型实现
ChannelModel Pydantic 类表示一个频道实例,包括用于权限检查的访问授权。
class ChannelModel(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: str
user_id: str
type: Optional[str] = None
name: str
description: Optional[str] = None
is_private: Optional[bool] = None
data: Optional[dict] = None
meta: Optional[dict] = None
access_grants: list[AccessGrantModel] = Field(default_factory=list)
created_at: int
updated_at: int
# ... 归档和删除字段
来源:
backend/open_webui/models/channels.py:64-91
---
访问控制架构
频道系统实现了一种复杂的访问控制机制,该机制因频道类型而异,依赖于显式成员关系和基于权限的访问授权。
按频道类型的访问控制流程
graph TD
UserRequest["用户请求"] --> CheckChannelType{"检查 channel.type?"}
CheckChannelType -->|"type='dm' 或 'group'"| CheckMembership["检查 ChannelMember 表"]
CheckChannelType -->|"type=None/empty"| CheckAccessGrants["检查 AccessGrants"]
CheckMembership --> IsMember{"用户是否在<br/>ChannelMember 中?"}
IsMember -->|"是"| AllowAccess["✓ 允许访问"]
IsMember -->|"否"| DenyAccess["✗ 拒绝访问"]
CheckAccessGrants --> HasPermission{"AccessGrants.has_access()?"}
HasPermission -->|"是"| AllowAccess
HasPermission -->|"否"| IsAdmin{"User.role == 'admin'?"}
IsAdmin -->|"是"| AllowAccess
IsAdmin -->|"否"| DenyAccess
来源:
backend/open_webui/routers/channels.py:75-94backend/open_webui/models/channels.py:373-381
访问授权结构
对于标准频道(type=None/""),access_grants 数组控制权限:
# 示例 access_grants 结构
access_grants = [
{
"principal_type": "user", # 或 "group"
"principal_id": "user-uuid", # 或 "*" 表示所有用户
"permission": "read" # 或 "write"
}
]
公开频道检测:如果频道具有 principal_id="*" 的访问授权,则视为公开频道。前端使用 hasPublicReadGrant 来判断频道是否公开。src/lib/components/layout/Sidebar/ChannelItem.svelte:29-46
来源:
backend/open_webui/routers/channels.py:108-128src/lib/components/layout/Sidebar/ChannelItem.svelte:29-46
权限检查函数
graph LR
channel_has_access["channel_has_access()<br/>backend/open_webui/routers/channels.py"] --> AccessGrants_has_access["AccessGrants.has_access()<br/>backend/open_webui/models/access_grants.py"]
get_channel_users_with_access["get_channel_users_with_access()<br/>backend/open_webui/routers/channels.py"] --> AccessGrants_get_users["AccessGrants.get_users_with_access()<br/>backend/open_webui/models/access_grants.py"]
get_channel_permitted_group_and_user_ids["get_channel_permitted_group_and_user_ids()<br/>backend/open_webui/routers/channels.py"] --> ParseAccessGrants["解析 channel.access_grants 数组"]
关键函数:
channel_has_access(user_id, channel, permission, strict):检查用户是否对频道具有特定权限。backend/open_webui/routers/channels.py:75-94get_channel_users_with_access(channel, permission):通过AccessGrants检索对频道具有特定权限的用户列表。backend/open_webui/routers/channels.py:97-105get_channel_permitted_group_and_user_ids(channel, permission):返回对频道具有特定权限的用户和组 ID 字典。backend/open_webui/routers/channels.py:108-129
来源:
backend/open_webui/routers/channels.py:75-129
---
消息架构
消息支持 Markdown 内容、层级线程、反应和置顶。
消息结构与线程模型
graph TD
RootMessage["根消息<br/>(parent_id=null)"] --> Thread1["线程回复 1<br/>(parent_id=root_id,<br/>reply_to_id=root_id)"]
RootMessage --> Thread2["线程回复 2<br/>(parent_id=root_id,<br/>reply_to_id=root_id)"]
Thread1 --> Thread1Reply["线程回复 1.1<br/>(parent_id=root_id,<br/>reply_to_id=thread1_id)"]
AnotherRoot["另一条根消息"] --> DirectReply["直接回复<br/>(parent_id=null,<br/>reply_to_id=another_root_id)"]
消息字段:
parent_id:线程根消息 ID(非线程消息为 null)。backend/open_webui/models/messages.py:51reply_to_id:直接回复目标消息 ID(创建引用链接)。backend/open_webui/models/messages.py:50is_pinned:布尔标志,表示消息是否置顶。backend/open_webui/models/messages.py:54content:Markdown 文本内容。backend/open_webui/models/messages.py:58data:包含文件附件和结构化数据。backend/open_webui/models/messages.py:59meta:元数据,如 AI 消息的model_id或webhook信息。backend/open_webui/models/messages.py:60
来源:
backend/open_webui/models/messages.py:43-63
消息响应模型
后端返回带有额外计算字段的丰富消息对象:
| 模型 | 用途 | 额外字段 |
|---|---|---|
MessageModel | 基础消息 | 仅核心数据库字段 |
MessageUserSlimResponse | 优化响应 | data: bool(如果存在非空数据则为 true) |
MessageResponse | 完整响应 | reply_count, latest_reply_at, reactions[] |
来源:
backend/open_webui/models/messages.py:113-138
消息反应系统
graph LR
MessageReaction["MessageReaction 表<br/>backend/open_webui/models/messages.py"] --> MessageReactionId["id: 唯一实例"]
MessageReaction --> UserId["user_id: 谁做出的反应"]
MessageReaction --> MessageId["message_id: 目标消息"]
MessageReaction --> Name["name: 表情符号短代码"]
GetReactions["get_reactions_by_message_id()<br/>backend/open_webui/models/messages.py"] --> GroupByName["按名称分组"]
GroupByName --> ReactionsArray["reactions: [{name, users[], count}]"]
反应 API 端点:
POST /channels/{id}/messages/{message_id}/reactions/add:向消息添加反应。backend/open_webui/routers/channels.py:1277-1326POST /channels/{id}/messages/{message_id}/reactions/remove:从消息移除反应。backend/open_webui/routers/channels.py:1329-1377
来源:
backend/open_webui/models/messages.py:24-30backend/open_webui/models/messages.py:481-518backend/open_webui/routers/channels.py:1277-1377
---
频道成员管理
对于群组和 DM 频道,ChannelMember 表跟踪用户参与情况和未读计数。
成员操作
ChannelTable 类提供了管理成员关系的方法:
# 添加成员(创建 ChannelMember 记录)
add_members_to_channel(channel_id, invited_by, user_ids, group_ids) # [backend/open_webui/models/channels.py:457-480]()
# 移除成员(删除 ChannelMember 记录)
remove_members_from_channel(channel_id, user_ids) # [backend/open_webui/models/channels.py:483-500]()
# 软隐藏/取消隐藏(用于 DM 频道)
update_member_active_status(channel_id, user_id, is_active) # [backend/open_webui/models/channels.py:503-524]()
来源:
backend/open_webui/models/channels.py:457-524
未读消息跟踪
每个 ChannelMember 记录维护一个 last_read_at 时间戳。
# 计算未读计数
unread_count = Messages.get_unread_message_count(channel_id, user_id, last_read_at) # [backend/open_webui/models/messages.py:520-539]()
# 更新最后读取时间戳(通过 Socket.IO 事件)
socket.emit('events:channel', { # [src/lib/components/channel/Channel.svelte:58-64]()
channel_id: id,
data: { type: 'last_read_at' }
})
来源:
backend/open_webui/models/messages.py:520-539src/lib/components/channel/Channel.svelte:57-77
---
实时通信事件
频道使用 Socket.IO 进行实时更新,事件类型为 events:channel。
事件类型与负载
| 事件类型 | 用途 | 负载数据 |
|---|---|---|
message | 新消息发布 | {type: 'message', data: MessageModel} |
message:update | 消息编辑 | {type: 'message:update', data: MessageModel} |
typing | 用户输入指示器 | {type: 'typing', data: {typing: bool}} |
last_read_at | 已读回执更新 | {type: 'last_read_at'} |
来源:
backend/open_webui/routers/channels.py:1146-1200src/lib/components/channel/Channel.svelte:115-188src/lib/components/channel/Thread.svelte:62-129
---
频道中的 AI 模型集成
频道支持通过提及和回复与 AI 模型直接交互。
模型响应机制
graph TD
UserMessage["用户发送包含 @model 的消息"] --> ExtractMentions["extract_mentions()<br/>backend/open_webui/utils/channels.py"]
ExtractMentions --> CheckReply{"回复模型消息?"}
CheckReply -->|是| AddParentModel["添加父消息 model_id"]
CheckReply -->|否| CheckMentions{"提及了模型?"}
CheckMentions -->|是| CollectModels["收集模型提及"]
CheckMentions -->|否| Done["无 AI 响应"]
ProcessModels["model_response_handler()<br/>backend/open_webui/routers/channels.py"] --> BuildHistory["构建线程历史"]
BuildHistory --> CallAPI["generate_chat_completion()<br/>backend/open_webui/utils/chat.py"]
CallAPI --> PostResponse["作为新消息发布,附带 meta.model_id"]
来源:
backend/open_webui/routers/channels.py:976-1139backend/open_webui/utils/channels.py:66-66
---
前端组件架构
频道 UI 使用 Svelte 组件构建,采用层级结构。
组件层级
graph TD
ChannelSvelte["Channel.svelte<br/>src/lib/components/channel/Channel.svelte"] --> NavbarSvelte["Navbar.svelte<br/>src/lib/components/channel/Navbar.svelte"]
ChannelSvelte --> MessagesSvelte["Messages.svelte<br/>src/lib/components/channel/Messages.svelte"]
ChannelSvelte --> MessageInputSvelte["MessageInput.svelte<br/>src/lib/components/channel/MessageInput.svelte"]
ChannelSvelte --> ThreadSvelte["Thread.svelte<br/>src/lib/components/channel/Thread.svelte"]
MessagesSvelte --> MessageSvelte["Message.svelte<br/>src/lib/components/channel/Messages/Message.svelte"]
ThreadSvelte --> ThreadMessages["Messages.svelte"]
ThreadSvelte --> ThreadInput["MessageInput.svelte"]
来源:
src/lib/components/channel/Channel.svelte:19-24src/lib/components/channel/Messages.svelte:16src/lib/components/channel/Thread.svelte:9-10
变量替换与文件
MessageInput.svelte 组件处理富文本输入、变量替换(例如 {{USER_NAME}}、{{CLIPBOARD}})和文件附件。src/lib/components/channel/MessageInput.svelte:86-223 文件通过 uploadFile 上传,并通过 inputFilesHandler 处理。src/lib/components/channel/MessageInput.svelte:355-505
来源:
src/lib/components/channel/MessageInput.svelte:86-223src/lib/components/channel/MessageInput.svelte:355-505
---
数据库模式总结
主要表
| 表 | 用途 | 关键列 |
|---|---|---|
channel | 频道定义 | id, user_id, type, name, is_private |
channel_member | 频道成员关系 | channel_id, user_id, is_active, last_read_at |
message | 频道消息 | id, channel_id, user_id, parent_id, reply_to_id, content |
message_reaction | 消息反应 | message_id, user_id, name(表情符号) |
来源:
backend/open_webui/models/channels.py:36-62backend/open_webui/models/channels.py:93-121backend/open_webui/models/messages.py:24-30backend/open_webui/models/messages.py:43-63