用 PyWebView + React 造了一个 ChromaDB 桌面客户端
背景
在用 ChromaDB 做本地向量数据库开发时,调试过程相当繁琐------要么写脚本查数据,要么对着 HTTP 接口手敲 curl。官方没有提供图形化管理界面,社区里的 Web 方案又需要额外起服务、开浏览器,体验割裂。
所以我用业余时间做了 Chroma Walnut UI:一个基于 PyWebView + React 的原生桌面客户端,支持 Windows / macOS / Linux,无需安装 Python 环境即可直接运行。
GitHub:github.com/[your-githu...
功能一览
- 多连接管理:同时管理多个 ChromaDB 连接(本地目录 / HTTP 服务),支持 Bearer Token 认证,一键测试连通性
- 集合管理:创建、重命名、编辑 Metadata、删除集合
- 文档浏览:分页展示(10 / 20 / 30 条可选),Metadata 彩色标签,支持查看完整 JSON 和框选复制
- 向量搜索:配置嵌入模型后输入文本即可进行语义相似度搜索,支持多条件过滤
- 向量模型配置:集合级别配置,兼容 OpenAI Embeddings 格式,内置 Ollama / OpenAI / LM Studio / 通义千问快速填充
- 一键生成测试数据:内置 50 条中文示例文档,配置好模型后一键插入
- 国际化 + 主题切换:中文 / English 随时切换,支持亮色 / 暗色 / 跟随系统


技术选型
| 层 | 选择 | 原因 |
|---|---|---|
| 桌面容器 | PyWebView 6 | 用系统原生 WebView 渲染,无需 Electron,包体极小 |
| 后端 | Python 3.12 + ChromaDB 0.6 | ChromaDB 官方 Python SDK,直接调用,无 HTTP 中转 |
| 前端框架 | React 19 + TypeScript | 生态成熟,类型安全 |
| UI 组件库 | Ant Design 6 | 开箱即用的企业级组件,内置暗色主题 |
| 状态管理 | Zustand 5 | 轻量,不需要 Redux 那么重 |
| 国际化 | i18next + react-i18next | 标准方案,切换零刷新 |
| 构建工具 | Vite 8 | 开发热更新快,构建产物小 |
| Python 包管理 | uv | 比 pip 快 10-100 倍,lockfile 可靠 |
| 打包 | PyInstaller | 三平台统一打包脚本 |
为什么选 PyWebView 而不是 Electron?
Electron 打包出来动辄 150MB+,本质上是把 Chromium 塞进去。PyWebView 直接调用操作系统已有的 WebView:
- Windows:Edge WebView2(Windows 10 1803+ 内置)
- macOS:WKWebView(系统内置)
- Linux:WebKitGTK
最终打包产物 Windows 约 40MB,用户无需安装 Python 或 Node.js,解压即用。
架构设计
javascript
┌─────────────────────────────────────┐
│ PyWebView 窗口 │
│ ┌──────────────────────────────┐ │
│ │ React 前端(TypeScript) │ │
│ │ Ant Design / Zustand │ │
│ └──────────┬───────────────────┘ │
│ │ window.pywebview.api │
│ ┌──────────▼───────────────────┐ │
│ │ Python API 层 (api.py) │ │
│ │ ChromaManager │ │
│ │ Embedding 配置管理 │ │
│ └──────────┬───────────────────┘ │
│ │ │
│ ┌──────────▼───────────────────┐ │
│ │ ChromaDB SDK │ │
│ └──────────────────────────────┘ │
└─────────────────────────────────────┘
前后端通信走 PyWebView 的 js_api 机制:Python 类的公开方法自动暴露为 window.pywebview.api.*,前端通过 TypeScript 封装的 bridge 调用,类型安全有保障。
typescript
// frontend/src/api/bridge.ts(精简示例)
export const api = {
listConnections: () =>
window.pywebview.api.list_connections() as Promise<Connection[]>,
queryDocuments: (connId: string, collection: string, params: QueryParams) =>
window.pywebview.api.query_documents(connId, collection, params),
}
几个实现细节
单实例锁
用绑定本地端口的方式实现单实例,进程退出时端口自动释放,跨平台无需平台特定 API:
python
_INSTANCE_PORT = 19527
def _acquire_instance_lock() -> bool:
global _instance_sock
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 0)
s.bind(("127.0.0.1", _INSTANCE_PORT))
s.listen(1)
_instance_sock = s
return True
except OSError:
return False
开发模式 vs 生产模式
arduino
# 开发模式:前端走 Vite 热更新
uv run python main.py --dev
# 生产模式:先 npm run build,再加载 dist/index.html
uv run python main.py
main.py 启动时检测 --dev 参数,自动拉起 Vite dev server 并等待端口就绪后再创建窗口,开发体验与纯前端项目一致。
响应式布局
窗口宽度 < 1100px 时侧边栏自动折叠,字体和间距用 CSS clamp() 自适应缩放,适配从 900px 到 1920px 的各种分辨率。
向量模型兼容设计
Chroma Walnut UI 不绑定任何特定的向量服务,只要接口兼容 OpenAI Embeddings 格式(POST /v1/embeddings)就可以接入:
| 服务 | 地址示例 |
|---|---|
| Ollama | http://localhost:11434/v1/embeddings |
| OpenAI | https://api.openai.com/v1/embeddings |
| LM Studio | http://localhost:1234/v1/embeddings |
| 通义千问 | https://dashscope.aliyuncs.com/compatible-mode/v1/embeddings |
配置保存在 ~/.chroma_walnut_ui/collection_embeddings.json,每个集合独立配置,不写注册表,不污染系统目录。
CI/CD:三平台自动发布
.github/workflows/release.yml 在推送版本 tag 时触发,三个平台并行构建:
perl
git tag v1.0.0
git push origin v1.0.0
工作流分别在 windows-latest、macos-latest、ubuntu-24.04 上运行同一个 build.py 脚本,完成后将三个压缩包上传至 GitHub Release,无需手动在各系统上分别打包。
Linux 构建需要预装 WebKitGTK 头文件,这部分在 CI 里用 apt-get 解决:
arduino
- name: Install system dependencies
run: |
sudo apt-get install -y \
libgirepository-2.0-dev gcc \
libcairo2-dev pkg-config python3-dev \
gir1.2-gtk-3.0 gir1.2-webkit2-4.1 \
libwebkit2gtk-4.1-dev
本地运行
bash
git clone https://github.com/[your-github-username]/chroma-walnut-ui.git
cd chroma-walnut-ui
# 安装 Python 依赖(推荐 uv)
uv sync
# 安装前端依赖
cd frontend && npm install && cd ..
# 启动(生产模式)
uv run python main.py
# 开发模式(前端热更新)
cd frontend && npm run dev &
uv run python main.py --dev
打包为可执行文件
arduino
uv run python build.py # 正式包
uv run python build.py --debug # 调试包(保留控制台)
脚本自动完成:检查依赖 → 构建前端 → 生成图标 → PyInstaller 打包 → 压缩分发文件。
| 平台 | 输出 |
|---|---|
| Windows | ChromaWalnutUI-Windows.zip |
| macOS | ChromaWalnutUI-macOS.dmg |
| Linux | ChromaWalnutUI-Linux.tar.gz |
小结
PyWebView + React 这个组合对于需要桌面原生窗口但又不想放弃 Web 前端生态的项目是个不错的选择。相比 Electron,它轻量很多;相比纯 Web 应用,它不需要用户开浏览器,体验更接近原生应用。
ChromaDB 生态里的工具目前还不多,欢迎 Star、提 Issue 或 PR,一起把这个工具做得更完善。
GitHub :github.com/a605204746/...