- 后端
- 前端
- 人工智能
- 大模型
- RAG
- 知识库
- 桌面应用
【免费下载链接】blinko
An open-source, self-hosted personal AI note tool prioritizing privacy, built using TypeScript .
本文以 Blinko 仓库中 test-docker 测试目录 的 README 为主干,系统讲解如何验证并复现"AI Provider 模型列表拉取"经由服务端代理、在 Docker 内部网络中正常工作的修复方案。你将掌握:该问题的成因(浏览器直连 Docker 内网主机名失败)、一键搭建的 Mock 测试环境(含 Mock OpenAI、PostgreSQL、Blinko 三个容器)、完整的 UI 验证步骤,以及从源码层面理解fetchProviderModels在 服务端路由、前端状态层 与 代理封装 中的真实调用链。
问题背景:浏览器直连 Docker 内网主机名为何失败
Blinko 支持对接 Ollama、OpenAI、Anthropic、Google、Azure、MiniMax、VoyageAI 以及任意 OpenAI 兼容协议的自建 Provider。在添加 Provider 时,用户可以点击"Fetch Models"按钮拉取该 Provider 支持的模型列表。
修复之前的实现存在一个关键缺陷:fetchProviderModels由浏览器直接发起 HTTP 请求。这意味着当用户自建的服务运行在 Docker 内部网络时,配置的 Base URL 形如http://ollama:11434这类Docker 内部主机名,浏览器所在的宿主机网络根本无法解析、访问该主机名,导致模型列表拉取必然失败。
本次修复的核心思路是:把模型拉取逻辑从浏览器端迁移到 Blinko 后端服务端。由 Blinko 服务端容器向目标 Provider 容器发起请求——由于两个容器同属一个 Docker bridge 网络,可以互相通过服务名通信,因此http://ollama:11434、http://mock-openai:8080/v1这类内网地址可以正常工作。
测试环境架构
test-docker目录提供了完整的可复现测试环境,核心编排文件为 docker-compose.test.yml,其中包含三个服务:
| 服务 | 镜像 | 作用 | 健康检查 |
|---|---|---|---|
mock-openai | node:20-alpine | 模拟 OpenAI 兼容的模型列表 API | wget --spider http://localhost:8080/models |
postgres | postgres:15-alpine | Blinko 依赖的数据库 | pg_isready -U blinko |
blinko | blinkospace/blinko:latest | 被测的 Blinko 应用本体 | 依赖上述两者 healthy 后启动 |
三者统一挂载到名为blinko-test-network的 bridge 网络中,这是整个测试成立的前提——Blinko 容器与 Mock OpenAI 容器在同一个 Docker 内部网络里,服务端才能通过服务名mock-openai互相访问。
关键配置点说明:
blinko服务的DATABASE_URL=postgresql://blinko:blinko@postgres:5432/blinko中数据库主机名直接使用服务名postgres,同样是内网通信的典型用法;NEXTAUTH_SECRET=test-secret-key-for-testing与NEXTAUTH_URL=http://localhost:1111用于本地登录鉴权;- 宿主机端口映射为
1111:1111,即浏览器通过http://localhost:1111访问 Blinko。
Mock OpenAI 服务实现
模拟服务源码位于 test-docker/mock-openai/server.js,它用 Node 原生http模块实现了一个极简的 OpenAI 兼容服务:
const models = { data: [ { id: 'gpt-4o', object: 'model' }, { id: 'gpt-4o-mini', object: 'model' }, { id: 'gpt-3.5-turbo', object: 'model' } ] };服务监听0.0.0.0:8080,对GET /v1/models与GET /models两个路径返回上述 JSON 模型列表,并输出访问日志(方法 + URL与Returning model list...)。同时设置了宽松的 CORS 响应头(Access-Control-Allow-Origin: *、Access-Control-Allow-Headers: Authorization, Content-Type, api-key),以便在任何来源下都可被调用。
测试步骤:一键启动与验证
第一步:启动测试环境
cd test-docker docker-compose -f docker-compose.test.yml up -d首次启动会拉取blinkospace/blinko:latest、postgres:15-alpine、node:20-alpine三个镜像,之后up -d可快速重建/恢复。
第二步:等待服务就绪
docker-compose -f docker-compose.test.yml ps由于编排文件中为mock-openai与postgres配置了 healthcheck,并为blinko配置了depends_on ... condition: service_healthy,blinko只有在两个依赖服务通过健康检查后才会启动。因此等待所有服务状态显示为healthy即可进入下一步。
第三步:访问 Blinko
浏览器打开http://localhost:1111,完成本地登录(使用测试环境的NEXTAUTH_SECRET/NEXTAUTH_URL即可正常走鉴权流程)。
第四步:在 AI 设置中添加 Provider 并拉取模型
- 进入Settings > AI Settings;
- 添加一个新的 Provider:
- Provider Type:选择
OpenAI或Custom; - Base URL:
http://mock-openai:8080/v1(注意:这是 Docker 内部服务名,而非localhost); - API Key:
test-key(Mock 服务不校验 Key,任意值均可);
- Provider Type:选择
- 点击Fetch Models按钮;
- 预期结果:模型下拉列表中应出现 3 个模型:
gpt-4ogpt-4o-minigpt-3.5-turbo
第五步:通过日志确认请求来自服务端
docker logs mock-openai预期输出类似:
2024-XX-XX... - GET /v1/models Returning model list...这条日志的关键意义在于:请求是Blinko 服务端容器发出的(GET /v1/models来自内网服务名解析),而不是浏览器直发——从而验证了修复确实生效。若请求仍由浏览器发出,则日志中会出现 CORS 预检(OPTIONS)以及实际请求,且由于浏览器无法解析mock-openai主机名,步骤四根本无法得到模型列表。
源码级原理:服务端如何拉取模型列表
理解了测试流程后,再看源码实现可以更透彻地明白"修复到底做了什么"。
前端:状态层发起 tRPC 调用
前端不再直接发 HTTP 请求,而是通过 tRPC 调用后端。在 app/src/store/aiSettingStore.tsx#L116-L134 中:
fetchProviderModels = new PromiseState({ successMsg: i18n.t('model-list-updated'), function: async (provider: AiProvider) => { // Call backend API to fetch models (enables Docker internal network access) const modelList = await api.ai.fetchProviderModels.mutate({ providerId: provider.id }); await this.aiProviders.call(); return modelList; }, });调用入口在 ModelDialogContent.tsx#L78-L86,点击"Fetch Models"按钮触发aiSettingStore.fetchProviderModels.call(selectedProvider),随后 tRPC 将providerId传给后端 server/routerTrpc/ai.ts。
服务端:fetchProviderModels 按 Provider 类型分发
server/routerTrpc/ai.ts#L586-L741 中的fetchProviderModels是本次修复的核心。它的流程是:
- 按
providerId从数据库查询aiProviders记录,查不到则抛出NOT_FOUND; - 通过
fetchWithProxy()获取一个已封装 HTTP 代理逻辑的 fetch 函数(见下文); - 根据
provider.provider的类型switch分发,构造对应的模型拉取请求:ollama:请求${baseURL}/api/tags,默认http://127.0.0.1:11434,解析data.models中的name字段;openai:请求${baseURL}/models,带Authorization: Bearer <apiKey>头,解析data.data;anthropic:无官方模型列表 API,返回静态清单(claude-3-5-sonnet、claude-3-opus 等 6 个模型);voyageai:同样返回静态清单(voyage-3、voyage-3-lite 等 8 个模型);google:请求${baseURL}/models?key=<apiKey>,解析data.models并去掉models/前缀;azure:请求${baseURL}/openai/models?api-version=2024-02-01,带api-key头;minimax:返回静态清单(MiniMax-M3、MiniMax-M2.7);default(Custom 及其他 OpenAI 兼容服务):请求${baseURL}/models,带 Bearer 头,解析data.data。
- 拉取成功后,将模型列表写入
aiProviders.config.models持久化到数据库,并返回给前端;前端通过getProviderModels(aiSettingStore.tsx#L136-L145)从provider.config.models读取展示。
正因为请求在服务端容器内发起,http://mock-openai:8080/v1这类内网地址才能被 Docker 内置 DNS 解析,这正是 README 所述修复的本质。
代理封装:fetchWithProxy
server/lib/proxy.ts#L20-L40 中的fetchWithProxy进一步增强了服务端请求的兼容性:若全局配置了 HTTP 代理,它会基于undici的ProxyAgent创建一个带dispatcher的 fetch 包装函数;未配置代理时直接返回原生fetch。因此服务端模型拉取既能走 Docker 内网,也能兼容企业代理等网络环境。
从源码结构看修复的调用链
综合以上代码,本次修复的完整调用链可以概括为:
浏览器点击 Fetch Models → ModelDialogContent.fetchProviderModels(前端组件) → aiSettingStore.fetchProviderModels(PromiseState 状态层) → api.ai.fetchProviderModels.mutate(tRPC 调用) → server/routerTrpc/ai.ts: fetchProviderModels(服务端,按 provider 类型 switch) → fetchWithProxy()(可选 HTTP 代理的 fetch) → GET http://mock-openai:8080/v1/models(Docker 内网解析) → 模型列表写入 aiProviders.config.models → 前端 getProviderModels 渲染模型选项清理测试环境
测试完成后,按 README 的清理步骤移除容器、网络与数据卷:
docker-compose -f docker-compose.test.yml down -v其中-v会一并删除postgres_data命名卷,确保下次测试从干净状态开始。
常见问题排查
- 服务迟迟不进入 healthy 状态:检查
docker-compose ps中mock-openai与postgres的健康检查结果,常见原因是端口被占用或镜像未拉取完成; - Fetch Models 报错 "Failed to fetch models":优先确认 Base URL 使用了 Docker 服务名(如
http://mock-openai:8080/v1)而非localhost,并确认目标容器与 Blinko 容器处于同一blinko-test-network; - 模型列表为空:确认 Mock 服务日志中有
GET /v1/models记录,若没有记录说明请求未到达服务端,应检查网络与 Base URL 拼接路径(Custom 类型默认请求${baseURL}/models,与 Mock 的/v1/models路径需保持一致)。
小结
通过test-docker这套最小可复现环境,开发者可以在本地一键验证 Blinko 的 AI Provider 模型拉取已从浏览器端迁移到服务端:三容器同处一个 Docker bridge 网络,Mock OpenAI 暴露内网服务名地址,Blinko 服务端通过fetchProviderModels拉取模型列表并落库,日志佐证请求确由容器发出。该方案同样适用于生产环境对接 Ollama 等自建模型服务时的内网连通性验证,是排查"浏览器无法访问 Docker 内网模型服务"类问题的最佳实践参考。
- 后端
- 前端
- 人工智能
- 大模型
- RAG
- 知识库
- 桌面应用
【免费下载链接】blinko
An open-source, self-hosted personal AI note tool prioritizing privacy, built using TypeScript .
相关推荐
Jumpserver网域内数据库资产连通性测试问题分析与解决方案
Jumpserver网域内数据库资产连通性测试问题分析与解决方案 问题背景 在使用Jumpserver 4.7.0社区版进行网域内数据库资产管理时,用户发现一个
后端认证鉴权运维网络安全Linux 网络诊断:ping6 命令详解——用 ICMPv6 测试 IPv6 网络连通性
Linux 网络诊断:ping6 命令详解——用 ICMPv6 测试 IPv6 网络连通性 ping6 是 ICMPv6 版本的 ping 实现,用于在 IPv
文档教程Obsidian全功能日历插件:知识管理系统的日程整合解决方案
Obsidian全功能日历插件:知识管理系统的日程整合解决方案 现代知识工作者面临着信息碎片化与时间管理分离的挑战,Obsidian全功能日历插件提供了将日程安
前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考