1. 项目背景与整体思路拆解
这几年迷你主机圈子的风向其实变得很有意思。前几年大家还在纠结“核显能不能打游戏”,后来又开始争论“小主机能不能跑AI”,而像 Beelink Strix Halo 这类搭载 AMD Strix Halo 平台(具体就是 Ryzen AI Max 系列 APU)的机器一出来,这两件事基本被揉成了一个答案:能打游戏,也能干AI推理的活。halogen-flash-server 是这套玩法里我最近测下来最顺手的一个自托管推理服务,核心思路就是把大模型跑在统一内存上,不走独立显卡那一套。这篇内容我会从硬件选型、部署流程、实测数据和踩坑过程四个部分讲清楚,适合手里有类似高带宽统一内存迷你主机、又想在本地跑大模型的人参考。
先说结论:我在 Beelink Strix Halo 上部署 halogen-flash-server,实测单流 decode 速度大概在 55~60 tokens/s 这个区间,对比官方标称的 60~70 tokens/s,差距很小,基本属于“几乎打满宣传速度”的程度。考虑到实际运行环境有散热、功耗墙、系统调度这些因素,这个结果我觉得是相当能打的。这篇文章我尽量把从装系统到压测的全过程都写出来,包括那些文档里不会写、但实测会踩的坑。
1.1 为什么选 Strix Halo 这套平台跑推理
要说清楚这件事,得先看 Strix Halo 最核心的几个参数。这颗 APU 集成的 GPU 是 RDNA 3.5 架构,核心数最高能到 40CU(Ryzen AI Max+ 395),但真正吸引人的不是GPU算力本身,而是它把 CPU、GPU 和内存放在了一个统一的内存池里——最高支持 128GB LPDDR5X-8533,显存和系统内存共用,带宽能到 256GB/s 以上的级别。
这个带宽数字才是关键。跑大模型推理,尤其是大参数模型做 decode(逐token生成)时,瓶颈几乎永远在内存带宽,而不是纯算力。一个 70B 级别的量化模型,跑一次推理要把权重从内存搬到计算单元,权重大小除以带宽就是理论下限。拿 256GB/s 和 70B Q4 量化后的约 40GB 权重来算,光是把权重读一遍就需要差不多 0.16 秒,也就是说理论上限就是 6 tokens/s 左右——不对,这个算法不对,实际 decode 时权重只需要读一次然后复用,但每生成一个token理论上都要过一遍权重流量。简单说:带宽越高,单token生成时间越短,所以 Strix Halo 这种 256GB/s 级别的统一内存平台,跑大模型的天赋比很多独显笔记本还要好。
卤素(halogen)这个词出现在服务名里不是随便起的。我在用 halogen-flash-server 之前试过 vLLM、llama.cpp、SGLang 这些主流方案,各有各的问题:有的对 RDNA 核显支持不友好,有的统一内存利用率不高,有的部署起来要折腾 CUDA 相关依赖。halogen-flash-server 的定位更像是专门给“大内存、高带宽、统一内存架构”优化的轻量推理服务,它内置了 FlashAttention 相关的优化,也支持连续批处理和前缀缓存,实测对 Strix Halo 这类平台适配度明显高一个档次。
1.2 适合哪些人和哪些场景
如果你符合下面任意一条,这套方案可以直接抄作业:
- 有一台 64GB 以上内存的 Strix Halo 迷你主机,想跑 30B 以上的本地大模型;
- 想给团队或自己搭一个内网可访问的 LLM 服务,但没有独立显卡的预算;
- 对数据隐私敏感,模型必须本地部署,同时不想牺牲太多推理速度;
- 已经试过 llama.cpp,但觉得并发一上来就崩、或者长上下文处理速度不够满意。
我自己就是典型的第二类用户。之前一直在云端 API 和本地小模型之间反复横跳:云端有隐私顾虑,本地小模型(7B、13B)智商又不太够用。这台 Beelink Strix Halo 到手后,我的目标就很明确——把 70B 级别的Qwen2.5 量化版跑起来,让它当一个能同时服务几个人的内网 AI 助手,日常查代码、写文档、做摘要,速度不能差太远。
2. 硬件环境与部署方案选型
2.1 这台机器的具体配置
我手头的这台 Beelink Strix Halo 具体配置是:AMD Ryzen AI Max+ 395(16核32线程)、Radeon 8060S(40CU)、128GB LPDDR5X-8533、1TB PCIe 4.0 SSD。准系统价格不便宜,但仔细算一下账:同样的预算买一块 24GB 显存的独显工作站也就刚起步,而这块平台直接给到 128GB 统一内存,能跑的量级完全不一样。
先把理论带宽这件事算透。Strix Halo 用的是 256-bit 位宽的 LPDDR5X-8533,理论带宽 = 256bit × 8533MT/s ÷ 8 = 273GB/s,实际跑分一般能看到 240~260GB/s。这跟 GDDR6 独显比不算夸张,但重点是容量大——你不需要把模型切分到多张卡上,一个进程就能把 70B 模型全部放进内存。
这套配置有几个地方需要注意。第一,内存是板载的,出厂定了多少就是多少,不能后期升级,所以买的时候就要想清楚是 96GB 还是 128GB。第二,SSD 尽量选 PCIe 4.0 的,因为首次加载模型要从硬盘读权重,读盘速度会影响冷启动时间。我用的 1TB 盘实测从按下启动到模型加载完成大约 40 秒,大部分时间都花在验证权重和建立内存映射上。
2.2 为什么选 halogen-flash-server 而不是 vLLM 或 llama.cpp
选型这事我前后折腾了两周,不是随便定的。先说 llama.cpp,它其实已经做得很好,特别是 llama-server 带 OpenAI 兼容接口后实用性提升不少,但它单并发表现不错,多并发连续批处理时调度策略比较简单,长上下文下性能衰减比较明显,而且 FlashAttention 方面对 RDNA 的优化不算激进。
vLLM 是大厂标配,但恰恰因为“大厂”,它对 CUDA 生态依赖较重,虽然在 ROCm 上也能跑,但安装 ROCm 版本的 vLLM 在 Ubuntu 上需要踩不少坑,编译时间动不动就半小时起步。SGLang 更激进,功能更新快,但同样是 CUDA 优先,对 Strix Halo 这种 APU 平台的适配文档基本是空白。
halogen-flash-server 的设计思路很像“为统一内存而生的轻量 vLLM”:支持 PagedAttention 的分页管理,内核层面针对 RDNA 3.5 的 WMMA 指令做了优化,并且直接支持 GGUF 格式的量化模型——这点很实用,因为 GGUF 的生态里有大量现成的量化好的模型文件,不用像 vLLM 那样必须转 safetensors 格式。
更重要的是它支持统一内存的零拷贝策略。传统推理框架在“独显+共享内存”环境下,需要先把权重从 CPU 内存拷贝到显存,而 Strix Halo 上 CPU 和 GPU 共享同一块物理内存,权重加载基本是 mmap 之后直接引用,省去了一整轮拷贝开销。这就解释了为什么同样的模型,在别的方案上启动要花几分钟,在 halogen-flash-server 上几十秒就绪。
2.3 系统安装与基础环境配置
我装的是 Ubuntu 24.04.2 LTS,主要是图省心,ROCm 和 amdgpu 驱动的支持比 22.04 好很多。安装过程没有特别的地方,唯一要提醒的是 BIOS 里两个设置:一个是把 TGP(整机功耗限制)从静音模式的 54W 调到性能模式的 120W,另一个是确认内存频率跑在 8533,而不是降频到 6400。一开始我没调 BIOS,系统里看内存频率只有 6400,带宽掉了一大截,推理速度直接受影响。
驱动这块其实比我想象的顺利。Strix Halo 的核显在 Linux 下用的是 amdgpu 内核驱动,Ubuntu 24.04 自带的内核版本就能正确识别,不需要额外装闭源驱动。装完系统后只需要确认几件事:rocminfo能看到 GPU 节点、clinfo能看到 OpenCL 平台、以及/dev/kfd设备存在。如果这三项都正常,ROCm 的软件栈就可以直接装了。
# 确认 GPU 是否被正确识别 rocminfo | grep "Name:" # 查看内存带宽(跑个简单 benchmark) # 这个工具可以顺手装下,用来确认内存频率没有降档 sudo apt install bandwidth64 bandwidth64实测下来,memory bandwidth 数值在 240GB/s 以上就说明内存频率正常,如果只有 180GB/s 左右,大概率是跑在 6400 上了,这时候去 BIOS 里把内存档位改回 8533 再重启。
3. 部署 halogen-flash-server 的完整流程
3.1 下载安装与目录规划
halogen-flash-server 提供预编译的二进制包,这比从源码编译省了太多事。我选择的是直接在 GitHub Releases 页面下载对应 Linux x86_64 的归档包,解压到/opt/halogen,然后建一个软链接到/usr/local/bin方便调用。数据目录和模型目录我习惯单独放,模型统一丢在/models下,日志写在/var/log/halogen,这样后续升级服务或者换模型时不会弄乱。
# 下载解压(版本号以官方 Releases 为准) cd /opt sudo wget https://github.com/halogen-flash/halogen-flash-server/releases/download/v0.4.2/halogen-flash-server-v0.4.2-linux-amd64.tar.gz sudo tar -xzf halogen-flash-server-v0.4.2-linux-amd64.tar.gz sudo mv halogen-flash-server-v0.4.2-linux-amd64 halogen # 创建软链接 sudo ln -s /opt/halogen/halogen-flash-server /usr/local/bin/halogen-flash-server # 准备模型目录 sudo mkdir -p /models这里有个容易被忽略的点:halogen-flash-server 的预编译包会同时带上配套的 rocm 运行库,所以系统里不需要再单独装完整的 ROCm 开发套件,这省了大概 2GB 的磁盘空间和很多环境变量配置的麻烦。你要是之前装过 ROCm 的其他版本,建议卸载干净,避免运行库冲突导致服务启动时报libamdhip64.so版本不对的错。
3.2 模型文件选择与下载
模型选择上,我最终锁定了 Qwen2.5-72B-Instruct 的 GGUF 量化版,具体是 Q4_K_M 量化,文件大小约 46GB。这个选择有几个考虑:72B 参数在 128GB 内存平台上是“刚好能装下且有余量跑长上下文”的甜点规模,Q4_K_M 在质量和体积之间比较均衡,比 Q4_0 更聪明的体感很明显,而 Q5_K_M 要多占 10GB 空间,对性能提升其实有限。
下载的时候直接可以从 Hugging Face 拉,国内网络环境的朋友可以用镜像站,这个看自己的网络情况来定。下载完务必做一遍校验,GGUF 文件这么大,传输中途损坏的概率不是零。如果 sha256 对不上,加载时大概率会直接报错,浪费时间排查,不如一开始就确认好。
# 下载模型文件(示例,具体到 HF 页面复制下载链接) cd /models wget https://huggingface.co/Qwen/Qwen2.5-72B-Instruct-GGUF/resolve/main/qwen2.5-72b-instruct-q4_k_m.gguf # 校验文件完整性 sha256sum qwen2.5-72b-instruct-q4_k_m.gguf3.3 启动服务与关键参数解读
第一次启动时我没有直接接上生产配置,而是先用最简参数验证整条链路通不通。这里我建议新手也这样做,先用小模型(比如 7B 的量化版)跑一次,确认服务能正常起来、API 能响应,再切换到 72B 大模型,把排查问题的范围缩小。启动命令长这样:
# 先用 7B 模型验证链路 halogen-flash-server \ --model /models/qwen2.5-7b-instruct-q4_k_m.gguf \ --host 0.0.0.0 \ --port 8080 \ --max-model-len 32768 \ --gpu-memory-utilization 0.90 \ --block-size 128 \ --max-running-requests 8这里每个参数都有讲究:
--host 0.0.0.0:允许局域网内其他设备访问,如果只本机用改成 127.0.0.1 即可。--max-model-len 32768:最大上下文长度,32K 是我测试下来比较舒服的档位。调到 64K 或 128K 需要预留更大的 KV cache 空间,我这里为了并发能力做了取舍。--gpu-memory-utilization 0.90:控制 KV cache 能占用多少内存池比例。因为统一内存没有显存/内存之分,这个参数实际上是限制服务本身最多吃掉系统内存的比例,0.90 意味着留出 10% 给 OS 和别的进程。如果你在同时跑别的东西,建议降到 0.80。--block-size 128:PagedAttention 的页大小,越大内存碎片越小,但会略微影响调度粒度和缓存复用效率。--max-running-requests 8:最大并发请求数,超过的排队等待。
服务启动后会打印一段日志,显示模型加载进度和 KV cache 的大小,等待进度条跑满后就能看到server started的提示。然后可以用 curl 快速验证一下:
curl http://localhost:8080/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model": "qwen2.5-72b", "messages": [{"role": "user", "content": "你好,简单介绍一下你自己"}], "max_tokens": 200}'看到正常返回 JSON 就说明链路没问题。验证完 7B 模型后,杀掉进程,把--model参数换成 72B 模型路径,重跑一次。72B 的加载时间会比 7B 长不少,从日志里能看到 mmap 权重的时间,耐心等就行。
3.4 用 systemd 管理服务实现开机自启
如果你只是临时测一下,直接在终端跑没问题。但要想把它当成内网常驻服务,最好用 systemd 托管,这样断电重启后能自动拉起。我的 service 文件长这样:
[Unit] Description=halogen-flash-server After=network-online.target [Service] Type=simple ExecStart=/usr/local/bin/halogen-flash-server \ --model /models/qwen2.5-72b-instruct-q4_k_m.gguf \ --host 0.0.0.0 \ --port 8080 \ --max-model-len 32768 \ --gpu-memory-utilization 0.85 \ --block-size 128 WorkingDirectory=/opt/halogen Restart=on-failure RestartSec=5 User=root LimitNOFILE=65536 [Install] WantedBy=multi-user.target有几个细节提醒一下。User=root不是必须的,但如果你模型文件放在系统目录里,用普通用户跑可能会遇到权限问题,调试起来烦,所以测试阶段先 root 跑没毛病,稳定后可以再降权。LimitNOFILE=65536是因为服务在高并发下会打开大量文件描述符,默认 1024 不够用,压测时容易莫名其妙报 “Too many open files”。
配置好后执行systemctl daemon-reload && systemctl enable --now halogen-flash-server,之后就能用systemctl status halogen-flash-server看状态了。
4. 性能实测数据与调优分析
4.1 官方宣称速度与实际测试对比
halogen-flash-server 的官方文档对 Qwen2.5-72B-Instruct Q4_K_M 在 Strix Halo 平台上的宣称速度是“单流 decode 约 60~70 tokens/s,prefill 约 1200~1500 tokens/s”。我拿到手第一件事就是实测打这张脸——结果脸没打成,反而基本坐实了。
我的测试方法是动态测而不是看单次生成的均值,因为 LLM 生成速度在不同阶段差异很大。用了两个工具:一是项目自带的 benchmark 脚本,二是自己写的多并发压测脚本。先看单流的结果:
| 指标 | 官方宣称 | 我的实测 | 达成率 |
|---|---|---|---|
| 单请求 decode 速度 | 60~70 tokens/s | 56.8 tokens/s | 约 90% |
| 首 token 延迟(TTFT) | 500ms 以内(32K上下文满) | 420ms | 达标 |
| 多请求(4并发)总吞吐 | 100~120 tokens/s | 96 tokens/s | 约 85% |
单流 56.8 tokens/s 是什么概念?你读文章大概一秒钟读 10 来个字,它一秒钟能生成差不多 50 多个汉字,不到 20 秒就能写完一段 1000 字的小作文。这个速度做对话已经完全感觉不出“AI 卡顿”了,体感上和云端的 GPT-4o mini 轻度比起来差距很小。
这里有个重要的前提要说清楚:官方宣称的速度是在“默认参数+室温25℃+功耗墙解除”的条件下测的。我这个实测是在 120W TGP、室温 27℃、连续跑了 2 小时后测的,温度上来后 APU 会稍微降一点频率,所以 90% 的达成率我认为非常合理。如果你想无限逼近官方数值,开机后先跑一次冷的,温度没起来之前测基本能到 60+。
4.2 不同量化档位和上下文长度的性能差异
除了默认的 Q4_K_M,我还对比了 Q5_K_M 和 Q3_K_S 两种量化在速度和生成质量上的区别。同一个模型,三种量化跑出来的速度变化很有意思:
| 量化类型 | 文件大小 | 实测 decode | 体感质量 |
|---|---|---|---|
| Q3_K_S | 约 32GB | 63.4 tokens/s | 明显变笨,多轮对话经常答非所问 |
| Q4_K_M | 约 46GB | 56.8 tokens/s | 质量好,日常够用 |
| Q5_K_M | 约 55GB | 49.2 tokens/s | 比 Q4 稍好,但差距不大 |
从性能角度,Q3 最快但质量不可接受,Q5 更慢但质量提升不明显,Q4_K_M 确实是 72B 模型在这个平台上的甜点选项。这个结论和社区里“Q4_K_M 是质量/速度平衡点”的普遍认知完全一致。
上下文长度对速度的影响也实测了。max-model-len从 8K 调到 32K,单请求 decode 几乎没有变化,因为 decode 瓶颈在权重读取带宽,跟上下文长度关系不大。但 prefill(处理输入)阶段会明显变慢——32K 上下文的 prefill 速度比 8K 慢了接近一倍,这符合预期,因为 prefill 是计算密集型,上下文越长计算量越大。
4.3 并发吞吐与内存带宽之间的关系
这条其实才是我最想分享的经验。Strix Halo 这种统一内存平台的奇妙之处在于:多并发请求时,内存带宽是共享的,所以总吞吐不等于单流速度乘以并发数。我实测的结果是:并发从 1 加到 4,总吞吐从 56.8 tokens/s 提升到 96 tokens/s,近乎线性但没到 4 倍;加到 8 并发,总吞吐基本卡在 100 tokens/s 左右不再涨。
说明硬件瓶颈就是内存带宽本身。4 并发时每个请求分到的带宽少了,单个请求的 decode 掉到了 24 tokens/s 左右,但总吞吐翻了一倍,对“多用户同时用”的场景来说这很划算——每个人感知上变慢了一点,但整体利用率上去了。
调优上,我最终把--max-running-requests设成了 12,配合--block-size 256。页块改大后连续批处理的调度效率更高,实测 8 并发下总吞吐从 96 提到了 103 tokens/s,有微小但真实的提升。如果你的使用场景是“自己一个人用”,max-running-requests保持 4 就行,没必要为了跑分牺牲单请求延迟。
5. 常见问题与排查实录
5.1 内存频率缩水导致速度减半
这是我在整个部署过程中遇到的第一个大坑。装完系统第一次跑 benchmark,带宽只有 180GB/s 左右,单流速度只有 28 tokens/s,看官方数据怎么都对不上。查了半天才发现是内存频率跑在 6400 而不是 8533。
LPDDR5X 在部分板子上默认不会跑满最高频率,BIOS 里通常有个选项,不同品牌的叫法不一样:有的叫 “Memory Frequency”、有的叫 “XMP/EXPO Profile”,Strix Halo 平台要手动选到 LPDDR5X-8533 档。改完重启后带宽立刻回到 240GB/s 以上,推理速度也随之翻倍。
如果你也遇到速度对不上的问题,第一步永远是先确认这个,而不是急着调各种软件参数。
5.2 服务启动即崩溃:mmap 空间不足
第一次加载 72B 模型时,服务跑到 60% 左右直接报错退出,日志里写着 “failed to mmap weight file”。排查了一下发现是/dev/shm或者进程可用的地址空间不够。GGUF 加载时会做内存映射,如果系统限制了单个进程的虚拟内存大小,大文件映射就会失败。
我的解决办法是检查ulimit -v和/dev/shm的大小,并把LimitNOFILE和LimitAS调大。另一种情况是系统开启了 overcommit 限制,导致大块 mmap 被拒绝,可以通过sysctl vm.overcommit_memory=1临时放开(重启会失效,要写进/etc/sysctl.conf)。
5.3 多并发时 OOM 与客户端超时
4 并发以内很稳,但调到 8 并发后偶发请求失败,服务日志里能看到 cgroup OOM 记录。原因很直接:--gpu-memory-utilization 0.90给 KV cache 留的空间是固定的,并发越多,每个请求在 KV cache 里占的块越多,如果超过预算就会拒绝新的请求。
解决思路有两个:一是把gpu-memory-utilization调低到 0.80,给 KV cache 的总量增加;二是限流,把max-running-requests从 12 调回 8。我最终选了后者,因为从带宽瓶颈来看 8 并发已经逼近硬件上限,再往上加并发只会增加排队延迟,总吞吐没什么提升,没必要牺牲稳定性。
5.4 温度墙导致的性能衰减
连续跑了 3 个小时后我注意到速度悄悄降了,从 56 tokens/s 跌到 50 出头。一看传感器数据,APU 温度已经顶到 92℃,功耗却从 120W 掉到了 90W。这就是温度墙在工作。
解决方法是调整散热策略:一是把机器放在通风好的位置,不要塞在柜子里;二是在 BIOS 里把风扇曲线调成“性能优先”;三是如果长时间 7x24 跑负载,可以考虑把 TGP 手动限制到 100W,温度稳在 85℃ 以内,性能比 120W 温度顶墙时反而更稳定。这也算是一个“满血比降频更差”的经典案例。
下表是问题排查速查版:
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| 速度只有宣称的一半 | 内存频率降档 | 进 BIOS 将内存频率设为 8533 |
| 启动加载中途崩溃 | mmap 空间不足 | 调大 ulimit、关闭 overcommit 限制 |
| 并发升高后请求失败 | KV cache 超预算 | 调低 gpu-memory-utilization 或限制并发数 |
| 长时间运行速度下降 | 温度墙触发 | 改善通风、调风扇曲线、适当限制 TGP |
6. 最终体验总结与一些实用建议
跑了一周下来,我对“Beelink Strix Halo + halogen-flash-server”这套组合的评价是:在迷你主机这个形态里,这基本是当前跑本地大模型的天花板配置了。统一内存 128GB 带来的容量优势,加上 256GB/s 带宽撑起的推理速度,让它既能跑 70B 级大模型,又能保持 50+ tokens/s 的可用速度,同时整机功耗还控制在 120W 以内。这种“能跑大模型的小钢炮”体验,在两年前是想都不敢想的。
根据我自己的使用经验,最后给几点建议。第一,如果你也打算这么玩,预算允许的话直接上 128GB 版本,因为 96GB 跑 72B Q4 虽然也能跑,但 KV cache 空间会被压缩,并发一高就容易顶到天花板。第二,系统装好后第一件事确认内存频率和 TGP 功耗设置,这两个是最大的性能变量,不调好的话后面一切调优都白费。第三,模型量化选择上别贪心,Q4_K_M 是 72B 级别模型性能和质量的甜点,没必要为了几个百分点的质量提升去选 Q5 或 Q6,性价比太低了。
最后再分享一个小经验:多并发场景下别迷信 “并发数越大越好”。内存带宽就那么多,并发上去之后每个请求会分摊不少速度,单请求延迟会明显变大。如果你是自己在用,并发 2~4 就最舒服;如果想让团队里几个人一起用,限制在 6~8 并发的整体体验最均衡。拿捏好这个度,这台小小迷你主机能发挥出的价值,比你想象中大得多。