跳转至内容
  • 版块
  • 最新
  • 标签
  • 热门
  • 用户
  • 群组
皮肤
  • 浅色
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • 深色
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • 默认(LCZ-Blue)
  • 不使用皮肤
  • LCZ-Green
  • LCZ-Blue
  • LCZ-Black
折叠
品牌标识

抡锤者

首页 版块 标签
硬件
装备秀
AI 广场
  1. 主页
  2. 版块
  3. LLM讨论区
  4. 【踩坑实录】本地 Qwen3.8-Flash-Next 在 agent 循环里"复读死循环":从 311×2 次重复调用到真根因(贪婪采样)

【踩坑实录】本地 Qwen3.8-Flash-Next 在 agent 循环里"复读死循环":从 311×2 次重复调用到真根因(贪婪采样)

已定时 已固定 已锁定 已移动 LLM讨论区
r9700qwen-flashstrata
6 帖子 6 发布者 811 浏览 2 关注中
  • 从旧到新
  • 从新到旧
  • 最多赞同
回复
  • 在新帖中回复
登录后回复
此主题已被删除。只有拥有主题管理权限的用户可以查看。
  • g dG
    g dG
    g d
    编写于 最后由 编辑
    #1

    先把机器和环境交代清楚,免得后面对不上号(这也是我一开始的排查方向之一:先确认不是硬件/环境的问题)。

    环境(完整)

    机器

    • CPU:AMD Ryzen 7 9700X(8 核 16 线程,最高 5.58 GHz,L3 32 MB),amd_pstate=active,测性能时把 governor 调成 performance、boost 打开
    • 内存:59 GiB
    • 主卡(跑模型的):AMD Radeon AI PRO R9700 32 GB(RDNA4 / gfx1201),ROCm 7.2.0,走 HIP 后端
    • 副卡:NVIDIA RTX 4060 8 GB(驱动 610.57.04)——跟这次推理无关,只是插着
    • 系统:Ubuntu 26.04 LTS,内核 7.0.0-30-generic,x86_64

    模型

    • Qwen3.8-Flash-Next,IQ3_S 量化,83.6 GB 的 MoE,两个分片(GSQ-RCO)
    • 上下文 256K,KV 用 int8、kv-resident 32768,MTP 草稿 spec 4,专家缓存开着(GPU 常驻 + 约 28.6 GiB 内存页缓存)
    • 实测速度:decode 54~75 tokens/s(短 prompt 能到 ~89),prefill 约 500~1300 tokens/s(看上下文多长),专家缓存命中率 95~97%——日常用完全够

    推理引擎

    • Strata 0.1.32:开源项目(MIT,上游 github.com/Niko1221/Strata),官方定位是"用一张 12–24 G 的 NVIDIA 卡 + 64 G 内存,在自己电脑上跑 125B 的 Qwen3.8-Flash-Next",默认面向 N 卡 + Windows/Linux 一键安装
    • 我们是把它搬到 AMD RDNA4 上跑(HIP/ROCm,加上 WMMA、hipBLASLt 调优表这些),所以配置里有一堆 STRATA_HIP_WMMA / STRATA_SELECT_WMMA / STRATA_PREFILL_MMQ 之类的开关
    • ⚠️ 关键前提:这个引擎没配 sampling 的时候默认是贪婪解码(greedy)——对单轮对话/代码生成这种要确定性输出的场景挺合理,但一放进 agent 循环就出大事

    Agent 壳

    • DeepSeek Harness(dsh)0.2.0-rc,agent 跑在 headless / web profile 里;权限模式设成完全放开,沙箱和审批都不介入(先把"卡审批"这条可能性排除掉)
    • 任务是一个 Rust 项目(多文件)的改造:agent 得自己读规格文档 → 改代码 → 编译 → 跑测试 → 写自查报告

    结论我先摆这儿,省得你往下翻半天:不是模型笨,是引擎默认走了贪婪解码。而 agent 每跑一步又会把"这次调用+结果"原样塞回上下文,上下文越长越自相似,贪婪一解码,输出就锁死在同一条上——稳定 2-周期。你在提示词里写一百遍"别重复",它照样重复。


    一、现场:看着忙得飞起,其实 53 分钟在空转

    看到的 实际
    工具调用总数 773
    其中两条一模一样的 bash 命令 各 311 次,加起来 622 次(80%)
    长啥样 严格 A/B 交替:命令1→命令2→命令1→命令2…(最长"连续相同"只有 2)
    那 311 次的结果 字节完全相同(同一个 MD5),而且不空、它想查的字段都在里面
    有内容的助手消息 整个回合就 1 条("我已掌握全部信息,开始实现")
    循环期间写文件 0
    正式卡住到被我掐 ~53 分钟

    掐掉之后 git status 看一眼:干净。一个字没写。

    记个教训:"文件 mtime 是新的 / 事件数在涨 / 进程活着"这三件事,全都是假信号。 复读的时候这三样一个不缺。别拿它们判断"agent 在干活"。


    二、我踩过的坑(这些假设全被我否了,贴出来给你省时间)

    我一开始的猜测 后来怎么否的
    上下文被裁剪,它"忘了自己读过" 时间线对不上:裁剪事件循环前后都有(11+4+1),而且循环期间每 10 分钟就裁一次。既不充分也不必要
    grep 窗口开小了,没看到想要的字段 直接否:311 次输出完全相同、非空、字段齐全。信息一直在上下文里
    它幻觉出一个不存在的类型,才反复 grep 只解释"为什么盯着同一个文件",不解释"结果一模一样还重发"。换个真名重查,照样循环
    harness 根本没做重复检测 方向对、事实错:harness 自带重复提醒插件,默认还开着

    那自带的守卫为啥没拦住?三层全漏:

    1. 它只数连续相同的调用 → 我这是 A/B 交替,"连续计数"永远是 1,阈值(3/5/8 三档)根本够不着 ⇒ 全场就响了 2 次;
    2. 它拿整个参数对象当键 → 模型只要把 description 改一下("第 N 次执行"),再随手补两个无关字段,就一次都数不上;
    3. 它只往上下文里塞提醒文字,不动控制流 → 后来实测提醒响了 8 次(连最高档都响了),模型在正文里连着写了三次"我已停止重复调用"——然后继续发同一条命令。

    三、真根因:引擎默认贪婪 × 自相似上下文

    证据是一步步挖出来的:

    1. 抓会话里每一轮的请求头:只有 {provider, model, maxTokens},没有 temperature;
    2. 翻 harness 的适配层代码:只有显式设置了 options.temperature 才会把它带上(if (options.temperature !== undefined));
    3. 看引擎侧 run config:没有 sampling 段 → 走引擎默认,而这个默认就是贪婪;
    4. 于是闭环成立:同一段上下文 → 同一个 argmax → 同一条命令;而 agent 每步都把"这次调用 + 结果"追加进上下文,上下文自相似 → 输出自相似 → 卡成 2-周期;
    5. 反证:引擎 run config 里加上 temperature=0.3 之后,同一个请求连发 3 次,输出各不相同(贪婪时是逐字节一样的)。

    为什么"写规矩"治不了这个病?

    我在任务书里加过一整套硬条款(同一条命令最多 2 次、一次读够、连续 5 次没推进就停下写报告)。结果:模型嘴上照做、行为照旧。

    道理很简单:贪婪解码下它没有"换个说法"的自由度。只要上下文差不多,输出就是那一条。这不是听话不听话的事。


    四、修:两头一起上(有前后对照)

    1)引擎侧——治根因(改配置,不用改引擎源码)

    sampling: { temperature: 0.3 }
    
    • 为什么改引擎不改 harness:大多数 harness 没有 per-model 采样字段,改引擎一次覆盖所有客户端;请求里显式带了 temperature 时,还是以请求为准。
    • 验证:引擎日志出现 sampling defaults from the config: temperature=0.3,同请求连发 3 次输出不同。
    • ⚠️ 有个副作用得知道:改完同一个输入不再有可复现的输出。以后别拿"同输入同输出"当验证手段了,要判稳不稳,就统计多次运行的重复率。

    2)harness 侧——兜底熔断

    判据(命中任一就动手):

    • 滑窗:最近 20 次调用里,同一条"语义载荷"出现 ≥8 次(bash 取整条 command,读写取文件路径+内容)——滑窗这一条专门干"连续判据抓不到的 A/B 交替";
    • 无信息:连续 10 次调用既没写文件、也没出现"以前没见过的调用"。

    处置两级:

    • 第一次命中:把这次调用拦下来,把"别重复了、用已有信息收尾"当工具结果还给模型;
    • 再犯:直接结束回合并落日志。

    写插件踩的两个坑:① harness 官方的"优雅收尾"接口在工具执行体外面调用没效果(收尾标记在更早阶段就结算了);② 拦调用时返回的反馈必须是"内容块数组",塞字符串会报 content.map is not a function。

    3)前后对照(同任务、同模型,隔离副本里跑,真实仓库零改动)

    修之前 修之后
    工具调用 101 153
    滑窗内重复峰值 9(最长连续 9) 1
    自带提醒命中 8 次(含最高档) 0 次(压根没复读)
    写文件 0 新模块 13.6KB + 3 个文件改动,还顺带出了演示和性能数据
    结局 回合 completed、退出码 0、答复"我已掌握全部信息,转入实现" ⇒ 假完工 正常推进中,被我按时间上限掐断

    再记一个坑:退出码 0 + completed ≠ 有产出。 判断有没有干活,用"工作区指纹":git status --porcelain -uall + git diff --numstat + 源码最新 mtime。别拿命令文本猜"这算不算写盘"——agent 爱用 bash heredoc 落盘,2>&1 这种字串一眼看过去很像写操作,其实什么都不是。


    五、同样在跑本地 agent 的,照这个清单查

    1. 先看你的客户端到底把采样参数发出去了没——抓一次请求体,看有没有 temperature。适配层"你不设置我就不带"是常态。
    2. 再看引擎/服务端默认用什么采样——不少后端默认就是 greedy(单轮推理常这么配),放到 agent 场景直接放大成复读。
    3. 重复判据用"滑窗内出现次数",别用"连续相同次数"——A/B 交替能骗过所有连续判据。
    4. 提醒 ≠ 拦截:只往上下文里塞提示的守卫,对这个病没用,必须"先拦调用、再结束回合"。
    5. 判产出用工作区指纹,别信 mtime / 事件数 / 进程存活 / 退出码。
    6. 调参和复现一定放隔离副本里跑:agent 会照着文档里的绝对路径直接改你的真实仓库(实测它的 grep 全打在真实仓库路径上)。unshare -m + bind 挂一个副本最省事。
    7. 把"假完工"当一等失效模式:回合 completed、工作区纹丝不动——长任务里这比直接崩还贵。

    六、还没搞定的

    • temperature=0.3 是"能跑"的起点,我没做系统调参。要是发现输出发散、格式不稳,可以试 0.2 + repetition_penalty 1.05,判据还是"多次运行的重复率",别看单次。
    • 熔断里"语义载荷"的定义:bash 取整条命令、写工具取"路径+内容"。实测仍有小概率把同一个文件的密集分段编辑误判成重复(后来把写工具的键改成"剔除包装字段后的整参数"——只改 description 的重复照样抓到,内容变了就不算重复)。
    • 这是单机、单模型、单个任务的经验(n=1)。如果你也遇到过"交替型"复读,欢迎补充:别的模型/引擎是不是也能用"greedy + 自相似上下文"解释掉。

    七、附:后端模型启动脚本(可直接抄)

    1)引擎运行配置 strata-iq3_s.json

    本次修复加的就是最后那个 sampling 块——不写它,引擎默认贪婪:

    {
      "exe": "$HOME/Strata/engine/strata",
      "args": [
        "--pack",            "$HOME/Strata-iq3s/packs/iq3_s",
        "--native",          "$HOME/Strata-iq3s/models/IQ3_S/Qwen3.8-Flash-Next-GSQ-RCO-IQ3_S-00001-of-00002.gguf",
        "--ple-gguf",        "$HOME/Strata-iq3s/models/IQ3_S/Qwen3.8-Flash-Next-GSQ-RCO-IQ3_S-00002-of-00002.gguf",
        "--expert-profile",  "$HOME/Strata/data/expert-profile.bin",
        "--expert-cache", "auto",
        "--mmap-experts", "--resident-cpu-experts",
        "--prefill", "auto",
        "--spec", "4",
        "--mtp", "$HOME/Strata-iq3s/mtp/rt",
        "--max-context", "262144",
        "--kv", "int8",
        "--kv-resident", "32768",
        "--spec-min-p", "0.5"
      ],
      "cwd": "$HOME/Strata",
      "tokenizer": "$HOME/Strata-iq3s/packs/iq3_s/tokenizer",
      "model_name": "qwen3.8-flash-next-iq3_s",
      "log": "$HOME/Strata/strata-iq3_s.log",
      "backend": "hip",
      "host": "127.0.0.1",
      "port": 8080,
      "env": {
        "STRATA_HIPBLASLT_TUNING": "$HOME/Strata/tools/hip/gfx1201-hipblaslt-100200.txt",
        "STRATA_PREFILL_MMQ": "1",
        "STRATA_PREFILL_RING": "96",
        "STRATA_IO_THREADS": "32",
        "STRATA_HIP_WMMA": "1",
        "STRATA_SELECT_WMMA": "1"
      },
    
      "sampling": { "temperature": 0.3 }
    }
    

    几个参数的作用:--spec 4 + --mtp 是草稿式投机解码;--expert-cache auto + --resident-cpu-experts 让 MoE 专家常驻(GPU 缓存 + 内存页缓存,实测命中 95~97%);--kv int8 + --kv-resident 32768 是 KV 量化与常驻量;--max-context 262144 = 256K。

    2)systemd 用户服务(端口 8081)

    # ~/.config/systemd/user/strata-iq3s.service
    [Unit]
    Description=Strata engine (Qwen3.8-Flash-Next IQ3_S)
    After=network-online.target
    
    [Service]
    Type=simple
    WorkingDirectory=%h/Strata
    ExecStart=%h/Strata/.venv/bin/python %h/Strata/serve/server.py \
              --engine strata --config %h/Strata/strata-iq3_s.json --port 8081
    Restart=no
    TimeoutStopSec=30
    KillMode=mixed
    MemorySwapMax=0
    MemoryMin=24G
    
    [Install]
    WantedBy=default.target
    

    ⚠️ 这行 MemoryMin=24G 是下限(保内存),别写成 MemoryMax:我们踩过——把它塞进带 MemoryMax=4G 的 cgroup scope 里,模型一涨到 4G 就被内核 OOM 杀掉(看着像"引擎自己崩了",其实是启动方式的问题)。

    3)启动器(精简版:起 / 停 / 等就绪 / 看指标)

    #!/usr/bin/env bash
    # strata-flash.sh —— 起服务 + 等就绪 + 打印模型与显存
    set -uo pipefail
    SVC=strata-iq3s.service
    PORT=8081
    BASE="http://127.0.0.1:${PORT}"
    LOG="$HOME/Strata/strata-iq3_s.log"
    
    wait_health() {                      # Strata 加载约 40~60s,别急着判失败
      echo -n "→ 等 health"
      for i in $(seq 1 60); do
        [ "$(curl -s -m 3 -o /dev/null -w '%{http_code}' "$BASE/health")" = "200" ] \
          && { echo " 就绪(约 $((i*2))s)"; return 0; }
        sleep 2; echo -n "."
      done
      echo " ❌ 超时;看日志 $LOG"; return 1
    }
    
    case "${1:-start}" in
      start)   systemctl --user start "$SVC" && wait_health
               curl -s -m 5 "$BASE/v1/models" | head -c 300; echo ;;
      stop)    systemctl --user stop "$SVC" ;;
      restart) systemctl --user stop "$SVC"; "$0" start ;;
      status)  echo -n "服务: "; systemctl --user is-active "$SVC"
               curl -s -m 5 -o /dev/null -w "health:%{http_code}\n" "$BASE/health" ;;
      health)  curl -s -m 5 "$BASE/metrics" | python3 -c '
    import json,sys
    e=json.load(sys.stdin).get("engine",{})
    for k in ("model","version","max_context","kv","kv_resident","expert_slots","spec","vram_free_mib"):
        if k in e: print(f"  {k}: {e[k]}")' ;;
      logs)    tail -f -n 80 "$LOG" ;;
      *) echo "用法: $0 [start|stop|restart|status|health|logs]" ;;
    esac
    

    单卡机器上记得:这个引擎和别的推理服务(另外的 llama/vLLM)抢同一张卡,启动前先把它们停掉,不然不是端口冲突就是显存不够。

    (路径里的 $HOME 按自己的目录替换;上游 Strata 自带的 run-iq3_s.sh 也能起,上面这份是我们这边加了"等就绪 + 健康指标"的日常用版本。)

    小注:配置里 "port": 8080,实际启动时由服务单元用 --port 8081 覆盖(同一台机器上 8080 留给别的引擎,方便来回切),别被两个数字绕晕。


    最后一句:如果你也撞上 agent 复读,先按上面第 3、5 条把现象量化(滑窗重复率 + 工作区指纹),再去查第 1、2 条的采样。"模型太笨"应该排在最后,不是第一个。

    1 条回复 最后回复
    2
    • 6
      6
      6cccccc
      编写于 最后由 编辑
      #2

      好耶,我最近使用也发现这个模型好像不是卡死,它倒是一直在干活,但是好像也没有快多少完成任务

      1 条回复 最后回复
      0
      • rich kingR
        rich kingR
        rich king
        编写于 最后由 编辑
        #3

        这问题我遇到过两次,很是崩溃,LZ帖子真是及时雨,马上安排Agent研究修复去,嘿嘿……

        1 条回复 最后回复
        0
        • ,perterP perter 引用了 此主题
        • stxpnetS
          stxpnetS
          stxpnet
          超凡大师
          编写于 最后由 编辑
          #4

          image.jpeg
          要改采样参数,用官方那套就没问题了。

          模式 temperature top_p top_k min_p presence_penalty repetition_penalty
          思考模式(规划/复杂任务) 1.0 0.95 20 0.0 0.0 1.0
          Instruct 模式(日常对话/直答) 0.7 0.80 20 0.0 1.5 1.0

          双卡3090 PCIE 4.0 16X/16X

          白天(宰相) Strata QFN3.8 IQ4_XS 262K ~120 t/s
          夜间(将军) vllm+swift 1.5 27B INT4-W4A8-dflash2 188K X 2 ~85 t/s
          1 条回复 最后回复
          0
          • ,terryT terry 固定了此主题
          • terryT
            terryT
            terry
            超级版主
            编写于 最后由 编辑
            #5

            很好的分享

            油管:https://www.youtube.com/@抡锤者

            1 条回复 最后回复
            0
            • xiaopbroX
              xiaopbroX
              xiaopbro
              德高望重
              编写于 最后由 编辑
              #6

              原来是这么回事,感谢分享

              1 条回复 最后回复
              0
              • ,系统 取消固定了此主题
              • ,PrioP Prio 引用了 此主题

              你好!看起来您对这段对话很感兴趣,但您还没有一个账号。

              厌倦了每次访问都刷到同样的帖子?您注册账号后,您下次访问时都将自动回到上次浏览的位置,并可选择接收新回复的通知(通过电子邮件或推送通知)。您还可以收藏帖子、为帖子点赞,以此向其他社区成员表达您的感谢。

              有了你的建议,这篇帖子会更精彩哦 💗

              注册 登录
              回复
              • 在新帖中回复
              登录后回复
              • 从旧到新
              • 从新到旧
              • 最多赞同


              • 登录

              • 登录或注册以进行搜索。
              • 第一个帖子
                最后一个帖子
              0
              • 版块
              • 最新
              • 标签
              • 热门
              • 用户
              • 群组