
1 项目背景业务场景「云帆科技」的 RAGFlow 平台已服务全公司 800 名员工日均问答 3000 次文档总量突破 500 份。系统规模和复杂度的增长带来了新的问题——某天上午 10 点多名用户同时反馈聊天机器人没反应了。运维小李打开监控——只有一个docker ps的输出——她没有任何仪表盘能快速判断是 API Server 挂了、LLM 超时了、还是 Redis 队列堵了。花了一个小时逐一排查后发现是 LLM API 的速率限制触发了连续超时导致 API Server 的线程池耗尽。但这个问题本该在 5 分钟内被定位——如果有日志聚合、关键指标仪表盘和告警规则的话。CTO 拍板建立 RAGFlow 的完整可观测性体系。痛点没有可观测性体系的典型症状故障定位靠猜不知道是哪个组件出问题——每个容器单独docker logs无法看到全貌。性能退化无感知检索延迟从 500ms 慢慢涨到 3000ms持续了两周没人发现——因为没有趋势图。告警缺失队列积压 200 个任务、LLM 错误率超 10%、磁盘使用率 95%——没人知道直到用户投诉。跨服务追踪困难一次问答请求横跨 API Server → Redis → Task Executor → Infinity → LLM没有 TraceID 串联无法定位慢在哪一步。从盲飞到可观测的转变 盲飞阶段 用户反馈 → 人工排查 → 花1小时 → 修复 → 没有总结 可观测阶段 指标趋势图提前发现 → 告警通知 → 5分钟定位根因 → 修复 → 复盘优化2 项目设计小胖指着三块黑屏的监控屏“大师老板批了预算买这三块监控大屏但上面现在啥也没有。RAGFlow 的可观测性到底要监控什么、用什么工具、怎么配告警”大师“可观测性有三根支柱——日志Logs、指标Metrics、链路追踪Traces。三根支柱缺一根排障就是’猜’。”可观测性三根支柱 1. 日志 (Logs)发生了什么 14:23:05 API Server响应500错误: LLM timeout 工具: ELK / Loki / OpenSearch Dashboards 2. 指标 (Metrics)量化趋势 过去5分钟问答错误率 12%阈值5% 工具: Prometheus Grafana 3. 链路追踪 (Traces)请求旅程 请求 req_abc: API(50ms) → Redis(2ms) → LLM(4500ms!!) → Total(4552ms) 工具: Jaeger / Zipkin / OpenTelemetry技术映射可观测性 医院体检——日志是病历记录症状指标是体检报告血压/血糖数值链路追踪是 CT/MRI看清每个器官的运行状态。小胖“那 RAGFlow 具体需要监控哪些指标”大师“从 RED USE 两个维度分别看”RED 指标面向服务——关注用户体验 Rate: 每秒问答请求数 Errors: 问答失败率LLM超时、检索异常、解析失败 Duration: 问答 P50/P95/P99 延迟 USE 指标面向资源——关注系统健康 Utilization: CPU/内存/磁盘使用率 Saturation: Redis队列积压数、MySQL连接池使用率 Errors: OOM次数、磁盘满次数、网络丢包 RAGFlow 专项指标 - 文档解析吞吐文档/小时 - Embedding 调用耗时与成功率 - 文档引擎查询延迟P50/P95 - LLM API 调用次数与费用 - 引用准确率趋势需要评测脚本配合小白列出需要监控的组件清单“具体到每个组件要监控什么用什么工具采集”大师组件关键指标采集方式告警阈值API ServerHTTP 状态码(2xx/4xx/5xx)、请求延迟、并发连接数Prometheus exporter 或日志解析5xx率 5%、P95 10sTask Executor队列长度、解析成功率、Worker 存活数Redis 日志队列 50、成功率 90%MySQL连接数、慢查询数、复制延迟mysqld_exporter连接数 80%、慢查询 10/minRedis内存使用率、命令延迟、连接数redis_exporter内存 80%、延迟 5msMinIO磁盘使用率、上传/下载吞吐minio_exporter磁盘 85%ES/Infinity集群状态、查询延迟 P95、JVM堆(ES)ES exporter / Infinity API非 green、P95 1sLLM API调用次数、成功率、P95延迟、费用应用埋点错误率 10%、费用日增 20%小胖“那链路追踪怎么搞RAGFlow 有自带 TraceID 吗”大师“当前版本 RAGFlow 的 TraceID 支持尚不完善——日志中没有统一的 trace_id 字段。但你可以在网关层注入 TraceID贯穿整个请求链路。核心思路在 API 入口生成 TraceID → 写入请求上下文 → 所有下游调用Redis/ES/LLM携带 TraceID → 在日志中打印。”# 日志注入 TraceID概念示例importuuidimportloggingfromcontextvarsimportContextVar trace_id_varContextVar(trace_id,defaultNone)classTraceIDFilter(logging.Filter):给每条日志自动注入trace_iddeffilter(self,record):record.trace_idtrace_id_var.get()orno-tracereturnTrue# API 入口中间件asyncdeftrace_middleware(request,call_next):trace_idrequest.headers.get(X-Trace-ID)orstr(uuid.uuid4())[:8]trace_id_var.set(trace_id)responseawaitcall_next(request)response.headers[X-Trace-ID]trace_idreturnresponse# 日志输出效果# [2024-06-15 14:23:05] [trace_ida3f2b1c4] [INFO] Retrieval took 230ms# [2024-06-15 14:23:05] [trace_ida3f2b1c4] [INFO] Rerank took 450ms# [2024-06-15 14:23:06] [trace_ida3f2b1c4] [INFO] LLM generation took 3200ms技术映射TraceID 快递单号——从揽收到派送每个中转站都扫一次单号全程可追踪。没有单号时包裹丢了都不知道在哪丢的。3 项目实战环境准备目标为 RAGFlow 部署 Prometheus Grafana Loki Jaeger 最小可观测套件。前提Docker Compose 环境准备docker-compose-observability.yml。分步实现步骤1部署 Prometheus Grafana目标5 分钟拉起指标采集和可视化。# docker-compose-observability.ymlservices:prometheus:image:prom/prometheus:v3.0.0container_name:prometheusvolumes:-./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml-prometheus_data:/prometheusports:-9090:9090restart:unless-stoppedgrafana:image:grafana/grafana:11.0.0container_name:grafanaenvironment:-GF_SECURITY_ADMIN_PASSWORDadminports:-3000:3000volumes:-grafana_data:/var/lib/grafana-./grafana/dashboards:/etc/grafana/provisioning/dashboardsrestart:unless-stopped# Node Exporter宿主机指标node_exporter:image:prom/node-exporter:v1.8.0container_name:node_exportervolumes:-/proc:/host/proc:ro-/sys:/host/sys:ro-/:/rootfs:rocommand:--path.procfs/host/proc--path.sysfs/host/sysports:-9100:9100restart:unless-stopped# Redis Exporterredis_exporter:image:oliver006/redis_exporter:v1.62.0container_name:redis_exporterenvironment:-REDIS_ADDRredis://redis:6379-REDIS_PASSWORD${REDIS_PASSWORD}ports:-9121:9121restart:unless-stoppedvolumes:prometheus_data:grafana_data:# prometheus/prometheus.ymlglobal:scrape_interval:15sscrape_configs:-job_name:nodestatic_configs:-targets:[node_exporter:9100]-job_name:redisstatic_configs:-targets:[redis_exporter:9121]-job_name:ragflowmetrics_path:/metricsstatic_configs:-targets:[ragflow-api:9380]# 注需要 RAGFlow 暴露 /metrics 端点需二次开发或通过 exporter步骤2搭建 Grafana 监控大屏目标导入预置 Dashboard 或自建 RAGFlow 专属仪表盘。# RAGFlow Dashboard 核心面板配置GrafanaJSON概念{dashboard:{title:RAGFlow 生产监控,panels:[{title:API QPS,targets:[{expr:rate(http_requests_total[1m])}],type:graph},{title:问答延迟 P50/P95/P99,targets:[{expr:histogram_quantile(0.50, chat_latency_seconds)},{expr:histogram_quantile(0.95, chat_latency_seconds)},{expr:histogram_quantile(0.99, chat_latency_seconds)}],type:graph},{title:LLM 错误率,targets:[{expr:rate(llm_errors_total[5m]) / rate(llm_calls_total[5m])}],type:stat,thresholds:[{value:0.05,color:red}]},{title:Redis 队列积压,targets:[{expr:redis_stream_length}],type:gauge,thresholds:[{value:50,color:orange},{value:100,color:red}]},{title:各组件健康状态,targets:[{expr:up{jobragflow}},{expr:up{jobredis}},{expr:up{jobnode}}],type:stat}]}}步骤3配置关键告警规则目标在 Prometheus AlertManager 中配置 5 条核心告警。# prometheus/alert_rules.ymlgroups:-name:ragflow_criticalrules:-alert:LLMErrorRateHighexpr:rate(llm_errors_total[5m]) / rate(llm_calls_total[5m])0.1for:5mlabels:severity:criticalannotations:summary:LLM 调用错误率超过 10%description:过去5分钟 LLM 错误率为 {{ $value | humanizePercentage }}-alert:QueueBacklogHighexpr:redis_stream_length100for:10mlabels:severity:warningannotations:summary:Redis 任务队列积压超过 100description:当前积压 {{ $value }} 个任务可能需要增加 Worker-alert:ApiErrorRateHighexpr:rate(http_requests_total{status~5..}[5m]) / rate(http_requests_total[5m])0.05for:5mlabels:severity:criticalannotations:summary:API 5xx 错误率超过 5%-alert:SlowQueryP95expr:histogram_quantile(0.95,rate(chat_latency_seconds_bucket[5m]))10for:10mlabels:severity:warningannotations:summary:问答 P95 延迟超过 10 秒-alert:DiskSpaceLowexpr:(node_filesystem_avail_bytes / node_filesystem_size_bytes) 0.15for:5mlabels:severity:warningannotations:summary:磁盘可用空间低于 15%# AlertManager 告警通知配置飞书 Webhook 示例catalertmanager/config.ymlEOF receivers: - name: feishu-webhook webhook_configs: - url: https://open.feishu.cn/open-apis/bot/v2/hook/xxx send_resolved: true route: receiver: feishu-webhook group_by: [alertname] group_wait: 10s group_interval: 5m repeat_interval: 4h EOF步骤4TraceID 注入与链路追踪目标用 OpenTelemetry 为 RAGFlow 注入 TraceID导出到 Jaeger。# opentelemetry_instrument.py - 应用埋点fromopentelemetryimporttracefromopentelemetry.sdk.traceimportTracerProviderfromopentelemetry.sdk.trace.exportimportBatchSpanProcessorfromopentelemetry.exporter.jaeger.thriftimportJaegerExporter# 初始化 Tracertrace.set_tracer_provider(TracerProvider())jaeger_exporterJaegerExporter(agent_host_namejaeger,agent_port6831,)trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(jaeger_exporter))tracertrace.get_tracer(__name__)asyncdefchat_with_trace(question,dataset_ids):带埋点的问答请求withtracer.start_as_current_span(chat_request)asspan:span.set_attribute(question,question[:100])span.set_attribute(dataset_count,len(dataset_ids))# 子 Span: 检索withtracer.start_as_current_span(retrieval)asretrieval_span:chunksawaitretrieve(question,dataset_ids)retrieval_span.set_attribute(chunks_count,len(chunks))# 子 Span: Rerankwithtracer.start_as_current_span(rerank):rerankedawaitrerank(chunks)# 子 Span: LLM 生成withtracer.start_as_current_span(llm_generation)asllm_span:answerawaitllm_generate(reranked,question)llm_span.set_attribute(answer_length,len(answer))span.set_attribute(total_chunks,len(reranked))returnanswer步骤5日志聚合——Loki Promtail目标将 RAGFlow 多容器日志汇聚到 Grafana Loki实现统一查询。# docker-compose-observability.yml补充 Loki Promtailservices:loki:image:grafana/loki:3.0.0ports:-3100:3100volumes:-./loki/loki-config.yaml:/etc/loki/loki-config.yaml-loki_data:/lokipromtail:image:grafana/promtail:3.0.0volumes:-/var/lib/docker/containers:/var/lib/docker/containers:ro-/var/log:/var/log:ro-./promtail/promtail-config.yaml:/etc/promtail/config.ymlcommand:-config.file/etc/promtail/config.ymlvolumes:loki_data:# promtail/promtail-config.yamlscrape_configs:-job_name:dockerdocker_sd_configs:-host:unix:///var/run/docker.sockrelabel_configs:-source_labels:[__meta_docker_container_name]target_label:container-source_labels:[__meta_docker_container_label_com_docker_compose_service]target_label:servicepipeline_stages:-static_labels:job:ragflow# Grafana Loki 查询示例 # 最近1小时内 API Server 的所有 ERROR 日志 {serviceragflow-api} | ERROR | json | line_format {{.message}} # 包含特定 trace_id 的跨容器日志 {jobragflow} | trace_ida3f2b1c4 # 统计5分钟内各容器的日志行数 rate({jobragflow}[5m]) by (container)测试验证# test_observability.pyimporttimeimportrequestsdeftest_metrics_endpoint():验证 Prometheus metrics 端点可访问rrequests.get(http://localhost:9090/api/v1/query,params{query:up})assertr.status_code200deftest_grafana_health():验证 Grafana 可访问rrequests.get(http://localhost:3000/api/health)assertr.status_code200deftest_alert_fires_on_high_errors():模拟高错误率触发告警# 连续发送导致 500 的请求for_inrange(20):try:requests.post(http://localhost/api/v1/chats,json{bad:data},timeout2)except:passtime.sleep(30)# 等 Prometheus 采集# 检查 AlertManager 是否有 firing alertrrequests.get(http://localhost:9093/api/v2/alerts)alertsr.json()llm_alerts[aforainalertsifLLMErrorRateHighina.get(labels,{}).get(alertname,)]print(fLLM错误告警状态:{llm_alerts[0][status]ifllm_alertselsenone})deftest_trace_in_jaeger():验证 Jaeger 中有 trace 数据rrequests.get(http://localhost:16686/api/traces,params{service:ragflow-api,limit:1})tracesr.json().get(data,[])assertlen(traces)0,Jaeger 中无 trace 数据完整代码清单路径说明api/ragflow_server.pyAPI 入口可添加 TraceID 中间件rag/svr/task_executor.pyTask Executor可添加埋点docker/docker-compose.yml基础部署column/chapter27/本章监控配置文件4 项目总结优点 缺点维度Prometheus GrafanaELK StackDatadog自建部署复杂度★★★ 容器化快速★★☆ ES 较重★★★ SaaS 免部署★☆☆ 开发量大指标采集★★★ 丰富 exporter★★☆ 偏日志★★★ 全覆盖★★☆ 需开发日志查询★★☆ 需 Loki 配合★★★ 核心能力★★★ 强大★★☆ 需开发链路追踪★★☆ 需 Jaeger 配合★★☆ APM★★★ 一体化★☆☆ 需开发告警能力★★★ AlertManager★★★ Watcher★★★ 智能告警★★☆ 需开发成本★★★ 开源免费★★★ 开源免费★★☆ 按量付费★☆☆ 开发成本适用场景生产环境日常运维三块大屏——服务健康、业务指标、资源水位。故障 5 分钟定位TraceID → Jaeger 看耗时分布 → Loki 查关联日志 → 定位慢点。容量规划6 个月的指标趋势 → 判断何时需要扩容。成本监控LLM API 调用次数和费用的日/周/月趋势。SLA 保障P95 延迟 10 秒、可用率 99.5% 的持续监控。不适用场景开发环境全套可观测性套件PrometheusLokiJaegerGrafana吃 3-4GB 内存。单机小规模 10 人在用、 100 份文档——docker logs够用。注意事项Prometheus 的存储默认保留 15 天。生产环境建议用 Thanos/Cortex/VictoriaMetrics 做长期存储。高基数标签陷阱不要用trace_id或user_id作为 Prometheus 的标签——会导致时间序列爆炸。Jaeger 采样率全量采集100%Trace 对性能有 2-5% 的影响。生产建议 10-20% 采样。告警静默期部署窗口期间手动设置 AlertManager 静默避免误报告警。Grafana Dashboard 版本管理Dashboard JSON 文件纳入 Git通过 Provisioning 自动加载。常见踩坑经验故障现象根因解决方法Prometheus 内存 OOM时间序列基数过高用了 user_id 做标签移除高基数标签用日志存储这些信息Grafana 面板显示 “No data”Datasource 配置的 URL 不对用了 localhost 而非容器名容器间通信用 service nameAlertManager 不发告警group_wait设太长默认 30s测试时以为无效测试时临时改短生产改回Loki 查询很慢未建索引或 label 过滤不够精确查询时尽量加{servicexxx}过滤Jaeger 中 trace 断掉跨服务时 trace context 未传播HTTP header 丢失确保中间件正确提取和注入traceparentheader思考题RAGFlow 的 LLM 调用费用每月波动很大$800-$3000。请设计一个LLM 费用异常检测方案——基于历史费用数据建模当日费用偏离预测区间超过 30% 时触发告警——防止 Prompt 改坏导致费用暴增而不自知。某次故障中你发现 Jaeger 中的 trace 记录显示 LLM 调用耗时 4.5 秒但 Loki 日志中同一 trace_id 的 LLM 调用日志只有一条start没有end。请设计一个不完整 Span 检测与告警——自动发现没有子 Span 闭合的异常 trace并通知开发排查死锁或超时问题。答案提示见第28章末尾或附录 D。延伸阅读与资源10倍开发者的 Dify 魔法书从零构建全栈 AI 应用后端工程师转型AI第一课-Ollama 与私有化大模型实战大型语言模型(LLM) vLLM 高性能推理落地实战Agent开发之LlamaIndex 实战修炼与源码进阶大语言模型Transformers 实战修炼与源码剖析