跳转到内容

LibreChat — 让一份聊天 UI 同时连 OpenAI / Anthropic / Google / 本地模型,对话留在自己的服务器

是什么

LibreChat 是一个开源的”自己装一台 ChatGPT”——你 docker compose 起来,浏览器打开就是熟悉的聊天界面,但你能自由切换底层用哪家 LLM:OpenAI、Anthropic、Google、AWS Bedrock、本地 Ollama,甚至任何”OpenAI 兼容的 API 地址”。

日常类比:像一台通用遥控器——同一份按键面板(聊天 UI),后面接的电视可以是索尼、三星、海信。你按”换台”,遥控器内部翻译成各家厂商的红外协议,但你不需要知道。

它解决的不是”我想用 ChatGPT”——那直接去 chat.openai.com 就行。它解决的是”我们公司 50 个人想共用一个内部 ChatGPT,对话不能上传到 OpenAI 服务器,要能切 Claude,要能接公司内部的工具”。所以它有真后端(Express)、真数据库(MongoDB)、真鉴权(JWT + 多用户权限),不是一个浏览器扩展。

GitHub 上 37k stars,MIT 协议,可以直接 fork 改名卖钱。技术栈是 TypeScript + JavaScript 双栈(packages/ 全 TS,api/server/ 仍是 JS 在迁移中),前端 React 19 + Vite,后端 Express + Mongoose,搜索 Meilisearch,可选 Redis 做多副本。

为什么重要

不理解 LibreChat 的设计,下面这些事都没法解释:

  • 为什么”多家 LLM 切换”这件事用抽象基类继承会越写越糟,正确做法反而是每家写一个独立函数
  • 为什么浏览器刷新一下,正在生成的回答还能接着看——传统 SSE 流明明刷新就丢
  • 为什么 plugin 生态可以外包给 MCP 协议而不必自己定义一套(对比 Dify 自研 plugin daemon)
  • 为什么”自托管 ChatGPT”这件事不是一个项目,而是 Dify / Lobe Chat / Open WebUI / LibreChat 四种心智模型的拉锯
  • 为什么 Express 这种”老派”框架在 2026 年还能撑起 37k stars 的产品——关键在于中间件链式架构职责分层

核心要点

LibreChat 的工程价值压在 三个核心抽象 上:

  1. per-provider 翻译函数(不是抽象基类):每家 LLM 写一个独立的 getLLMConfig(credentials, options) 函数,返回该 provider 真实 SDK 需要的客户端选项。类比:每家厂商一份翻译手册,而不是逼所有厂商遵守同一个接口规范——因为它们本来就长得不一样。代码层面 OpenAI / Anthropic / Google / Bedrock 各自一个独立目录,平级,没人继承谁。

  2. 可恢复 SSE(GenerationJobManager):把流式输出拆成三层——jobStore 持久化已生成的 chunks、eventTransport 做 pub/sub、runtime 持有不可序列化的 abort 控制器。浏览器刷新后用 streamId 重新订阅,把已生成内容重放一遍再续上。类比:直播 + 时移功能。单进程默认 InMemory,多副本切 Redis 后主代码无改动。

  3. MCP 作为 plugin 抽象:放弃自研 plugin 协议,直接接 Anthropic 推的 MCP(Model Context Protocol)开源标准。Claude Desktop / Cursor 装的 MCP server 直接能用。类比:不自己造 USB 协议,直接支持 USB-C。代价是丢失协议层定制权,收益是与生态共振——MCP 标准升级 LibreChat 跟着升 SDK 即可。

实践案例

案例 1:docker compose 起全栈,UI 里切换 provider

完整命令清单(约 3 分钟拉镜像 + 启动):

Terminal window
git clone --depth 1 https://github.com/danny-avila/LibreChat.git
cd LibreChat
cp .env.example .env # 编辑填 OPENAI_API_KEY 和 ANTHROPIC_API_KEY
cp librechat.example.yaml librechat.yaml
docker compose up -d # 起 mongo + meilisearch + librechat 三个容器
docker compose ps # 应该看到 4 个 service running
open http://localhost:3080 # 注册第一个账号自动成为 admin

进 UI 后发一条消息走 OpenAI,再用顶部的 EndpointMenu 切到 Anthropic 继续聊——同一对话窗口、不同模型,消息历史完整保留。这是因为 messages 在 MongoDB 里按 conversation 维度存,不绑 endpoint。如果你想接团队的其他成员,注册新账号即可,admin 用户能在 UI 里管理 quota 和封禁。

案例 2:用 console.log 验证抽象边界

packages/api/src/endpoints/anthropic/llm.tsgetLLMConfig 函数末尾、return 语句之前加一行:

console.log('[ANTHROPIC]', {
model: requestOptions.model,
hasThinking: requestOptions.thinking != null,
hasVertex: typeof requestOptions.createClient === 'function',
})

UI 里发 3 条消息:第 1 条用 OpenAI、第 2 条切 Anthropic、第 3 条切 Anthropic + thinking。看后端日志(docker compose logs librechat | grep ANTHROPIC)——只有第 2、3 条出现 [ANTHROPIC],第 1 条根本不走这个文件。这就证明了 controller 代码对 provider 完全无知,“我现在调谁”这个信息只在 endpoints/<provider>/ 这一层存在。这种用扰动法验证抽象边界的小实验,比读 100 行架构图都更有效。

案例 3:浏览器刷新看 resumable SSE

让 Anthropic 写一段 500 字回答,写到一半时按浏览器刷新。新页面打开后,前端会带 streamId 重新连 /chat/stream/:id,后端把已生成 chunks 从 jobStore 重放一遍,然后把后续的实时 chunks 续上——你看到回答从开头出现,到刷新前的位置时速度变慢(实时 token),整段不丢

要让这一切工作,SSE 入口必须设三个 header:Content-Type: text/event-streamCache-Control: no-cache, no-transformX-Accel-Buffering: no(专门告诉 Nginx 别缓冲)。少一个都会导致 chunk 在中间某层被攒起来,体验直接退回到”等几秒一卡顿”。

如果你切到 Redis transport(多副本部署),chunk 不在内存而在 Redis Stream 里,新订阅者可以是另一台机器——这就是为什么 LibreChat 不需要 sticky session 也能横扩

踩过的坑

  1. provider 抽象用基类继承会腐烂:OpenAI 有 reasoning_effort,Anthropic 有 thinking,Google 要 service account JSON 凭证,硬塞 class LLMClient 抽象基类最终会逼出 extraOptions: Record<string, any> 后门,基类成空壳。LibreChat 的解法是根本不抽象,每家一个独立函数,签名一致但函数体完全自由。
  2. SSE 直接挂在 res 上 = 浏览器刷新就丢消息:传统做法是 res 自己持有 EventEmitter、断开就 emit('close'),这样无法 resumable。必须把 chunks 写到 jobStoreres 只是订阅者,下个新订阅者还能拿到。
  3. Nginx 反代下 SSE 会卡顿:必须设 X-Accel-Buffering: no + Connection: keep-alive,否则 Nginx 缓冲 chunks 等到一定大小再发,SSE 流变成”几秒一卡顿”。这种坑只有踩过的项目才会写在中间件里,新人独立写很难提前想到。
  4. MCP 双层连接的优先级陷阱getConnection 先查 app-level 命中即返回。如果 app-level 是公共 readonly token、user-level 才是用户 OAuth 私库 token,这个查找顺序会让用户期望的”用我的 token”被覆盖——配置 librechat.yaml 时要小心顺序。

适用 vs 不适用场景

适用

  • 团队 50 人共用一个内部 ChatGPT,要 OpenAI + Anthropic 混用 + 数据留在自己 MongoDB
  • 想给业务系统暴露 OpenAI 兼容的 /v1/chat/completions endpoint,用 LibreChat 做网关 + logging + quota(业务侧 SDK 改 baseURL 就能接入)
  • 接团队私有的 MCP server(如内部数据库、Slack、GitHub)让 agent 调用
  • 需要”浏览器刷新不丢消息”的可恢复流式输出
  • 单实例 < 100 用户的中等规模——稳定,docker compose 一键起;超过这个量级要自己上 Redis + Nginx + Mongo replica

不适用

  • 个人 BYO key 重 UI 美学 → 用 Lobe Chat(前端做得最漂亮,后端最薄)
  • 主要跑 Ollama 本地模型 → 用 Open WebUI(Ollama 团队主推,本地模型一等公民)
  • PM / 设计师不写代码做 LLM 应用 + RAG → 用 dify(visual workflow 平台派,重 10 倍但定位是”做应用”而非”做 chat”)
  • 极简部署 + Vercel 一键 → 用 NextChat(无后端、零运维)
  • 真正的多租户 SaaS(给 100 个企业用)→ LibreChat 的 tenantId 校验是 row-level 不是物理隔离,需自己加额外保护

历史小故事(可跳过)

  • 2023-02:danny-avila fork 自 ChatGPT-Clone(一个早期开源 ChatGPT UI),最初只有单 provider
  • 2023 年中:加入 Anthropic / Google 支持,开始做”多 provider”定位,区分自己和 NextChat 等单 provider 项目
  • 2024 年:开放赞助 + 企业咨询商业化路线,contributors 700+ 但核心 5 人;选 MIT 协议而非 Apache + brand 限制(Dify 路线),换更广的采用
  • 2024-11:Anthropic 发布 MCP 协议,LibreChat 是最早接入的开源 chat 之一,packages/api/src/mcp/ 目录成型
  • 2025 年GenerationJobManager 三层架构上线,从单进程 SSE 升级到 Redis 可恢复多副本,单进程 / 多副本切换变成一行配置
  • 2026 上半年:OpenAI Responses API 兼容层加入,Code Interpreter 支持 7 种语言(Python / Node.js / Go / Java / Rust 等)
  • 2026-05:v0.8.6-rc1 发布,37k stars 稳定爬升,与 Lobe Chat / Open WebUI 同梯队

学到什么

  1. “多 backend variant”不要套抽象基类——当 N 种实现真实差异巨大,写 N 个独立函数 + 调用方拿 config 后统一实例化,比继承更不容易在长期演进里腐烂成 extraOptions: any 后门
  2. 资源所有权要和 pub/sub 解耦——把”谁产生数据”和”谁消费数据”拆开,单进程是 InMemory transport、多副本切 Redis transport,主代码无需改动;这是大型 Node.js 应用的通用范式
  3. 协议外包优于自研——能用业界共识的开源协议(MCP)就别自己造一套(plugin daemon RPC),代价是丢失协议层定制权,收益是与生态共振
  4. license 是商业模式选择——MIT 完全开放靠企业咨询变现 vs Apache + brand 限制靠协议变现,两条路都成立但战术差异巨大,选错了会反噬
  5. 小扰动验证抽象边界——给 anthropic/llm.ts 加一个 console.log 就能证明 controller 对 provider 无知,比读架构图有效得多

延伸阅读

  • LibreChat GitHub 主仓 —— README / 配置示例 / 部署文档
  • LibreChat 官方文档 —— self-host 教程 + librechat.yaml 配置参考
  • MCP 协议规范 —— 想理解 plugin 抽象层就要读这份
  • Anthropic Vertex AI deployment 指南 —— 解释 LibreChat 为什么要在 anthropic/llm.ts 里搞 Vertex 双路径
  • dify —— 平台派对照组:visual workflow + 多租户 + plugin daemon RPC,定位”做应用”而非”做 chat”
  • continue —— IDE 派对照组:编辑器内嵌 + 本地 + 远端模型混合
  • claude-code —— Anthropic 官方 CLI agent,与 LibreChat 都重度依赖 MCP 但形态完全不同

关联

  • dify —— 同 Season AI 应用范式三角的”平台派”,与 LibreChat 的”通用 chat 派”形成对照
  • continue —— 同三角的”IDE 派”,三家心智模型互相参照才能看清解空间
  • mcp-ts-sdk —— LibreChat plugin 生态的协议底座,由 Anthropic 维护
  • langchain —— LibreChat 的 agent 子模块(@librechat/agents)封装了 LangGraph
  • express —— LibreChat 后端框架,中间件链式架构是它的工程范式
  • mongodb —— LibreChat 的对话存储,messages / convos / agents 都在这里
  • react —— LibreChat 前端,ChatView / Endpoints / Agents 组件树跑在 React 19
  • redis —— 多副本部署时 SSE 走 Redis Stream + Pub/Sub,单进程默认 InMemory
  • meilisearch —— LibreChat 的全文搜索引擎,对话历史中文分词友好
  • claude-code —— Anthropic 官方 CLI,同样深度依赖 MCP 协议但形态完全不同

反向链接

  • claude-code —— Claude Code — Anthropic 终端编程助手
  • continue —— Continue — 让 AI code review 跑成 git 跟踪的 PR status check
  • express —— Express — Node.js 最经典的 Web 框架
  • librechat —— LibreChat — 让一份聊天 UI 同时连 OpenAI / Anthropic / Google / 本地模型,对话留在自己的服务器
  • mcp-ts-sdk —— MCP TS SDK — Model Context Protocol TypeScript 实现
  • meilisearch —— MeiliSearch — 开发者友好的搜索引擎
  • mongodb —— MongoDB — 文档型 NoSQL 数据库
  • react —— React UI 组件库
  • redis —— Redis — 内存键值数据库