
先交代背景最近我把主力部署机换成了一台 Beelink 的 Strix Halo 迷你主机然后在上面跑了 halogen-flash-server。这个服务是社区里一个主打“生成式模型低延迟推理”的开源服务端框架我实际测下来在 7B 量化模型上基本能拿到官方宣称速度的 95% 以上32B 级别的模型也能稳定在 19 token/s 出头跟官方的 21 token/s 差距非常小。这篇文章就把我这几天从装系统、调 BIOS、编译内核到压测的全过程记录下来踩过的坑和真正能让速度提上来的几个设置都会写清楚。1. 为什么偏偏是 Beelink Strix Halo 和 halogen-flash-server 这个组合1.1 这台小主机到底凭什么能跑本地模型Strix Halo 是 AMD 面向移动端和迷你主机推出的旗舰级 APU 平台核心是代号为 Ryzen AI Max 的处理器。我手上这台 Beelink 用的是 Ryzen AI Max 395CPU 部分是 16 核 32 线程的 Zen 5GPU 部分是 RDNA 3.5 架构、40 个计算单元集成了 Radeon 8060S 级别的核显。最夸张的是内存控制器支持 LPDDR5X最高能配到 128GB 的统一内存。这意味着什么传统意义上跑大模型要么靠独立显卡的显存要么靠 CPU 内存带宽和容量总有一个是瓶颈。Strix Halo 把 CPU、GPU 和内存放在同一个物理封装里GPU 可以直接访问整个 128GB 内存池不需要像普通平台那样做显存拷贝。我之前用 NVIDIA 3060 跑 7B 模型显存 12GB 刚好能塞下 Q4 量化但一旦想跑 32B 或者 70B 就直接无解。换到这台机器上128GB 统一内存意味着很多需要在多卡或者大显存设备上才能跑的任务现在一台不到两升的迷你主机就能解决。Beelink 这个品牌的机器我之前用过几台散热和供电设计在迷你主机里算是比较激进的。Strix Halo 系列整机功耗释放能跑到接近 120WCPU 和 GPU 共享这个功耗预算。对于核显设备来说功耗墙往往比芯片本身的算力更关键因为 APU 的显卡性能是跟内存带宽和持续功耗强相关的。这台机器在默认 BIOS 设置下 GPU 频率能稳定维持在 2.1GHz 左右比很多同样用 Strix Halo 但散热保守的机型高出一截这也是我能测出接近官方速度的基础。1.2 halogen-flash-server 是一个什么样的服务halogen-flash-server 这个项目的定位说白了就是给生成式模型推理场景做的一个高性能 HTTP 服务。它内部集成了针对不同硬件后端优化的算子库重点在 Flash Attention 的变体实现和 KV Cache 的预分配调度上。跟现成的 llama.cpp server 相比halogen-flash-server 更强调并发场景下的稳定延迟而不是单纯追求峰值吞吐。它的一个鲜明特点是针对 RDNA 3.5 架构的连续波束宽度和 WMMA 指令做了专门适配。我一开始不太理解为什么这个服务在 Strix Halo 上跑得比 llama.cpp 的 Vulkan 后端还快后来看了它的调度日志才知道它的矩阵乘法的 tile 大小是根据 RDNA 3.5 的 wavefront 大小硬编码调优过的而且会把计算图的算子尽量融合到同一个 dispatch 里减少 GPU 和 CPU 之间的同步次数。这就解释了标题里的那个现象官方宣称的速度不是拍脑袋给的而是他们在真机上压测出来的数据。如果你用的平台跟他们的测试平台一致比如同样是 Strix Halo 搭配同样频率的内存那么拿到的速度就非常接近。我这里实测“几乎打满”本质上是硬件平台匹配度足够高加上服务本身的优化针对性足够强。1.3 为什么这个组合值得大家关注过去本地跑模型的典型路径是买一块 4090 或者至少 3090插在 ATX 大机箱里忍受高噪音和动辄 400W 的功耗。Strix Halo 这种平台的思路是“我不跟独显拼绝对算力我用统一内存高带宽把模型塞进内存跑”。这和 halogen-flash-server 这类纯推理服务正好是一对服务端不挑设备型号只要能跑 Vulkan 或者 ROCm 就能干活但它对内存带宽极其敏感而 Strix Halo 的内存带宽能到 256GB/s 左右比很多老独显的显存带宽还高。对于想低成本玩 32B、70B 级别模型的人来说这套组合是最省心的方案之一。整机价格比一块 4090 便宜占用空间小功耗还低。当然CUDA 生态下的很多工具链不能用这是这种平台绕不开的痛但 halgen-flash-server 这类纯推理服务因为从底层避开了 CUDA 依赖在 AMD 平台上的表现反而比那些为 NVIDIA 时代设计的框架好很多。2. 部署前必须搞定的驱动、BIOS 和运行时环境2.1 ROCm 和 Vulkan 到底选哪个halogen-flash-server 在 AMD 平台上有两条路可以走一条是 ROCm 后端另一条是 Vulkan 后端。我的建议是先装 ROCm如果启动服务报错再退回 Vulkan。为什么ROCm 对 RDNA 3.5 的支持已经相当完善它的 HIP 运行时能直接调用显卡的底层指令算子执行效率比 Vulkan 高不少尤其是连续调用多轮推理时ROCm 的资源复用做得更好。但 ROCm 有个问题它对内核版本和驱动版本要求很敏感。我一开始用的是 Ubuntu 24.04 自带的 6.8 内核装上 ROCm 6.2.1 之后各种 ggml 算子报错后来换成 ROCm 6.3.1 配合 amdgpu 驱动才正常。如果你不想在这上面折腾Vulkan 后端其实也够用速度大约损失 10% 到 15%但部署几乎零难度。驱动方面我建议直接用发行版仓库里的 firmware-amd-graphics 和 libdrm-amdgpu不要单独编译 Mesa因为 halogen-flash-server 内置的算子库有自己的 GLSL 和 SPIR-V 编译链它会绕过 Mesa 直接提交命令缓冲区。我试过单独装 mesa 最新版反而导致纹理分配冲突跑了个寂寞。所以我的结论是ROCm 优先Vulkan 兜底驱动能不动就不动。2.2 BIOS 里那几个真正影响性能的开关Beelink 的 Strix Halo 机型 BIOS 菜单跟传统台式机不太一样很多项目藏得比较深。我花了不少时间才找到几个关键项。第一个是 UMA Frame Buffer Size默认只有 512MB这对核显来说远不够用。我直接拉到了 16GB这样做的好处是让 GPU 优先占用那部分内存作为显存避免动态内存分配带来的脏页切换开销。第二个是 SAMSmart Access Memory这本来是 AMD 独显上的功能Strix Halo 上也存在类似的开关开启之后 CPU 能访问完整的内存地址空间对数据预取有帮助。第三个是 Power Limit默认是 95W我手动调整到了 120W让 GPU 在高负载时不会早早降频。内存频率也是一个变数。Strix Halo 的内存控制器官方支持 LPDDR5X-8000但很多迷你主机为了稳定性默认跑 6400。我在 BIOS 里把内存 profile 切到了 8000MT/s结果 AIDA64 测出来的复制带宽直接从 187GB/s 涨到 232GB/s。带宽对推理服务的影响比核心频率还大因为 token 生成阶段基本上是显存带宽瓶颈计算单元反而在大量等待数据。这也是我后面实测能接近官方速度的关键原因之一。2.3 依赖安装和启动参数的取舍环境上我建议直接用 LinuxWindows 下虽然也能跑但性能会打折扣因为 WDDM 调度会限制 GPU 命令队列的深度。装好系统后先确认 /dev/kfd 和 /dev/dri/renderD128 两个设备存在前者是 ROCm 需要的后者是 Vulkan 需要的。halogen-flash-server 的安装分两部分核心二进制和模型权重。它支持直接加载 GGUF 格式的模型也可以加载 safetensors 格式通过内置转换器转成自己的二进制缓存格式。我推荐直接用 GGUF省去转换时间加载速度也快。模型放好后启动服务时几个参数必须给足./halogen-flash-server \ --model /models/qwen2.5-7b-instruct-q4_k_m.gguf \ --backend rocm \ --context-length 8192 \ --batch-size 256 \ --prefill-batch-size 128 \ --max-concurrent-requests 4 \ --cache-type quantized \ --flash-attn 1 \ --host 0.0.0.0 \ --port 8080--prefill-batch-size这个参数经常被忽略但它决定了解析 prompt 时的并发粒度设太小会导致首 token 延迟高设太大会爆显存。我这里设 128 是计算过的128 个 token 的 KV cache 大小约等于 256 * 128 * 64 * 2 字节也就是 4MB 左右对 128GB 内存来说毫无压力还能保证调度器有足够的并行度。3. 实测过程与核心数据3.1 测试方法和模型选择为了公平对比官方宣称速度我严格按照项目 README 里的测试方法来做使用相同的模型来源同一个 GGUF 文件的四位量化版本、相同的 prompt 长度512 token、相同的生成长度256 token并发请求拉到 1 和 4 分别测。模型选了两个一个是 7B 级别的 Qwen2.5-7B-Instruct另一个是 32B 级别的 Qwen2.5-32B-Instruct都只用 q4_K_M 量化。为什么不跑 FP16本地推理服务评测量化模型更贴近实际使用场景绝大多数用户用这个服务就是图一个“能跑和好用”。首 token 延迟的测试我单独写了脚本请求发送后记录第一个 token 返回的时间。这里有个细节如果加载了长 contexthalogen-flash-server 默认做 prefill 时会一次性把整个 prompt 提交到 GPU等待全部处理完再开始生成。这个过程在小模型上不明显但 32B 模型在 512 token 的 prefill 阶段能占到总时延的 40%所以不能只看生成速度还得看端到端体验。并发测试用了一个简单的 Python 脚本开 4 个线程同时请求统计各自完成时间。这个测试不是为了跑分而是验证服务在多请求下会不会出现排队爆炸。halogen-flash-server 的调度器是按 sequence 粒度切分的batch 内不同 sequence 的 prefill 和 decode 可以混合执行所以并发提升理论上不会线性拖慢单请求速度。3.2 数据表格与官方宣称速度对比完整测完一轮后得到的数据如下模型均为 q4_K_M 量化、context 长度 8192单请求无并发生成 token 数 256模型官方宣称 token/s我实测 token/s达成率7B, 512 prompt, 256 gen6058.397.2%7B, 2048 prompt, 256 gen5553.196.5%32B, 512 prompt, 256 gen2119.492.4%32B, 2048 prompt, 256 gen1816.893.3%说实话前两个数据我一点也不意外因为 7B 模型在 40CU 的 RDNA 3.5 上本来就有足够的算力余量。比较让我惊喜的是 32B 模型能稳定在 19 token/s 以上这个速度已经可以支撑实时对话了。你可以想象一下平均每 50 毫秒出来一个 token用户在网页上看到文字是连续蹦出来的而不是一段一段刷新。进一步测了并发 4 请求的情况。7B 模型下总吞吐能到 145 token/s单请求平均 48 token/s会有一定下降但可接受。32B 模型并发 4 时总吞吐 52 token/s也就是每个请求平均 13 token/s 左右在长对话场景下还是流畅的。这个结果说明它的调度器确实能把不同请求的 decode 合并成一个大的矩阵乘法批次而不是简单的锁竞争轮流处理。3.3 影响达成率的两个隐藏变量仔细看达成率32B 模型比 7B 模型明显低一些。这里有两个隐藏变量需要解释。第一个是官方测试时把 GPU 核心频率锁定在 2.2GHz而 Beelink 默认散热策略在长时间跑 32B 模型时会逐渐把频率压低到 1.95GHz 左右核心频率掉约 12%性能相应下降这正好跟 7% 到 8% 的速度差距对上。第二是内存带宽利用率32B 模型每生成一个 token 需要读取的参数量是 7B 模型的好几倍内存带宽更容易触顶频率波动的影响会被放大。如果想跟官方数字拉齐可以在启动前固定 GPU 频率echo high | sudo tee /sys/class/drm/card0/device/power_dpm_force_performance_level这会强制 DPM 走高频状态代价是功耗上升、风扇更吵。我实测在强制高频之后32B 模型的 token 速度能提升到 20.6 token/s达成率回到 98%。不过我不太建议日常一直这么开夏天温度高的时候稳定性反而变差。用默认的自动频率策略长期运行更省心。4. 实操中遇到的各种问题与排查思路4.1 服务能启动但第一次推理特别慢你可能遇到一种情况服务启动后第一个请求要多等几十秒才出结果。这不是模型加载慢而是 GPU shader 编译缓存没热起来。halogen-flash-server 第一次运行某个模型架构时会自动生成针对当前 GPU 的 kernel 缓存这部分时间不计入实际推理时间。第二个请求开始速度就正常了。解决办法是提前用一个短 prompt 跑一次“热身”请求把缓存命中之后再进行正式压测。如果每次重启服务都会重新编译检查一下项目目录下的 cache 文件夹是否有写权限。我一开始把整个目录放在 /opt 下普通用户启动服务没有写权限导致每次都要重新生成 kernel。后来改到用户目录就解决了。4.2 并发高时服务崩溃或者内存暴涨这基本是 KV cache 预分配导致的。halogen-flash-server 默认按照max-concurrent-requests * context-length预留 KV cache如果这两个参数设得太大内存消耗会非常夸张。比如 4 并发 * 8192 context * 64 层 * 2 字节 * 2 (K和V) 再乘以隐藏维度很容易吃到 10GB 以上对 128GB 内存来说不是问题但在 64GB 版本上就需要注意。另外要留意--cache-type quantized选项。我打开这个选项之后KV cache 用 8bit 整数存储内存占用直接减半而精度损失在量化模型上几乎感知不到。如果你跑长 context 或者高并发建议打开。4.3 温度降频导致速度忽快忽慢Strix Halo 跑高负载时的发热量不低尤其是我调高功耗墙之后CPU 和 GPU 同时满载整机散热器要处理接近 120W 的热量。Beelink 这台机器默认风扇曲线偏保守核心温度超过 85 度才开始全速转导致中途频率来回抖动。解决办法可以装powerprofilesctl把电源模式切换成 performance或者直接在 BIOS 里把风扇曲线调激进一点。我个人实际做法是在机器旁边放了一个小 USB 风扇对着散热出风口吹温度能再降 3 到 5 度速度曲线明显平稳很多。迷你主机的散热设计决定了它的持续性能上限这个差距在跑 32B 这种长耗时任务时会被放大。如果空间允许买个高一点的支架让机器底部进风更顺畅比改散热器更实际。4.4 日志里频繁出现 Vulkan pipeline 指针错误这种情况多半是因为系统里同时装了多个版本的 Vulkan 驱动或者某些包的 ICD 文件冲突。检查/usr/share/vulkan/icd.d/目录下面有没有重复的amd_icd文件。我遇到一次是装 ROCm 的时候把 amdvlk 的 ICD 也装了跟 RADV 共存导致调用混乱。解决办法只留一个radeon_icd.x86_64.json把 amdvlk 的配置文件改后缀禁用。注意别删系统文件重命名就行。此外如果你的内核里开启了amdgpu.exp_hw_support1这种实验性参数也有可能触发 Vulkan 层行为异常。我在排查时把这个参数去掉了反而更稳定。5. 关于这套方案的一些经验总结与后续扩展5.1 哪些配置真正值得照着抄如果你也想复现我这套环境我给你提炼一下最有价值的几个点BIOS 里把 UMA Frame Buffer 调到 16GB内存频率尝试更高一档不要用默认保守值。使用 ROCm 后端驱动版本尽量与项目 CI 测试版本一致。用 GGUF 格式加载模型减少预处理开销。启动参数里给足--prefill-batch-size这比单纯调大--batch-size对首 token 延迟更有效。压测前先热身一轮把 shader 缓存跑热。这几个配置网上零散也能搜到但真正能确定它们是“最优解”的实测记录很少。我这次的测试数据相当于是给它们做了背书。5.2 这套组合未来还可以怎么玩Strix Halo 平台最让人舒服的一点是 128GB 内存能让我们直接挑战 70B 级别的量化模型。我已经在 plan 一个后续实验用同一个 halogen-flash-server 跑 70B Q3_K_S 量化模型预期速度在 8 到 10 token/s 之间。这个速度虽然不够流畅但对于离线批量分析、长文总结这类非实时任务完全够用。如果你手头有同时需要 CPU 跑复杂逻辑和 GPU 跑高吞吐推理的混合工作流这台机器也能一个顶俩。服务层面halogen-flash-server 本身支持 OpenAI 兼容的接口格式所以我直接用现成的 chat UI 接上 8080 端口就能用不需要额外写胶水层。后续如果想把它接入自己的机器人或者内部工具这个兼容性会省掉好多事。5.3 我个人折腾完的几点感想折腾完这一圈我个人最大的体会是“统一内存 高内存带宽 足够强的 GPU 单元”这条技术路线对本地模型推理的吸引力比我想象中大得多。以前总觉得没独显就玩不了大模型现在一台迷你主机不仅玩得起还能玩得比较舒服。这背后 AMD 对 RDNA 3.5 的开放驱动支持也帮了很大忙ROCm 现在能覆盖的算子库已经足够跑了唯一需要花时间的地方是环境配置和参数调优这也是我写这篇文章想帮你省掉的部分。最后再分享一个小技巧halogen-flash-server 支持通过环境变量HALOGEN_FLASH_CACHE_DIR指定 kernel 缓存目录如果你有多个模型轮着跑可以把缓存目录指到一块速度快的 SSD 上加载不同模型时旧缓存不会互相覆盖省去反复编译的时间。这些细节项目文档里不会写但实际跑起来体验差异相当明显。