资讯动态

AI代理可观测性实战:OTel+OpenLit+Elastic全链路追踪

发布时间:2026/9/26 4:06:58 来源:尧图企业网站定制
1. AI代理可观测性为什么成了绕不开的坎AI代理和传统后端服务有一个本质区别它的执行路径不是确定性的。你给它一个输入它可能调用三次工具、也可能调用十次可能走检索增强生成RAG链路也可能直接凭模型内部知识作答同一个问题问两遍token消耗和响应延迟可能差出一倍。这种不确定性带来的直接后果是——出了问题你根本不知道从哪儿查。我最早接触AI代理监控是在一个客服问答机器人的项目上。用户反馈“回答变慢了”但我们翻遍应用日志只看到一条“请求完成耗时8.2秒”中间发生了什么完全是黑盒。是模型推理慢是向量检索慢还是某个外部工具调用超时重试了三次没有链路数据只能靠猜。后来我们接入了OpenTelemetry简称OTel做分布式追踪把代理的每一步——规划、工具调用、模型推理、结果聚合——都打上span才第一次看清了整条执行链路。这就是AI代理可观测性要解决的核心问题让一个非确定性的、多步骤的、涉及外部依赖的执行过程变得可追踪、可度量、可归因。OTel负责采集和标准化遥测数据OpenLit负责把AI相关的语义约定比如token数、模型名、prompt内容自动注入到span里Elastic负责存储、检索和可视化。三者组合起来就是一套从采集到分析的完整方案。这套东西适合谁如果你正在把AI代理往生产环境推或者已经被“代理行为不可预测”折磨过那这套方案值得花时间搭起来。如果你只是本地跑个demo玩玩那确实用不上但了解一下思路没坏处。2. 三个组件各自扮演什么角色2.1 OTel遥测数据的“普通话”OpenTelemetry的核心价值在于标准化。在OTel出现之前每个监控厂商都有自己的SDK和数据格式你用了A厂商的APM想换B厂商就得把所有埋点重写一遍。OTel定义了一套与厂商无关的API、SDK和协议OTLP你只需要按它的规范埋点后端想换谁换谁。对于AI代理场景OTel提供三种信号Traces链路记录一次请求从入口到出口的完整调用链每个步骤是一个spanspan之间有父子关系。这是排查“哪一步慢了”的核心武器。Metrics指标聚合性的数值比如请求总数、平均延迟、token消耗总量。适合做告警和趋势分析。Logs日志离散的事件记录适合记录具体的错误信息和调试细节。三者不是孤立的。OTel的Exemplar机制可以把trace ID关联到metric数据点上你在看延迟飙升的指标时能直接跳到对应的慢链路。这个能力在排查AI代理的间歇性性能问题时特别有用。2.2 OpenLit给AI代理装上“AI语义”OTel本身是通用的它不知道什么是“模型推理”、什么是“token消耗”。OpenLit做的事情就是在OTel的基础上为AI/LLM场景补充语义约定。它提供了一套自动埋点能力你只需要初始化OpenLit它就会自动拦截主流AI框架LangChain、LlamaIndex、OpenAI SDK等的调用生成带有AI专属属性的span。这些属性包括但不限于属性名含义排查时的用途gen_ai.systemAI系统标识如openai区分不同模型提供商gen_ai.request.model请求的模型名对比不同模型的表现gen_ai.usage.prompt_tokens输入token数分析成本构成gen_ai.usage.completion_tokens输出token数发现异常长的输出gen_ai.response.finish_reasons结束原因判断是否被截断没有这些属性你看到的只是一个普通的HTTP调用span根本不知道这次调用消耗了多少token、用的是哪个模型。OpenLit把这些信息补全了让链路数据真正对AI场景有意义。2.3 Elastic存储、检索与可视化Elastic在这里承担的是可观测性后端的角色。OTel Collector把数据通过OTLP协议发过来Elastic的APM Server接收后存入ElasticsearchKibana提供可视化界面。选择Elastic的理由有几个一是它对OTLP的原生支持已经比较成熟不需要额外的转换层二是它的查询语言KQL、ES|QL足够灵活能做复杂的聚合分析三是它的APM界面开箱即用服务地图、延迟分布、错误率这些视图不需要自己从零搭。当然Elastic不是唯一选择Jaeger、Grafana Tempo、Datadog都能接OTel数据。但如果你已经在用Elastic Stack做日志分析那把它扩展成可观测性后端是最省事的路径。3. 从零搭建环境准备与部署实操3.1 部署Elastic Stack我推荐用Docker Compose来搭本地环境比手动安装省心得多。Elastic官方提供了docker-compose.yml模板但默认配置对可观测性场景不够用需要做几处调整。首先创建一个docker-compose.ymlversion: 3.8 services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0 environment: - discovery.typesingle-node - xpack.security.enabledfalse - ES_JAVA_OPTS-Xms2g -Xmx2g ports: - 9200:9200 volumes: - es-data:/usr/share/elasticsearch/data kibana: image: docker.elastic.co/kibana/kibana:8.13.0 environment: - ELASTICSEARCH_HOSTShttp://elasticsearch:9200 ports: - 5601:5601 depends_on: - elasticsearch apm-server: image: docker.elastic.co/apm/apm-server:8.13.0 command: apm-server -e -E output.elasticsearch.hosts[elasticsearch:9200] -E apm-server.auth.anonymous.enabledtrue -E apm-server.rum.enabledfalse ports: - 8200:8200 depends_on: - elasticsearch volumes: es-data:几个关键点说明一下。xpack.security.enabledfalse是为了本地调试方便生产环境必须开启。ES_JAVA_OPTS设置堆内存为2GB低于这个值在数据量上来后容易OOM。APM Server的auth.anonymous.enabledtrue允许匿名上报同样只适合本地环境。启动后访问http://localhost:5601确认Kibana正常访问http://localhost:8200看到APM Server的JSON响应就算通了。注意Elastic 8.x默认开启安全认证如果不想关安全需要生成 enrollment token 并配置证书步骤会多不少。本地开发建议先关掉跑通流程后再补安全配置。3.2 配置OTel CollectorOTel Collector是数据管道的中枢它接收应用发来的遥测数据经过处理后转发给Elastic。创建一个otel-collector-config.yamlreceivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 processors: batch: timeout: 5s send_batch_size: 1024 memory_limiter: check_interval: 1s limit_mib: 512 exporters: elasticsearch: endpoints: [http://apm-server:8200] tls: insecure: true service: pipelines: traces: receivers: [otlp] processors: [memory_limiter, batch] exporters: [elasticsearch] metrics: receivers: [otlp] processors: [memory_limiter, batch] exporters: [elasticsearch]memory_limiter这个processor建议一定要加。AI代理的span数据量可能很大特别是prompt内容被完整记录时没有内存限制Collector可能被撑爆。batch的timeout设为5秒是个折中值太短会增加网络请求数太长会导致数据延迟可见。3.3 应用侧接入OpenLitPython环境下接入最简单pip install openlit opentelemetry-exporter-otlp然后在应用入口处初始化import openlit openlit.init( otlp_endpointhttp://localhost:4318, application_namemy-ai-agent, environmentdevelopment, capture_message_contentTrue, )capture_message_contentTrue会把prompt和completion的完整内容记录到span里。这个选项在调试阶段非常有用但生产环境要慎重——一是数据量大二是可能包含敏感信息。建议生产环境关掉或者只记录摘要。初始化完成后OpenLit会自动拦截LangChain、OpenAI SDK等库的调用。你不需要改任何业务代码原有的代理逻辑照常跑遥测数据会自动上报。4. 核心细节埋点策略与数据采集要点4.1 手动埋点补充自动埋点的盲区OpenLit的自动埋点覆盖了主流AI框架的调用但代理的“规划”和“决策”环节往往是自己写的逻辑自动埋点覆盖不到。这时候需要手动加spanfrom opentelemetry import trace tracer trace.get_tracer(agent.planner) def plan_task(user_input): with tracer.start_as_current_span(agent.plan) as span: span.set_attribute(agent.input_length, len(user_input)) plan llm_plan(user_input) span.set_attribute(agent.step_count, len(plan.steps)) span.set_attribute(agent.plan_type, plan.type) return plan手动span的价值在于把代理的决策过程显式化。当用户反馈“代理选错了工具”时你能直接看到规划阶段的输入和输出而不是只能看到工具调用的结果。4.2 Span的粒度控制粒度太粗排查时定位不到具体步骤粒度太细数据量爆炸且链路图难以阅读。我的经验是遵循“一个可独立失败的步骤一个span”原则。具体来说每次模型推理调用 → 一个span每次外部工具调用 → 一个span每次向量检索 → 一个span代理的整体规划 → 一个span父span整个请求入口 → 一个span根span不要为每个token生成事件也不要把整个代理循环塞进一个span。前者数据量不可控后者失去了追踪的意义。4.3 采样策略的选择生产环境不可能记录100%的链路采样是必须的。OTel支持两种采样头部采样Head-based在链路开始时决定是否采样实现简单但可能漏掉慢请求。尾部采样Tail-based等链路结束后根据条件决定能保证慢请求和错误请求被采集但需要Collector缓存完整链路。对于AI代理场景我强烈建议用尾部采样。因为AI代理的慢请求往往是间歇性的头部采样很容易漏掉。在Collector里配置processors: tail_sampling: decision_wait: 10s policies: - name: errors type: status_code status_code: {status_codes: [ERROR]} - name: slow-requests type: latency latency: {threshold_ms: 5000} - name: sample-10-percent type: probabilistic probabilistic: {sampling_percentage: 10}这个配置保证所有错误链路和超过5秒的慢链路都被采集其余链路按10%采样。decision_wait设为10秒是因为AI代理的链路可能很长需要等足够时间让所有span到达。提示尾部采样会显著增加Collector的内存消耗因为要缓存等待中的链路。如果内存紧张可以适当降低decision_wait或减少采样策略。5. 实操过程从数据采集到问题定位5.1 验证数据链路是否通畅搭好环境后第一步是确认数据能到Elastic。在Kibana里进入Observability → APM如果看到my-ai-agent这个服务出现说明链路通了。点进去应该能看到服务地图展示服务间的调用关系延迟分布P50、P95、P99延迟曲线事务列表每次请求的详细链路如果服务没出现按这个顺序排查应用是否成功初始化OpenLit → OTel Collector是否收到数据看Collector日志→ APM Server是否正常接收看APM Server日志→ Elasticsearch是否有索引写入。5.2 用KQL定位慢请求假设用户反馈“某些问题回答特别慢”在Kibana的APM界面用KQL过滤service.name: my-ai-agent and transaction.duration.us 5000000这会筛出所有超过5秒的请求。点进任意一条能看到完整的span瀑布图。我实际排查过的一个案例中瀑布图显示根span8.2秒规划span0.3秒向量检索span0.5秒模型推理span7.1秒结果聚合span0.3秒问题一目了然——模型推理占了87%的时间。进一步看span属性发现gen_ai.usage.completion_tokens高达2000而正常请求只有200左右。原因是某个用户的提问触发了模型的长篇输出而我们的max_tokens设置得太宽松。5.3 用ES|QL做聚合分析Kibana的ES|QLElasticsearch Query Language适合做跨链路的聚合分析。比如统计不同模型的平均token消耗FROM traces-apm* | WHERE service.name my-ai-agent | STATS avg_prompt AVG(gen_ai.usage.prompt_tokens), avg_completion AVG(gen_ai.usage.completion_tokens) BY gen_ai.request.model这个查询能帮你判断哪个模型的性价比最高。我们当时对比了三个模型发现其中一个模型虽然单价低但completion token数平均是其他模型的两倍实际成本反而更高。没有这个聚合数据光看单价很容易做出错误决策。5.4 建立告警规则可观测性的最终目的是提前发现问题而不是等用户投诉。在Kibana的Alerting里可以基于APM指标建告警告警项条件严重级别高延迟P95延迟 10秒持续5分钟Critical错误率错误率 5%持续3分钟CriticalToken异常单次请求completion token 4000Warning工具调用失败工具span错误率 10%Warning告警触发后可以对接邮件、Slack或PagerDuty。关键是阈值要结合业务实际调整不要照搬默认值。我们一开始把延迟阈值设为3秒结果告警天天响后来发现AI代理的正常延迟就在2-4秒之间调到10秒后才变得有意义。6. 常见问题与排查技巧实录6.1 数据不上报的排查路径这是最常见的问题按以下顺序检查OpenLit是否初始化成功在应用启动日志里搜索“openlit”确认没有报错。OTLP端点是否可达用curl http://localhost:4318/v1/traces测试返回405说明端点活着。Collector日志是否有错误docker logs otel-collector看有没有导出失败的信息。APM Server是否接收docker logs apm-server看有没有publish相关的日志。Elasticsearch索引是否存在curl http://localhost:9200/_cat/indices?v看有没有traces-apm*索引。我踩过的一个坑是OpenLit初始化时otlp_endpoint写成了http://localhost:4317gRPC端口但OpenLit默认用HTTP协议导致数据发不出去。改成4318就好了。gRPC和HTTP的端口别搞混。6.2 Span丢失与链路断裂有时候能看到部分span但链路不完整。常见原因上下文传播失败跨进程调用时trace context没有正确传递。检查是否在HTTP header里带了traceparent。异步任务未关联Python的asyncio任务如果没正确传递contextspan会变成孤儿span。用trace.use_span()手动关联。采样决策不一致如果多个服务各自采样可能出现上游采了下游没采的情况。统一在Collector做尾部采样可以避免。6.3 数据量过大导致Elasticsearch压力AI代理的span属性多、内容长数据量比普通APM大得多。几个优化手段关闭prompt内容记录生产环境设capture_message_contentFalse。设置索引生命周期ILMtrace数据保留7天之后自动删除或归档到冷存储。限制属性长度在Collector里用attributesprocessor截断过长的属性值。调整刷新间隔Elasticsearch默认1秒刷新一次对trace数据可以调到30秒减少写入压力。6.4 常见问题速查表现象可能原因解决方法服务不出现在APMOpenLit未初始化或端点错误检查初始化代码和端点端口链路只有根span自动埋点未生效确认AI框架版本被OpenLit支持延迟数据偏高采样包含了大量慢请求检查采样策略是否偏向慢请求token数为0模型响应未包含usage信息确认模型API返回了usage字段Kibana查询超时索引过大或查询范围太广缩小时间范围或优化查询条件7. 生产环境部署的几点经验本地跑通和上生产是两回事。几个我在实际部署中总结的要点安全配置不能省。本地关掉的安全认证生产必须开。APM Server的secret token、Elasticsearch的TLS、Kibana的认证一个都不能少。我见过因为APM端点暴露导致trace数据被篡改的案例虽然不常见但后果严重。资源规划要留余量。Elasticsearch对内存很敏感trace数据又是写入密集型的。建议至少给Elasticsearch分配4GB堆内存并且用SSD存储。如果数据量特别大考虑用Elastic Cloud的Serverless模式省去运维成本。采样率要动态调整。业务低峰期可以调高采样率获取更多细节高峰期调低减少压力。这个可以通过Collector的配置热更新实现不需要重启服务。和现有监控体系打通。如果团队已经在用Prometheus做指标监控可以把OTel的metric数据同时导出到Prometheus和Elastic避免形成数据孤岛。OTel Collector支持配置多个exporter一份数据多处消费。定期review span属性。随着代理逻辑的迭代span属性可能会变得冗余或缺失。建议每个季度review一次埋点方案删掉不再使用的属性补充新业务需要的属性。我们有一次发现某个关键的工具调用参数没有被记录导致排查问题时缺少关键信息后来补上才解决。这套方案我从最初搭建到稳定运行大概花了两周时间其中大部分时间花在调采样策略和优化Elasticsearch性能上。一旦跑顺了排查AI代理问题的效率提升是数量级的——以前靠猜现在靠数据。如果你也在被AI代理的“黑盒”问题困扰建议尽早把这套可观测性体系搭起来越早搭收益越大。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑