将 AI 应用 Trace 导出到 Confident AI Observatory)
DeepEval 与 Confident AI用原生 OpenTelemetryOTLP将 AI 应用 Trace 导出到 Confident AI Observatory【免费下载链接】deepevalThe LLM Evaluation Framework项目地址: https://gitcode.com/GitHub_Trending/de/deepeval本文围绕 DeepEval 仓库中skills/deepeval-otel技能文档展开讲解如何不依赖deepevalPython 包仅用任意语言的 OpenTelemetry SDK 通过 OTLP/HTTP 将 LLM 应用、Agent、RAG 流水线或聊天机器人的 trace 发送到 Confident AI 的 Observatory。读完本文你将掌握 Confident AI OTLP 端点的选择与鉴权方式、confident.span.*/confident.trace.*属性契约、OTLP 数据类型规则、GenAI 语义约定gen_ai.*回退机制以及“只导出 AI span”的管线隔离方案并能直接复用仓库中的可运行模板完成接入。适用边界只针对 AI 应用该技能的核心前提是只对被测对象中的 AI 部分打点。confident.*属性与 span 类型——agent、llm、retriever、tool——都是为描述 AI 组件而设计的Confident AI 的 Observatory 也是围绕 AI 行为的评估与监控构建的。只应打点系统中的 AI 部分Agent 循环与规划、LLM 调用、检索/向量搜索、工具调用不要把confident.*属性应用到非 AI 软件Web 服务器、CRUD 后端、数据库层、基础设施或非 AI span 上——这些数据不属于 Confident AI也无法被有意义地渲染如果目标系统既没有 LLM、没有 Agent 循环、没有检索也没有工具调用则此方案不适用。此外DeepEval 仓库中的技能体系按职责划分本方案deepeval-otel负责厂商中立的 OTLP 导出而用 pytest 构建评估套件、生成数据集/goldens、编写 metrics、运行deepeval test run、使用observe装饰器等场景则应使用 DeepEval SDK 本身参见仓库中的 deepeval 技能文档 与 deepeval-tracing 技能文档。两者是互补关系而非替代关系。前置条件一个 Confident AI 账号以及对应的CONFIDENT_API_KEY应用语言对应的 OpenTelemetry SDK。Python 场景需要安装opentelemetry-sdkopentelemetry-exporter-otlp-proto-http端点只接受 OTLP/HTTP绝不接受 gRPC——这是贯穿全文的第一条硬约束。工作原理Confident AI 暴露一个 OTLP/HTTP traces 端点。把任意 OpenTelemetry span exporter 指向该端点并携带x-confident-api-key请求头即可。Confident AI 侧的 exporter 随后从每个 span 上读取confident.*属性来构建 trace 与 span 结构。关键点在于父子嵌套关系来自原生 OpenTelemetry span contextspan 上下文不来自任何属性。也就是说只要在父 span 的with上下文内开启子 spanConfident AI 就会自动恢复完整的树形结构无需任何额外的“父子”属性约定。端到端接入工作流技能文档给出的标准工作流共 8 步可视为一份接入检查单确认目标是 AI 应用含 LLM 调用、Agent 循环、检索或工具调用否则停止同时检查是否已存在 OpenTelemetry 设施TracerProvider、span exporter 或 OpenTelemetry Collector优先改造已有管线而非新建平行管线根据 API key 的区域前缀选择端点见下文“端点与鉴权”接入或改指一个带x-confident-api-key头的 OTLP/HTTP span exporterPython 场景可直接从 confident_otel_setup.py 模板起步如果进程中还有其他 OpenTelemetry instrumentation 或 APM agentHTTP/DB 自动埋点、Datadog 等隔离 Confident AI 导出确保只有 AI span 到达它见下文“只导出 AI span”在 span 上设置confident.span.*属性trace 级字段设置confident.trace.*见下文属性契约两节遵守 OTLP 数据类型规则dict/metadata 必须 JSON 编码字符串列表用原生数组见“OTLP 数据类型规则”如果应用已经在产生 OpenTelemetry GenAI 语义约定gen_ai.*span先了解回退行为再决定是否补充冗余属性见“gen_ai 回退机制”在 Confident AI Observatory 中验证 trace 是否出现。端点选择、鉴权与传输协议两个区域端点Confident AI 每个区域暴露一个 OTLP/HTTP traces 端点恰好两个区域Base endpointTraces 实际 POST 到默认US/AUhttps://otel.confident-ai.comhttps://otel.confident-ai.com/v1/tracesEUhttps://eu.otel.confident-ai.comhttps://eu.otel.confident-ai.com/v1/traces这里有一个容易踩坑的细节直接配置 OTLP/HTTP span exporter 时endpoint值必须包含/v1/traces后缀而通过标准环境变量OTEL_EXPORTER_OTLP_ENDPOINT配置时只需给 base endpoint——SDK 会自动追加/v1/traces。按 API key 前缀选择端点Confident AI 的 API key 带区域前缀选择规则如下API key 前缀端点confident_eu_…https://eu.otel.confident-ai.comconfident_us_…https://otel.confident-ai.com其他任意前缀https://otel.confident-ai.com默认只有confident_eu_…开头的 key 使用 EU 端点拿不准时用默认端点。confident_otel_setup.py 中的pick_endpoint函数正是按此逻辑实现的def pick_endpoint(api_key: str) - str: if api_key.startswith(confident_eu_): return https://eu.otel.confident-ai.com return https://otel.confident-ai.com鉴权与标准环境变量每个请求都必须携带 API keyx-confident-api-key: CONFIDENT_API_KEYkey 应从CONFIDENT_API_KEY环境变量读取永远不要硬编码到源码中。也可以完全用标准 OpenTelemetry 环境变量配置无需改代码export OTEL_EXPORTER_OTLP_ENDPOINThttps://otel.confident-ai.com export OTEL_EXPORTER_OTLP_HEADERSx-confident-api-keyCONFIDENT_API_KEY传输只有 HTTPPython使用opentelemetry.exporter.otlp.proto.http.trace_exporter中的OTLPSpanExporter包opentelemetry-exporter-otlp-proto-http不要使用opentelemetry.exporter.otlp.proto.grpc变体OpenTelemetry Collector使用otlphttpexporter而不是otlpgRPC其他 SDK选择 OTLP/HTTP exporterproto-http、HttpProtobuf或语言等价物。Python 最小接入示例最小路径分四步创建TracerProvider挂一个包裹 OTLP/HTTPOTLPSpanExporter的BatchSpanProcessor指向endpoint/v1/traces并带x-confident-api-key头注册为全局 tracer provider获取 tracer、开启 span 并设置confident.*属性import os from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter api_key os.environ[CONFIDENT_API_KEY] endpoint ( https://eu.otel.confident-ai.com if api_key.startswith(confident_eu_) else https://otel.confident-ai.com ) provider TracerProvider() provider.add_span_processor( BatchSpanProcessor( OTLPSpanExporter( endpointf{endpoint}/v1/traces, headers{x-confident-api-key: api_key}, ) ) ) trace.set_tracer_provider(provider) tracer trace.get_tracer(__name__) with tracer.start_as_current_span(my-llm-app) as span: span.set_attribute(confident.span.type, agent) span.set_attribute(confident.trace.name, my-llm-app)完整的可运行版本见 confident_otel_setup.py。该模板同时演示了一条完整示例 traceagent 根 span 子 LLM span并覆盖了属性与数据类型契约的几个关键点字符串列表用原生 OTLP 数组root.set_attribute(confident.trace.tags, [support, example])、metadata 用 JSON 编码字符串json.dumps({...})、span 错误用原生 OTelStatus而非confident.*属性、进程退出前调用trace.get_tracer_provider().shutdown()冲刷批次。直接python confident_otel_setup.py即可作为连通性冒烟测试。其他语言接线形状在任何 OpenTelemetry SDK 中都相同只有类名/包名不同。所有语言里都是同样的四步构造 OTLP/HTTP span exporter将endpoint/url设为区域端点/v1/traces添加x-confident-api-key头将其注册到 tracer provider 的 batch span processor 上。之后照常发 span、设置confident.*属性即可——属性 key 就是完整契约与语言无关这正是“语言无关”声明的落地方式。Trace 级属性confident.trace.*契约Trace 级属性描述整条 trace一次端到端执行而非单个 span。它们可以设置在 trace 中任意 span上——最自然的位置是根 span——Confident AI 会将其聚合到 trace 层。完整属性表如下全部可选只设置有意义的字段属性 key类型说明confident.trace.namestring人类可读的 trace 名称confident.trace.inputstringtrace 输入透传非字符串需先 JSON 编码confident.trace.outputstringtrace 输出透传非字符串需先 JSON 编码confident.trace.user_idstring最终用户/客户标识confident.trace.thread_idstring会话或线程标识confident.trace.tagslist of strings分组标签原生 OTLP 字符串数组或 JSON 数组字符串confident.trace.metadataJSON string任意键值上下文必须是 JSON 编码的对象字符串OTLP 无 map 类型confident.trace.environmentstring部署环境默认production见下文 Environment Resolutionconfident.trace.retrieval_contextlist of stringstrace 的检索片段/文档confident.trace.contextlist of stringstrace 的 ground-truth 上下文confident.trace.tools_calledlist of strings本次 trace 调用的工具原生 OTLP list每个元素为 JSON 序列化的ToolCallconfident.trace.expected_toolslist of strings本应调用的工具同上编码方式confident.trace.test_case_idstring关联的测试用例 IDconfident.trace.turn_idstring多轮对话的轮次标识confident.trace.metric_collectionstringConfident AI metric collection 名称用于对该 trace 运行在线服务端评估Environment Resolutionconfident.trace.environment接受部署环境字符串常见为production、staging、development、testing默认值为production。它可以在两个位置设置且Resource 属性优先于 span 属性作为 span 属性在某 span 上设置confident.trace.environment作为TracerProvider的Resource上的 OpenTelemetry Resource 属性confident.trace.environment——这是推荐的整进程一次打环境戳的方式。Span 级属性confident.span.*契约与数据类型规则Span 级属性描述单个 spantrace 中的一个组件设置为该 span 上的confident.span.*以及按类型的confident.llm.*、confident.agent.*、confident.retriever.*、confident.tool.*属性。confident.span.type决定哪些按类型的 key 有意义应最先设置。允许的类型取值恰好是llm、tool、agent、retriever以及无额外类型化字段的通用类型base。通用 span 属性所有类型有效属性 key类型说明confident.span.typestringllm/tool/agent/retriever/base之一缺省时从gen_ai.*属性推断confident.span.namestring显示名覆盖原生 OTel span 名confident.span.inputstringspan 输入透传非字符串需 JSON 编码confident.span.outputstringspan 输出透传非字符串需 JSON 编码confident.span.metadataJSON string帮助诊断故障的组件事实必须是 JSON 编码的对象字符串confident.span.contextlist of strings该 span 的 ground-truth 上下文confident.span.retrieval_contextlist of strings该 span 的检索片段confident.span.tools_calledlist of strings原生 OTLP list元素为 JSON 序列化的ToolCall字符串confident.span.expected_toolslist of strings原生 OTLP list元素为 JSON 序列化的ToolCall字符串confident.span.metric_collectionstringConfident AI metric collection 名称对该 span 运行在线评估各类型专属属性LLM spanconfident.span.type设为llm属性 key类型说明confident.llm.modelstring模型名如gpt-4o回退gen_ai.request.modelconfident.span.providerstringLLM 提供方如openai、anthropic可选缺省时从模型名推断confident.llm.input_token_countint输入/prompt token 数回退gen_ai.usage.input_tokensconfident.llm.output_token_countint输出/completion token 数回退gen_ai.usage.output_tokensconfident.llm.cost_per_input_tokenfloat每输入 token 成本用于成本汇总confident.llm.cost_per_output_tokenfloat每输出 token 成本用于成本汇总如果 span 引用了在 Confident AI 中管理的 prompt还可选设离散 prompt 字段只设置有意义的confident.span.prompt_aliasprompt 别名、confident.span.prompt_version版本标识、confident.span.prompt_commit_hash提交哈希、confident.span.prompt_label标签。Agent spanconfident.span.type设为agent属性 key类型说明confident.agent.namestringAgent 名称/标识confident.agent.available_toolslist of strings该 agent 可用的工具confident.agent.agent_handoffslist of strings可交接的其他 agentRetriever spanconfident.span.type设为retriever属性 key类型说明confident.retriever.embedderstring嵌入模型名如text-embedding-3-smallconfident.retriever.top_kint检索结果数confident.retriever.chunk_sizeint文档 chunk 大小检索到的片段应放在通用的confident.span.retrieval_context上。Tool spanconfident.span.type设为tool属性 key类型说明confident.tool.namestring工具/函数名回退gen_ai.tool.nameconfident.tool.descriptionstring人类可读的工具描述工具的参数放在confident.span.input结果放在confident.span.output。OTLP 数据类型规则OpenTelemetry 属性值只能是原始类型string、bool、int、float或同质原始类型列表不存在 map/object 属性类型。编码规则对象/dictconfident.span.metadata、confident.trace.metadata必须JSON 编码为字符串json.dumps(...)字符串列表tags、context、retrieval_context、available_tools、agent_handoffs用原生 OTLP 字符串数组Python 的list/tupleofstrJSON 数组字符串也被接受ToolCall列表tools_called、expected_tools必须是原生 OTLP list且每个元素是一个 JSON 序列化的ToolCall字符串——即“JSON 字符串的列表”而不是“一个列表的 JSON 字符串”input/output透传值若不是字符串则先 JSON 编码数字top_k、chunk_size、token 数、成本设为原生 int/float不要写成字符串。span 错误与嵌套span 错误不是confident.*属性而应使用原生 OpenTelemetry spanStatusfrom opentelemetry.trace import Status, StatusCode try: ... except Exception as e: span.set_status(Status(StatusCode.ERROR), str(e)) span.record_exception(e)带StatusCode.ERROR的 span 会在 Observatory 中渲染为出错若它是根 span则整条 trace 被标记为出错。span 嵌套父子关系完全来自原生 OTel span context——在父 span 的上下文中开启子 span 即可不存在任何confident.*的父子属性。使用tracer.start_as_current_span(...)时with块内打开的 span 会自动嵌套。gen_ai 语义约定回退机制当confident.*属性缺失时Confident AI 的 exporter 会回退读取标准的 OpenTelemetryGenAI 语义约定属性gen_ai.*。这意味着如果应用已经被某个 GenAI 感知的库打点、天然产生gen_ai.*span这些数据无需任何额外confident.*属性即可带进 Confident AI。span 类型推断未设置confident.span.type时条件推断出的confident.span.typegen_ai.operation.name为chat、generate_content或text_completionllm存在gen_ai.tool.nametool其他base属性回退表confident.*属性回退到gen_ai.*confident.llm.modelgen_ai.request.modelconfident.llm.input_token_countgen_ai.usage.input_tokensconfident.llm.output_token_countgen_ai.usage.output_tokensconfident.tool.namegen_ai.tool.name使用建议两者同时存在时confident.*属性总是胜出新打点优先显式设置confident.*属性——它们映射直接且无歧义依赖回退只是为了避免与既有 GenAI 集成重复属性除非需要覆盖否则不要为应用已设置的gen_ai.*属性添加confident.*副本。这一回退机制在 DeepEval 的 Python 侧同样有实现佐证从源码结构看deepeval/tracing/otel/exporter.py 中调用了check_span_type_from_gen_ai_attributes、check_model_from_gen_ai_attributes、check_tool_name_from_gen_ai_attributes等一组gen_ai属性回退检查函数与技能文档描述的回退契约一致。只导出 AI span与 APM/自动埋点隔离真实应用中跑的 OpenTelemetry instrumentation 往往远不止 AI 代码。自动埋点库与 APM agentDatadog、New Relic、Grafana、OpenTelemetry auto-instrumentation 等会为 HTTP 请求、数据库查询、缓存调用、出站网络调用和框架内部逻辑产生 span。如果 Confident AI exporter 与这些埋点共享同一个 tracer provider 或 processor 管线所有这些无关 span 都会被发送到 Confident AI Observatory把 AI trace 淹没在非 AI 噪音里。规则Confident AI 导出管线只能承载 AI span。有两种做法方案 1 —— 专用管线可行时优先把 Confident AI exporter 注册到一个只被 AI instrumentation 使用的 tracer provider / processor 上与自动埋点和 APM agent 使用的全局 provider 分离。AI span 用该专用 provider 的 tracer 创建——非 AI span 从未进入它的管线自然到不了 Confident AI exporter。方案 2 —— 管线过滤当 AI span 与其他 span 不可避免地共享一个 provider 时AI 框架把 span 发到全局 provider 很常见把面向 Confident AI 的 processor 或 exporter 包在一个过滤器里只转发 AI span丢弃其余。判定一个 span 是 AI span 的依据满足其一即可设置了confident.span.type属性携带gen_ai.*语义约定属性span 名匹配已知的 AI 框架前缀例如 Vercel AI SDK 产生名为ai.*的 span。过滤器可做成两种形态之一一个对非 AI span 的onStart/onEnd直接 no-op 的span processor或一个在调用真正的 OTLP exporter 前从每个批次中剔除非 AI span 的exporter wrapper。仓库中有一个可直接参照的工作实现DeepEval TypeScript SDK 的 typescript/src/integrations/ai-sdk/index.ts 中的DeepEvalBatchFilterProcessor按 span 名前缀过滤的 span processor只放行ai.前缀的 span和DeepEvalExporterWrapperexporter wrapper。可以推断其设计意图正是上述方案 2DeepEvalBatchFilterProcessor在onStart/onEnd中对非ai.span 直接跳过而DeepEvalExporterWrapper在导出批次时记录 AI span id并对已知 AI 根 span 剥离悬空的parentSpanContext。注意——过滤时要保留 span 嵌套。丢弃一个中间的非 AI span 可能使其 AI 子 span 成为孤儿它们的parentSpanId指向一个从未被导出的 span。过滤时应把孤儿 AI span 重新挂到最近的已导出祖先上或者剥掉悬空 parent 引用让其成为干净的根 span。上述DeepEvalExporterWrapper对根 span 恰好做了这件事。核心原则速查技能文档总结的 8 条核心原则可作为上线前的最后自检只打点 AI 组件——agent、LLM、retriever、tool span绝不把confident.*属性用于非 AI 软件或非 AI span只导出 AI span。进程若有其他 OTel instrumentation 或 APM agent隔离 Confident AI 管线专用 provider 或 span filter确保 HTTP 请求、DB 查询、基础设施 span 永不导出优先改造已有的 OTLP exporter而非新增平行管线confident.*属性 key 就是完整契约——各语言中完全相同语言选择无关紧要永远使用 OTLP/HTTP端点不接受 gRPC遵守 OTLP 数据类型规则属性值必须是原始类型或同质原始类型列表dict/metadata 必须 JSON 编码已知时显式设置confident.span.typegen_ai.*推断只作为回退绝不把密钥、凭证或原始敏感数据放进 span 属性。参考文件索引主题文件端点、区域选择、鉴权、exporter 接线、AI span 隔离endpoint-and-exporter.mdTrace 级confident.trace.*属性trace-attributes.mdSpan 级confident.span.*属性与数据类型规则span-attributes.md标准 OTelgen_ai.*回退行为gen-ai-fallbacks.md最小可运行的 Python OTLP exporter 设置 示例 traceconfident_otel_setup.py技能入口文档SKILL.md最后强调适用前提本方案要求一个 Confident AI 账号与CONFIDENT_API_KEY依赖应用语言的标准 OTel SDKPython 示例假设opentelemetry-sdk与opentelemetry-exporter-otlp-proto-http且端点仅支持 OTLP/HTTP。只要你的应用中有 LLM、Agent、检索或工具调用这任一类 AI 组件这套“属性 key OTLP 端点”的语言无关契约即可直接套用。【免费下载链接】deepevalThe LLM Evaluation Framework项目地址: https://gitcode.com/GitHub_Trending/de/deepeval创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考