自托管模型
Takuto Core 可以通过 OpenCode 提供商驱动一个自托管、OpenAI 兼容的模型服务器 —— LM Studio、Ollama、vLLM 等。这让源代码和 prompt 完全留在你掌控的基础设施上。本页讲解 设置过程,以及我们用 Docker Desktop 接 LM Studio 时撞上的几种失败模式,省得你再去重新 推导一遍。
下面每一项设置都可从仪表盘的 Configuration → AI Settings → OpenCode 编辑。无需 手工编辑
config.toml。
基本设置
-
在 Configuration → AI Settings 中把提供商设为 OpenCode。
-
设置 Model 字段。OpenCode 的
-m标志期望的格式是<providerId>/<modelId>, 而 Takuto Core 生成的配置总是把提供商命名为self_hosted,因此该值必须形如:self_hosted/<model-id-as-reported-by-the-server>服务器报告的模型 id 在 Takuto 中填写 qwen/qwen2.5-vl-7bself_hosted/qwen/qwen2.5-vl-7blmstudio-community/Llama-3.1-8B-Instruct-GGUFself_hosted/lmstudio-community/Llama-3.1-8B-Instruct-GGUF -
把 Base URL 设为 OpenAI 兼容的端点,包含末尾的
/v1:http://host.docker.internal:1234/v1 -
如果你的服务器不需要真实的 API key(LM Studio、Ollama 通常不需要),勾选 Allow shared default token,让 Takuto Core 注入一个占位 bearer。
-
把 Context limit / Output limit 设成与你的模型相符 —— 本地端点无法报告这些 值,所以 OpenCode 依赖你提供的数值。
模型服务器一侧
让服务器可从 container 访问:
- LM Studio: 打开 Developer → Local Server → “Serve on Local Network”。不开
它,LM Studio 只绑定到
127.0.0.1,没有任何 container 能访问到它。 - macOS 防火墙: 要么关闭,要么明确放行该模型服务器。
确认它绑定到了所有网络接口,而不只是回环:
lsof -nP -iTCP -sTCP:LISTEN | grep 1234
# Want: *:1234 (LISTEN) — bound to all interfaces
# If it shows 127.0.0.1:1234, "Serve on Local Network" is OFF.
桥接 sidecar(gVisor 变通方案)
只有当模型服务器跑在宿主 Mac 上而且 Docker Desktop 使用 gVisor 网络栈(4.34+ 的 默认设置)时,你才需要它。 对于云提供商你不需要它;当模型服务器作为一个 container 跑在 Takuto Core 的 compose 网络内部时也不需要 —— 那种情况下把 Base URL 指向服务名(例如
http://lm-studio:1234/v1)并跳过这个桥接。
在 gVisor 下,从 container 到 Mac 局域网上私有 IP 的流量 —— 包括
host.docker.internal(在 container 内部解析为 192.168.65.254)—— 可能会静默超时,
而公网 IP 却一切正常。检查你的网络类型:
ps ax | grep com.docker.virtualization | grep -o 'networkType [a-z]*'
# networkType gvisor ← affected
确认这是 gVisor 问题
如果服务器绑定到 *:1234、防火墙关着、从 container 访问公网正常,但从 container 内部
访问 host.docker.internal:1234 和 Mac 的局域网 IP 都超时 —— 那就是 gVisor 栈。
# Public internet works from a container:
docker exec <takuto-container> sh -c 'wget -q -O - -T 3 https://1.1.1.1 | head -3'
# host.docker.internal resolves but connections time out:
docker exec <takuto-container> sh -c 'curl -v -m 3 http://host.docker.internal:1234/v1/models 2>&1 | tail -5'
# * Connection timed out after 3001 milliseconds
解决办法:lm-bridge socat sidecar
Takuto Core 附带了一个小巧的 socat container,它同时接入默认的 bridge 网络
(在 gVisor 下能正确访问宿主)和 compose 网络(这样 DinD 嵌套的 worker 也能路由到它)。
用一个标志就能把它启动起来 —— 下面的 make 目标是 Takuto Core 引擎仓库提供的便捷封装
(即自建 container 的路径);在底层,LM_BRIDGE=1 只是把
docker-compose.lm-bridge.yml 合并进 Compose 栈:
make start BACKEND=postgres LM_BRIDGE=1
那会在固定 IP 172.20.0.250 上启动 takuto-lm-bridge,把 TCP/1234 转发到
host.docker.internal:${LM_HOST_PORT:-1234}。然后把 AI Settings 里的 Base URL
设为:
http://172.20.0.250:1234/v1
对于非默认端口(比如 Ollama 的 11434):
LM_HOST_PORT=11434 make start BACKEND=postgres LM_BRIDGE=1
桥接起来后做一次冒烟测试
docker exec takuto-core-dind-1 docker run --rm --entrypoint /bin/bash \
takuto:latest -c \
'exec 3<>/dev/tcp/172.20.0.250/1234;
printf "GET /v1/models HTTP/1.0\r\nHost: x\r\n\r\n" >&3;
timeout 5 cat <&3 | head -5'
一个 200 OK 后面跟着 JSON,就说明 worker 路径是健康的。
OpenCode error: unknown error 排查清单
当仪表盘显示晦涩的 OpenCode error: unknown error 时,按顺序逐项排查 —— 每一项都是
真实的失败模式:
- Model 字段以
self_hosted/开头。 - Allow shared default token 已勾选(除非你保存了一个按用户的 bearer)。当它关着
且没有保存 bearer 时,不会有
opencode.json被挂载进 worker,OpenCode 会在它的 首次运行数据库迁移之后立刻退出。 - Base URL 以
/v1结尾。 - 模型服务器开启了 “Serve on Local Network”(是
*:<port>,而非127.0.0.1:<port>)。 - Docker Desktop 网络是健康的 —— 跑一遍冒烟测试;如果超时,就用上面的
LM_BRIDGEsidecar。
如果这五项都绿了运行却仍然失败,就在 container 内部用 --print-logs --log-level WARN
手动运行 opencode run,以查看 OpenCode 自己的 stderr,而不是那条被隐藏的
“unknown error”。