1. 项目概述一个面向未来的AI桌面工作台如果你和我一样每天需要在ChatGPT、Claude、本地部署的Ollama模型甚至是一些特定领域的AI工具之间来回切换那么你一定能理解这种“多窗口、多标签、多API密钥”的混乱与低效。我们渴望一个统一的入口一个能聚合所有AI能力并且像使用本地软件一样流畅、可扩展的桌面应用。这正是Zeek.ai项目诞生的初衷。Zeek.ai不是一个简单的聊天客户端外壳。它是一个基于现代Web技术栈Electron Vue 3构建的、模块化设计的AI桌面工作台。它的核心目标是成为连接各类大语言模型LLM和AI工具的“中枢神经”通过一个优雅的桌面应用将分散的AI能力整合进你的日常工作流。无论是代码生成、文案创作、数据分析还是简单的日常问答你都可以在这里一站式完成无需再为管理多个浏览器标签和API而分心。它适合所有希望提升AI使用效率的开发者、内容创作者和知识工作者无论你是想快速体验多模型对比还是希望深度定制自己的AI助手工作流Zeek.ai的架构都为此提供了坚实的基础。2. 核心架构与设计哲学解析2.1 为什么选择Electron MonorepoZeek.ai的技术选型清晰地反映了其定位一个功能强大、体验接近原生、且高度可扩展的桌面应用。首先Electron的选择是决定性的。它允许开发者使用熟悉的Web技术HTML, CSS, JavaScript来构建跨平台的桌面应用。对于Zeek.ai这样一个以复杂交互和实时通信为核心的AI工具集来说利用Web生态海量的UI库和工具链如Vue 3, Element Plus可以极大加速开发并保证在Windows、macOS和Linux上拥有一致的用户体验。Electron主进程与渲染进程分离的架构也天然适合处理应用生命周期、系统原生API调用如文件系统、自动更新与复杂UI渲染的职责分离。其次Monorepo单体仓库架构是项目可扩展性的关键。传统的多仓库管理在模块间依赖和联调上非常繁琐。Zeek.ai将主进程、多个渲染器模块、预加载脚本、版本管理等全部放在一个仓库的packages/目录下通过pnpm或npmworkspace进行管理。这样做的好处非常明显依赖管理清晰所有子包共享顶层的依赖配置版本冲突易于解决。开发体验流畅代码修改可以跨包即时生效配合Vite的热重载调试效率极高。构建部署统一可以轻松配置一套构建脚本一次性产出所有模块的最终产物。团队协作高效所有相关代码的变更历史集中便于代码审查和理解项目全貌。这种设计意味着未来如果你想为Zeek.ai新增一个“图像处理”工具模块或者接入一个新的AI供应商你只需要在packages/下新建一个独立的包并通过定义清晰的接口与其他模块通信即可不会对现有核心代码造成侵扰。2.2 模块化渲染器功能解耦的艺术Zeek.ai的UI部分渲染器没有做成一个臃肿的整体而是进一步拆分为basic、tools、chat等子模块。这是一种非常先进的前端架构思想。renderer/basic这是应用的“骨架”和“基础能力”。它承载核心的布局框架、路由导航、主题样式以及一些基础的AI工具执行环境。你可以把它想象成电脑的主板和操作系统为其他功能模块提供运行平台。renderer/tools这是“可插拔的工具箱”。所有文本转图片、图片转文本、视频处理等独立功能理论上都可以作为一个个工具插件Plugin存在于此。这种设计让功能扩展变得极其灵活社区开发者可以遵循一定的规范独立开发工具插件然后集成进来。renderer/chat这是“AI对话的核心引擎”。它专门处理与各种AI代理如ChatGPT, Grok, Ollama的通信、会话管理、消息渲染和上下文保持。值得注意的是这里提到了“混合 LibreChat 组件”。LibreChat是一个开源的ChatGPT UI克隆功能成熟。Zeek.ai选择集成或借鉴其部分组件而非完全重造轮子是一个务实的策略能快速获得一个稳定、功能丰富的聊天界面然后将精力集中在多代理调度和桌面端特性优化上。实操心得模块边界的设计在实际开发中定义清晰的模块边界是成败关键。我们的原则是basic模块提供公共服务如状态管理Pinia的根Store、全局事件总线、通用工具函数tools模块内的工具彼此独立通过basic提供的接口注册和调用chat模块则专注于数据流发送请求、接收流式响应、管理会话历史。避免模块间直接相互引用而是通过依赖注入或事件通信这样才能真正保持架构的整洁和可维护性。3. 开发环境搭建与核心配置详解3.1 环境准备与依赖安装Zeek.ai对开发环境有明确要求这是保证所有依赖包能够正确编译和运行的基础。Node.js版本管理项目要求Node.js 20.0.0。我强烈建议使用nvmMac/Linux或nvm-windows来管理Node版本。这样可以轻松切换不同项目所需的环境。# 使用nvm安装并切换至20.x版本 nvm install 20 nvm use 20包管理器选择官方推荐使用pnpm。pnpm相比npm和yarn通过硬链接和符号链接来存储依赖能极大节省磁盘空间并提升安装速度尤其适合Monorepo项目。如果你尚未安装pnpmnpm install -g pnpm克隆与安装git clone https://github.com/zeeklog/zeek.ai.git cd zeek.ai pnpm install这里有一个至关重要的细节如果你使用npm必须加上--legacy-peer-deps标志。这是因为项目内某些依赖包对React等库的版本要求可能存在冲突此标志会忽略peerDependencies的严格校验采用更宽松的安装策略。而pnpm默认处理此类冲突的方式更为智能通常无需额外参数。3.2 项目启动与脚本解析安装完成后查看package.json中的scripts脚本是理解项目入口的关键{ scripts: { dev: electron-vite dev, build: electron-vite build, preview: electron-vite preview, postinstall: electron-builder install-app-deps } }pnpm run dev启动开发模式。这个命令背后electron-vite会同时启动Vite开发服务器用于渲染进程的热更新和Electron主进程。你会看到两个终端窗口一个输出Vite日志一个输出Electron日志。主进程和渲染进程的代码修改都能实时反映在应用上。pnpm run build执行生产环境构建。这个过程会编译、打包所有渲染器代码并与Electron主进程代码一起生成可分发应用程序如.dmg,.exe,.AppImage。pnpm postinstall这是一个钩子脚本在pnpm install之后自动运行。它的作用是运行electron-builder install-app-deps确保与当前平台架构如Windows上的特定原生模块相关的依赖被正确安装。如果安装后运行应用报错尝试手动执行此命令往往是有效的排查步骤。注意事项跨平台开发的依赖陷阱Electron项目经常依赖一些需要原生编译的Node模块例如某些加密库、数据库驱动。在Windows上开发完成后直接打包Mac版本可能会失败。解决方案是在CI/CD流水线中为每个目标平台分别执行pnpm install和构建或者在本地通过Docker模拟不同平台环境。electron-builder本身支持多平台打包但确保依赖正确是关键。4. 核心功能实现与二次开发指南4.1 如何接入一个新的AI代理这是Zeek.ai最吸引人的功能之一。假设我们想接入国内的一个大模型API例如“智谱AI”ChatGLM我们可以遵循以下步骤这清晰地展示了其模块化设计的优势在packages/chat模块中创建代理类 首先在packages/chat/src/agents/目录下假设此结构新建一个文件ZhipuAIAgent.ts。这个类需要实现一个基础的IAgent接口该接口需要根据项目现有代码抽象通常包含sendMessage,streamResponse等方法。// packages/chat/src/agents/ZhipuAIAgent.ts import { IAgent, ChatMessage } from ../types; export class ZhipuAIAgent implements IAgent { name ChatGLM; apiKey: string; baseURL https://open.bigmodel.cn/api/paas/v4/; constructor(config: { apiKey: string }) { this.apiKey config.apiKey; } async sendMessage(messages: ChatMessage[], onStream?: (chunk: string) void) { // 1. 将messages格式化为智谱API要求的格式 const formattedMessages this.formatMessages(messages); // 2. 使用fetch或axios发起请求注意设置Authorization头 const response await fetch(${this.baseURL}chat/completions, { method: POST, headers: { Authorization: Bearer ${this.apiKey}, Content-Type: application/json, }, body: JSON.stringify({ model: glm-4, messages: formattedMessages, stream: !!onStream, // 是否开启流式输出 }), }); // 3. 处理流式或非流式响应 if (onStream response.body) { const reader response.body.getReader(); // ... 处理流式数据调用onStream(chunk) } else { const data await response.json(); return data.choices[0].message.content; } } private formatMessages(messages: ChatMessage[]) { // 实现消息格式转换逻辑 return messages.map(m ({ role: m.role, content: m.content })); } }注册代理到工厂 在packages/chat的某个集中注册点例如agentFactory.ts将新创建的代理类注册进去。// packages/chat/src/agentFactory.ts import { ZhipuAIAgent } from ./agents/ZhipuAIAgent; import { OpenAIAgent } from ./agents/OpenAIAgent; // 假设已有 export function createAgent(type: string, config: any): IAgent { switch (type) { case openai: return new OpenAIAgent(config); case zhipu: return new ZhipuAIAgent(config); default: throw new Error(Unsupported agent type: ${type}); } }在渲染器UI中添加配置项 最后需要在renderer/chat的UI组件中更新代理类型选择列表和对应的配置表单让用户可以在界面上选择“智谱AI”并填写其API密钥。通过以上三步一个新的AI代理就接入了系统。整个过程主要修改的是packages/chat模块对主进程和其他工具模块几乎没有影响充分体现了模块化的低耦合优势。4.2 工具模块的开发与集成renderer/tools目录是可扩展工具的乐园。假设我们要开发一个“Markdown美化工具”。创建工具定义在tools模块内创建一个新的工具目录例如md-beautifier。里面包含index.ts: 工具的主入口导出一个符合ITool接口的对象。ToolView.vue: 工具的Vue组件提供用户界面。beautifier.ts: 具体的工具逻辑例如使用markdown-it和prettier进行格式化。// packages/renderer/tools/md-beautifier/index.ts export const MardownBeautifierTool: ITool { id: md-beautifier, name: Markdown美化, icon: Markdown, component: defineAsyncComponent(() import(./ToolView.vue)), description: 格式化并美化Markdown文本, };注册工具在tools模块的全局注册文件如tools-registry.ts中导入并注册这个新工具。import { MardownBeautifierTool } from ./md-beautifier; export const allTools [MardownBeautifierTool, /* ...其他工具 */];在renderer/basic中动态加载basic模块的侧边栏或工具面板会从注册表读取所有工具并动态渲染其对应的ToolView.vue组件。这个过程就像为Zeek.ai安装了一个“插件”。工具开发者只需要关注自己工具的内部逻辑和UI无需关心应用的整体状态和路由极大地降低了开发门槛。5. 构建、分发与问题排查实战5.1 生产环境构建与优化开发完成后运行pnpm run build进行构建。electron-vite会根据electron.vite.config.ts的配置完成以下工作渲染器构建使用Vite打包优化renderer代码进行Tree Shaking、代码压缩、资源哈希等。主进程与预加载脚本构建同样进行打包和转译确保Node.js环境兼容性。资源整合将构建产物、静态资源图标、文档等复制到输出目录。生成安装包调用electron-builder根据package.json或独立配置文件中build字段的配置生成目标平台的安装包。关键配置示例 (package.json):{ build: { appId: com.zeeklog.zeekai, productName: Zeek.ai, directories: { output: dist }, files: [packages/**/dist/**, !**/node_modules/**/*], mac: { category: public.app-category.developer-tools, target: [dmg, zip] }, win: { target: [nsis, portable] }, linux: { target: [AppImage, deb] }, publish: { provider: github, releaseType: release } } }这个配置定义了应用ID、名称、输出目录、包含的文件以及针对不同平台的目标包格式。publish配置则与electron-updater联动支持构建完成后自动发布到GitHub Releases。5.2 常见问题与排查技巧实录在开发和部署Zeek.ai这类Electron应用时我踩过不少坑这里分享几个典型问题的解决思路问题一开发模式运行正常打包后白屏或功能异常。排查思路这通常是路径问题或依赖缺失。Electron打包后__dirname、process.cwd()等路径与开发环境不同。解决方案在主进程和预加载脚本中所有文件路径必须使用app.getAppPath()、path.join(app.getAppPath(), resources, ...)等Electron API来动态获取切勿使用相对路径。检查build.files配置确保所有必要的资源文件如配置文件、静态图片、预编译的二进制模块都被包含在内。对于需要原生编译的模块确保在postinstall脚本中正确执行了electron-builder install-app-deps或者使用electron-rebuild。问题二接入第三方AI API时渲染进程中出现跨域错误CORS。原因在渲染进程中直接使用fetch请求外部API会受到浏览器同源策略限制。解决方案这是Electron应用的经典模式。永远不要在渲染进程中直接使用API密钥请求第三方服务。正确做法是在预加载脚本preload中通过contextBridge.exposeInMainWorld向渲染器暴露一个安全的API例如window.electronAPI.callAgent。渲染器调用window.electronAPI.callAgent(agentType, messages)。主进程main监听这个调用在Node.js环境中不受CORS限制使用node-fetch或axios发起真正的网络请求并将结果返回给渲染器。 这既解决了CORS问题也保护了敏感的API密钥不暴露在客户端。问题三应用体积过大。分析Electron应用包含完整的Chromium和Node.js运行时体积本身就不小。再加上依赖很容易超过100MB。优化策略依赖审查使用pnpm why package或npm ls仔细检查依赖树移除未使用的依赖。特别是devDependencies不能被打包进去。构建优化确保Vite配置正确进行了代码分割和压缩。使用vite-plugin-compression压缩资源。资源优化对图片等静态资源进行压缩。考虑替代方案对于极致的体积要求可以评估TauriRust Webview等更轻量的方案但需要权衡生态和开发成本。问题四自动更新Auto-Update功能失效。排查步骤检查配置确认publish配置中的provider如github和仓库信息正确。检查签名macOS和Windows的自动更新通常要求应用有有效的代码签名。未签名的应用可能无法触发更新流程。查看日志在主进程启动时启用详细日志electron-updater的日志会输出检查更新、下载、安装等各阶段信息是定位问题的关键。模拟测试可以本地搭建一个简单的更新服务器进行测试确保更新逻辑本身无误。Zeek.ai作为一个活跃的开源项目其架构设计体现了现代桌面应用开发的最佳实践。从Monorepo管理、模块化设计到具体的ElectronVite技术栈选型都为开发者提供了一个高性能、可扩展的AI桌面应用样板。无论是想直接使用它来整合你的AI工作流还是想借鉴其架构来开发自己的跨平台桌面应用这个项目都极具参考价值。我个人的体会是理解其模块间的通信机制IPC和状态管理Pinia在渲染器间的共享是进行深度定制开发的关键。