news 2026/10/3 12:14:37

openwebui开发部署教程:Docker 环境下的 one-api 与 langfuse 集成实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
openwebui开发部署教程:Docker 环境下的 one-api 与 langfuse 集成实践

1. 为什么要在 Docker 里折腾 OpenWebUI + one-api + Langfuse

如果你正在找一个能自己掌控的 ChatGPT 式界面,OpenWebUI 基本是绕不开的选择。它本身是一个自托管的 Web 前端,能对接 Ollama、OpenAI 兼容接口,也能通过管道扩展出联网搜索、代码执行这类能力。但真正把它放到团队或本地开发环境里用,问题就来了:模型来源太杂。OpenAI、Azure OpenAI、通义、DeepSeek、本地 Ollama,每家的接口格式、鉴权方式、endpoint 路径都不一样,OpenWebUI 里一个个配连接既乱又难维护。这时候 one-api 就派上用场了——它把各种大模型统一成 OpenAI 格式的 API,OpenWebUI 只需要认一个地址、一个 Key。

另一个容易被忽略的是可观测性。你在 OpenWebUI 里聊了什么、调用了哪个模型、耗时多少、token 消耗多少,默认是看不到调用链的。Langfuse 正好补上这块,它能把每次对话以 trace 的形式记录下来,方便排查“为什么这个请求这么慢”“哪个模型在偷偷烧钱”。

这篇就聚焦 OpenWebUI 在 Docker 中的开发部署流程,把 one-api 做统一模型接入、Langfuse 做调用链追踪这两件事串起来。我会给出可复制的 docker-compose 配置、环境变量清单,以及接口连通性验证步骤。适合已经会用 Docker、想搭一套本地可观测 AI 开发环境的人。整个过程我在 CentOS 服务器上实测过,踩的坑会一并写出来。

需要先说明一个前提:OpenWebUI 官方文档里的开发指南分“本机部署”和“Docker Compose 部署”两条路。本机部署是 conda 起前端、sh dev.sh 起后端,适合改源码;Docker 部署更适合环境隔离和长期运行。本文走 Docker 路线,但会保留开发模式的热更新能力,这样你改前端 src 或后端代码能直接生效。

2. 前置准备:TaoToken 统一接入与 Docker 环境

在动手写 compose 之前,先把“模型从哪来”这件事定下来。one-api 的作用是统一分发,但它自己不带模型,需要你往里面填上游渠道。如果你手头有多个厂商的 Key,一个个配渠道比较繁琐;更省事的做法是先用一个聚合接入层把模型统一暴露成 OpenAI 兼容接口,再让 one-api 去对接。

我这边用的是 TaoToken 的接入方式,它的 API 地址是https://taotoken.net/api,兼容 OpenAI 的/v1/chat/completions格式。你可以在 one-api 里把它当成一个 OpenAI 类型的渠道填进去,Base URL 填https://taotoken.net/api,Key 填你申请到的令牌,模型名按需填。这样 one-api 对外就有一套统一的模型列表,OpenWebUI 只连 one-api 就行。

具体操作上,先拿到 Key:打开https://taotoken.net/api-keys(带 utm 的完整链接是https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=),创建一个令牌并复制。这个 Key 后面会填到 one-api 的渠道配置里,不要直接写进 OpenWebUI。

Docker 环境这边,CentOS 上装 Docker 按官方文档走即可。装完后建议配一下镜像加速,否则拉ghcr.io和docker.io的镜像会非常慢。我实测可用的配置如下,写入/etc/docker/daemon.json:

{ "registry-mirrors": [ "https://docker.1ms.run", "https://doublezonline.cloud" ] }

然后重载并重启:

sudo systemctl daemon-reload sudo systemctl restart docker

Node 版本是个隐藏坑。OpenWebUI 前端要求 Node 18.17.0 左右,版本不对npm ci会卡在 pyodide 相关依赖上。用 nvm 管理最稳:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.4/install.sh | bash source ~/.bashrc nvm install 18.17.0 nvm use 18.17.0 nvm alias default 18.17.0

确认node -v输出 v18.17.0 再继续。如果 npm 版本低于 6,执行npm install -g npm@latest。这些准备工作做完,后面 compose 启动才不会因为依赖问题反复失败。

3. 可复制配置:docker-compose 编排 OpenWebUI、one-api、Langfuse

这一节是核心,直接给可复制的配置。整体思路是三个服务:open-webui(开发模式,挂载源码)、one-api(统一模型网关)、langfuse(追踪)。为了减少依赖,Langfuse 这里用它的云端服务做追踪后端,本地只跑 OpenWebUI 的 pipelines 容器来转发 trace,这样不用自己维护 Postgres、ClickHouse 那一套。

先看 OpenWebUI 的开发 compose。文件名建议compose-dev.yaml,放在 open-webui 源码根目录:

name: open-webui-dev services: frontend: build: context: . target: build command: ["npm", "run", "dev"] depends_on: - backend ports: - "3000:5173" extra_hosts: - host.docker.internal:host-gateway volumes: - ./src:/app/src backend: build: context: . target: base command: ["bash", "dev.sh"] env_file: ".env" environment: - ENV=dev - WEBUI_AUTH=False - OPENAI_API_BASE_URL=http://host.docker.internal:3001/v1 - OPENAI_API_KEY=sk-oneapi-local ports: - "8080:8080" extra_hosts: - host.docker.internal:host-gateway volumes: - ./backend:/app/backend - data:/app/backend/data volumes: data: {}

几个关键点。前端3000:5173是容器外 3000、容器内 5173,Vite 开发服务器默认监听 5173,映射错了会打不开。extra_hosts里的host.docker.internal:host-gateway让容器能访问宿主机上的 one-api,这是 Linux 下必须加的,否则容器里解析不了这个域名。WEBUI_AUTH=False在开发阶段跳过登录,省得反复认证。

one-api 的 compose 单独放一个目录,比如one-api/docker-compose.yml:

services: one-api: image: justsong/one-api:latest container_name: one-api restart: always ports: - "3001:3000" volumes: - ./data:/data environment: - TZ=Asia/Shanghai - SQL_DSN=root:123456@tcp(mysql:3306)/oneapi depends_on: - mysql mysql: image: mysql:8.0 container_name: one-api-mysql restart: always environment: - MYSQL_ROOT_PASSWORD=123456 - MYSQL_DATABASE=oneapi volumes: - ./data/mysql:/var/lib/mysql

one-api 对外映射 3001,容器内是 3000。它默认管理员账号root、密码123456,首次登录后务必改掉。登录进去后,在“渠道”里新建一个 OpenAI 类型渠道,Base URL 填https://taotoken.net/api,Key 填你在 TaoToken 拿到的令牌,模型名按你实际要用的填,比如gpt-4o-mini、claude-3-5-sonnet之类。保存后测试渠道,返回绿色即通。

Langfuse 这边,先在https://cloud.langfuse.com注册项目,拿到 public key 和 secret key。然后在 OpenWebUI 里启用 pipelines 容器:

docker run -p 9099:9099 \ --add-host=host.docker.internal:host-gateway \ -v pipelines:/app/pipelines \ --name pipelines \ --restart always \ ghcr.io/open-webui/pipelines:main

启动后,在 OpenWebUI 管理设置里新建一个 OpenAI API 连接,URL 填http://host.docker.internal:9099,密码填0p3n-w3bu!。这是 pipelines 的标准密码,不是你的 Langfuse key。Langfuse 的 key 在 pipelines 的管道配置里填,具体在 OpenWebUI 的“管道”页面找到 Langfuse 过滤器,把 public key、secret key、host 填进去。

环境变量清单整理成表格方便对照:

变量作用示例值
OPENAI_API_BASE_URLOpenWebUI 指向 one-apihttp://host.docker.internal:3001/v1
OPENAI_API_KEYone-api 的访问令牌sk-oneapi-local
WEBUI_AUTH开发阶段跳过登录False
LANGFUSE_PUBLIC_KEYLangfuse 项目公钥pk-lf-xxx
LANGFUSE_SECRET_KEYLangfuse 项目私钥sk-lf-xxx
LANGFUSE_HOSTLangfuse 服务地址https://cloud.langfuse.com

配置写完后,启动顺序建议:先起 one-api 和 mysql,确认 3001 能访问;再起 pipelines;最后起 OpenWebUI 开发环境。这样排查问题时边界清晰。

4. 验证请求:从 OpenWebUI 发一条消息看 trace 是否落库

配置写完不代表通了,得实际发一条请求验证。启动 OpenWebUI 开发环境:

docker compose -f compose-dev.yaml up -d

等容器起来后,访问http://localhost:3000。如果前端没起来,进容器看日志:

docker exec -it open-webui-dev-frontend-1 sh netstat -tuln | grep 5173

容器内 5173 有监听说明 Vite 起来了。宿主机上curl http://localhost:3000能返回 HTML 就对了。

接着验证 one-api 连通性。在宿主机上直接打 one-api 的接口:

curl http://localhost:3001/v1/chat/completions \ -H "Authorization: Bearer sk-oneapi-local" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [{"role": "user", "content": "ping"}] }'

返回里带choices字段就说明 one-api 到上游是通的。如果返回 401,检查 Key 是否和 one-api 里创建的令牌一致;如果返回model not found,检查渠道里模型名是否填对。

然后在 OpenWebUI 界面里,左下角设置里确认模型列表能看到 one-api 暴露的模型。选一个模型发一条“你好”,正常返回即打通。这时候去 Langfuse 的 Traces 页面刷新,应该能看到一条新的 trace,点进去有 input、output、latency、model 这些字段。如果没看到,检查 pipelines 容器日志:

docker logs pipelines --tail 50

常见的是 Langfuse key 填错,日志里会有 401 或unauthorized。另外 pipelines 容器和 OpenWebUI 容器之间的网络要通,host.docker.internal在两边都要能解析。

验证成功后,你改一下./src下的前端代码,Vite 会热更新,浏览器自动刷新。改./backend下的 Python 代码,dev.sh会重载。这就是开发模式的价值——不用每次重建镜像。

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth

部署过程中最容易卡住的几个报错,我按实际遇到的整理出来。

401 Unauthorized。出现在 OpenWebUI 调 one-api 时,多半是OPENAI_API_KEY和 one-api 里创建的令牌不匹配。one-api 的令牌是在“令牌”页面生成的,不是渠道里的 Key。渠道里的 Key 是上游厂商的,令牌才是给下游用的。两者别搞混。另外 one-api 默认令牌有额度限制,额度用完也会 401,去令牌页面看剩余额度。

local proxy failed。这个报错通常出现在 OpenWebUI 容器里访问host.docker.internal失败。Linux 下 Docker 默认不解析这个域名,必须在 compose 里加extra_hosts: - host.docker.internal:host-gateway。如果加了还不行,检查 Docker 版本,20.10 以上才支持host-gateway。实在不行就用宿主机内网 IP 替代。

reading choices 报错。一般是 one-api 返回的响应格式和 OpenWebUI 预期不一致。检查 one-api 渠道的 Base URL 是否带了/v1。TaoToken 的地址是https://taotoken.net/api,one-api 里填这个就行,它会自动补/v1/chat/completions。如果填成https://taotoken.net/api/v1可能重复。另外模型名要和上游实际支持的完全一致,大小写敏感。

OAuth 相关报错。如果你开了WEBUI_AUTH=True又配了 OAuth,回调地址不对会报错。开发阶段直接WEBUI_AUTH=False跳过。生产环境再配 OAuth,回调地址要填http://你的域名/auth/oauth/...,和 OpenWebUI 里配的一致。

还有一个跨域问题要提。OpenWebUI 前后端分容器时,浏览器直接访问后端接口会有 CORS。官方后端 config 里不允许cross_origin配*,所以开发阶段可能遇到跨域拦截。我试过用浏览器插件临时放行access-control-allow-origin,但这只是开发权宜。更稳的做法是让前端通过 Vite 的 proxy 转发到后端,在vite.config.ts里配server.proxy,把/api指到http://backend:8080。这样浏览器只和 3000 通信,不跨域。

端口问题也常见。云服务器要在控制台安全组放行 3000、3001、8080、9099。服务器本机防火墙firewalld或iptables也要放行。容器内端口映射别写反,3000:5173是宿主 3000 对容器 5173。进容器用netstat -tuln确认监听端口,宿主机用curl确认能通。

6. 后续怎么用:从开发环境到长期编码与 Agent

环境搭好之后,日常开发就是改代码、看 trace、调模型。Langfuse 的 trace 能帮你定位慢请求——比如某个模型首 token 延迟高,或者某次对话 token 消耗异常。one-api 的日志能看到每个渠道的调用量和失败率,方便你决定要不要换渠道。

如果你后面要做长期编码或者 Agent 类应用,OpenWebUI 的 pipelines 可以扩展出函数调用、工具链。这时候模型接入的稳定性就很重要。TaoToken 的 Coding Plan 适合这种持续调用的场景,地址是https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,它按套餐走,比按量计费更适合高频开发。模型对话调试可以用https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,快速验证某个模型是否可用。控制台在https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,能看用量和余额。接入文档在https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,里面有各语言的调用示例。

如果你用 Claude Code 做开发,它的 Anthropic 兼容接入可以参考https://taotoken.net/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。API Keys 管理在https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=。

最后说个实际经验:开发环境别用生产数据库。OpenWebUI 的datavolume 和 one-api 的data/mysql分开挂载,清库重建不心疼。Langfuse 云端项目也分 dev 和 prod 两个,trace 别混在一起。这样你折腾坏了随时能重来,不影响线上。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 12:13:48

一键安装 MoonBit pilot:用 TaoToken 统一 Key 打通多语言 AI 开发助手

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/3 12:13:48

国内外大模型 SuperCLUE 基准测试:用 TaoToken 统一 Key 跑通评测链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/3 12:13:33

RISC-V端侧推理能效优化:调度、量化与空闲态协同设计

说实话,第一次看到这个标题的时候,我脑子里快速过了一遍这几年在端侧AI项目里踩过的坑,顿时觉得这个题目抓得挺准的。过去我们在嵌入式平台做功耗优化,思路基本都是“先跑起来,烫了就降频,再烫就限流”&…

作者头像 李华
网站建设 2026/10/3 12:12:46

OpenAI发布Dots智能体;GPT-6 Astra提速最高8倍 | 科技日报1002

OpenAI发布Dots智能体 #1在OpenAI年度 DevDay 大会上,公司 CEO萨姆奥特曼登台宣布推出名为Dots的 AI 智能体,由 GPT-6 Astra 驱动。奥特曼称它是"真正的 AI",灵感来自"我们从小在电影里看到的那些很酷的智能体"。 Dots与…

作者头像 李华