@ivanalog_com: 调试了一会儿,现在在Google A100上运行Qwen Flash的速度(3000+预填充,90+ tps)已经更快了…

X AI KOLs Timeline 工具

摘要

一个名为collabosm的GitHub仓库提供了一个优化设置,用于在Google Colab A100上运行Qwen3.8-Flash-Next模型,实现了比商业API更快的推理速度,并附有详细的性能指标和说明。

调试了一会儿,现在在Google A100上运行Qwen Flash的速度(3000+预填充,90+ tps)已经比一般商业API更快了。对于偶尔的短期重度并发使用,可以将其放在Colab上。为了节省大家的时间,我已经将重建这个Qwen Flash在Colab上的方法上传到了GitHub。需要的人可以自行获取。https://github.com/architectds/collabosm…
查看原文
查看缓存全文

缓存时间: 2026/09/26 06:50

调试了一段时间后,现在在Google A100上运行Qwen Flash的速度(预填充3000+ tokens/s,解码90+ tokens/s)已经超过了一般的商用API。对于偶尔的短期高并发使用,可以将其部署在Colab上。为了节省大家的时间,我已经将这个Qwen Flash在Colab上重建的方案上传到了GitHub。有需要的人可以自行获取。
https://github.com/architectds/collabosm


architectds/collabosm

来源: https://github.com/architectds/collabosm

collabosm

在 一台Colab A100-80GB 高内存实例 上运行 Qwen3.8-Flash-Next(125B-A6B MoE,混合门控DeltaNet + 全注意力机制,262144原生上下文),并提供一个OpenAI兼容的端点供客户端连接。

以下是在构建此仓库的实例上测量的性能数据:

指标数值
预填充(30K提示)2,806 t/s
预填充 -gcs 4096(30K提示)3,360 t/s
预填充 -gcs 8192(30K提示)3,882 t/s
解码,MTP ndt=4,30K上下文97.4 t/s
解码,MTP ndt=4,114K上下文90.1 t/s
解码,无MTP56 t/s
KV缓存10,752 B/token(262K时2.63 GiB,500K时5.01 GiB)
恢复一个完全被逐出的32K对话0.58 秒,而非9.72秒的重新预填充(16.8倍提升)
成本7.52 CU/小时(A100 高内存)≈ $0.75/小时,≈26.6小时/200 CU

ExLlamaV3是本仓库中唯一的引擎。详细测量来源和注意事项请参阅 docs/MEASURED.md,关于显卡实际能承载的并发会话数请参阅 docs/CONCURRENCY.md。

要求

  • 能够分配 A100 的Colab套餐(本套件在拥有约200 CU/月的Pro套餐上开发)。
  • 必须是高内存(HIGH_RAM)。标准的40GB A100 完全无法加载此模型——约63.6 GiB的权重必须常驻显存。scripts/restore.py会明确请求此规格,并拒绝40GB的实例。
  • uv tool install google-colab-cli(如果需要fork/push,还需安装 gh)。
  • 约110 GiB的Colab磁盘空间用于存放权重。

快速开始

bash scripts/up.sh    # 恢复/创建实例,安装运行时,下载权重,启动服务
bash scripts/down.sh  # 停止虚拟机。在按量计费套餐中,这是最重要的命令。

up.sh 在端点响应 /health 时会打印隧道URL。将你的客户端指向 /v1,并使用它打印的API密钥(密钥也位于虚拟机上的 /content/api-key.txt)。

有用的配置项,均通过环境变量传递:

SESSION=mybox CACHE_SIZE=524288 CPU_CACHE_GB=8 bash scripts/up.sh
变量默认值含义
SESSIONcollabosm本地会话名称
CACHE_SIZE500224所有任务的KV总令牌数(必须是256的倍数)
CACHE_QUANT4KV位数(4 = Q4,允许 2-8)
CPU_CACHE_GB32固定内存二级KV页缓存(0 = 关闭)。按92K令牌/GB估算大小;不要将其视为免费内存——它会作为固定内存被完全分配(36.4 GiB n-gram表旁约32 + 24 = ~56 GB)
RECURRENT_CACHE_GB24用于Gated-DeltaNet检查点的主机RAM存储(约2048令牌间隔,每个116 MB)
GCS8192生成器块大小——这是我们发现的最大的预填充优化杠杆
NDT4MTP草稿深度
RUNTIMEwheelwheel(预编译,无需编译)或 source
TUNNEL_TOKEN未设置命名隧道令牌:提供稳定主机名而非快速隧道。配合 PUBLIC_URL 用于状态中显示的URL

这些默认值尚未一起加载过:docs/MEASURED.md 中经过验证的负载运行参数是 -gcs 4096 -ccs 16 -rcs 16。GET /v1/status 会报告运行中的服务器实际获得的参数。up.sh 在就绪时退出码为 0——表示API健康且发布了隧道URL——否则退出码为 1(上传/引导失败)、2-6(来自restore.py)、7(超时)、8(serve.sh失败)或 9(虚拟机上健康,但无隧道URL)。

此仓库包含什么

| 路径 | 角色 | |—|—|—| | scripts/restore.py | 会话恢复脚本。 从服务器真实状态重新连接孤立的虚拟机,或创建一个并实际请求高内存规格。在消耗任何资源前就拒绝/停止40GB实例。 | | scripts/probe_gpu.py | 在虚拟机上运行;以单行JSON报告显存/RAM/计算能力/磁盘信息 | | scripts/up.sh | 恢复 → 上传 → 引导 → 服务 → 等待健康 | | scripts/down.sh | 停止虚拟机并报告仍在计费的部分 | | scripts/bootstrap.sh | 运行时(固定版本wheel)+ 权重(来自HF的固定修订版),幂等 | | scripts/serve.sh | 启动API + cloudflared隧道(在虚拟机上运行) | | scripts/api_server.py | 极简OpenAI兼容服务器;一个长生命周期的生成器 | | scripts/status.py | 一目了然的阶段/健康报告 | | scripts/dev_stub.py | 使用存根引擎在回环地址上运行真正的Handler:在没有GPU和权重的情况下测试线协议格式 | | scripts/check_surface.py | 通过HTTP驱动运行中的服务器并判断其表面特性(增量、终止事件、ID、序列号) | | manifest.json | 所有固定修订版、大小和测量数量 | | docs/MEASURED.md | 测量数据,附来源和注意事项 | | docs/RUNBOOK.md | 常见陷阱、操作流程、成本防护措施 |

为什么运行时和模型来自不同地方

运行时是来自ExLlamaV3 GitHub发布版的固定预编译wheel——无需编译步骤,约22秒,绑定特定的 (python, torch, cuda) 组合,因此 bootstrap.sh 会探测镜像并选择匹配的资源。
权重来自Hugging Face的固定修订版(约100 GiB,匿名测量传输速度约380 MB/s,耗时4分40秒;当Xet路径停滞时,HF_HUB_DISABLE_XET=1 是文档记载的备选方案)。这里不需要Google Drive、Colab密钥或任何个人路径——仓库无法托管你的Drive,任何依赖Drive的东西都不可分享。

本仓库旨在帮你避开的四个陷阱

  1. colab new --gpu A100 是一场赌博。 它从不发送 shape 参数,因此你得到的是80GB高内存或40GB标准版。连续十一次未打补丁的尝试都得到了40GB版本。restore.py 修改了URL构建器以发送 shape=hm(google-colab-cli#47:枚举值存在且 machineShape 可被解析,但从未被发送)。
  2. 你的本地会话记录是可丢弃的。 当运行时代理令牌过期时,CLI会报告“未找到活动会话”并删除其记录——而此时虚拟机仍在运行并仍在计费。我们一天内遇到过两次,其中一次在运行中途,/content 完全完好。restore.py 通过 list_assignments() 重新连接,而非创建第二个虚拟机。
  3. 绝不要通过查找“80”来识别80GB显卡。 A100报告计算能力 sm_80,因此40GB实例在任何地方都会打印“80”。请比较 vram_GiB。
  4. 新的生成器意味着冷缓存。 PageTable 和CPU页缓存在 Generator.__init__ 内部构建。每个请求使用新的生成器会静默禁用提示缓存和固定内存KV层——故障不可见,你只会悄悄地重新预填充所有内容。api_server.py 持有一个生成器实例。

端到端验证

2026年9月25日,在一个账户上,除了本仓库中的脚本外无任何手动步骤:

  • scripts/restore.py 重新连接了一个孤立的分配(在此之前Colab CLI当天第三次丢弃了本地记录,虚拟机存活且仍在计费),并确认了实例:79.3 GiB显存,167.1 GiB内存,计算能力8.0,Python 3.13.15。
  • scripts/serve.sh 在 cache_size 500224(每流500K) 下加载了4.05 bpw打包模型,耗时259.5秒,并在显存使用 76,437 / 81,920 MiB 时达到 /health 200状态。
  • 通过公共隧道:/v1/models 在无密钥时返回 401,有密钥时返回200,一次真实的聊天补全在 3.1秒 内返回。
  • 当天晚些时候,使用真实客户端重新验证了整个链路:Codex CLI 0.144.6,wire_api = "responses",通过快速隧道连接到运行中的4.05 bpw打包模型——Reply with exactly: pong 返回了 pong,退出码0,8,536个提示令牌。

已知的明确缺口:

  • 流式传输现在是增量式的。 collect() 驱动 Generator.enqueue() / iterate() 并转发每个解码步骤,因此 /v1/chat/completions 和 /v1/responses 都在模型工作时发出文本。通过真实的Codex CLI客户端在本地验证:首个增量在0.01秒到达,共11个增量,存在终止 response.completed 事件,sequence_number 单调递增。旧的阻塞路径作为 _generate_blocking() 保留,仅在构建版本的Job API不同时使用。
  • 请求由锁序列化——一个生成器,一个缓存。“多流”今天意味着排队,而非并行。
  • max_batch_size > 1 未经测试。 所有测量均运行 num_slots = 1。
  • 会话分配是脚本化的;它尚未成为一个可配置的托管层。

无GPU测试

容易出错的是协议,而证明协议变更过去需要一次会话恢复加上四分钟的权重加载。两个脚本消除了这个成本:

python scripts/dev_stub.py --port 8099 --chunk 24 --delay 0.01   # 真实Handler,伪引擎
python scripts/check_surface.py --base http://127.0.0.1:8099/v1   # 13项检查,失败时退出码1

dev_stub.py 导入了正式的 Handler 并仅替换 _engine_fragments(),因此被测试的代码就是部署的代码。check_surface.py 断言了客户端实际依赖的内容:增量在结束前到达,发送终止事件,每个增量携带 item_id / output_index / content_index,sequence_number 单调递增,聊天和Responses视图对同一补全的结果逐字一致。

也可以指向真实客户端——这是了解流格式错误的最快方式:

# CODEX_HOME/config.toml
model = "qwen3.8-flash-next-exl3"
model_provider = "collabosm"
preferred_auth_method = "apikey"
[model_providers.collabosm]
name = "collabosm"
base_url = "http://127.0.0.1:8099/v1"
wire_api = "responses"
env_key = "COLLABOSM_TEST_KEY"

向 dev_stub.py 添加 --think 以测试推理项的生命周期。Codex CLI 0.144.6 接受了两种格式(codex exec --skip-git-repo-check 'Reply with exactly: pong')。

能承载多少会话

在此显卡上测量的承载能力(详情和假设见 docs/CONCURRENCY.md):

每流上下文最大并发活动会话数限制因素
500K1KV缓存
262K2KV缓存
131K5两者共同限制
32K11循环状态
16K14循环状态

每个活动槽位在无任何KV缓存前就消耗约 546 MiB 的Gated-DeltaNet状态,因此当上下文变短时,并发度在约20个槽位达到饱和(16K:14槽位,8K:17槽位),8-14是实际可用范围。固定内存层不会提高这些数字——逐出仅影响未引用的页面,并且它不是活动流的交换设备——但它能让约147万令牌的空闲对话在不到一秒内恢复,而非重新预填充。docs/CONCURRENCY.md 解释了为什么内存层无法扩展活动容量。

许可证

我们的脚本:MIT(见 LICENSE)。
权重未包含在此仓库中,遵循其自身许可证——见 turboderp/Qwen3.8-Flash-Next-exl3 和 NOTICE。
ExLlamaV3 是 MIT 许可。

API接口

服务器是我们自己的(scripts/api_server.py)——ExLlamaV3不提供HTTP服务器。它支持两种OpenAI方言,且所有错误路径都返回JSON(HTML错误页面是bug,不是客户端问题):

端点说明
POST /v1/chat/completionschoices[].message.content,finish_reason = stop/length,usage.prompt_tokens_details.cached_tokens;stream: true 返回SSE块 + [DONE](使用 stream_options.include_usage 时包含usage)
GET /v1/status只读合约:启动参数、缓存大小、正常运行时间、视觉能力和图像输入策略
POST /v1/responsesResponses接口:status,output[].content[].text,output_text,usage.{input,output,total}_tokens;stream: true 发送以下完整生命周期
GET /v1/models唯一的模型ID,包含 created
GET/health简单返回 ok,无需认证
其他任何JSON 404/405(从不返回HTML)

接受的参数:max_tokens 和 max_completion_tokens,temperature,top_p,stop(字符串或列表),stream,stream_options.include_usage。

流式 /v1/responses 在每个事件上发送 sequence_number,顺序如下:
response.created -> response.in_progress -> (如果思考开启) output_item.added(reasoning) -> reasoning_text.delta -> reasoning_text.done -> output_item.done -> output_item.added(message) -> content_part.added -> output_text.delta xN -> output_text.done -> content_part.done -> output_item.done -> response.completed。

增量始终携带 item_id、output_index 和 content_index,终止事件中的ID就是流中宣布的ID——Codex会将增量绑定到已宣布的项,否则会拒绝该流。

文本在引擎解码同时被转发:服务器将一个 Job 入队并排空 Generator.iterate(),而非对完成的补全进行分块。如果某个构建版本的增量路径不产生任何内容,服务器会回退到阻塞生成器并记录 incremental path produced no text (new=... eos=...)——它从不返回空响应。

思考默认关闭,因为这是普通聊天客户端的预期。可通过 enable_thinking: true 或 reasoning_effort: xhigh|medium|low 开启(打包模型自己的模板接受两者);追踪信息在 message.reasoning_content 中返回,且永不泄露到 content 中。

客户端及使用真实WebUI

collabosm.py 是本地客户端。仅使用标准库,无需安装步骤:

python collabosm.py config --init --endpoint https://.trycloudflare.com/v1 --api-key <your-key>
python collabosm.py ui      # http://127.0.0.1:8790 (页面 + 代理)
python collabosm.py chat "hello"  # 同一路径,在终端
python collabosm.py update-ui     # 从本仓库拉取 ui/ 并缓存

它只实现了两种方言,即Codex使用的两种:/v1/responses 和 /v1/chat/completions(加上 /v1/models,所有OpenAI兼容客户端都会首先探测它)。其他任何请求都返回JSON 404。

为什么使用本地代理而非直接将客户端指向端点

  • 承载令牌留在此进程中,永不交给浏览器。
  • 页面与代理同源,因此完全不存在CORS问题。
  • UI可以独立于虚拟机进行更新。

这里故意没有 Access-Control-Allow-Origin: *:在注入承载令牌的代理上使用通配符,会让你访问的任何网页都能读取你GPU所说的内容。单凭这一点并不能阻止页面发送 text/plain 或表单POST——这些不需要预检请求——因此每个POST也必须是 application/json,来自此源(或非浏览器),并在 Host 中命名此代理,这也排除了DNS重绑定攻击。frontend/server.py 对 /control/* 应用相同规则,其中POST可能开始计费。服务器端UI不受影响(它们从自己的后端调用上游);如果浏览器托管的UI需要接入,请添加明确的源白名单,而非通配符。

两个命名窗口

客户端提供三个页面,启动器会打开两个重要的页面,以便一眼就能看出哪个是哪个:

python collabosm.py start       # 如需要则启动客户端,然后打开两个窗口
python collabosm.py startup     # 在每次登录时执行相同操作(启动文件夹快捷方式)
python collabosm.py startup --remove
页面标题描述
/collabosm带有两个入口的着陆页,适用于手动打开
/chatcollabosm — chat对话,流式,思考过程折叠
/statuscollabosm — status端点状态、实时生成以及测量的预填充/解码/首token延迟

start 刻意容忍未配置或不可达的端点:客户端无论如何都会启动,以便状态页可以说明缺少什么。启动或停止A100仍使用 scripts/up.sh / scripts/down.sh;此客户端本身不消耗任何费用。

如果你更喜欢在Open WebUI中聊天,可以将聊天窗口指向别处并保留此仪表板:

python collabosm.py config --chat-url http://127.0.0.1:8080

指标合约

OpenAI协议没有用于预

相似文章

Qwen3.8-Flash-Next 针对 Mac 优化版

Reddit r/LocalLLaMA

本文详细介绍了在 Mac M1 Max 硬件上运行 Qwen3.8-Flash-Next AI 模型的自定义优化,包括 SSD 流、自定义量化和稀疏注意力机制,以提升性能。