本文描述当前产品的管理控制面与推理数据面。历史模板中的 JSON-RPC、WebSocket、gRPC、用户 JWT/Auth 和通用 Task/Policy 不属于 vllm-use。
管理能力只有两种 Adapter:
/api/*:供 React Web Admin 和运维客户端使用的资源化 HTTP 路由。POST /mcp:MCP2026-07-28stateless Streamable HTTP,使用官方 Go SDK。
两者都必须完成 Bearer 认证,并将授权信息写入 context,然后进入同一条调用链。认证只接受单个规范的 Authorization: Bearer <token>;重复或逗号合并的认证头会 fail closed:
Adapter → api_executer.ExecuteAbility/APIExecuter
→ api_supported_methods.Method
→ SupportedMethod.Execute
→ ability_<domain>
HTTP Adapter 把资源路由映射为注册方法名和 arguments;MCP Adapter 原生接收 tools/call → name → arguments。Adapter 不得直接持有或调用域 Service 来绕过注册表和 scope 门禁。
SupportedMethod 保存 Name、Description、InputSchema、Scope、Public 和 Execute。api_executer 负责方法查找与 fail-closed scope 校验;Ability 负责严格解码参数和业务执行。test 是唯一公开方法,但 /mcp 外层仍要求 API key。
当前 scope:
- 管理 HTTP:bootstrap admin token,或
admin.read/admin.write。 - MCP:
mcp.read、mcp.models、mcp.runtime、mcp.admin;mcp.admin可调用全部 MCP tools,但不隐含admin.read、admin.write或inference,不能跨协议认证管理 HTTP 或推理 Gateway。
MCP 还要求且只接受一个精确的 Mcp-Protocol-Version: 2026-07-28;缺失、重复、逗号合并、旧版或带额外空白的版本值都会以 HTTP 400 和当前受支持版本响应,不能回落为空白 200,也不能让不同代理层选择不同版本;同时使用 Go 标准库跨源保护,可信浏览器 Origin 只能由显式配置加入。未显式配置管理 token 时,服务仅以原子排他创建方式生成 0600 的 bootstrap 凭据文件;重启读取时拒绝符号链接、非普通文件、控制字符和异常长度,并收紧遗留的过宽权限。
ability_model:扫描、登记、查询和删除模型。模型 ID 固定为服务端生成的 32 位小写十六进制值,模型查询、下载、runtime 切换和 SQLite 恢复共用同一校验,路径形式或非规范 ID 会在数据库查询与隔离区文件操作前拒绝。本地模型必须是 models 根目录下的独立真实子目录,不能把根目录本身登记为一个模型;同一规范受管目录只能对应一个模型记录,应用层串行门禁与 SQLite 唯一索引共同阻止重复登记,避免删除一条记录后另一条记录仍引用已移除文件。升级时若历史数据库已存在这种冲突会阻止启动并保留原数据,不会猜测哪条记录应被删除。持久化名称必须是至多 256 字节、无控制字符的合法 UTF-8。Hugging Face 登记与下载共用同一组 repository/revision 校验:repository 必须符合 Hub 的owner/name字符与 96 字节边界,revision 必须是至多 255 字节且不含空白、控制字符或前导短横线的分支、标签或提交引用,避免先落库、后由宿主 CLI 拒绝的不可执行记录。读取单个模型或模型列表时会再次校验 ID、名称、类型、Hub 坐标、类型间字段关系、状态枚举、受管路径、非负大小以及时间先后;外部编辑或历史损坏的数据会让该请求 fail closed,不会以部分列表或貌似可用的模型进入 runtime、下载或删除流程。删除与 runtime 启动、停止、重启、切换共用同一生命周期门禁:正在按注册 ID 运行的模型,以及通过底层直接启动且实际路径相同的模型,都拒绝删除;门禁会一直持有到删除提交结束,避免“检查后启动”的并发竞态。删除本地文件时先把模型目录原子移动到模型根目录下的私有隔离区,再提交 SQLite 删除;进程若在两步之间退出,下次启动以 SQLite 为权威恢复未提交删除的目录,或清理已提交删除的隔离目录。未知隔离区内容会被保留并导致启动失败,避免误删运维人员数据。ability_download:通过宿主机 Hugging Face CLI 下载、重试、取消、查询日志。HTTP/MCP 只能携带任务id、已登记 Hugging Face 模型的model_id和一次性 token;服务从 SQLite 读取 repository/revision,并把目标目录固定派生为<models-dir>/<model_id>,客户端不能注入仓库或主机路径。任务 ID 固定为 1–128 字节的可移植 ASCII 标识(字母或数字开头,其余仅允许字母、数字、点、下划线和短横线),并是不可重定向的持久审计身份:普通启动不能复用任何已有终态 ID 来覆盖仓库、模型或日志,只有显式downloads.retry可以为同一已登记模型复用该 ID;取消终态任务会明确失败,不会返回虚假的取消成功。重启恢复把 SQLite 视为不可信输入,除 ID、Hub 坐标、状态、进度和日志外,还校验规范绝对目标路径、UTF-8/长度边界、创建/更新/开始/完成时间顺序和各状态允许的生命周期字段;仍为 pending/running 的关联任务必须与当前模型登记、downloading状态及受管目标完全一致,否则启动在监听前失败且不会执行宿主命令。宿主错误在持久化前按 UTF-8 边界限制为 64 KiB;下载日志除单行 64 KiB 和条数限制外,还按任务限制为累计 4 MiB,并始终淘汰最旧行、保留最新诊断。恢复时会拒绝超过累计字节上限的 SQLite 日志,避免外部编辑或旧数据让启动加载无界内容。终态任务保留为历史审计,重试仍会重新解析当前模型登记,不把历史任务中的仓库、revision 或目标路径当成新下载的权威;仅失败或取消且仍处于可下载状态的已登记模型可以重试。启动 CLI 前会检查目标及现有父路径,拒绝符号链接和非目录目标,避免预先植入的模型路径把宿主机写入重定向到模型根目录之外;CLI 完成后仍会重新解析并校验最终目录。一次性 token 有严格长度/控制字符边界,只经 Hugging Face 子进程环境传递;管理 token 和 Gateway 上游凭据不会被该子进程继承。服务会先在同一 SQLite 事务中持久化任务,并以条件更新把模型从registered/error/failed/canceled原子切换为downloading;有空闲 worker 时立即启动宿主机 CLI,超过并发上限时则以pending状态持久排队;worker 释放后必须先持久化实际开始时间和running状态,成功后才启动宿主机 CLI,写入失败会将任务置为失败而不会产生数据库仍视为排队中的宿主机进程。暂时繁忙本身不会造成假失败。服务关闭或异常重启会把尚未完成的排队/运行任务明确标记为canceled。任一受理持久化步骤失败,或模型已经ready/downloading,都会回滚且不会发布内存任务或启动下载进程。CLI 退出成功后还会校验目标是模型根目录内真实可读的目录并计量文件大小,校验通过才在同一事务中将任务及对应模型记录转为succeeded/ready,避免数据库故障留下成功任务与仍在下载模型的分裂状态;终态持久化失败会显式标记内存任务失败,并使服务关闭返回错误,而不是假报持久化成功。ability_runtime:构造受约束参数,监督唯一宿主机 vLLM 进程并切换活动模型。runtime.switch以 SQLite 中的model_id为权威,只允许切换到状态为ready且具有受管本地路径的模型;启动前会重新确认登记路径仍是模型根目录内的真实目录,拒绝缺失、普通文件、被替换的符号链接或逃逸路径,调用方不能用options.model绕过模型登记状态。切换会接管并停止此前通过底层runtime.start直接启动的进程;重启会先完整校验替换参数,非法配置不会停止健康进程。运行状态只在当前进程确由模型注册表启动时返回对应active_model_id,直接启动或重启不会沿用过期关联。Web Admin 的启动/切换入口只选择这些就绪模型。常用 vLLM flags 使用类型化字段,模型、解析器、对外名称、GPU/并行配置与extra_args都有明确的 UTF-8、数量、单值和总字节边界;非有限浮点数、重复 GPU/扩展 flag、控制字符以及用值注入另一项--flag会在创建宿主进程前被拒绝。Supported Methods Registry 同步发布完整的嵌套 JSON Schema,使 HTTP 与 MCP 客户端看到同一组选项边界。就绪探测只访问由已校验 runtime host/port 派生的 loopback/health;HTTP/MCP schema 不暴露调用方可控的探测 URL,探测也不会采用宿主代理设置或跟随重定向,避免越出本机 vLLM 边界。停止时先向进程组发送SIGTERM,宽限期后升级为SIGKILL;强杀后的回收等待同时受调用方 deadline 和固定内部上限约束,无法回收的异常宿主进程会返回明确错误而不会永久阻塞管理服务关闭。启动请求若在就绪阶段被取消,清理会沿用调用方 deadline 并立即强杀未就绪进程,不会改用无界后台等待。vLLM 子进程继承运行所需的普通宿主环境,但不会继承管理 token 或 Gateway 上游凭据。监督器把 stdout/stderr 接入同一个有序管道并持续排空,因此终态只会在全部输出读取完成后发布,stderr 的最终诊断也不会因两个读取协程的调度顺序被较早 stdout 挤出保留窗口;每个日志单行最多保留 64 KiB 并按 UTF-8 边界截断,整个当前 runtime 的日志累计最多保留 4 MiB,超限时淘汰最旧行并保留最新诊断;后续输出仍会持续读取,避免异常输出堵塞 vLLM 进程或无界占用管理服务内存。模型删除只由与实际单进程监督器串行化的 Ability guard 判断运行占用;为数据库兼容保留但未接入当前监督器的旧runtime_configs.active预设不会永久锁住已经停止的模型。ability_gpu:读取真实nvidia-smi状态。父层system.get还会按配置用exec.LookPath预检vllm、hf与nvidia-smi,并在后者存在时经gpu.list执行真实驱动查询;结果明确区分available、missing和error,包含已解析路径及可用 GPU 数量,不把命令缺失或驱动故障伪装成健康。ability_api_key:创建、列出、启停和删除带 scope 的 API key。key secret 固定为vu_加 48 位字母数字,随机字符使用无模偏差采样;公开 key ID 固定为 24 位字母数字,启停和删除在查询 SQLite 前校验该边界,Supported Methods Schema 同步发布相同约束。认证先做固定成本的 secret 格式校验,再从 SQLite 读取记录,并在执行 scrypt 或发布身份前完整校验 ID、名称、前缀、salt/hash 长度、enabled 标记、scope 集合,以及last_used_at不早于created_at的时间关系。未知、空或重复 scope 等持久化损坏会 fail closed,且不会更新last_used_at或进入列表;认证查询在更新使用时间前关闭读游标,不依赖额外空闲连接,避免并发请求耗尽小型 SQLite 连接池后相互等待。scrypt 完成后还会用已验证的权威字段和enabled=1条件化提交使用时间;若 key 在派生期间被禁用、删除或替换,本次认证会失败而不会发布撤销前的旧身份,并且并发认证不会让last_used_at倒退。ability_settings:保存、删除非敏感设置与读取最近 Gateway 请求元数据。HTTP Web Admin 和 MCP 都通过统一注册方法删除设置;token、password、credential、API key 等敏感键会在忽略标点、Unicode 格式字符和符号等分隔符后识别并拒绝写入,凭据只能来自环境变量或 CLI flags。每次打开 SQLite 都复用同一检测规则清理旧版或外部写入的敏感设置行,避免 SQL 字符替换规则遗漏 Unicode 伪装。每次列表读取还会验证设置键和值的 UTF-8/长度边界、规范键名、secret 标记和时间戳,防止服务运行期间的外部编辑绕过启动清理。
SQLite 是持久化真相源。启动时数据库路径必须是普通文件且不能是符号链接,既有数据库会收紧为 0600,防止错误配置跟随链接修改无关文件。数据、模型及显式 Hugging Face cache 路径也必须是真实目录而非符号链接,并在目录身份校验后通过已打开的描述符收紧为 0700;这避免拒绝恶意或误配路径时跟随链接修改运维人员目录。非敏感 settings 在每次打开数据库时都会复用写入侧的 Unicode 归一化规则进行清理,历史或外部写入的伪装凭据键不会再经管理 API/MCP 暴露。下载进程和 vLLM runtime 由宿主机进程组管理;Linux 进程领导者还配置父进程退出信号,管理服务异常退出时内核会终止领导者,正常关闭则显式清理整个进程组;已受理的下载不依赖 HTTP/MCP 请求 context,服务退出时会停止接收请求、取消并等待下载状态落库后再关闭 SQLite。重启恢复会先完整读取并关闭下载查询游标,再把中断任务及关联模型事务化写为取消状态;即使 SQLite 连接池只有一个连接也不会自我阻塞,任何恢复读取、解码或写入失败都会阻止服务对外启动,而不是带着不一致的 running / downloading 状态继续服务。vllm、hf 与 nvidia-smi 子进程都不会继承管理 token 或 Gateway 上游凭据;仅当 nvidia-smi 不存在时 GPU 查询降级为空列表,其他执行故障会作为错误返回。不存在 MySQL Worker 或通用异步任务框架。
/v1/* 是独立的推理 Gateway Adapter,校验 inference scope 后反向代理到配置的 vLLM upstream。它只接受单个规范 Bearer 凭据;Anthropic 端点可改用单个 X-API-Key,但两种认证同时出现、重复或逗号合并时都会拒绝。upstream 配置只能是无凭据、无路径/查询/fragment 的 loopback HTTP(S) origin,且连接不使用宿主机 HTTP_PROXY / HTTPS_PROXY,确保数据面直连本机受管 vLLM,而不是被误配或被环境代理重定向到远端。它支持:
- OpenAI Chat Completions、Completions、Responses、Embeddings 和 Models 端点。
- Anthropic Messages 与 token counting 兼容端点。
- SSE 流式透传、请求取消传播、模型 alias 重写与可选上游凭据注入。alias 由
VLLM_USE_MODEL_ALIASES/--model-aliases以逗号分隔的alias=upstream-model配置,并从应用组合根传入真实 Gateway;重写保留大整数等 JSON 数值的原始精度,审计记录客户端别名。重复、空白、控制字符或超过边界的映射会在启动时失败。所有 POST 推理请求统一限制为 16 MiB,不能通过省略或伪装Content-Type绕过。 - 只记录非敏感且有长度上限的请求元数据,并以 API key ID(不含 secret)标记已认证请求,便于审计和撤销分析;每条记录有服务端生成的唯一
audit_id,客户端X-Request-ID仅作为可重复的关联字段,超过 128 字节或含非可见 ASCII 时会替换为服务端 ID,重复值不会覆盖、丢弃或混淆审计事件;模型名等审计字段按 UTF-8 边界截断但不会改写原推理请求;客户端 Authorization/X-API-Key 不转发给 upstream。SQLite 写入和读取都会验证审计 ID、UTF-8/字段长度、HTTP 状态码与非负耗时,损坏记录会使requests.recent在 HTTP/MCP 中 fail closed;旧版客户端请求 ID 主键在升级时一次性规范化为随机审计 ID。审计历史由VLLM_USE_MAX_AUDIT_RECORDS/--max-audit-records限制(默认 10000),每次写入与淘汰最旧记录在同一 SQLite 事务内完成,设为0可停止新增记录而不删除已有历史;服务优雅退出时会在关闭 SQLite 前等待已接收的审计写入完成。
Gateway 不执行业务管理 Ability,也不伪造推理结果。upstream 不可用时返回明确的 502。
单一 listener 默认 127.0.0.1:8080:
GET /healthz无需认证,只说明管理进程存活。/api/*、/mcp、/v1/*按上述规则认证。- 其余 GET 路由由嵌入的 React SPA 处理;后端命名空间不会回落为 SPA 假成功。
所有管理控制面和推理数据面响应(包括认证、参数和 upstream 错误)都返回 Cache-Control: no-store 与兼容旧客户端的 Pragma: no-cache。Gateway 在提交响应头前重新覆盖 upstream 缓存策略,避免一次性 API key secret、模型管理数据、提示词和生成内容被浏览器或中间代理持久缓存;该策略不影响带内容哈希的 Web Admin 静态资源长期缓存。
生产 Web 资源来自 web/dist 的 Go embed。运行不依赖 Node/Bun 或额外静态文件服务。
- HTTP 管理 Adapter 使用 HTTP 状态表达路由、认证、参数与业务错误。
- MCP 的已注册 tool 业务结果使用
CallToolResult,并显式输出isError;协议损坏和未知 tool 使用 MCP/JSON-RPC 协议错误。 - Gateway 保留 upstream 正常响应;认证、路由、请求体限制和 upstream 不可用使用兼容 JSON error。
- 无 vLLM、Hugging Face CLI 或
nvidia-smi时返回真实失败/空状态,不得合成成功数据。