在 Modal 无服务器 GPU 上按需部署 Tabby:完整实操指南
2026/9/10 2:02:28 网站建设 项目流程

在 Modal 无服务器 GPU 上按需部署 Tabby:完整实操指南

【免费下载链接】tabbySelf-hosted AI coding assistant项目地址: https://gitcode.com/GitHub_Trending/tab/tabby

Modal 是一个 serverless GPU 平台,通过它运行 Tabby 可以实现"按需启动、空闲休眠"的弹性部署:当一段时间没有请求到达时,Modal 会自动让容器休眠以节省 GPU 成本。本文以 modal/index.md 为核心教程骨架,结合仓库中 app.py 的完整代码与 Tabby 服务端源码,从镜像构建、模型预热、ASGI 代理到modal serve发布,带你一步步把 Tabby 跑在云端,并给出每个配置项的源码级解释。

为什么选择 Modal 运行 Tabby

Tabby 是一个自托管的 AI 编码助手(self-hosted AI coding assistant),通常以tabby serve方式常驻运行,持续占用一块 GPU。而 Modal 的价值在于:

  • 按需运行(on demand):Tabby 实例只在有请求时才启动;
  • 自动休眠省成本:当 Tabby 服务器一段时间内没有请求时,Modal 会调度容器休眠(sleep),从而停止 GPU 计费;
  • 弹性并发:容器内可配置同时处理多个请求,空闲容器可保留一段时间后再回收。

这种模式非常适合个人开发者或小团队:既拥有自托管 Tabby 的全部能力,又不必为 24 小时空转的 GPU 付费。

环境准备与核心变量

首先在 Python 脚本中导入 Modal 的必要组件:

from modal import Image, App, asgi_app, gpu
  • Image:定义运行容器镜像;
  • App:声明一个 Modal 应用;
  • asgi_app:把 Tabby 的 HTTP 服务挂载为 Modal 的 web endpoint;
  • gpu:声明 GPU 配置。

然后设置基础变量:

IMAGE_NAME = "tabbyml/tabby" MODEL_ID = "TabbyML/StarCoder-1B" CHAT_MODEL_ID = "TabbyML/Qwen2-1.5B-Instruct" EMBEDDING_MODEL_ID = "TabbyML/Nomic-Embed-Text" GPU_CONFIG = gpu.T4() TABBY_BIN = "/opt/tabby/bin/tabby"

各变量含义如下:

变量作用
IMAGE_NAME基础 Docker 镜像,使用 Tabby 官方镜像tabbyml/tabby
MODEL_ID代码补全模型,/completions端点使用(仓库中 serve.rs 注释明确其为/completionsAPI 的模型)
CHAT_MODEL_ID对话模型,供/chat/completions端点使用(见 serve.rs)
EMBEDDING_MODEL_ID嵌入模型,用于代码搜索 / 文档检索等 embedding 服务
GPU_CONFIGModal 的 GPU 配置,这里选用gpu.T4()
TABBY_BINTabby 二进制在镜像内的路径/opt/tabby/bin/tabby,与官方 Dockerfile 的安装位置一致(见 Dockerfile.cuda)

值得注意的是:Tabby 官方镜像默认的ENTRYPOINT就是/opt/tabby/bin/tabby(见 Dockerfile.cuda),后续构建镜像时需要清空它以交给 Modal 接管进程。

选择 GPU:Modal 支持的配置

教程中GPU_CONFIG = gpu.T4()选择了低成本 T4,同时给出 Modal 目前支持的 GPU 清单(数据来自官方教程原文):

GPU显存定位与说明
T416 GiB低成本选项,适合小模型
L424 GiB中端选项
A10040 / 80 GiB云端最强 GPU 之一
H10080 GiBHopper 架构旗舰数据中心 GPU,强化 FP8 精度支持,内置 Transformer Engine,对 GPT-3 (175B) 级模型训练较上一代最高快 4 倍
A10G相比 T4,ML 训练性能最高提升 3.3 倍、推理性能最高提升 3 倍、图形性能最高提升 3 倍
Any按可用性自动选择任意 GPU 类别

选择 GPU 的关键标准是:让所选模型能装进显存(fit the model into VRAM)。1B 级补全模型 + 1.5B 级对话模型 + 嵌入模型,在 T4 的 16 GiB 显存内可以合理共存,这也是教程选择gpu.T4()的原因。

定义容器镜像:预热模型权重

为了让容器冷启动更快,教程把模型权重预置进镜像,这样容器启动时无需重新下载模型,而是利用 Modal 内部文件系统实现更快的冷启动。

下载权重的函数

def download_model(model_id: str): import subprocess subprocess.run( [ TABBY_BIN, "download", "--model", model_id, ] )

该函数调用tabby download --model <model_id>。在服务端源码中,download子命令对应 download.rs:它接收--model(模型 ID)和--prefer-local-file(跳过远程文件检查,默认 false)两个参数,底层通过 tabby-download 从模型注册表解析模型信息(含 sha256 校验)并下载权重。也就是镜像构建期间就把权重落盘,运行时serve阶段无需再联网拉取。

组装镜像

image = ( Image.from_registry( IMAGE_NAME, add_python="3.11", ) .dockerfile_commands("ENTRYPOINT []") .run_function(download_model, kwargs={"model_id": EMBEDDING_MODEL_ID}) .run_function(download_model, kwargs={"model_id": CHAT_MODEL_ID}) .run_function(download_model, kwargs={"model_id": MODEL_ID}) .pip_install("asgi-proxy-lib") )

构建过程分四步:

  1. Image.from_registry(IMAGE_NAME, add_python="3.11"):基于tabbyml/tabby镜像,并补充 Python 3.11 运行时;
  2. .dockerfile_commands("ENTRYPOINT []"):清空官方镜像默认的 ENTRYPOINT(即tabby命令入口),让 Modal 以自己的入口运行,实现 seamless serverless 部署;
  3. 三个.run_function(download_model, ...):依次预下载嵌入、对话、补全三个模型的权重,写入镜像层;
  4. .pip_install("asgi-proxy-lib"):安装asgi-proxy-lib,用于在 localhost 上对接 Modal 的 ASGI web server。

应用函数:启动 Tabby 并桥接 ASGI

核心端点函数用 Modal 的@app.function表示,完成四件事:启动 Tabby 进程并等待就绪、创建 ASGI 代理把 Modal web endpoint 的请求隧道转发到本地 Tabby 服务、设置单容器最大并发请求数、设置空闲容器回收时间。

app = App("tabby-server", image=image) @app.function( gpu=GPU_CONFIG, allow_concurrent_inputs=10, container_idle_timeout=120, timeout=360, ) @asgi_app() def app_serve(): import socket import subprocess import time from asgi_proxy import asgi_proxy launcher = subprocess.Popen( [ TABBY_BIN, "serve", "--model", MODEL_ID, "--chat-model", CHAT_MODEL_ID, "--port", "8000", "--device", "cuda", "--parallelism", "1", ] ) # Poll until webserver at 127.0.0.1:8000 accepts connections before running inputs. def tabby_ready(): try: socket.create_connection(("127.0.0.1", 8000), timeout=1).close() return True except (socket.timeout, ConnectionRefusedError): # Check if launcher webserving process has exited. # If so, a connection can never be made. retcode = launcher.poll() if retcode is not None: raise RuntimeError(f"launcher exited unexpectedly with code {retcode}") return False while not tabby_ready(): time.sleep(1.0) print("Tabby server ready!") return asgi_proxy("http://localhost:8000")

Modal 函数参数逐项解读

参数含义
gpuGPU_CONFIG(T4)指定容器 GPU
allow_concurrent_inputs10单个容器允许同时处理最多 10 个请求
container_idle_timeout120空闲容器保留 120 秒(2 分钟)后回收
timeout360函数执行超时上限 360 秒

Tabby serve 参数与源码对应

启动命令对应tabby serve,其参数在 serve.rs 中定义:

  • --model <MODEL_ID>:指定/completions补全模型;
  • --chat-model <CHAT_MODEL_ID>:指定/chat/completions对话模型(设置它后,serve.rs 才会注册/v1/chat/completions/v1beta/chat/completions路由,否则这两个路由返回501 NOT_IMPLEMENTED);
  • --port 8000:监听端口 8000(默认是 8080,见 serve.rs);
  • --device cuda:使用 GPU 推理(默认是 CPU,见 serve.rs);
  • --parallelism 1:模型推理并行度。源码注释明确提示:增加该值会显著提升内存(尤其是显存)占用(serve.rs),在 T4 上设为 1 是保守且合理的选择。

merge_args(serve.rs)会把 CLI 参数合并进配置:--model覆盖 completion 配置,--chat-model覆盖 chat 配置(若config.toml中已有同名模型会打印覆盖警告)。因此本教程通过命令行参数注入三个模型,完全等价于在config.toml中配置对应模型字段。

就绪探活(health check)

tabby_ready()每 1 秒尝试连接127.0.0.1:8000

  • 连接成功 → 返回 True,Tabby 已就绪;
  • 超时 / 拒绝连接 → 检查launcher进程是否已退出,若已退出则抛出RuntimeError(避免无限空等),否则继续轮询。

这一步非常关键:Modal 只有等app_serve返回 ASGI 代理后才开始路由流量,所以必须先确保 Tabby 内部 HTTP 服务真正可接受连接。

ASGI 代理桥接

asgi_proxy("http://localhost:8000")把 Modal web endpoint 收到的请求,在容器内隧道转发到 Tabby 的 8000 端口。对客户端(编辑器扩展)而言,看到的就是一个标准的 Tabby server URL。

发布服务:modal serve

在包含app.py的目录下执行:

modal serve app.py

部署成功后,Modal 会输出 web endpoint 地址,格式为:

https://<USERNAME>--tabby-server-app-serve-dev.modal.run

tabby-server对应App("tabby-server", ...)的应用名,app-serve对应@app.function装饰的函数名,dev表示modal serve的开发(dev)环境。

强制重建镜像

如果遇到问题,尤其是缓存相关的问题(比如镜像里拉到了旧的模型权重或旧的镜像 tag),可以用强制重建来忽略缓存层、拉取最新镜像 tag:

MODAL_FORCE_BUILD=1 modal serve app.py

这也与app.py头部注释中的用法说明一致(见 app.py)。

部署完成后,把输出的 URL 填入 Tabby 编辑器扩展的 server url 配置,即可开始使用云端代码补全与对话能力。完整可运行的代码可直接参考教程同目录的 app.py。

小结

本文完整走通了"Modal 无服务器 GPU + Tabby"的部署链路:用Image预置三个模型的权重以加速冷启动,用@app.function(gpu=..., allow_concurrent_inputs=..., container_idle_timeout=...)声明按需运行与休眠策略,用asgi_proxy将本地 8000 端口的 Tabby HTTP 服务桥接为 Modal web endpoint,最后通过modal serve app.py一键发布。核心收益是:只有请求到来时才启动 GPU 容器,空闲 2 分钟自动休眠,GPU 成本随流量按需产生——这正是自托管 AI 编码助手在云端低成本运行的典型姿势。

如果你对 Tabby 的 serve 参数或模型下载机制感兴趣,可以继续阅读 serve.rs 与 tabby-download 的源码实现。

【免费下载链接】tabbySelf-hosted AI coding assistant项目地址: https://gitcode.com/GitHub_Trending/tab/tabby

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询