news 2026/9/13 22:02:07

DeepEval OTel 指南:`confident.trace.*` 追踪级属性全解与 Confident AI 观测数据契约

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DeepEval OTel 指南:`confident.trace.*` 追踪级属性全解与 Confident AI 观测数据契约

DeepEval OTel 指南:confident.trace.*追踪级属性全解与 Confident AI 观测数据契约

【免费下载链接】deepevalThe LLM Evaluation Framework项目地址: https://gitcode.com/GitHub_Trending/de/deepeval

本篇基于 DeepEval 仓库中 trace-attributes.md 参考文档,系统讲解 Confident AI 观测平台(Observatory)在接收原始 OpenTelemetry(OTLP)追踪时如何识别"整条 Trace"级别的元数据:全部 15 个confident.trace.*属性的键名、类型与语义、环境(environment)的解析优先级,以及 OTLP 数据类型编码规则。读完后你能够不依赖deepevalPython 包、仅用任意语言的 OpenTelemetry SDK,把 AI 应用(LLM 应用、Agent、RAG 管线、聊天机器人)的完整追踪以正确的数据契约导出到 Confident AI,并用仓库内的模板代码做冒烟验证。

追踪级属性与 Span 级属性的边界

在动手之前必须先分清两级数据的语义边界:

  • Trace(追踪)是一次端到端的完整执行(例如一次用户提问触发的 Agent 运行),它的各个组成部分是 Span;
  • Span 级属性confident.span.*及按类型划分的confident.llm.*confident.agent.*confident.retriever.*confident.tool.*)描述的是单个 Span——也就是追踪中的某一个组件,这些字段单独记录在 span-attributes.md 中;
  • Trace 级属性(即本篇主题)用confident.trace.*前缀,描述的是整条追踪。设置方式非常直接:把它们作为普通属性写到该追踪中的任意一个 Span上——最自然的位置是根 Span。Confident AI 的导出端会把这些属性聚合(aggregate)到 Trace 层面,你无需在 OTLP 协议之外再做任何 Trace 级封装。

这个设计带来两个实用推论:其一,属性写在哪个 Span 上都合法,但集中在根 Span 上可读性最好;其二,父子嵌套关系不靠属性表达,而完全来自原生 OpenTelemetry 的 Span 上下文(在tracer.start_as_current_span(...)with块内开启的子 Span 会自动挂到父 Span 下)。

confident.trace.*属性全表

以下是参考文档定义的完整属性表。所有属性均为可选——只设置对你的应用有意义的字段即可。

属性键类型说明
confident.trace.namestring人类可读的追踪名称。
confident.trace.inputstring追踪输入。透传字段;若值本身不是字符串,先 JSON 编码。
confident.trace.outputstring追踪输出。透传字段;若值本身不是字符串,先 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",解析规则见下文专节。
confident.trace.retrieval_contextlist of strings该追踪检索到的文本块 / 文档。原生 OTLP 字符串数组,或 JSON 数组字符串。
confident.trace.contextlist of strings该追踪的"真值"(ground-truth)上下文。原生 OTLP 字符串数组,或 JSON 数组字符串。
confident.trace.tools_calledlist of strings追踪过程中实际调用的工具。原生 OTLP 列表,其中每个元素是一个 JSON 序列化的ToolCall
confident.trace.expected_toolslist of strings本应被调用的工具。原生 OTLP 列表,元素为 JSON 序列化的ToolCall字符串。
confident.trace.test_case_idstring对某个测试用例(test case)ID 的引用。
confident.trace.turn_idstring多轮对话中的轮次标识。
confident.trace.metric_collectionstring一个 Confident AI 指标集合(metric collection)的名称,用于对该追踪执行在线(服务端)评估。

几点使用提示(直接来自参考文档的语义):

  • confident.trace.input/confident.trace.output透传(passthrough):它们不做解析,所以如果你的输入输出是对象(如消息列表),请先json.dumps再写入,否则会被序列化器拒绝或丢失结构;
  • confident.trace.tags用于在 Observatory 里对追踪做分组筛选,user_id/thread_id则是用户维度与多轮会话维度分析的基础字段;
  • confident.trace.metric_collection在线评估(server-side evals)的入口:写上指标集合名后,Confident AI 会在服务端对落地的追踪自动跑这套指标,无需在应用侧实现评估逻辑;
  • test_case_idturn_id用于把生产追踪与离线评估的测试用例、多轮会话的轮次对应起来,属于把"线上观测"与"离线评测"打通的关键字段。

Environment 解析:Resource 优先,默认production

confident.trace.environment接受部署环境字符串,常见取值为"production""staging""development""testing"缺省值为"production"。它可以在两个位置设置,且Resource 属性优先于 Span 属性

  1. 作为Span 属性confident.trace.environment直接写在某个 Span 上;
  2. 作为 OpenTelemetryResource 属性:挂在TracerProviderResource上,键名同样是confident.trace.environment。这是推荐做法——对整个进程一次性打上环境戳,避免每个 Span / 每次埋点重复设置。

当两处同时存在且取值冲突时,以 Resource 上的值为准。这个优先级设计的意图很清晰:环境是部署层面的事实,应由进程级配置(Resource)表达,Span 级设置只是细粒度覆盖的退路。

用 Python 表达即:

from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.resources import Resource # 推荐:进程级一次性打环境戳(Resource 优先于 Span 属性) resource = Resource.create({ "service.name": "my-ai-app", "confident.trace.environment": "staging", }) provider = TracerProvider(resource=resource)

OTLP 数据类型规则:JSON 字符串 vs 原生数组

参考文档明确声明:对象用 JSON 字符串、列表用原生 OTLP 数组、ToolCall列表的特殊编码,这三条规则对追踪级与 Span 级属性完全一致,统一收录在 span-attributes.md 的Data-Type Rules一节。在编码tagsmetadatacontextretrieval_contexttools_calledexpected_tools之前必须先读那一节。其核心内容如下(OpenTelemetry 属性值只允许原始类型同质的原始类型列表,不存在 map / object 属性类型):

  • 对象 / dictconfident.span.metadataconfident.trace.metadata)必须是JSON 编码字符串——即json.dumps(...)的结果,而不是 dict 本身;
  • 字符串列表tagscontextretrieval_context,以及 Span 级的available_toolsagent_handoffs)可以用原生 OTLP 字符串数组(Python 里的list/tupleofstr),JSON 数组字符串也可以被接受;
  • ToolCall列表tools_calledexpected_tools)必须是原生 OTLP 列表、每个元素是一个 JSON 序列化的ToolCall字符串——即"一个列表装若干 JSON 字符串",而不是"一个 JSON 字符串装一个列表"。这是最容易被写错的形态;
  • input/output是透传:值若不是字符串,先 JSON 编码再设置;
  • 数字top_kchunk_size、token 数、成本等)以原生 int / float 设置,不要写成字符串。

对应的最小编码示例:

import json span.set_attribute("confident.trace.tags", ["support", "example"]) # 原生数组 ✅ span.set_attribute( "confident.trace.metadata", json.dumps({"app_version": "1.0.0", "route": "order_status"}), # dict 必须 dumps ✅ ) span.set_attribute( "confident.trace.tools_called", [json.dumps({"name": "lookup_order", "args": {"order_id": "123"}})], # 列表,元素各自是 JSON 字符串 ✅ )

源码级证据:ConfidentAttr键注册表与update_current_trace

参考文档定义的是"原始 OTLP 契约",而 DeepEval Python SDK 侧存在与之对应的规范键注册表,可以拿来交叉印证键名的拼写与集合。

ConfidentAttr(位于 attributes.py)集中定义了所有confident.*规范键,其中追踪级字段(第 54–87 行)与参考文档的 15 个属性一一对应:TRACE_NAMETRACE_INPUTTRACE_OUTPUTTRACE_USER_IDTRACE_THREAD_IDTRACE_TAGSTRACE_METADATATRACE_ENVIRONMENTTRACE_RETRIEVAL_CONTEXTTRACE_CONTEXTTRACE_TOOLS_CALLEDTRACE_EXPECTED_TOOLSTRACE_TEST_CASE_IDTRACE_TURN_IDTRACE_METRIC_COLLECTION。从源码结构看,该注册表还额外包含了TRACE_TEST_RUN_ID以及一组confident.trace.llm_test_case.*前缀键(input / context / expected_output / actual_output / retrieval_context / tools_called / expected_tools),这些是 SDK 把LLMTestCase字段落到追踪上时使用的内部键,不在原始 OTLP 参考文档的对外契约表里。

该模块的文档字符串也解释了为什么键名必须精确:

集成方把键写到 OTel Span 上,ConfidentSpanExporter再读回来,因此拼写错误是隐性的——错误会落在一个没人查看的键上,对应字段就会无声地从追踪中消失。

这正是参考文档反复强调键名一字不差的原因。

SDK 的编程接口侧,update_current_trace(位于 context.py)暴露了与上述属性几乎同名的参数:nametagsmetadatathread_iduser_idinputoutputretrieval_contextcontextexpected_outputtools_calledexpected_toolstest_casetest_case_idturn_idmetric_collection等,并支持直接传入一个test_case参数,一次性把LLMTestCase的 input、actual_output、expected_output、retrieval_context、context、tools_called、expected_tools 全部写入当前追踪上下文。可以看到,参考文档中的每个追踪级属性都在 SDK API 中有对应入口,两者是同一契约的"OTLP 原始形态"与"Python 便捷形态"。

实战:用官方模板发出一条带confident.trace.*的示例 Trace

confident_otel_setup.py 模板提供了可直接运行的最小示例:一个 agent 根 Span 包裹一个子 LLM Span,并在根 Span 上设置追踪级属性。模板中追踪级属性的写法(第 75–84、107 行)恰好覆盖了前文所有编码规则的典型形态:

with tracer.start_as_current_span("support-agent") as root: # 追踪级属性(confident.trace.*)可写在任意 Span 上,根 Span 最自然。 root.set_attribute("confident.trace.name", "support-chat") root.set_attribute("confident.trace.input", "Where is my order?") # 字符串列表 → 原生 OTLP 数组 root.set_attribute("confident.trace.tags", ["support", "example"]) # dict / metadata → 必须 JSON 编码为字符串(OTLP 没有 map 类型) root.set_attribute( "confident.trace.metadata", json.dumps({"app_version": "1.0.0", "route": "order_status"}), ) # ...(子 LLM Span 见模板第 87–104 行) root.set_attribute("confident.trace.output", answer)

运行前需要:

  1. 安装依赖:pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
  2. 导出CONFIDENT_API_KEY环境变量(不要硬编码在源码里);
  3. 直接python confident_otel_setup.py——脚本会自动按 API key 的地区前缀选择端点(confident_eu_...https://eu.otel.confident-ai.com,其余走https://otel.confident-ai.com),以OTLPSpanExporter指向<endpoint>/v1/traces并携带x-confident-api-key头完成导出,退出前调用trace.get_tracer_provider().shutdown()冲刷批处理器(BatchSpanProcessor)。

端点、鉴权头与"仅 OTLP/HTTP、拒绝 gRPC"等网络侧细节,完整说明见同目录的 endpoint-and-exporter.md;整体接入流程与"只导出 AI Span"的隔离原则见 SKILL.md。

关键要点回顾

  1. 两级契约confident.trace.*描述整条追踪、confident.span.*描述单个组件;追踪级属性写在任意 Span(推荐根 Span)上,由 Confident AI 端聚合到 Trace。
  2. 15 个属性全部可选:name / input / output / user_id / thread_id / tags / metadata / environment / retrieval_context / context / tools_called / expected_tools / test_case_id / turn_id / metric_collection,只设置有意义的字段。
  3. Environment 解析:默认"production";Span 属性与 Resource 属性两处可设,Resource 优先,推荐进程级 Resource 一次性打戳。
  4. 数据类型规则与 Span 级完全一致:dict 一律json.dumps,字符串列表用原生 OTLP 数组(JSON 数组字符串亦可),tools_called/expected_tools是"元素各自为 JSON 字符串"的列表,数字用原生 int / float——详见 span-attributes.md。
  5. 键名是硬契约:拼写错误不会报错,只会让字段静默消失;对照 ConfidentAttr 注册表可校验键名,用 confident_otel_setup.py 模板可端到端冒烟验证。

【免费下载链接】deepevalThe LLM Evaluation Framework项目地址: https://gitcode.com/GitHub_Trending/de/deepeval

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 22:01:37

Newsletter产品化升级:从内容推送走向决策工具箱

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 21:55:58

Lithe-IDEA:专为Spring Boot开发者优化的轻量开源IDE

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 21:55:05

Iris数据集与Redis缓存实战:从序列化到分布式锁的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 21:53:47

RK3568 Linux驱动开发实战:设备树、I2C/CAN与模块加载全链路解析

1. 这不是教科书&#xff0c;是我在RK3568产线踩出来的驱动开发路径图你手上正拿着一块瑞芯微RK3568的开发板&#xff0c;板子上焊着SSD1306 OLED屏、AD9361射频芯片、还有几路CAN总线接口——但Linux系统起来后&#xff0c;ls /dev里啥也没有&#xff0c;dmesg | grep i2c只看…

作者头像 李华
网站建设 2026/9/13 21:51:52

WinForm拖动封装:一个DragHandler类统一管理窗体与控件拖拽

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 21:49:38

Yolo 小白入门 69:摄像头与 RTSP 不稳定?重连、丢帧与队列设计

Yolo 小白入门 69:摄像头与 RTSP 不稳定?重连、丢帧与队列设计 [!NOTE] 你现在位于《Yolo 全速入门到精通【持续更新中】》的 第七章 推理工程化。这一篇不追求堆满参数,而是带你比较“视频流稳定性”的最小可验证闭环,并能说清它在数据、模型与业务之间的位置。我们用 ul…

作者头像 李华