感谢xiaote的肯定 :)
上下文翻倍我觉得不会帮助日常对话,hermes 128k感觉基本上都覆盖了,加到256k会比较适合复杂任务,交给ds v4 pro或者claude去执行就好了.
换到metal 是不是还是会有prefill很慢的问题?推理的话差不多22tk/秒,那就意味着metal能跑到30-40. 对比下5090差不多60-70tk.
感谢xiaote的肯定 :)
上下文翻倍我觉得不会帮助日常对话,hermes 128k感觉基本上都覆盖了,加到256k会比较适合复杂任务,交给ds v4 pro或者claude去执行就好了.
换到metal 是不是还是会有prefill很慢的问题?推理的话差不多22tk/秒,那就意味着metal能跑到30-40. 对比下5090差不多60-70tk.
头一次发技术贴, 请留情.
本人最近有幸看到了lcz视频并且也开始试着玩hermes. Deepseek很好用但是我一直都有CC和一个打游戏用的5090. 想试试怎么样跑最好. 现在hermes跑在我m1 mac mini 上. DS真的好用很香, 但是抱着爱折腾的心里决定测试一下, 反正有CC帮忙, 很快就部署完成并且测试了下来. 部分由CC替写.
5090 PC
Mac Studio
云端
claude -p CLI 后面会有讲)Hermes
5个不同复杂度的任务,6个模型逐一跑。时间是端到端wall clock。
| 测试场景 | DS Flash | DS Pro | Qwen 5090 | Qwen MLX | Opus 代理 | Sonnet 代理 |
|---|---|---|---|---|---|---|
| 简单问答 | 4.0s | 5.1s | 2.7s | 26.1s | 6.0s | 4.5s |
| 中等代码 | 29.2s | 20.4s | 13.4s | 31.3s | 15.5s | 10.4s |
| 找BUG | 13.2s | 21.0s | 9.0s | 37.9s | 19.6s | 12.3s |
| 逻辑推理 | 9.1s | 15.3s | 10.1s | 32.0s | 10.8s | 16.3s |
| 复杂SQL | 36.4s | 31.3s | 26.5s | 49.2s | 20.4s | 32.4s |
Mac Studio MLX 全场垫底,简单问答都要26秒。后面有详细分析,先看每道题的具体回答。
What is the time complexity of binary search? One sentence.
| 模型 | 时间 | 回答 |
|---|---|---|
| DS Flash | 4.0s | Binary search has a time complexity of O(log n), repeatedly halving the search space with each comparison. |
| DS Pro | 5.1s | O(log n) — each step halves the search space. |
| Qwen 5090 | 2.7s | O(log n) |
| Qwen MLX | 26.1s | O(log n) — each step halves the search space, so it takes logarithmic time relative to the input size. |
| Opus | 6.0s | O(log n) — each comparison halves the search space. |
| Sonnet | 4.5s | O(log n) — each step halves the search space. |
正确性:全员正确,没啥好说的。Qwen 5090 最快最惜字如金,MLX 同一个模型反而写了一句完整的解释——可能是量化差异导致采样路径不同。
Write a Python decorator that retries a function up to N times with exponential backoff on exception. Include type hints.
| 模型 | 时间 | 字符数 | 风格 |
|---|---|---|---|
| DS Flash | 29.2s | 643c | 写了文件,没贴代码,讲解为主 |
| DS Pro | 20.4s | 436c | 写了文件,有on_retry回调 |
| Qwen 5090 | 13.4s | 3160c | 完整代码+示例+edge case |
| Qwen MLX | 31.3s | 2602c | 完整代码,结构跟5090几乎一样 |
| Opus | 15.5s | 1122c | 15行核心代码,ParamSpec完美推导 |
| Sonnet | 10.4s | 1118c | 跟Opus同思路,TypeVar bound |
正确性:
ParamSpec + TypeVar 完美保留被装饰函数签名,2**attempt 指数退避,没有一行废话。functools.wraps、使用示例全有。同一个模型,质量一致。TypeVar bound 代替 ParamSpec,有个 type: ignore 不太干净。merge_sorted 函数缺少处理剩余元素的逻辑。
| 模型 | 时间 | 诊断 |
|---|---|---|
| DS Flash | 13.2s | 发现文件已被修复(上下文污染),额外讨论了稳定性 |
| DS Pro | 21.0s | 正确,解释了slice安全性 |
| Qwen 5090 | 9.0s | 最快,简洁直接 |
| Qwen MLX | 37.9s | 正确,总结很清晰 |
| Opus | 19.6s | 完整修复代码+解释 |
| Sonnet | 12.3s | 附带了具体的输入输出例子 |
正确性:全员正确识别同一个bug(result.extend(a[i:]) + result.extend(b[j:]))。Sonnet的具体例子最直观:merge_sorted([1, 3], [2, 4, 5]) 返回 [1, 2, 3],丢了 4, 5。
30英尺深井,白天爬3英尺,晚上滑2英尺,第几天到顶?
全员回答:第28天 
| 模型 | 时间 | 风格 |
|---|---|---|
| DS Flash | 9.1s | 表格推演+通用公式+陷阱提醒 |
| DS Pro | 15.3s | 逐步推演+公式 (30-3)/1+1=28 |
| Qwen 5090 | 10.1s | Step-by-step + 陷阱分析 |
| Qwen MLX | 32.0s | 同样的思路,32秒属实慢了 |
| Opus | 10.8s | 5行搞定,极简主义 |
| Sonnet | 16.3s | 数学证明:(n-1)+3≥30 → n≥28 |
正确性:全员正确。经典陷阱是 30÷1=30天,正确答案是前27天净爬27英尺,第28天白天冲刺3英尺直接到顶不用再滑。
4张表联查,找回头客(2+完成订单)上季度Top 3品类收入+月环比增长率。
这题拉开差距最大:
| 模型 | 时间 | 字符数 | 亮点 |
|---|---|---|---|
| DS Flash | 36.4s | 2741c | LEFT JOIN pivot思路,附设计决策表 |
| DS Pro | 31.3s | 2750c | RANK()处理并列,附跨DB移植说明 |
| Qwen 5090 | 26.5s | 4107c | 硬编码日期,偏SQLite语法 |
| Qwen MLX | 49.2s | 4837c | 标准PostgreSQL,CROSS JOIN传参 |
| Opus | 20.4s | 2342c | 最快,额外算了avg_mom均值 |
| Sonnet | 32.4s | 2910c | RANK()处理tie,4个key decisions |
正确性排名:
strftime + 硬编码日期,不够通用。有意思的是同一个Qwen模型,5090 GGUF写出了SQLite风格,M4 Max MLX写出了标准PostgreSQL风格——量化方式的微妙差异影响了采样路径。
同一个 Qwen 3.6 27B,不同硬件不同量化:
| 测试 | 5090 CUDA | M4 Max MLX | 速度比 |
|---|---|---|---|
| 简单问答 | 2.7s | 26.1s | 9.7x |
| 中等代码 | 13.4s | 31.3s | 2.3x |
| 找BUG | 9.0s | 37.9s | 4.2x |
| 逻辑推理 | 10.1s | 32.0s | 3.2x |
| 复杂SQL | 26.5s | 49.2s | 1.9x |
简单问答差距9.7倍,复杂SQL只差1.9倍。差距随output长度增加而缩小——说明瓶颈不在generation而在prefill。
为了验证,做了一组纯prefill压力测试。固定 max_tokens=50(几乎不生成),逐步增大prompt长度:
| Prompt tokens | 5090 CUDA | M4 Max MLX | 速度比 |
|---|---|---|---|
| 119 | 1.1s | 3.3s | 3.1x |
| 1,019 | 1.1s | 7.2s | 6.4x |
| 5,019 | 2.0s | 22.6s | 11.6x |
| 10,019 | 2.5s | 28.7s | 11.7x |
| 20,019 | 4.1s | 63.3s | 15.3x |
几个关键发现:
5090 的 prefill 几乎是平的。 从119 tokens到20019 tokens,只从1.1秒涨到4.1秒——200倍的token量,耗时只增加了3倍。CUDA tensor cores的批量矩阵乘法在这里是碾压级的,大batch prefill几乎是计算bound而非memory bound。
M4 Max MLX 是线性增长。 119 tokens 3.3秒,20019 tokens 63.3秒,基本上每多1000 tokens就多3秒。MLX在Apple Silicon上的prefill实现是memory bandwidth bound的——M4 Max的统一内存带宽大概是546GB/s,看着不低,但跟5090的1.8TB/s GDDR7比差了3倍多,再加上CUDA的tensor core并行度优势,实际prefill吞吐差了10倍+。
这就是为什么Mac Studio跑Hermes这么慢。 Hermes Agent的系统提示词大概有6000-8000 tokens,每次请求Mac Studio光prefill就要20-25秒。5090处理同样的提示词只要2秒。简单问答的26秒里,有20多秒都在prefill,实际generation可能就3-4秒。
结论:agent场景下prefill性能 > generation性能。 如果你只是跑一个简单的chatbot,prompt短,MLX的generation速度其实还行。但一旦上了agent框架(Hermes、OpenClaw、AutoGPT之类的),系统提示词动辄上万token,prefill就成了致命瓶颈。M4 Max MLX在这个场景下基本不可用,只能当备机。
主力:DeepSeek V4 Flash
代码参谋:Claude Code(Opus/Sonnet)
备用:Qwen 5090
DS Pro:没有存在感
M4 Max MLX:准备退了
Claude Code 是个CLI工具不是API,没法直接给Hermes当provider用。所以写了个FastAPI服务把 claude -p 命令包装成 OpenAI 兼容的 /v1/chat/completions 接口,跑在 localhost:8765,注册成 macOS launchd 服务开机自启、挂了自动重启。这也是Claude code 帮我写的 
支持 --model opus 和 --model sonnet 两个档位,通过请求体里的 model 字段自动路由。
Hermes发请求的时候会注入自己的系统提示词(身份信息、人设、工具说明等),如果直接透传给Claude会有风险被收取API所以代理层做了一层自动替换:
Hermes Agent → AI assistant
NousResearch → (删除)
nousresearch.com → (删除)
HERMES.md → project rules
SOUL.md → personality config
delegate_task → subtask
hermes-cli tools → available tools
kawaii assistant → helpful assistant
nya~ desu~ → (删除)
不是简单的正则删除——会留下 "You are , a helpful assistant by ." 这种残句。所以做成了带上下文的替换,比如 (?:Visit )?nousresearch\.com(?:\s+for\s+more\s+info)? 这种模式,把整个句子片段干净地替换或删除。
Claude完全不知道请求来自Hermes。
模型名一开始叫 claude-code-cli,结果Hermes的provider自动检测看到名字里有 claude,直接归类为Anthropic provider,然后用Anthropic Messages API格式发请求——代理只支持OpenAI chat completions格式,直接404。
改名叫 local-code-agent 就好了。这个坑踩了半小时。
以上。有问题评论区聊。