メインコンテンツまでスキップ

数据流

本文档描述 Elftia 中数据在各层之间的流转方式,包括消息发送、工具调用、状态管理和缓存策略。

消息发送全流程

从用户在输入框输入到 AI 回复渲染完成的完整数据流:

sequenceDiagram
participant U as 用户输入
participant UI as UnifiedInput
participant UCC as UnifiedChatContext
participant CBC as ChatBackendContext
participant IPC as IPC Layer
participant CR as CompletionRouter
participant CS as CompletionService
participant ED as EngineDispatcher
participant Engine as Engine (Chat/SDK/TinyElf/CLI)
participant LLM as LLM API
participant DB as DbClient (Worker)
participant Store as chatStore (Zustand)
participant Render as MessageRenderer

U->>UI: 键入消息, 按 Enter
UI->>UCC: sendMessage(content, attachments)
UCC->>UCC: 创建 user message, 更新本地状态
UCC->>CBC: 通过 IPC 发送消息
CBC->>IPC: window.api.completion.chatInSession(params)
IPC->>CR: secureHandle 验证 token
CR->>CS: completion.chatInSession(sessionId, messages, config)
CS->>ED: engineDispatcher.chat(session)
ED->>Engine: 路由到对应引擎
Engine->>LLM: HTTP 请求 (SSE stream)

loop SSE 流式响应
LLM-->>Engine: data chunk
Engine-->>CR: IPC event (stream:delta)
CR-->>IPC: mainWindow.send('stream:delta', chunk)
IPC-->>CBC: onStreamDelta callback
CBC-->>Store: setStreamingState({content})
Store-->>Render: 重渲染 StreamingMessage
end

Engine-->>CR: stream 完成
CR->>DB: 持久化 assistant message
CR-->>IPC: stream:end event
IPC-->>CBC: onStreamEnd callback
CBC-->>UCC: 更新消息列表
UCC-->>Store: clearStreamingState, addMessage
Store-->>Render: 渲染最终消息

关键步骤说明

  1. 用户输入UnifiedInput 组件捕获输入、附件、模型选择
  2. UnifiedChatContext — 创建 user 消息对象,乐观更新本地状态
  3. IPC 调用 — 通过 Preload 暴露的 window.api.completion.chatInSession() 发送到主进程
  4. CompletionRouter — 验证 token,解析参数,调用 CompletionService
  5. EngineDispatcher — 根据 Agent 的 engineType 路由到对应引擎
  6. LLM API — 引擎发起 HTTP 请求,接收 SSE 流式响应
  7. 流式推送 — 每个 delta 通过 IPC 事件推送到前端,Zustand store 实时更新
  8. 持久化 — 完成后后端将 assistant 消息写入数据库
  9. 状态同步 — 前端清除流式状态,显示最终消息

Agent 工具调用流

当 LLM 返回工具调用(tool_use)时的处理流程:

flowchart TB
LLM[LLM 返回 tool_use] --> Parse[解析 tool_call]
Parse --> FW{ExecutionFirewall<br/>路径检查}

FW -->|拒绝| Block[返回 denied 结果给 LLM]
FW -->|通过| Guardian{GuardianAgent<br/>AI 安全审查}

Guardian -->|risk: high/critical| PermGate{ChannelPermissionGate<br/>人工确认}
Guardian -->|risk: low/none| Execute[执行工具]
Guardian -->|monitor 模式| LogOnly[记录日志后执行]

PermGate -->|用户拒绝| Block
PermGate -->|用户批准| Execute

Execute --> Result[工具执行结果]
Result --> Audit[AuditLogger 记录]
Result --> BackToLLM[结果返回给 LLM]
BackToLLM --> LLM

LogOnly --> Execute
{/* TinyElf Agent Loop 中的工具调用管线 */}
interface ToolCallPipeline {
firewall: ExecutionFirewall; // 1. 确定性检查 (零 LLM 开销)
guardian: GuardianAgent; // 2. AI 审查 (按模式决定)
permissionGate: ChannelPermissionGate; // 3. 人工确认 (仅 Channel 来源)
executor: ToolExecutor; // 4. 执行
auditLogger: AuditLogger; // 5. 审计
}

状态管理层次

前端状态管理分为三层,各层有明确的职责边界:

graph TB
subgraph "Layer 1: Zustand Store (核心状态)"
CS[chatStore — 会话/消息/流式/分支]
SS[settingsStore — 设置状态]
end

subgraph "Layer 2: React Context (领域状态)"
CDC[ChatDataContext — 数据缓存 wrapper]
UCC2[UnifiedChatContext — 统一聊天 API]
TC[ThemeContext — 主题]
AC[AuthContext — 认证]
EC[ElfiContext — Elfi 助手]
end

subgraph "Layer 3: Feature Context (功能状态)"
CTC[ChatTabsContext — 多标签]
WIC[WorldInfoHighlightContext — WI 高亮]
MSC[MessageSelectionContext — 消息多选]
end

CS --> CDC
CDC --> UCC2
UCC2 --> CTC

各层职责

层级技术特征适用场景
Layer 1Zustand高频更新、精确订阅、无 Provider 嵌套流式消息、分支切换、会话列表
Layer 2React Context中频更新、提供 API 方法、依赖注入聊天操作(发送/重新生成)、认证、主题
Layer 3React Context低频更新、功能隔离多标签、关键词高亮、消息选择

状态迁移方向

ChatDataContext (deprecated) ──迁移──> chatStore (Zustand)

v
UnifiedChatContext (统一 API 层)

ChatDataContext 是历史遗留的 Context wrapper,正在逐步迁移到 Zustand store。新代码应直接使用 chatStoreUnifiedChatContext

消息分支机制

聊天消息使用树结构支持分支(regenerate/edit 创建新分支):

graph TB
M1[User: 你好] --> M2a[Assistant: 你好! v1]
M1 --> M2b[Assistant: 嗨! v2]
M2a --> M3[User: 帮我写代码]
M3 --> M4a[Assistant: 好的 v1]
M3 --> M4b[Assistant: 当然 v2]
{/* 分支数据结构 */}
interface BranchInfo {
id: string;
parentMessageId: string;
children: string[];
currentIndex: number;
}

{/* 分支操作 */}
interface BranchOperations {
switchBranch(messageId: string, index: number): void;
getActivePath(rootId: string): Message[];
regenerate(messageId: string): void;
editMessage(messageId: string, newContent: string): void;
}

分支切换逻辑

  1. 用户点击分支导航箭头
  2. switchBranch(parentMessageId, newIndex) 更新 BranchInfo.currentIndex
  3. getActivePath() 重新计算从根到叶的活动消息路径
  4. 消息列表重新渲染

缓存策略

前端缓存

缓存技术TTL用途
消息缓存Zustand messageCache会话生命周期避免重复加载消息
UI 状态IndexedDB (frontendCache)持久草稿、折叠状态、滚动位置
会话列表Zustand sessions刷新时更新侧边栏会话列表
提供商列表Zustand providers刷新时更新模型选择器

后端缓存

缓存位置TTL用途
MCP 工具列表CacheService5 分钟避免重复列举 MCP 工具
Transformer 链TransformerService10 分钟编译后的转换链
提供商索引LLMConfigServiceO(1) Map按 ID 快速查找提供商
API Key 冷却ApiKeyPoolService60s-15min 指数退避429/529 错误后冷却
PromptGuardian 结果PromptGuardianSHA-256 key已审查提示的缓存结果
GuardianAgent 结果GuardianAgentSHA-256 key已审查工具调用的缓存结果

会话保护机制

防止 WebSocket 项目更新在活动对话期间刷新侧边栏并清除聊天消息:

{/* 会话保护流程 */}
interface SessionProtection {
activeSessions: Set<string>;
processingSessions: Set<string>;

markActive(sessionId: string): void; // 用户发消息时标记
shouldSkipRefresh(): boolean; // activeSessions.size > 0
markInactive(sessionId: string): void; // 对话完成后移除
}

多密钥轮询 (ApiKeyPoolService)

后端支持每个 LLM 提供商配置多个 API Key,使用加权轮询 + 会话亲和策略:

flowchart LR
Req[请求] --> Check{会话已绑定?}
Check -->|是| BoundKey[使用绑定的 Key]
Check -->|否| RR[加权轮询选择 Key]
RR --> Bind[绑定到会话]
Bind --> Call[API 调用]
BoundKey --> Call
Call --> OK{成功?}
OK -->|429/529| Cool[冷却该 Key]
Cool --> Retry[切换到下一个 Key 重试]
OK -->|成功| Done[返回结果]
{/* 简化的 ApiKeyPoolService */}
class ApiKeyPoolService {
private sessionBindings: Map<string, string>;
private cooldowns: Map<string, { until: number; backoff: number }>;

resolveApiKeyForRequest(
providerId: string,
sessionId?: string,
): Promise<{ keyId: string; apiKey: string }>;

markKeyError(keyId: string, statusCode: number): void;
}

相关文件

文件说明
packages/renderer/src/shared/state/chatStore.tsZustand 聊天状态 Store + 统一聊天 API(发送/重新生成/编辑、数据缓存;原 UnifiedChatContext / ChatDataContext 已迁入此处)
packages/renderer/src/features/chat/hooks/useSessionProtection.ts会话保护
packages/renderer/src/shared/utils/frontendCache.ts前端 IndexedDB 缓存
packages/desktop/app/main/services/capabilities/llm/completion/CompletionService.tsLLM 补全服务
packages/desktop/app/main/services/capabilities/llm/completion/ApiKeyPoolService.ts多密钥轮询
packages/desktop/app/main/services/agent-core/engine/EngineDispatcher.ts引擎调度
packages/desktop/app/main/services/routers/CompletionRouter.ts补全 IPC 路由
packages/desktop/app/main/services/platform/security/ExecutionFirewall.ts路径防火墙
packages/desktop/app/main/services/platform/security/GuardianAgent.tsAI 工具审查
packages/desktop/app/main/services/infra/cache/CacheService.ts后端缓存服务