← 返回首页

从 Ollama 迁到 Docker Model Runner 的端点对照

DockerOllama本地大模型

我实际测试了一遍「把现有 Ollama 客户端迁到 Docker Model Runner(DMR)」这件事,结论比预期更分裂:用 Ollama 原生 API 的项目几乎不用改代码,用 OpenAI 兼容 API 的项目必须改一个 base URL,而只用到 embeddings 的项目会撞上一个很隐蔽的坑——Docker 官方兼容的那个 embeddings 端点,恰恰是 Ollama 官方文档里标注「已被取代」的旧端点。

⚠️ 实测口径声明:本机没有 Docker Desktop,也没有可用 GPU,无法启动真实 DMR 服务进程。下文所有「实测」指的是 openai 3.32.0、ollama 0.6.3、httpx 0.28.1 三个官方客户端在本机发出的真实 HTTP 请求行,一共 29 组;服务端是我按 Docker 官方 api-reference 端点表实现的回放服务器,只用于判断「这条路径是否落在 DMR 公布过的路由上」。DMR 服务端的实际响应以官方文档为准,凡属文档未覆盖的行为我都单独标注了。

TL;DR:Ollama 原生客户端只改端口(11434 → 12434)就能跑通聊天与列举模型,实测请求行 POST /api/chat、GET /api/tags 都落在官方路由上;OpenAI 兼容客户端必须把 base URL 从 http://localhost:11434/v1/ 改成 http://localhost:12434/engines/v1,只换端口会发出 POST /v1/chat/completions 并拿到 404;embeddings 要改用 /api/embeddings 或 /engines/v1/embeddings,Ollama 现行的 /api/embed 在 DMR 官方文档里没有对应。

迁移代价分三档:先数清楚你要改几行

迁移前最容易犯的错,是以为「换一个端口就行」。代价完全取决于你用的是哪一层 API。按我这轮实测,可以明确分成三档:

档位你现在的写法要改什么实测结果
零改动档Ollama 原生客户端(ollama SDK / curl /api/chat)只把端口从 11434 换成 12434请求行不变,落在官方路由上
一行改动档OpenAI 兼容客户端(各类框架与 SDK)base URL 从 ...:11434/v1/ 改为 ...:12434/engines/v1只换端口会 404
必须重构档Modelfile 造模型、embeddings 管线、Responses API换机制,不是换地址官方文档无对应端点

第三档是真正会让人卡住的地方。Ollama 的 ollama create -f Modelfile 在 DMR 里没有等价的 HTTP 端点,Docker 官方给的替代路径是 CLI 的 docker model package --gguf;而 embeddings 的错配更隐蔽,下面单独讲。

端点对照一:OpenAI 兼容层,`/v1` 要换成 `/engines/v1`

两边都实现了 OpenAI 兼容 API,但路径前缀完全不同,这是绝大多数 404 的来源。

能力Ollama 官方(base http://localhost:11434/v1/)Docker Model Runner 官方(base http://localhost:12434/engines/v1)
聊天/v1/chat/completions/engines/v1/chat/completions
文本补全/v1/completions/engines/v1/completions
列举模型/v1/models/engines/v1/models
单个模型/v1/models/{model}/engines/v1/models/{namespace}/{name}
向量/v1/embeddings/engines/v1/embeddings
Responses API/v1/responses官方文档未列出

注意最后一列的两个细节。第一,DMR 的「单个模型」路径模板是 {namespace}/{name} 两段而不是一段——官方模型名一律带 ai/ 前缀,真实路径形如 /engines/v1/models/ai/smollm2。第二,Ollama 官方文档列了 /v1/responses,DMR 的端点表里没有它;实测 client.responses.create(...) 发出 POST /engines/v1/responses,落在公布路由之外。

DMR 还允许把引擎名写进路径,变成 /engines/llama.cpp/v1/chat/completions。实测带引擎名的写法同样命中路由,这在同时跑多个推理引擎时才用得上。

另外一条官方标注的差异:DMR 官方文档写明「Token counting 使用模型原生 token 编码器,可能与 OpenAI 的不同」。如果你的代码里拿 usage 做计费或截断判断,这一条值得单独回归一次。

端点对照二:Ollama 兼容层,5 个对 15 个

Docker 官方明确写了「Ollama-compatible clients」的 base URL 就是 http://localhost:12434,不带任何路径。按官方 api-reference 的兼容端点表统计,只有 5 个:

DMR 官方列出的 Ollama 兼容端点对应 Ollama 官方端点
GET /api/tags/api/tags
POST /api/show/api/show
POST /api/chat/api/chat
POST /api/generate/api/generate
POST /api/embeddings/api/embeddings(Ollama 已标注 superseded)

而 Ollama 官方 docs/api.md 里一共列了 15 个端点路径:/api/generate、/api/chat、/api/create、/api/tags、/api/show、/api/copy、/api/delete、/api/pull、/api/push、/api/embed、/api/embeddings、/api/ps、/api/version,以及 /api/blobs/{sha256}(HEAD 查存在、POST 推 blob 各一个)。按文档口径,覆盖率是 5/15,约 33%。

最值得注意的一条错配:Ollama 官方文档在 /api/embeddings 那一节写了原话 this endpoint has been superseded by /api/embed,也就是说 Ollama 自己已经不推荐这个旧端点、改推 /api/embed;而 DMR 公布的兼容清单里只有旧的 /api/embeddings,没有 /api/embed。结果就是:一个按 Ollama 现行最佳实践写的 embeddings 项目,迁过去会 404。实测 ollama SDK 的 embed() 发出 POST /api/embed,落在 DMR 公布路由之外。

其余没有对应端点的能力,官方文档里也没给替代 HTTP 方案:/api/pull、/api/push 走 CLI 的 docker model pull / docker model push;/api/create(Modelfile)走 CLI 的 docker model package;/api/ps 在 HTTP 兼容层缺失,但 CLI 有 docker model ps;/api/version 对应 CLI 的 docker model version。

端点对照三:CLI 怎么换

Ollama CLIDocker Model Runner CLI备注
ollama pull llama3.2docker model pull ai/smollm2:360M-Q4_K_M官方示例带命名空间与量化标签
ollama run llama3.2docker model run ai/smollm2
ollama listdocker model list
ollama psdocker model ps
ollama rmdocker model rm
ollama showdocker model show / docker model inspect
ollama create -f Modelfiledocker model package --gguf ./model.gguf --push myorg/mistral-7b-v0.1:Q4_K_M机制不同:GGUF 打成 OCI Artifact
无对应docker model tag / docker model push官方示例 docker model tag ai/smollm2 myorg/smollm2
Modelfile 参数docker model configure --context-size 8192 ai/qwen2.5-coder官方 configuration 页示例
无对应docker model logs / docker model requests排障入口

从 Docker 官方 CLI 参考页看,docker model 有 30 多个子命令,比 ollama 的管理面更宽(df、bench、status、purge、unload、gateway 等等)。如果你的迁移动机是「想要一套更像容器工作流的管理方式」,CLI 这一层其实是加分项。

端点对照四:模型名与环境变量

改动最小,但最容易漏。

客户端实测:29 组写法,11 组落在官方路由上

我把常见的 base URL 与 host 写法穷举了一遍,全部用真实 SDK 发真实请求,服务端按官方端点表判路由。29 组里 11 组(37.9%)落在 DMR 公布过的路径上。几种典型结果:

写法实测请求行命中官方路由
openai base_url=...:12434/engines/v1POST /engines/v1/chat/completions是
openai base_url=...:12434/engines/v1/(带尾斜杠)POST /engines/v1/chat/completions是,尾斜杠不影响
openai base_url=...:12434(只换端口)POST /chat/completions否
openai base_url=...:12434/v1/(Ollama 官方写法)POST /v1/chat/completions否
openai base_url=...:12434/engines/llama.cpp/v1POST /engines/llama.cpp/v1/chat/completions是
ollama SDK host=...:12434POST /api/chat是
ollama SDK host=...:12434 + list()GET /api/tags是
ollama SDK host=...:12434/engines/v1POST /engines/v1/api/chat否
ollama SDK host=...:12434 + embed()POST /api/embed否

两条可以直接用的结论:尾斜杠不用纠结,openai SDK 对 .../engines/v1 和 .../engines/v1/ 拼出的路径完全一样;ollama SDK 的 host 里不能带路径,它会在你给的路径后面再拼 /api/xxx。

想自己复跑的话,核心就是起一个记录请求行的本地服务,再用两个 SDK 各打一遍:

import threading, http.server, socketserver
from openai import OpenAI

SEEN = []

class H(http.server.BaseHTTPRequestHandler):
    def do_POST(self):
        n = int(self.headers.get("Content-Length") or 0)
        self.rfile.read(n)
        SEEN.append(self.path)          # 记录真实请求行
        body = b'{"choices":[{"message":{"role":"assistant","content":"ok"}}]}'
        self.send_response(200)
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

srv = socketserver.TCPServer(("127.0.0.1", 18888), H)
threading.Thread(target=srv.serve_forever, daemon=True).start()

OpenAI(base_url="http://127.0.0.1:18888/engines/v1", api_key="x", max_retries=0) \
    .chat.completions.create(model="ai/smollm2", messages=[{"role": "user", "content": "hi"}])
print(SEEN)   # ['/engines/v1/chat/completions']

踩坑录:5 个真实报错

下面 5 条都是本机实跑出来的。请求行与状态码是实测的;报错文案里的响应体由回放服务器生成,真实 DMR 的 404 报文可能不同,但异常类型来自官方 SDK 本身。

报错一:只换端口,`openai.NotFoundError: Error code: 404`

openai.NotFoundError: Error code: 404 - {'error': {'message': 'no route for /v1/chat/completions'}}

实测请求行是 POST /v1/chat/completions。原因:你沿用了 Ollama 官方示例里的 base_url='http://localhost:11434/v1/',只把端口换成了 12434。修法是把 base URL 整体换掉:

from openai import OpenAI
client = OpenAI(base_url="http://localhost:12434/engines/v1", api_key="not-needed")

报错二:ollama SDK 的 host 写了路径,`ollama.ResponseError`

ollama.ResponseError: no route for /engines/v1/api/chat

实测请求行 POST /engines/v1/api/chat。原因是 Client(host=...) 会把你给的路径原样保留,再往下拼 /api/chat。修法是 host 只写到端口为止:Client(host="http://localhost:12434")。同理,写成 Client(host="http://localhost:12434/v1") 会拼出 POST /v1/api/chat,一样挂。

报错三:embeddings 端点错配,`ollama.ResponseError: no route for /api/embed`

ollama.ResponseError: no route for /api/embed

实测请求行 POST /api/embed。这是本轮最反直觉的一条:你的代码完全符合 Ollama 现行官方文档,但 DMR 公布的兼容清单里只有旧端点 /api/embeddings。两条修法——留在 Ollama 兼容层就把调用改成 /api/embeddings(注意它的参数名是 prompt,不是 /api/embed 的 input);或者干脆迁到 OpenAI 兼容层用 /engines/v1/embeddings,实测 POST /engines/v1/embeddings 命中路由。

报错四:Responses API 没有对应,`openai.NotFoundError: Error code: 404`

openai.NotFoundError: Error code: 404 - no route for /engines/v1/responses

实测请求行 POST /engines/v1/responses。Ollama 官方 openai-compatibility 文档列了 /v1/responses,DMR 端点表里没有。修法是改回 chat.completions.create(...)。

报错五:模型名只有一段,匹配不上官方路径模板

实测 models.retrieve("smollm2") 发出的请求行是 GET /engines/v1/models/smollm2,而 DMR 官方路径模板是 /engines/v1/models/{namespace}/{name} 两段。修法是把模型名写成 ai/smollm2。这条我没有在真实 DMR 上验证过失败形态(回放服务器对单段名是放行的),属于按官方路径模板推出的结论,请以你自己环境为准。

哪些场景建议先别迁

FAQ

Q: 只把 11434 改成 12434,最小改动能跑通哪些功能?

A: 按本轮实测,/api/chat、/api/tags、/api/generate、/api/show、/api/embeddings 这 5 个 Ollama 原生端点都落在 DMR 官方公布路由上。前提是你走 Ollama 兼容层,并且模型名带上 ai/ 这类命名空间。

Q: OpenAI 兼容层的 base URL 到底写哪个?

A: 官方「Base URLs for third-party tools」表里分三类:OpenAI SDK 类写 http://localhost:12434/engines/v1;Anthropic SDK 类写 http://localhost:12434;Ollama 兼容客户端也写 http://localhost:12434。差别就在 /engines/v1 这个后缀。

Q: embeddings 到底该用哪个端点?

A: 留在 Ollama 兼容层就用 /api/embeddings(参数是 prompt);迁到 OpenAI 兼容层就用 /engines/v1/embeddings。Ollama 现行的 /api/embed 在 DMR 官方文档里没有对应,别用。

Q: 容器里怎么连?

A: 官方口径分三套:Desktop 容器内用 http://model-runner.docker.internal(不带端口),Engine 容器内用 http://172.17.0.1:12434,Compose 项目里可能还需要 extra_hosts。我本机起不了真实环境,建议按你用的是 Desktop 还是 Engine 二选一,再用 docker model logs 看请求。

Q: DMR 版本号怎么查?

A: 官方 get-started 页给的命令是 docker model version。我这台机器没有 Docker,无法给出具体版本号;本文涉及 DMR 的描述均来自 2026-10-17 抓取的官方文档,请以你本地 docker model version 的输出为准。

延伸阅读

本文所有官方事实取自 Docker 官方 api-reference、get-started、configuration 与 CLI 参考页,以及 Ollama 官方仓库的 docs/api.md 与 docs/api/openai-compatibility.mdx,抓取时间 2026-10-17;Ollama 最新 release 为 v0.40.5(2026-10-14 发布)。价格与版本均标注「截至发稿」,请以官方页面为准。

👉 立即参与小米 MiMo 开放平台:国内领先的 AI 大模型开放平台,高性价比推理服务

👉 立即参与阿里云 AI:汇集爆款 AI 产品,热门模型专属权益优惠券助力企业创新加速

📌 本文由 AI 辅助生成并经人工审核发布 | TechPassive — AI 驱动的内容测试站点,专注于效率工具与 SaaS 真实评测

🔗 精选推荐工具

使用以下链接支持我们持续产出高质量内容(点击可直接前往购买):

☁️ DigitalOcean 云服务器 ⚡ Vultr 高性能 VPS 🤖 QoderWork 中国版(推荐有奖) ☁️ 阿里云爆款 AI 产品 📚 WordPress 实用书单 🔍 WordPress SEO 书单 🌐 虚拟主机书单 🐳 Docker 书单 🐧 Linux 书单 🐍 Python 书单 💰 联盟营销书单 💵 被动收入书单 🖥️ 服务器书单 ☁️ 云计算书单 🚀 DevOps 书单 🤖 小米 MiMo 开放平台
← 返回首页