详情

首页手游攻略 大模型应用开发中的可观测性实战要注意什么-核心信息和使用场景

大模型应用开发中的可观测性实战要注意什么-核心信息和使用场景

佚名 2026-09-02 19:23:55

大模型应用开发中的可观测性实战要注意什么-核心信息和使用场景的重点在于把前置条件、操作顺序和容易误判的地方分清楚。

大模型应用开发中的可观测性实战:从日志到调用链,构建 LLM 应用的可靠性工程

需要先分清的是,、二、三支柱落地实践等重点拆开说明,方便直接对照使用。大模型应用开发中的可观测性实战要注意什么-核心信息和使用场景不能只看功能名称,更要看它在什么场景下能解决问题。按大模型应用开发中的可观测性实战:从日志到调用链,构建 LLM 应用的可靠性工程、一、为什么传统监控不灵了?

换到实际使用里,分享一套面向 LLM 应用的可观测性体系设计方案涵盖结构化日志、全链路追踪、语义指标监控三大支柱并提供可落地的代码实践。从操作角度看基于我们团队在金融 QA 机器人上的真实踩坑经历

一、为什么传统监控不灵了?

传统的 APM(应用性能监控)针对确定性代码设计,你能预判每行代码的输入输出。而 LLM 应用具有三大不确定性:

输入无限:用户问题无法穷举,意图分布长尾。中间过程黑盒:检索召回了哪些片段?重排序丢掉了什么?Prompt 被如何拼装?输出“软错误”:语法正确、逻辑通顺,但事实错误(例如回答年假天数比制度多一倍)。

因此,我们需要一种可解释、可回溯、可量化的观测体系,让每一次请求都像一段可解剖的流水线。

二、三支柱落地实践实际怎么用

2.1 结构化日志:让每一帧都有迹可循

不要用 print(),不要用 logging.info() 随便拼字符串。采用 JSON 格式结构化日志,并强制包含以下字段:

trace_idspan_id(用于关联调用链)session_iduser_idstep(检索、重排、生成、校验)token_usagelatency_msretrieved_docs(只记录文档 ID 和 score)prompt_preview(截断过长)

Python 实现:

代码语言:javascript

从操作角度看,"query": user_query"top_doc_ids": [d.metadata['id'] for d in docs]"top_scores": [s for _s in docs_with_scores]"cost_ms": elapsed})这些 JSON 日志直接灌入 ELK 或 Loki你可以通过 trace_id 一键聚合所有步骤快速定位“检索召回太靠后”还是“Prompt 被截断”。复制import jsonimport loggingfrom pythonjsonlogger import jsonloggerclass LLMJsonFormatter(jsonlogger.JsonFormatter):def add_fields(selflog_recordrecordmessage_dict):super().add_fields(log_recordrecordmessage_dict)if not log_record.get('timestamp'):log_record['timestamp'] = datetime.utcnow().isoformat()# 强制注入全局 trace_id(需从 context 中取)log_record['trace_id'] = get_current_trace_id() or 'unknown'logger = logging.getLogger('llm_app')handler = logging.StreamHandler()handler.setFormatter(LLMJsonFormatter())logger.addHandler(handler)# 使用示例logger.info("retrieval_completed"extra={"step": "retrieve"

2.2 全链路追踪(OpenTelemetry Jaeger)

从操作角度看,LLM 应用本质是一条流水线:意图分类 → 重写 → 检索 → 重排序 → 上下文压缩 → LLM 生成 → 事实校验。用 OpenTelemetry 自动埋点并可视化在 Jaeger 中。需要先分清的是,每一步都可能变慢或出错。

部署 OpenTelemetry Collector 并集成 FastAPI:

代码语言:javascript

更直接地说,复制# docker-compose 部分services:app:image: my-llm-appenvironment:- OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318- OTEL_SERVICE_NAME=llm-qaotel-collector:image: otel/opentelemetry-collector-contrib:latestvolumes:- ./otel-config.yaml:/etc/otel/config.yamlcommand: ["--config=/etc/otel/config.yaml"]jaeger:image: jaegertracing/all-in-one:latestports:- "16686:16686"代码中手动创建子 Span:

代码语言:javascript

需要先分清的是,query)with tracer.start_as_current_span("retrieve") as span:docs = retriever.get_relevant_documents(query)span.set_attribute("doc_count"复制from opentelemetry import tracetracer = trace.get_tracer(__name__)@app.post("/ask")async def ask(query: str):with tracer.start_as_current_span("full_pipeline") as parent_span:parent_span.set_attribute("query"len(docs))with tracer.start_as_current_span("rerank") as span:top_docs = reranker.rerank(querydocstop_n=3)span.set_attribute("top_scores"[d.score for d in top_docs])with tracer.start_as_current_span("llm_generate") as span:answer = llm.generate(querytop_docs)span.set_attribute("token_usage"answer.usage)return answer在 Jaeger UI 中你可以清晰看到每一步的耗时占比发现“检索”阶段突然从 50ms 飙到 800ms立即排查向量数据库连接池是否耗尽。

2.3 语义指标监控(RAGAS 自定义 Metrics)

换到实际使用里,这些可通过离线评测框架(如 RAGAS)计算,但生产环境需要实时或准实时监控。放在具体场景中,业务指标不是 QPS 和错误率,而是 检索命中率、答案忠实度、答案对应性。

我们实现了一个异步评分器,将请求日志采样后发送至评估服务:

代码语言:javascript

放在具体场景中,value in score.items():llm_metric.labels(metric=metric_name).set(value)return scorePrometheus 指标暴露与告警规则:复制# evaluator.pyfrom ragas import evaluatefrom ragas.metrics import faithfulnessanswer_relevancycontext_relevancydef online_evaluate(sample: dict):# sample 包含 questionanswercontextsground_truth (若有)score = evaluate(dataset=[sample]metrics=[faithfulnessanswer_relevancycontext_relevancy])# 推送至 Prometheusfor metric_name

代码语言:javascript

更直接地说,['metric'])@app.get("/metrics")def metrics():return Response(generate_latest()media_type="text/plain")告警规则:如果 faithfulness 连续 3 个采样周期低于 0.7触发告警提示可能需要更新知识库或调整 Prompt。复制from prometheus_client import Gaugegenerate_latestllm_metric = Gauge('llm_qa_ragas_score''RAGAS evaluation score'

三、缓存与降级:可观测性驱动的韧性设计

有了观测数据,我们能精准优化。换到具体场景里,我们发现高频问题(“年假如何计算”)占请求量的 20%,完全可缓存。

Redis 缓存语义相似结果:

代码语言:javascript

更直接地说,decode_responses=True)encoder = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')def get_cached_answer(query):# 对 query 做语义哈希(如用 embedding 的前 10 维作为 key)emb = encoder.encode(query)key = hashlib.md5(emb[:10].tobytes()).hexdigest()cached = cache.get(f"qa:{key}")if cached:logger.info("cache_hit"复制import hashlibimport redisfrom sentence_transformers import SentenceTransformercache = redis.Redis(host='localhost'extra={"query": query})return json.loads(cached)return None同时当 LLM API 连续超时我们利用观测数据触发降级——回退到只返回检索片段拼接的摘要避免无响应。

四、落地效果与总结

从操作角度看,进一步查结构化日志发现,某个向量库索引被意外重建,导致 embedding 分布偏移。半小时内回滚索引,指标恢复。我们这套体系上线后,问题定位时间从平均 2 小时缩短到 15 分钟。典型场景:某天 faithfulness 指标突降,Jaeger 显示 llm_generate 耗时正常但 retrieve 返回的文档平均分变低。

核心经验提炼:

日志结构化是基础,没有它后续无从谈起。链路追踪让黑盒可视化,尤其适合多步骤流水线。语义指标才是 LLM 应用的“健康检查”,QPS 只能告诉你系统没崩,不能告诉你回答对不对。缓存与降级策略必须依赖观测数据驱动,否则无处下手。

放在具体场景中,工具选型上,推荐 OpenTelemetry Jaeger Prometheus Grafana 组合,全部开源且生态成熟。放在具体场景中,从结构化日志 trace_id 关联开始,两周内你就能感受到差异。收尾时,不要试图一次性做全。

相关资讯
点击查看更多
游戏推荐
推荐专题
热门阅读
推荐下载