📎 配套脚本附件正文未内嵌 · 共 26 个 · 点开可在线查看
📚 另需公共库(正文未重复内嵌,点名字直接看):_agent_cfg.py、_bootstrap.py、_config.py、_plugin_util.py
📂 查看全部 761 个脚本附件 →
⚠️ 脚本内含明文凭据(与本页正文一致),请勿在公网环境直接运行。
Dify · 专题十四

知识库问答变慢 / 卡住 / 失败
排查思路、日志定位与容量规划

分层定性、十类场景、按人数容量规划。步骤未改,代码块已换成完整程序。

专题十四:知识库问答变慢 / 卡住 / 失败的完整排查与容量规划

本文基于 192.168.110.207(Dify 1.16.1 新 Agent)+ 116.62.10.183(vLLM Qwen3.6-27B,H20)实战。

覆盖三类问题:看起来慢、界面一直思考像卡死、已经失败但页面还停在工具调用。

全文四部分:排查思路、看什么日志怎么定位、分场景报错与解法、按公司人数和硬件给参数建议。

相关专题不要混:专题四是问答期协议/端点类报错,专题五是「模型已起来但 Dify 不通」,专题十一/十二是 max_tokens 落库,专题十三是 Rerank 怎么开。本文把它们串成一条可执行的排障主线,并补上容量规划。

运行环境:业务脚本均在 207 固定目录 /opt/workbuddy 执行,Python 为 /usr/bin/python3。 Windows 开发机仅保留 _probe_* 调试脚本;同步命令:python scripts_cursor/完整代码约定/00_部署_workbuddy到207.py。


目录

  1. 第一部分 原理与排查总图
  2. 第二部分 详细操作:看日志、怎么定位
  3. 第三部分 分场景:常见报错与解决办法
  4. 第四部分 按公司人数与硬件的参数建议

第一部分 原理与排查总图

一、本文解决什么问题

知识库智能体「不好用」时,用户看到的往往只有一句话:慢、卡住、没回答。后台其实可能是完全不同的层坏了。

本文要能做到:

  1. 先判断这轮是 还在跑、已经失败、还是 成功但就是慢。
  2. 按时间线把请求对齐到具体容器、具体接口。
  3. 对上号的场景,用已经验证过的办法修,而不是同时改十个参数。
  4. 按公司规模和 GPU/CPU/内存给出一套可落地的默认参数,避免把 100 人公司的配法直接抄到 500 人。

验收一条故障是否「定位完成」:

二、一条知识库问答实际走哪几层

新 Agent(mode=agent)问制度类问题,典型是两轮模型调用,中间夹一次检索:

text
用户发问
  │
  ▼
① docker-api-1 收请求,交给 docker-agent_backend-1
  │
  ▼
② 第一次 LLM(qwen3.6-27b / vLLM)
     决定调用工具 knowledge_base_search
     界面开始显示「思考中」
  │
  ▼
③ POST /inner/api/knowledge/retrieve
     Embedding 召回(Xinference bge-m3 + Weaviate)
     若开启 Rerank:再 POST Xinference /v1/rerank
     界面仍停在 knowledge_base_search
  │
  ▼
④ 第二次 LLM
     Prompt = 系统提示 + 历史对话 + 检索到的 Top-K 片段
     Qwen3.6 会先 thinking,再写正文
     若 thinking 把 max_tokens 用完,界面仍像卡在检索上
  │
  ▼
⑤ 写 messages 表,可选上报 Langfuse

关键误区:

三、先把表象分成四类(再动手)

类型页面上看库表 messages.status真正含义
还在跑思考、有工具名、时间在增加还没有最终行,或 latency 仍在涨等;同时看日志确认卡在哪一层
已失败,界面没刷新空泡、3/3、工具框一直在error已经结束。继续点发送只会更乱
成功但慢最终有正文normal,provider_response_latency 大性能问题,不是故障
明确报错文案红色错误 / 400error,error 字段有原文按文案进第三部分对号入座

人数再多,排查顺序也不变:先定性,再分层,最后才改参数。

四、排查总流程(不要一上来改配置)

text
A. 这轮对话的 message_id / 时间点是什么?
        │
        ▼
B. SELECT status, error, message_tokens, answer_tokens
   已是 error → 读 error 原文,跳到第三部分对应场景
   仍像 running → 看 agent_backend 当前卡在 chat 还是 retrieve
        │
        ▼
C. 用同一秒去对齐四类日志
   api / agent_backend / plugin_daemon / xinference(或 vLLM)
        │
        ▼
D. 确认 Prompt 体积和 max_tokens
   message_tokens 是否已经接近或超过 max_tokens
        │
        ▼
E. 只改一个根因对应的项
   改完不要点发布;新开对话验证

和已有专题的分工:

你看到的先看
System message must be at the beginning专题四
模型容器 Up,Dify 测连通失败专题五
Agent 里选不到知识库专题三
Max Tokens 改了又变回 8192专题十一
空泡 + token limit 2048专题十二
命中测试排序差、要开 Rerank专题十三
开了 Rerank 后变慢、思考停住、8192 thinking 耗尽本文

五、本次环境(对照用,换机器请重查)

项值
Dify1.16.1,http://192.168.110.207
Dify 机无 GPU,内存约 31Gi,同时跑 Dify + Weaviate + Xinference + Langfuse
应用播城行政问答智能体
应用 ID40e95fd3-e7f5-44f2-a03b-dc3e60413540
Agent ID01a012e7-bed3-7574-b0d1-a5cc79a0d3de
活动快照01a0135c-320e-79dc-97a0-94da9b904c13
编辑草稿01a012e7-bf60-7673-a894-64551d984a23
知识库ee2495bf-c370-49d1-8268-10c51f650fa6
EmbeddingXinference bge-m3,CPU,http://192.168.110.207:9997
RerankXinference bge-reranker-v2-m3,CPU
LLMqwen3.6-27b,vLLM,http://116.62.10.183:8000/v1
GPUH20 约 96GB,与业务 mxh_env / mxh_live 共享,--gpu-memory-utilization 0.75,--max-model-len 65536,--max-num-seqs 8
Dify 中 context_size64000
当前 max_tokens32768(2026-08-19 因 thinking 耗尽 8192 而改;改前是 8192)
当前检索语义检索 + Rerank,Top-K=5

UUID、密钥、IP 都是本环境实录。换环境必须重查,不要直接抄进生产脚本当常量。


第二部分 详细操作:看日志、怎么定位

Python 约定(全库统一)

- 每个操作步骤对应 /opt/workbuddy/scripts_cursor/ 下一个完整可运行程序(含 main()、登录、常量);不要从正文里抄片段拼程序。

- 有配置改动时提供 修改前 / 修改后 两个文件(文件名带 _修改前 / _修改后),正文附 改动对比 表。

- 换环境只改 /opt/workbuddy/scripts_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/_config.py。在 207 上运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/脚本名.py

- 程序索引见下文「本专题 Python 程序一览」;插件源码级补丁见各步骤正文(补丁也做成完整 apply 脚本)。

下面按真实顺序写。人在 207 上可直接 docker exec;从 Windows 工作区过去,普通 ssh 容易卡密码,用现有 dify_api.py(Paramiko)即可。

排查步骤速查(1~7)

步干什么做完应得到什么卡住 → 第三部分场景
1库表定性知 status/error/latency—
2四容器日志对齐时间线知卡在哪一层A~J 场景表
3分层探针embedding/rerank/vLLM 分层 OKC/F/G
4看 Token 预算是否 prompt 吃光A/B
5检索+Rerank 计时知慢在检索还是 LLMC/I
6新开对话排除会话污染B/H
7收尾检查单可交变更单第四部分容量

步骤 1 · 用库表给这轮对话定性

不要先猜「是不是 Rerank」。先问数据库:这轮到底成功、失败,还是还在写。

bash
docker exec docker-db_postgres-1 psql -U postgres -d dify -c "
SELECT id, created_at, status,
       message_tokens, answer_tokens,
       round(provider_response_latency::numeric, 1) AS lat_s,
       left(query, 40) AS q,
       length(coalesce(answer,'')) AS ans_len,
       left(coalesce(error,''), 180) AS err
FROM messages
ORDER BY created_at DESC
LIMIT 8;
"

怎么读:

字段含义
status=normal已经成功。慢就看 lat_s 和 message_tokens
status=error已经失败。页面还在转,只是前端没跟上
error 含 token limit (2048)专题十二,生成预算太小
error 含 token limit (8192) 且 answer_tokens=0多半是 thinking 把预算用光,见场景 B
message_tokens这轮 Prompt 体积。知识库问答经常 6k–15k
answer_tokens=0 且 latency 很大模型跑了很久但没产出可见正文
lat_s 2–30正常单轮知识问答区间(本环境)
lat_s 120+卡在第二次 LLM 或排队,不是检索

查某一个 Agent 当前 max_tokens 和检索配置:

完整脚本:scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_01.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_01.sh

bash
#!/usr/bin/env bash
set -euo pipefail

docker exec docker-db_postgres-1 psql -U postgres -d dify -c "
SELECT
  config_snapshot::json -> 'model' -> 'model_settings' -> 'max_tokens' AS max_tokens,
  config_snapshot::json -> 'knowledge' -> 'sets' -> 0 -> 'retrieval' AS retrieval
FROM agent_config_snapshots
WHERE id = '01a0135c-320e-79dc-97a0-94da9b904c13';
"

注意:config_snapshot 在库里经常是 text,查询时要 ::json 或 ::jsonb,不要直接对 text 用 ->。

步骤 2 · 对齐时间线:四个容器各看什么

把步骤 1 的 created_at(UTC)记下来。207 上 Docker 日志一般也是 UTC。例如失败发生在 02:27:09,就按前后 3 分钟滤。

2.1 docker-agent_backend-1 —— 新 Agent 的主时间线

这是定位「卡在第几步」的第一日志。

完整脚本:scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_02.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_02.sh

bash
#!/usr/bin/env bash
set -euo pipefail

docker logs docker-agent_backend-1 2>&1 | grep -E '02:27:|knowledge_base_search|chat qwen|token limit|retrieve'

本环境一次真实失败的时间线(问「管理人员需要钉钉打卡吗」):

text
02:27:09.307  agent run
02:27:09.309  chat qwen3.6-27b          ← 第一次 LLM,决定用工具
02:27:20.825  running tool: knowledge_base_search
02:27:20.825  POST .../knowledge/retrieve
02:27:22.936  chat qwen3.6-27b          ← 检索已结束,第二次 LLM 开始
02:27:22 ~ 02:29:54                     ← 这里空了 150 秒,页面仍显示检索
02:29:54      token limit (8192) exceeded before any response was generated

读法:

源码对应(容器内,只读,用于理解,不要改):

text
/app/api/.venv/lib/python3.12/site-packages/pydantic_ai/_agent_graph.py

判断逻辑是:响应只有 ThinkingPart、或 parts 为空,且 finish_reason == 'length',就报上述错误。注释写明:*possibly during thinking*。

2.2 docker-api-1 —— 控制台看到的失败包装

完整脚本:scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_03.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_03.sh

bash
#!/usr/bin/env bash
set -euo pipefail

docker logs --since 30m docker-api-1 2>&1 | grep -Ei 'Unknown Error|token limit|Agent App generate'

典型:

text
Unknown Error in Agent App generate worker
AgentBackendRunFailedError: Model token limit (8192) exceeded before any response was generated.
(agent_run_id=...)

agent_run_id 可拿去 agent_backend 日志里精确搜这一轮。

2.3 xinference —— Embedding / Rerank 是否慢、是否 403

完整脚本:scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_04.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_04.sh

bash
#!/usr/bin/env bash
set -euo pipefail

docker logs --since 20m xinference 2>&1 | grep -E 'POST /v1/rerank|POST /v1/embeddings|/v1/rerank|ERROR|403'

正常知识问答会看到:

text
Rerank with kwargs: {}
"POST /v1/rerank HTTP/1.1" 200

本环境短文档 Rerank 约 0.15s,真实制度片段约 2s,10 条长文档 CPU 可达 16s。超过 10s 才优先怀疑 Rerank;2s 级不要先关 Rerank。

列模型必须带推理 Key,否则 Could not validate credentials:

完整脚本:scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_05.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_05.sh

bash
#!/usr/bin/env bash
set -euo pipefail

curl -s -H 'Authorization: Bearer xf-K8H3LiS27H4188XdOyWJj74MWMOlIR9tZbiybDbxbSas7eAI' \
  http://127.0.0.1:9997/v1/models

期望同时有 bge-m3(embedding)和 bge-reranker-v2-m3(rerank)。重启 Xinference 后实例会丢,见场景 G。

2.4 docker-plugin_daemon-1 —— LLM / Embedding 插件调用

完整脚本:scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_06.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_06.sh

bash
#!/usr/bin/env bash
set -euo pipefail

docker logs --since 20m docker-plugin_daemon-1 2>&1 | grep -Ei 'xinference|openai|timeout|error|session'

这里确认请求有没有真正 dispatch 到 langgenius/openai 或 langgenius/xinference。session 缓存 WARN 可以忽略。

2.5 GPU 机 vLLM —— 是否在排队、是否 OOM

在 116.62.10.183 上:

完整脚本:scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_07.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_07.sh

bash
#!/usr/bin/env bash
set -euo pipefail

docker logs --since 20m vllm-qwen3.6-27b 2>&1 | tail -n 80
nvidia-smi
curl -s -H 'Authorization: Bearer 123456' http://127.0.0.1:8000/v1/models

看:

--max-num-seqs 8 表示大约 8 路并发生成。超过就会排队,用户感觉「突然全面变慢」,日志上检索却很快。

2.6 Weaviate / 中继 —— 检索本身失败

完整脚本:scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_08.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_08.sh

bash
#!/usr/bin/env bash
set -euo pipefail

docker logs --since 20m docker-weaviate-1 2>&1 | tail -n 50
docker logs --since 20m docker-weaviate_relay-1 2>&1 | tail -n 50

知识库突然从 Agent 列表消失,优先查 Embedding 实例是否还在(专题三),不要先重建知识库。

2.7 Langfuse —— 看本轮 Trace,不要用来看召回名次

完整脚本:scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_09.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_09.sh

bash
#!/usr/bin/env bash
set -euo pipefail

curl -s -u 'pk-lf-...:sk-lf-...' \
  'http://127.0.0.1:3000/api/public/traces?limit=8'

本环境 Generation Input 经常只有用户原话,看不到逐条 chunk。召回名次以知识库命中测试为准(专题十三)。Langfuse 适合确认:这轮有没有记到、总 Token、是否 error。

步骤 3 · 分层探针(绕过页面,确认哪一层活着)

按这个顺序,哪一层 curl 失败就停在哪一层,不要跳着改。

完整脚本:scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_10.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_10.sh

bash
#!/usr/bin/env bash
set -euo pipefail

# 1) Embedding / Rerank 还在不在
curl -s -m 15 -H 'Authorization: Bearer xf-...' http://127.0.0.1:9997/v1/models

# 2) Rerank 能不能打分(应在 1 秒内)
curl -s -m 30 -H 'Authorization: Bearer xf-...' \
  -H 'Content-Type: application/json' \
  -d '{"model":"bge-reranker-v2-m3","query":"管理人员需要钉钉打卡吗","documents":["管理人员应通过钉钉打卡。","班车时间以通知为准。"]}' \
  http://127.0.0.1:9997/v1/rerank

# 3) 知识库命中测试(含 Rerank 的完整检索)
# 用 Dify 控制台或 dify_api.py POST /datasets/<id>/hit-testing
# 本环境该问句约 2.4s HTTP 200

# 4) vLLM 还在不在(在 207 上测跨机)
curl -s -m 10 -H 'Authorization: Bearer 123456' \
  http://116.62.10.183:8000/v1/models

# 5) 最短对话(不走知识库)
curl -s -m 60 -X POST http://116.62.10.183:8000/v1/chat/completions \
  -H 'Authorization: Bearer 123456' -H 'Content-Type: application/json' \
  -d '{"model":"qwen3.6-27b","messages":[{"role":"user","content":"只回:pong"}],"max_tokens":16}'

判断:

探针失败结论
/v1/models 无 rerankXinference 实例丢了场景 G
/v1/rerank 超时CPU 过载或模型没加载完场景 C
命中测试慢、对话也慢检索侧查 Weaviate / 文档切块过长
命中测试快、对话慢或失败LLM / token / 会话历史场景 A/B
vLLM /v1/models 不通专题五 B 层场景 F
最短对话通、知识问答失败Prompt 体积或工具链路继续步骤 4

步骤 4 · 看 Token:是不是 Prompt 已经把预算吃光

Qwen3.6-27B 在 Dify 里 context_size=64000,vLLM --max-model-len 65536。真正容易踩的是 Agent 的 max_tokens(生成预算,含 thinking)。

关系:

text
可用生成预算 ≈ max_tokens
thinking + 正文 都从这里扣

若 thinking 先把 max_tokens 用完
→ finish_reason=length
→ 页面像卡在知识库
→ error: token limit (N) exceeded before any response was generated

本环境对照:

问句会话message_tokensmax_tokens结果
法定假日加班费怎么算新对话73258192成功,约 23s
管理人员需要钉钉打卡吗旧会话第 3 轮失败时未写入8192想了 150s 后失败
同上(修复后新开对话)新对话1392732768成功,约 21s

注意:打卡条款原文长,即使新开对话 Prompt 也有 1.4 万,已经超过旧的 8192。所以不是「只有长会话才会炸」,长文档 + Top-K=5 一样会炸。

改 max_tokens 必须改两张表,且 不要点发布(专题十一、十二):

sql
BEGIN;
UPDATE agent_config_snapshots
SET config_snapshot = jsonb_set(
  config_snapshot::jsonb,
  '{model,model_settings,max_tokens}',
  '32768'::jsonb
)::text
WHERE id = '01a0135c-320e-79dc-97a0-94da9b904c13';

UPDATE agent_config_drafts
SET config_snapshot = jsonb_set(
  config_snapshot::jsonb,
  '{model,model_settings,max_tokens}',
  '32768'::jsonb
)::text
WHERE id = '01a012e7-bf60-7673-a894-64551d984a23';
COMMIT;

约束:prompt_tokens + max_tokens 不应长期顶满 65536。Prompt 1.4 万、max_tokens 32768,合计约 4.7 万,仍低于 65536,这是本环境可接受的组合。

步骤 5 · 单独给检索和 Rerank 计时

命中测试(走知识库当前检索配置):

完整程序:/opt/workbuddy/scripts_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_01.py

运行/引用:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_01.py

python
from dify_api import Dify
import time
d = Dify("38205036@qq.com", "Difyai123456")
d.login()
t0 = time.time()
r = d.post(
    "/datasets/ee2495bf-c370-49d1-8268-10c51f650fa6/hit-testing",
    body={"query": "管理人员需要钉钉打卡吗"},
    extra="-m 180 --max-time 180",
    t=200,
)
print(r["code"], round(time.time() - t0, 2), "s")

本环境约 2.4s。若这里就要 20s+,先优化切块或把 Rerank 换 GPU,不要先加 max_tokens。

CPU 上 10 条中等长度文档的 Rerank 实录约 16.6s。并发一高,207 的 CPU Rerank 会成为全员变慢的原因。容量建议见第四部分。

步骤 6 · 新开对话验证(不要在失败会话里继续点)

失败会话会带着超长历史和 error 气泡。验证必须:

  1. 强刷页面。
  2. 新开对话。
  3. 问同一句。
  4. 再跑步骤 1 的 SQL,确认 status=normal。

用 API 新开(conversation_id 留空):

完整程序:/opt/workbuddy/scripts_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_02.py

运行/引用:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_02.py

python
payload = {
    "inputs": {},
    "query": "管理人员需要钉钉打卡吗",
    "response_mode": "streaming",
    "files": [],
    "conversation_id": "",
}
r = d.post(
    "/agent/01a012e7-bed3-7574-b0d1-a5cc79a0d3de/chat-messages",
    body=payload,
    extra="-m 420 --max-time 420",
    t=450,
)

步骤 7 · 收尾检查单



本专题 Python 程序一览

| 文件 | 用途 | |---|---|| 专题十四_01_消息表定性.py | 专题十四 · 步骤 1:用 messages 表给最近对话定性。 | | 专题十四_02_读Agent配置.py | 专题十四 · 步骤 1:读 Agent 快照 max_tokens 与 retrieval。 | | 专题十四_03_分层探针.py | 专题十四 · 步骤 3:分层探针(Xinference / Rerank / vLLM / 最短对话)。 | | 专题十四_04_改max_tokens.py | 专题十四 · 步骤 4:快照+草稿 max_tokens 改为 32768(不要点发布)。 | | 专题十四_05_命中测试计时.py | 专题十四 · 步骤 5:命中测试计时(走知识库当前检索配置)。 | | 专题十四_06_新开对话验收.py | 专题十四 · 步骤 6:新开 Agent 对话验收(conversation_id 留空)。 | | 专题十四_07_采样容器日志.py | 专题十四 · 步骤 2:采样 agent_backend / xinference / api 日志。 |

专题十四_01_消息表定性.py

运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_01_消息表定性.py

完整补丁:patches_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_01.py

运行/引用:见 patches_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_01.py

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题十四 · 步骤 1:用 messages 表给最近对话定性。"""
from __future__ import annotations

import sys

import _bootstrap  # noqa: F401
import _config as C
from dify_api import Dify


def main() -> int:
    d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
    try:
        sql = """
SELECT id, created_at, status,
       message_tokens, answer_tokens,
       round(provider_response_latency::numeric, 1) AS lat_s,
       left(query, 40) AS q,
       length(coalesce(answer,'')) AS ans_len,
       left(coalesce(error,''), 180) AS err
FROM messages
ORDER BY created_at DESC
LIMIT 8;
"""
        out, err = d.sh(
            'docker exec %s psql -U postgres -d dify -c "%s"'
            % (C.PG_CONTAINER, sql.replace("\n", " "))
        )
        print(out or err)
        print("\n读法:status=error 已失败;answer_tokens=0 + token limit → 场景 B")
        return 0
    finally:
        d.close()


if __name__ == "__main__":
    sys.exit(main())

专题十四_02_读Agent配置.py

运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_02_读Agent配置.py

完整补丁:patches_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_02.py

运行/引用:见 patches_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_02.py

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题十四 · 步骤 1:读 Agent 快照 max_tokens 与 retrieval。"""
from __future__ import annotations

import sys

import _bootstrap  # noqa: F401
import _config as C
from dify_api import Dify


def main() -> int:
    d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
    try:
        sql = """
SELECT
  config_snapshot::json -> 'model' -> 'model_settings' -> 'max_tokens' AS max_tokens,
  config_snapshot::json -> 'knowledge' -> 'sets' -> 0 -> 'retrieval' AS retrieval
FROM agent_config_snapshots
WHERE id = '%s';
""" % C.SNAP_ID
        out, err = d.sh(
            'docker exec %s psql -U postgres -d dify -c "%s"'
            % (C.PG_CONTAINER, sql.replace("\n", " "))
        )
        print(out or err)
        return 0
    finally:
        d.close()


if __name__ == "__main__":
    sys.exit(main())

专题十四_03_分层探针.py

运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_03_分层探针.py

完整补丁:patches_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_03.py

运行/引用:见 patches_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_03.py

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题十四 · 步骤 3:分层探针(Xinference / Rerank / vLLM / 最短对话)。"""
from __future__ import annotations

import json
import sys

import _bootstrap  # noqa: F401
import _config as C
from dify_api import Dify


def main() -> int:
    d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
    try:
        probes = [
            ("1) Xinference /v1/models", (
                "curl -s -m 15 -H 'Authorization: Bearer %s' %s/v1/models"
                % (C.XF_KEY, C.XF_URL)
            )),
            ("2) Xinference /v1/rerank", (
                "curl -s -m 30 -H 'Authorization: Bearer %s' -H 'Content-Type: application/json' "
                "-d '{\"model\":\"%s\",\"query\":\"%s\",\"documents\":[\"管理人员应通过钉钉打卡。\",\"班车时间以通知为准。\"]}' "
                "%s/v1/rerank"
                % (C.XF_KEY, C.RERANK_MODEL, C.PROBE_QUERY_KB, C.XF_URL)
            )),
            ("3) vLLM /v1/models", (
                "curl -s -m 10 -H 'Authorization: Bearer %s' %s/models"
                % (C.VLLM_KEY, C.VLLM_BASE)
            )),
            ("4) vLLM 最短对话", (
                "curl -s -m 60 -X POST %s/chat/completions "
                "-H 'Authorization: Bearer %s' -H 'Content-Type: application/json' "
                "-d '{\"model\":\"%s\",\"messages\":[{\"role\":\"user\",\"content\":\"只回:pong\"}],\"max_tokens\":16}'"
                % (C.VLLM_BASE, C.VLLM_KEY, C.QWEN_MODEL)
            )),
        ]
        for title, cmd in probes:
            print("\n=== %s ===" % title)
            out, err = d.sh(cmd)
            text = out or err
            print(text[:1500] if len(text) > 1500 else text)
        return 0
    finally:
        d.close()


if __name__ == "__main__":
    sys.exit(main())

专题十四_04_改max_tokens.py

运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_04_改max_tokens.py

完整补丁:patches_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_04.py

运行/引用:见 patches_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_04.py

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题十四 · 步骤 4:快照+草稿 max_tokens 改为 32768(不要点发布)。"""
from __future__ import annotations

import sys

import _bootstrap  # noqa: F401
import _agent_cfg as AC
import _config as C
from dify_api import Dify


def main() -> int:
    d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
    try:
        d.login()
        out, err = d.sh(
            """docker exec %s psql -U postgres -d dify -c "
SELECT 'snapshot' AS which,
       config_snapshot::json -> 'model' -> 'model_settings' -> 'max_tokens' AS max_tokens
FROM agent_config_snapshots WHERE id='%s'
UNION ALL
SELECT 'draft',
       config_snapshot::json -> 'model' -> 'model_settings' -> 'max_tokens'
FROM agent_config_drafts WHERE id='%s';
"
"""
            % (C.PG_CONTAINER, C.SNAP_ID, C.DRAFT_ID)
        )
        print("before:\n", out or err)

        AC.set_max_tokens(d, C.SNAP_ID, C.DRAFT_ID, C.MAX_TOKENS)

        out2, err2 = d.sh(
            """docker exec %s psql -U postgres -d dify -c "
SELECT 'snapshot' AS which,
       config_snapshot::json -> 'model' -> 'model_settings' -> 'max_tokens' AS max_tokens
FROM agent_config_snapshots WHERE id='%s'
UNION ALL
SELECT 'draft',
       config_snapshot::json -> 'model' -> 'model_settings' -> 'max_tokens'
FROM agent_config_drafts WHERE id='%s';
"
"""
            % (C.PG_CONTAINER, C.SNAP_ID, C.DRAFT_ID)
        )
        print("after:\n", out2 or err2)
        print("\n[WARN] 改完不要点「构建/发布」;新开对话验证")
        return 0
    finally:
        d.close()


if __name__ == "__main__":
    sys.exit(main())

专题十四_05_命中测试计时.py

运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_05_命中测试计时.py

完整补丁:patches_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_05.py

运行/引用:见 patches_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_05.py

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题十四 · 步骤 5:命中测试计时(走知识库当前检索配置)。"""
from __future__ import annotations

import sys
import time

import _bootstrap  # noqa: F401
import _config as C
from dify_api import Dify


def main() -> int:
    d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
    try:
        d.login()
        t0 = time.time()
        r = d.post(
            "/datasets/%s/hit-testing" % C.DS_ID,
            body={"query": C.PROBE_QUERY_KB},
            extra="-m 180 --max-time 180",
            t=200,
        )
        elapsed = round(time.time() - t0, 2)
        print("HTTP", r.get("code"), "elapsed", elapsed, "s")
        j = r.get("json")
        if isinstance(j, list):
            recs = j
        else:
            recs = (j or {}).get("records") or []
        for i, rec in enumerate(recs[:5], 1):
            seg = rec.get("segment") or rec
            print(i, rec.get("score"), (seg.get("content") or "")[:80])
        return 0 if r.get("code") == "200" else 1
    finally:
        d.close()


if __name__ == "__main__":
    sys.exit(main())

专题十四_06_新开对话验收.py

运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_06_新开对话验收.py

完整补丁:patches_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_06.py

运行/引用:见 patches_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_06.py

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题十四 · 步骤 6:新开 Agent 对话验收(conversation_id 留空)。"""
from __future__ import annotations

import sys

import _bootstrap  # noqa: F401
import _config as C
from dify_api import Dify


def main() -> int:
    d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
    try:
        d.login()
        payload = {
            "inputs": {},
            "query": C.PROBE_QUERY_KB,
            "response_mode": "streaming",
            "files": [],
            "conversation_id": "",
        }
        r = d.post(
            "/agent/%s/chat-messages" % C.AGENT_ID,
            body=payload,
            extra="-m 420 --max-time 420",
            t=450,
        )
        print("HTTP", r.get("code"))
        text = r.get("text") or ""
        print(text[-1500:] if len(text) > 1500 else text)
        return 0 if r.get("code") == "200" else 1
    finally:
        d.close()


if __name__ == "__main__":
    sys.exit(main())

专题十四_07_采样容器日志.py

运行:/usr/bin/python3 /opt/workbuddy/scripts_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_07_采样容器日志.py

完整补丁:patches_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_07.py

运行/引用:见 patches_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_07.py

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""专题十四 · 步骤 2:采样 agent_backend / xinference / api 日志。"""
from __future__ import annotations

import sys

import _bootstrap  # noqa: F401
import _config as C
from dify_api import Dify


def main() -> int:
    d = Dify(C.DIFY_EMAIL, C.DIFY_PASSWORD)
    try:
        cmds = [
            ("agent_backend", "docker logs --since 20m docker-agent_backend-1 2>&1 | grep -Ei 'knowledge_base_search|chat qwen|token limit|retrieve' | tail -30"),
            ("api", "docker logs --since 20m docker-api-1 2>&1 | grep -Ei 'Unknown Error|token limit|Agent App generate' | tail -20"),
            ("xinference", "docker logs --since 20m %s 2>&1 | grep -E 'POST /v1/rerank|POST /v1/embeddings|ERROR|403' | tail -20" % C.XF_CONTAINER),
            ("plugin_daemon", "docker logs --since 20m %s 2>&1 | grep -Ei 'xinference|openai|timeout|error' | tail -15" % C.PLUGIN_CONTAINER),
        ]
        for name, cmd in cmds:
            print("\n=== %s ===" % name)
            out, err = d.sh(cmd)
            print((out or err)[-3000:])
        return 0
    finally:
        d.close()


if __name__ == "__main__":
    sys.exit(main())

第三部分 分场景:常见报错与解决办法

每一条都按 现象 → 看什么 → 原因 → 解决 → 不要做什么 写。优先用本环境真实出现过的原文。

场景 A · 空泡 / 3/3 / token limit (2048)

现象:回复是空气泡,角标 3/3,输入框发不出新问题,像卡死。

看什么:

sql
SELECT status, left(error, 160) FROM messages ORDER BY created_at DESC LIMIT 5;

status=error,文案:

text
Model token limit (2048) exceeded before any response was generated.

原因:专题十一曾把 max_tokens 写成 2048。带知识库的 Prompt 经常超过 2048,模型还没写出可见正文就 length。页面空泡是失败态,不是还在生成。专题十二。

解决:快照 + 草稿把 max_tokens 改回至少 8192;失败会话弃用;新开对话。不要点发布。

不要:反复在同一会话点发送(会计到 3/3);把页面刷新理解成「模型死了」。

场景 B · 界面停在 knowledge_base_search,最终 token limit (8192)

现象:思考框里工具名是知识库检索,等一两分钟后失败,或一直转。用户感觉「开了 Rerank 更慢、甚至不工作」。

看什么:

  1. 步骤 1:error 含 token limit (8192) 且 answer_tokens=0。
  2. 步骤 2.1:POST knowledge/retrieve 两秒后已再次 chat qwen,说明检索已结束。
  3. message_tokens:同类成功问句可达 13927,已经大于 8192。

原因:不是 Rerank 死锁。Rerank 约 2s。第二次 LLM 里 Qwen3.6 的 thinking 把 max_tokens=8192 用完,finish_reason=length,pydantic_ai 判定「没有任何正文」。长文档 Top-K=5、多轮历史会加重。

解决:

  1. 把 max_tokens 提到 16384 或 32768(本环境已用 32768)。
  2. 保证 prompt + max_tokens < 65536。
  3. 新开对话复测。
  4. 制度原文很长时,Top-K 用 3–5,不要 10。

本环境复测:同一句新开对话,21s,status=normal,message_tokens=13927,answer_tokens=777。

不要:关掉 Rerank 当第一反应;在失败会话里继续问;点发布。

场景 C · Rerank 本身慢、超时、校验失败

现象:命中测试十几秒才出;或添加 Rerank 凭据失败;或对话报 Rerank 不可用。

看什么:docker logs xinference 的 POST /v1/rerank 状态码和间隔;GET /v1/models 有没有 model_type=rerank。

常见原文与解法:

报错 / 现象原因解决
Could not validate credentials没带 API KeyHeader 加推理 Key
API keys can only access model query and inference(403)用推理 Key 去 launch容器内 xinference login 管理员再 launch
Cannot find access token没 login 就 launch同一 bash -lc 里先 login 再 launch
--n-gpu 0 ValueError无 GPU 机器不能传 0不要传 --n-gpu
CLI 100% 但列表没有 rerankwait_ready=False 先返回,worker 随后失败以 /v1/models 和 ModelActor loaded 为准
添加 Dify 凭据失败模型还没 running先 launch 成功再 POST credentials
10 条长文档 16s+CPU 上 bge-reranker-v2-m3 正常现象降召回条数、切短块、或把 Rerank 放到 GPU

详细 launch 命令见专题十三,此处不重复整段。

场景 D · 400 System message must be at the beginning

现象:一发知识库问题就 400,聊天助手有时正常。

看什么:报错原文来自 Qwen chat template,说明 已经打到 vLLM,不是网断。

原因:Qwen3 只接受一条 system,且必须在最前。新 Agent 会塞多条。专题四,补丁在 OpenAI 插件 chat.py。

解决:按专题四合并 system;改完 docker compose restart plugin_daemon。插件升级会丢补丁。

不要:去重启 vLLM 碰运气;把问题当成 Rerank 故障。

场景 E · Agent 里选不到知识库 / 知识库变灰

现象:配置页知识库列表空,或曾经能选后来没了。

看什么:

完整脚本:scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_11.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_11.sh

bash
#!/usr/bin/env bash
set -euo pipefail

curl -s -H 'Authorization: Bearer xf-...' http://127.0.0.1:9997/v1/models

没有 bge-m3 就会让知识库 unavailable(专题三)。

原因:Xinference 重启后 embedding 实例不持久化。Weaviate 中继坏了也会(专题六)。

解决:重新 login + launch bge-m3(以及若需要的 rerank),uid 保持原名。不必重建知识库。

场景 F · Connection error / 超时 / 模型列表空

现象:保存模型失败、问答 Connection error、创建 Agent 没有模型。

看什么:从 Dify 所在机 curl vLLM;专题五七层;专题十 schema。

原因 常见:vLLM 没 Up;API Base 漏了 /v1;模型名和 --served-model-name 不一致;context_size 与 --max-model-len 差一个数量级导致校验失败。

解决:专题五、九、十。本环境 API Base 应为 http://116.62.10.183:8000/v1,模型名 qwen3.6-27b,context_size=64000。

场景 G · 重启后 Embedding / Rerank 消失

现象:昨天还好,重启 xinference 后命中测试失败、Agent 里知识库没了、Rerank 校验失败。

原因:launch 的实例不写进镜像。Dify 凭据还在,对面 uid 没了。

解决:

完整脚本:scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_12.sh

运行/引用:bash /opt/workbuddy/scripts_bash_cursor/Dify_专题十四_知识库问答变慢卡住失败排查与容量规划/专题十四_内联_12.sh

bash
#!/usr/bin/env bash
set -euo pipefail

docker exec xinference bash -lc '
xinference login -e http://127.0.0.1:9997 --username admin --password admin1234
xinference launch -e http://127.0.0.1:9997 -n bge-m3 -t embedding -u bge-m3
xinference launch -e http://127.0.0.1:9997 -n bge-reranker-v2-m3 -t rerank -u bge-reranker-v2-m3
'

不要加 --n-gpu 0。不要重加 Dify 凭据(uid 没变的话)。

场景 H · 改完配置一点「发布」,Max Tokens 又乱了

现象:刚改完 Rerank 或 max_tokens,点构建/发布后对话又超限,或抽屉里的值跳回默认。

原因:新 Agent UI 发布不一定把 model.model_settings.max_tokens 正确落库(专题十一)。

解决:改库后只强刷、新开对话。不要发布。

场景 I · 全体突然变慢,但单条命中测试仍约 2 秒

现象:多人同时问,每个请求都排队到 1 分钟;单独命中测试却很快。

看什么:GPU 机 nvidia-smi;vLLM 日志是否在排队;--max-num-seqs(本环境 8)。

原因:并发超过 vLLM 同时生成路数。检索不是瓶颈。

解决:错峰;加副本;或换更小模型做日常问答、27B 只给复杂题。不要先关 Rerank。

场景 J · Langfuse 里看不到 chunk,误以为没检索

现象:Trace 只有用户原话;retriever_resources 为空数组。

原因:当前上报链路经常不把逐条片段做成 Observation。新 Agent 结束事件里 retriever_resources 也经常是 []。

解决:召回看命中测试;对错看答案是否出现制度原文数字;Trace 只用来确认记到了。不要因此重装插件或再 launch 一次。

场景速查表

你看到的先打开对应
空泡 3/3messages.errorA / 专题十二
思考停在知识库工具agent_backend 时间线B 或 C
token limit (8192) 且无正文max_tokens vs message_tokensB
命中测试 > 10sxinference /v1/rerankC
400 System message专题四D
选不到知识库/v1/models 有无 bge-m3E / 专题三
连不上模型207 上 curl 116:8000F / 专题五
重启后检索挂了重新 launchG
发布后参数复原两张配置表H / 专题十一
大家一起慢vLLM 并发 / GPUI
Langfuse 没有片段命中测试J / 专题十三

第四部分 按公司人数与硬件的参数建议

人数不等于并发。内部制度问答,高峰同时在问的人数通常远小于花名册:

在职人数典型高峰同时提问设计并发(含余量)
约 1002–6按 8 路生成来规划
200–3006–15按 16 路
300–50010–25按 24–32 路
500 以上20–50+按 32+ 路,并准备水平扩展

本环境 H20 + --max-num-seqs 8,对应「约 100 人公司、内部知识问答」这一档。200 人以上不要默认还能共用这一张卡上的 0.75 显存配额(还要给 mxh_env / mxh_live)。

下面每档都给出:检索参数、生成参数、硬件、明确不要做什么。数值是起点,不是法律。改完用步骤 1 的 message_tokens / lat_s 回看。

通用原则(所有规模都遵守)

  1. 先定并发,再定 GPU。 27B 权重大约 50–55GB(FP16/BF16),剩下的显存才是 KV cache,才决定能同时跑几路。
  2. Embedding / Rerank 能上 GPU 就不要长期趴在 Dify 同机 CPU 上。 100 人可以;300 人以上会把 207 这种 31Gi 主机拖成公共瓶颈。
  3. Top-K 不是越大越准。 K 增大,Prompt 线性变长,thinking 更容易把 max_tokens 吃光,也更容易慢。
  4. max_tokens 必须大于「最长知识问答的 Prompt」里 thinking 还需要的余量。 本环境打卡类问句 Prompt 已 1.4 万,8192 不够,32768 才过。
  5. max_tokens + 典型 Prompt 必须小于 --max-model-len(65536)。
  6. 新 Agent 改库后不要点发布。
  7. 切块:制度类中文建议 400–800 汉字一块、重叠 10–15%。一块几千字再 Top-K=5,Prompt 会爆。

硬件速算(Qwen3.6-27B + 知识库)

组件最小能跑比较舒服说明
LLM GPU单卡 ≥ 80GB(H20/A100-80)跑 27B + 8K–32K 上下文独占一张 80GB+,或两卡并行24GB 消费卡不要跑 27B 全量
LLM 显存利用率共享卡 0.70–0.75独占卡 0.90本环境因业务进程必须 0.75
KV / 并发max-num-seqs=8 配 8 路16–32 路要更多显存或更短上下文concurrent 不够就排队
EmbeddingCPU 8 核 + 8Gi 也能跑 bge-m3GPU 再加 4–8GB 显存生产检索 QPS 高时必须 GPU
RerankCPU 可以,Top-K=5、低并发GPU 2–4GB 或独立小卡CPU 10 条长文可到 16s
Dify 主机内存16Gi 很紧32Gi 起(Dify+Weaviate+Postgres+Redis)本环境 31Gi 已同时塞了 Xinference+Langfuse
Dify 主机 CPU8 核16 核+CPU Rerank 和 Weaviate 都吃 CPU
磁盘SSDNVMe模型权重与 Weaviate 数据

24GB / 48GB 卡怎么选模型(不要硬上 27B):

显存建议 LLM知识库
24GB(如 4090)7B–14B,上下文 8K–16KEmbedding+Rerank 同卡要精打细算,或放到 CPU
48GB14B–32B 量化,或 27B 但缩短 max-model-lenEmbedding 可同卡 4GB
80–96GB27B BF16,上下文 32K–64K可同卡也可拆到 CPU/小卡

档位 1 · 约 100 人公司

画像:行政/人事内部问答,同时在线很少,文档量以制度汇编为主(本环境就是这一档)。

硬件建议:

软件参数建议:

参数建议本环境现状理由
检索方式语义检索语义制度问答够用
Top-K3–55>5 对 100 人收益小,Prompt 涨得快
Rerank建议开已开 CPU低并发下 CPU 2s 可接受
Rerank 模型bge-reranker-v2-m3同左中文制度合适
score 阈值默认关关先保证能召回
context_size与 --max-model-len 对齐,6400064000不要用克隆 schema 的 1.05M
max_tokens16384–3276832768含 thinking;8192 会被长条款打爆
温度0–0.3未强制制度要稳
会话策略复杂题新开对话—第三轮历史 + Top-K=5 最容易炸
vLLM max-num-seqs88匹配 100 人高峰
Xinference可与 Dify 同机 CPU同机省卡

建议怎么用:开 Rerank、Top-K=5、max_tokens=32768,强调新开对话。这正是当前 207 的配法。

档位 2 · 200–300 人公司

画像:两个部门以上同时用,午休/上班高峰会叠请求。CPU Rerank 开始排队。

硬件建议:

软件参数建议:

参数建议不要
Top-K3–5不要 8–10
Rerank开,但必须 GPU 或独立机不要继续和 Dify 挤一台 CPU
max_tokens16384 起步,长文档 32768不要 2048/4096
--max-model-len32768 或 65536不要 1M
切块400–800 字不要整章当一块
应用拆分考勤一套、财务一套知识库不要一个库塞所有制度再 Top-K=10
Dify worker按官方 compose 增加 worker 副本前,先加 GPU 并发不要只加 API 副本却仍 8 路 vLLM

建议怎么用:200 人仍可用 27B,但要把检索模型从 Dify 主机挪开,并把 vLLM 并发提到 16,否则会出现场景 I(全体变慢、命中测试却很快)。

档位 3 · 300–500 人公司

画像:多部门、多知识库,高峰 20+ 路生成。单卡 27B + 64K 上下文会不够。

硬件建议:

软件参数建议:

参数建议
Top-K3 为主,个别应用 5
Rerank必须开在 GPU;QPS 高时考虑轻量 reranker
max_tokens8192–16384(上下文已降到 32K 时不要再 32768)
知识库按部门拆,Agent 只绑相关库
会话控制台提示「新话题请新开对话」;必要时限制历史轮数
限流网关或 Dify 侧按用户限流,避免 8 人同时长文打爆 KV

建议怎么用:宁可略降上下文、略降 Top-K,也要保证高峰不排队到一分钟。300 人公司最常见的误区是「参数仍按 100 人抄,只是人变多了」。

档位 4 · 500 人以上

画像:全公司入口、多应用、可能对外或跨园区。需要容量规划,而不是再调一个 Top-K。

硬件建议:

软件参数建议:

参数建议
模型分层简单 FAQ 小模型;制度精读 27B
Top-K3;Rerank GPU
上下文16K–32K 为主,64K 只给少数应用
max_tokens按应用分开:FAQ 2048–4096;制度精读 8192–16384
知识库严格分域,禁止「一个万能库」
发布流程新 Agent 参数走改库或修复后的 UI,禁止未验证就点发布
SLO例如:命中测试 P95 < 3s,端到端 P95 < 30s(无排队)

建议怎么用:500 人以上先做监控和副本,再谈「要不要把 Rerank 模型换成更大的」。没有副本时,把 Top-K 调到 10 只会让所有人一起慢。

一张总表(复制到变更单上用)

档位高峰并发LLM检索Top-KRerankmax_tokensmax-model-lenmax-num-seqsDify 主机
~100 人81×80GB 27B 可共享CPU 可接受5开,CPU 可16384–3276865536832Gi
200–3001680GB 尽量独占 27BEmbedding/Rerank 离 CPU 主机3–5开,GPU16384–3276832K 或 64K1632–64Gi
300–50024–3227B 多卡或 14B+27B 分层独立 GPU3开,GPU8192–163843276824–3264Gi+ 拆库
500+32+多副本 27B + 小模型检索集群3开,多副本按应用16K–32K每卡 8–16集群

和本环境怎么对应

当前 207 + H20 共享卡 = 档位 1(约 100 人内部问答)。

已经按档位 1 做对的:

若公司人数涨到 200+ 仍用这一套,会先出现场景 I(GPU 排队)和场景 C(CPU Rerank 变慢),而不是先出现「答案不准」。那时优先拆检索 GPU / 独占 LLM 卡,而不是把 Top-K 加到 10。

改参数时的顺序(避免一次改五个)

  1. 用第二部分确认是慢、是炸 token、还是排队。
  2. token 炸 → 只动 max_tokens(两张表,不发布)。
  3. 检索慢 → 只动切块 / Top-K / Rerank 所在设备。
  4. 全体排队 → 只动 max-num-seqs、卡是否独占、是否加副本。
  5. 每次改完:命中测试计时 + 新开对话同一问句 + 看 messages 一行。

附录 · 本次实战如何套进本文

2026-08-19 用户反馈「开了 Rerank 更慢、甚至不工作」,页面停在 knowledge_base_search。

按本文走:

  1. 步骤 1:messages.status=error,token limit (8192),不是还在检索。
  2. 步骤 2:检索 2s 结束,第二次 LLM 想了 150s。
  3. 场景 B:thinking 耗尽 8192;该问句 Prompt 实际 1.4 万。
  4. 只改 max_tokens → 32768,不关 Rerank,不点发布。
  5. 新开对话 21s 成功。属于档位 1 的正确参数,不是架构不够。

附录 · 结论

  1. 先看 messages 和 agent_backend 时间线,再决定动哪一层。
  2. 停在知识库工具名上,经常是后面的 LLM thinking,不是 Weaviate 死了。
  3. 常见爆炸点是 max_tokens 相对 Prompt+thinking 太小,以及 Xinference 重启丢实例。
  4. 100 人可以 CPU Rerank + 单卡共享;200 人以上先把检索和 LLM 的硬件拆开;500 人以上先做副本和监控。
  5. 改新 Agent 配置只改快照和草稿,不要发布。