跳转至

问题排查

按现象查原因。先确认一件事:CG_RAG 的 HTTP 200 不等于业务成功。 检索成功但生成失败时,HTTP 仍然是 200,失败信息在 body 里。

先跑这两条命令

# 服务活着吗?配置齐吗?
curl --noproxy '*' -sS http://127.0.0.1:8864/cg-rag/health

# 有哪些检索范围可用?
curl --noproxy '*' -sS http://127.0.0.1:8864/cg-rag/profiles

health 里要看的几项:

字段 期望 不对时说明
ok true 服务整体不健康,看 config_issues
config_issues [] 有内容就是配置缺失,照着改
available_scopes 含你要用的 scope 语料或索引路径没配好
generation.configured true 文本生成没配,rag / constrained-generate 会失败
vision.configured true 视觉没配,只影响 vision/*

按错误码查

generation_not_configured

生成端点没配。检索接口不受影响,但 ragconstrained-generate 用不了。

需要这四个环境变量:

export CG_RAG_GENERATION_ENDPOINT='https://example.com/v1/chat/completions'
export CG_RAG_GENERATION_MODEL='your-model'
export CG_RAG_API_KEY='server-side-secret'
export CG_RAG_LLM_PROVIDER='deepseek'   # 或 poly / openai_compatible

改完重启服务,再用 health 确认 generation.configured 变成 true

vision_not_configured

视觉上游没配。检索和文本生成都正常,只有 vision/* 会失败。

export CG_RAG_VISION_ENDPOINT='https://example.com/v1/chat/completions'
export CG_RAG_VISION_MODEL='your-vlm'
export CG_RAG_VISION_API_KEY='server-side-secret'

部署顺序

如果有上层应用依赖 CG_RAG 的视觉能力,先重启 CG_RAG 并确认 healthvision.configured=true,再重启上层应用。反过来会让上层在一段时间内对所有图片请求返回失败。

no_stable_article

检索到了候选,但模型没能稳定选出条文。这不是崩溃,是「这批候选里没有能确定回答该问题的条文」。

常见原因和处理:

  • 问题太宽泛(「安全怎么做」)→ 问得具体一点。
  • scope 选窄了 → 从 usual 换成 full
  • topk 太小 → 调大到 10~20,给模型更多候选。

generation_timeout / generation_request_failed

到上游模型的请求超时或失败。先确认上游本身可用:

curl -sS -o /dev/null -w '%{http_code}\n' \
  -X POST "$CG_RAG_GENERATION_ENDPOINT" \
  -H "Authorization: Bearer $CG_RAG_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"model":"'"$CG_RAG_GENERATION_MODEL"'","messages":[{"role":"user","content":"ping"}],"max_tokens":1}'

如果上游正常而 CG_RAG 报超时,调大 CG_RAG_TIMEOUT_SECONDS(默认 120 秒),并把客户端超时同步调大。当前生效值见 healthgeneration.timeout_seconds

generation_response_invalid

上游返回了内容,但不是能解析的形状——通常是模型没按要求输出 JSON。多见于把 CG_RAG_LLM_PROVIDER 配错(例如上游是 OpenAI-compatible 却配成 deepseek),导致 thinking 参数注入方式不匹配。

vision_upstream_error

视觉上游调用失败。图片过大、格式不支持、上游过载都会走到这里。先把图片压到 2 MB 以内、转成标准 JPEG/PNG 再试。

invalid_image

base64 解不开,或者不是支持的图片格式。检查:

  • data 字段是纯 base64,不带 data:image/jpeg;base64, 前缀。
  • mime_type 和实际内容一致。
import base64
encoded = base64.b64encode(open("site.jpg", "rb").read()).decode("ascii")
payload = {"images": [{"data": encoded, "mime_type": "image/jpeg"}]}

invalid_request

请求体没通过校验。最常踩的两个坑:

  • include_debuggeneration_enable_thinking 必须是 JSON boolean"true"10 都会被拒。
  • retrieval_docs 不能是空数组。

capacity.exceeded(HTTP 429)

并发超过服务端限流。检索和生成分别限流,所以只有一类会先满。

  • 非流式请求:等待超时后返回 HTTP 429。
  • /rag/stream:如果响应已经开始,容量错误通过 SSE 的 error + final 表达,HTTP 状态仍是 200

客户端应该退避重试,而不是立刻重发。

按现象查

第一次请求特别慢,之后就快了

正常。首次访问某个 scope 要加载索引。上线后先 warmup

改了索引/语料,但结果还是旧的

检索缓存的 key 里带 profile_fingerprint,配置真的变了就不会命中旧缓存。如果结果没变,多半是配置没有真正生效——对比 health 里的 profile_fingerprint_summary 和你期望的值。

pred_indices 的序号对不上我的文档

pred_indices1-based,对应 retrieval.retrieval_docs 的位置。取文档时要 docs[i - 1]

SSE 卡住不动 / 收不到 token

按顺序排查:

  1. 请求头带了 Accept: text/event-stream 吗?
  2. 中间有没有反向代理做了缓冲?Nginx 需要 proxy_buffering off;
  3. 受约束生成本来就不是真流——答案在服务端拼好之后才被切成几段重放,所以「很久没动静、然后一下子出完」是正常的。想看真正边生成边到达的输出,用视觉接口或自由生成。

视觉智能生成要一两分钟

正常。它会多轮检索法规再作答。要快就用 vision/answer(自由生成),代价是没有法规引用。

明明配了代理,请求却连不上本机服务

curl 会读 http_proxy / https_proxy 环境变量,把发往 127.0.0.1 的请求也送进代理。示例里的 --noproxy '*' 就是为此。Python 的 requests 同样受影响,可以:

session = requests.Session()
session.trust_env = False   # 忽略环境里的代理设置

还是不行

带上这三样去查日志,能省很多时间:

  • 响应头里的 X-Request-ID(或 body 里的 request_id)。
  • 完整的请求体(去掉图片 base64)。
  • health 的完整输出。

请求 ID 会串联服务端日志,可以直接定位到那一次调用。你也可以自己指定:

curl --noproxy '*' -sS -H 'X-Request-ID: my-trace-001' \
  http://127.0.0.1:8864/cg-rag/health

服务端不会在响应里返回 API key、完整本地路径或上游响应正文;日志同样做了脱敏。