跟踪数据模型

本文档详细概述了 MLflow 跟踪数据模型。 了解此模型是利用 MLflow 跟踪来观察性和分析生成 AI 应用程序的关键。

MLflow 跟踪旨在 与 OpenTelemetry 规范兼容,这是一种广为采用的可观测性行业标准。 这可确保互作性并允许导出 MLflow 跟踪,并将其与其他 OpenTelemetry 兼容的系统一起使用。 MLflow 通过定义生成 AI 用例的特定结构和属性来增强基本的 OpenTelemetry Span 模型,从而提供更丰富的上下文和更深入的质量和性能见解。

跟踪的结构

概括而言,MLflow 追踪 由两个主要对象组成:

  1. TraceInfo
    • 有助于解释跟踪的起源、跟踪的状态、有关执行总时间的信息等的元数据。
    • 为跟踪提供其他上下文的标记,例如用户、会话和开发人员提供的键值对。 标记可用于搜索或筛选跟踪。
    • 通过评估,可以将来自人类、LLM 评委或真实数据的结构化反馈标签添加到跟踪或跟踪中的特定范围。
  2. TraceData
    • 实际有效负载,其中包含检测的 Span 对象,这些对象从输入到输出捕获应用程序的分步执行。

小窍门

有关这些数据类对象的帮助程序方法的详细信息,请查看 API 文档,了解有关如何从这些对象转换或提取数据的详细信息。

跟踪体系结构

1. 跟踪信息

MLflow TraceInfo 的跟踪功能旨在提供有关整个跟踪的关键数据的轻型快照。 TraceInfo 是包含有关跟踪的元数据的 dataclass 对象。

此元数据包括有关跟踪的来源、状态以及各种其他数据信息,这些信息在与mlflow.client.MlflowClient.search_traces一起使用时,有助于在 MLflow UI 中进行跟踪的检索、筛选和导航。 若要详细了解元数据如何 TraceInfo 用于搜索,可 在此处查看示例。

参数 数据类型 DESCRIPTION
trace_id str 跟踪的主要标识符。
trace_location TraceLocation 存储跟踪的位置,表示为 :p y:class:~mlflow.entities.TraceLocation 对象。 MLflow 目前支持将 MLflow 试验或 Databricks 推理表设置为跟踪位置。
request_time int 跟踪的开始时间(以毫秒为单位)。
state TraceState 跟踪的状态,表示为 :py:class:~mlflow.entities.TraceState 枚举。 可以是 [OKERRORIN_PROGRESSSTATE_UNSPECIFIED] 之一。
request_preview Optional[str] 对模型/代理的请求,其等同于根范围的输入,经过 JSON 编码,且可以被截断。
response_preview Optional[str] 来自模型/代理的响应,相当于根级范围的输出,以 JSON 编码形式呈现,并且可能被截断。
client_request_id Optional[str] 客户端提供与跟踪关联的请求 ID。 这可用于标识来自生成跟踪的外部系统的跟踪/请求,例如 Web 应用程序中的会话 ID。
execution_duration Optional[int] 跟踪的持续时间(以毫秒为单位)。
trace_metadata dict[str, str] 与跟踪关联的键值对。 它们专为不可变值而设计,例如与跟踪关联的运行 ID。
tags dict[str, str] 与跟踪关联的标记。 它们专为可变值而设计,可在通过 MLflow UI 或 API 创建跟踪后进行更新。
assessments list[Assessment] 与跟踪关联的评估列表。

对象中包含的 TraceInfo 数据用于填充 MLflow 跟踪 UI 中的跟踪视图页,如下所示。

TraceInfo 在 MLflow UI 中的使用方式

下面列出了 MLflow TraceInfo 对象的主要组件。

元数据

评估

评估对于确定在跟踪中捕获的 GenAI 应用程序行为的质量和正确性至关重要。 它们允许您将结构化标签、分数或真实信息附加到跟踪或跟踪内的特定范围。

MLflow 定义了两种主要类型的评估,这两种评估都继承自基本 Assessment 概念:

  1. 反馈:表示对操作输出的定性和/或定量判断。 这可以来自人工审阅者、LLM 即评委或自定义评分函数。
  2. 预期:表示给定作的基础真相或预期结果,通常用于与实际输出的直接比较。

评估通常使用类似 mlflow.log_feedback()mlflow.log_expectation()或更通用的 mlflow.log_assessment()的函数记录在跟踪日志中。

评估源

每个评估都与源相关联,以跟踪其源。

  • source_type:一个mlflow.entities.AssessmentSourceType枚举。 关键价值包括:
    • HUMAN:人类提供的反馈或期望。
    • LLM_JUDGE:由充当法官的 LLM 生成的评估。
    • CODE:由编程规则、启发式或自定义记分器生成的评估。
  • source_id:特定源的字符串标识符(例如,用户 ID、LLM 法官的模型名称、脚本名称)。
from mlflow.entities import AssessmentSource, AssessmentSourceType

# Example: Human source
human_source = AssessmentSource(
    source_type=AssessmentSourceType.HUMAN,
    source_id="reviewer_alice@example.com"
)

# Example: LLM Judge source
llm_judge_source = AssessmentSource(
    source_type=AssessmentSourceType.LLM_JUDGE,
    source_id="gpt-4o-mini-evaluator"
)

# Example: Code-based scorer source
code_source = AssessmentSource(
    source_type=AssessmentSourceType.CODE,
    source_id="custom_metrics/flesch_kincaid_scorer.py"
)

反馈

反馈收集对跟踪或跨度输出的质量或特征的评估。

键字段

参数 数据类型 DESCRIPTION
name str 评估的名称。 如果未提供名称,将使用默认名称“feedback”。
value Optional[FeedbackValueType] 反馈值。 可以是 float、int、str、bool、这些类型的列表,或是具有字符串键和这些类型值的字典。
error Optional[Union[Exception, AssessmentError]] 与反馈关联的可选错误。 这用于指示反馈无效或无法处理。 接受一个异常对象、一个 :py:class:~mlflow.entities.Exception 对象或一个 AssessmentError.
rationale Optional[str] 反馈的理由/正当性。
source Optional[AssessmentSource] 评估的来源。 如果未提供,则默认源为 CODE。
trace_id Optional[str] 与评估关联的跟踪的 ID。 如果未设置,则评估尚未与任何追踪相关联。
metadata Optional[dict[str, str]] 与评估关联的元数据。
span_id Optional[str] 与评估关联的范围 ID(如果评估应与跟踪中的特定范围相关联)。
create_time_ms Optional[int] 评估的创建时间(以毫秒为单位)。 如果未设置,则使用当前时间。
last_update_time_ms Optional[int] 评估的最后一次更新时间(以毫秒为单位)。 如果未设置,则使用当前时间。

示例

import mlflow
from mlflow.entities import Feedback, AssessmentSource, AssessmentSourceType

# Log simple binary feedback
mlflow.log_feedback(
    trace_id="trace_123",
    name="is_correct",
    value=True,
    source=AssessmentSource(source_type=AssessmentSourceType.HUMAN, source_id="user_bob"),
    rationale="The answer provided was factually accurate."
)

# Log a numeric score from an LLM judge
llm_judge_feedback = Feedback(
    name="relevance_score",
    value=0.85,
    source=AssessmentSource(source_type=AssessmentSourceType.LLM_JUDGE, source_id="claude-3-sonnet"),
    rationale="The response directly addressed the user's core question.",
    metadata={"judge_prompt_version": "v1.2"}
)
# Assuming trace_id is known, you can also use log_assessment
# mlflow.log_assessment(trace_id="trace_456", assessment=llm_judge_feedback)

预期

期望定义操作的基准真实值或目标输出。

键字段

参数 数据类型 DESCRIPTION
name str 评估的名称。
value Any 操作的预期值。 这可以是任何 JSON 可序列化的值。
source Optional[AssessmentSource] 评估的来源。 如果未提供,则默认源为 HUMAN。 (有关更多详细信息,请参阅 评估源 )。
trace_id Optional[str] 与评估关联的跟踪的 ID。 如果未设置,则评估尚未与任何跟踪相关联。
metadata Optional[dict[str, str]] 与评估关联的元数据。
span_id Optional[str] 与评估关联的范围 ID(如果评估应与跟踪中的特定范围相关联)。
create_time_ms Optional[int] 评估的创建时间(以毫秒为单位)。 如果未设置,则使用当前时间。
last_update_time_ms Optional[int] 评估的最后一次更新时间(以毫秒为单位)。 如果未设置,则使用当前时间。

示例

import mlflow
from mlflow.entities import Expectation, AssessmentSource, AssessmentSourceType

# Log a ground truth answer
mlflow.log_expectation(
    trace_id="trace_789",
    name="ground_truth_response",
    value="The Battle of Hastings was in 1066.",
    source=AssessmentSource(source_type=AssessmentSourceType.HUMAN, source_id="history_expert_01")
)

# Log an expected structured output for a tool call
expected_tool_output = Expectation(
    name="expected_tool_call_result",
    value={"result": {"status": "success", "data": "item_abc_123"}},
    metadata={"tool_name": "inventory_check"}
)
# Assuming trace_id is known:
# mlflow.log_assessment(trace_id="trace_101", assessment=expected_tool_output)

评估错误

用于记录在生成或计算反馈或期望期间发生的错误(例如 LLM 判断失败)。

关键字段

  • error_code (str):错误的代码(例如“RATE_LIMIT_EXCEEDED”、“JUDGE_ERROR”)。
  • error_message (可选[str]):详细的错误消息。
  • stack_trace (可选[str]):堆栈跟踪(如果可用)。

示例

import mlflow
from mlflow.entities import AssessmentError, Feedback, AssessmentSource, AssessmentSourceType

judge_error = AssessmentError(
    error_code="LLM_JUDGE_TIMEOUT",
    error_message="The LLM judge timed out after 30 seconds while assessing relevance."
)

mlflow.log_feedback(
    trace_id="trace_error_example",
    name="relevance_with_judge_v2",
    source=AssessmentSource(source_type=AssessmentSourceType.LLM_JUDGE, source_id="custom_judge_model"),
    error=judge_error
    # Note: `value` is typically None when an error is provided
)

这些实体提供了一种灵活的结构化方法,用于将丰富的定性和定量数据与跟踪相关联,从而构成 MLflow 跟踪中可观测性和评估功能的关键部分。

标记

MLflow TraceInfo 对象中的tags属性用于为追踪提供额外的上下文。 这些标记可用于搜索、筛选或提供有关跟踪的其他信息。

标记是键值对,它们是可变的。 这意味着,即使在跟踪记录到实验之后,也可以随时添加、修改或删除标记。

要了解如何添加自定义标签来捕获自定义元数据,请查看附加自定义标签/元数据

标准标记

MLflow 使用一组标准标记来获取有关用户、会话和环境的常见上下文信息,从而在 MLflow UI 和 SDK 中启用增强的筛选和分组功能:

  • mlflow.trace.session跟踪用户和会话中引入的会话 ID 的标准标记。
  • mlflow.trace.user跟踪用户和会话中引入的用户 ID 的标准标记。
  • mlflow.source.name:生成跟踪的入口点或脚本。
  • mlflow.source.git.commit:如果从 Git 仓库中运行,该源代码的提交哈希值。
  • mlflow.source.type:生成跟踪的源类型,通常 PROJECT (对于 MLflow 项目运行)或 NOTEBOOK (如果从笔记本运行)。

可以在跟踪 用户和会话跟踪环境和上下文的指南中详细了解如何实现这些内容。

2. 跟踪数据

MLflow TraceData 对象可通过 Trace.data 访问,包含跟踪的核心有效负载。 它主要包含操作序列(跨度),以及触发追踪的初始请求和生成的最终响应。

键字段

  • spans (列表[Span]):

    • 这是一个对象列表 Span,这些对象(符合 mlflow.entities.Span 和 OpenTelemetry 规范)表示跟踪中的各个步骤、操作或函数调用。 每个范围详细介绍了一个特定的工作单元。
    • 跨度按分层 parent_id 方式进行组织,以表示执行流。
    • 请参阅下面的 Span Schema 部分,以获取有关Span对象的详细信息。

注释

requestresponse 属性被保留以保持向后兼容。 它们的值是从根范围的相应 inputsoutputs 属性中查找的,而不是由用户直接在 TraceData 对象上设置的。

  • request (str):

    • 表示追踪根跨度输入数据的 JSON 序列化字符串。 这通常是最终用户的请求或调用跟踪的应用程序或工作流的初始参数。
    • 示例'{"query": "What is MLflow Tracing?", "user_id": "user123"}'
  • response (str):

    • 一个 JSON 序列化字符串,表示来自跟踪应用程序或工作流根范围的最终输出数据。
    • 示例'{"answer": "MLflow Tracing provides observability...", "confidence": 0.95}'

概念表示形式

虽然通常通过客户端mlflow.entities.Trace检索到的对象(TraceData例如),但从概念上讲,client.get_trace(trace_id).data它会捆绑这些核心组件:

# Conceptual structure (not direct instantiation like this)
class TraceData:
    def __init__(self, spans: list[Span], request: str, response: str):
        self.spans = spans # List of Span objects
        self.request = request # JSON string: Overall input to the trace
        self.response = response # JSON string: Overall output of the trace

了解 TraceData 是以编程方式分析整个 GenAI 应用程序生命周期内的详细执行路径和数据转换的关键。

跨度

MLflow 跟踪功能中的 Span 对象提供有关跟踪的各个步骤的详细信息。

它符合 OpenTelemetry Span 规范。每个 Span 对象都包含有关正在检测的步骤的信息,包括span_id、名称、start_time、parent_id、状态、输入、输出、属性和事件。

Span 体系结构

跨度架构

跨度是跟踪数据的核心。 它们记录有关 genai 应用程序中每个步骤的关键关键数据。

当您在 MLflow 用户界面中查看跟踪时,您会看到一个跨度的集合,如下所示。

MLflow UI 中的跨度

以下部分提供了跨度结构的详细说明。

范围类型

跨度类型是对跟踪中的跨度进行分类的方法。 默认情况下,使用跟踪修饰器时,范围类型将设置为 "UNKNOWN" 。 MLflow 为常见用例提供了一组预定义的跨度类型,同时允许你设置自定义跨度类型。

以下跨度类型可用。 此外,还可以将范围类型设置为任何开发人员指定的 str 值。

范围类型 说明
"CHAT_MODEL" 代表对聊天模型的查询。 这是 LLM 交互的一种特殊情况。
"CHAIN" 表示一系列操作。
"AGENT" 自主代理运作。
"TOOL" 表示工具执行(通常由代理执行),例如查询搜索引擎。
"EMBEDDING" 表示文本嵌入操作。
"RETRIEVER" 表示上下文检索作,例如查询向量数据库。
"PARSER" 表示分析作,将文本转换为结构化格式。
"RERANKER" 表示重新排名作,根据相关性对检索的上下文进行排序。
"UNKNOWN" 未指定其他跨度类型时使用的默认范围类型。

若要设置范围类型,可以将参数mlflow.trace传递给span_type修饰器或mlflow.start_span上下文管理器。 使用 自动跟踪时,范围类型由 MLflow 自动设置。

import mlflow
from mlflow.entities import SpanType


# Using a built-in span type
@mlflow.trace(span_type=SpanType.RETRIEVER)
def retrieve_documents(query: str):
    ...


# Setting a custom span type
with mlflow.start_span(name="add", span_type="MATH") as span:
    span.set_inputs({"x": z, "y": y})
    z = x + y
    span.set_outputs({"z": z})

    print(span.span_type)
    # Output: MATH

特定跨度类型的架构

MLflow 具有一组预定义的跨度类型(请参阅 mlflow.entities.SpanType),某些范围类型具有属性,以便启用 UI 和下游任务(例如评估)中的其他功能。

检索器范围区间

范围 RETRIEVER 类型用于涉及从数据存储中检索数据的操作(例如,从向量存储库查询文档)。 RETRIEVER 范围的输出应为一个文档列表。

列表中的每个文档都应是字典(或可使用以下键序列化到字典的对象),理想情况下包括:

  • page_contentstr):检索到的文档区块的文本内容。
  • metadataOptional[Dict[str, Any]]):与文档关联的其他元数据的字典。
    • MLflow UI 和评估指标可能会特别查找 doc_uri (用于文档源的字符串 URI)和 chunk_id (如果该文档是较大分块文档的一部分的字符串标识符),以增强显示和功能。
  • idOptional[str]):文档区块本身的可选唯一标识符。

检索器跨度实例操作示例

import mlflow
from mlflow.entities import SpanType, Document


def search_store(query: str) -> list[(str, str)]:
    # Simulate retrieving documents (e.g., from a vector database)
    return [
        ("MLflow Tracing helps debug GenAI applications...", "docs/mlflow/tracing_intro.md"),
        ("Key components of a trace include spans...", "docs/mlflow/tracing_datamodel.md"),
        ("MLflow provides automatic instrumentation...", "docs/mlflow/auto_trace.md")
    ]


@mlflow.trace(span_type=SpanType.RETRIEVER)
def retrieve_relevant_documents(query: str):
    # Get documents from the search store
    docs = search_store(query)

    # Get the current active span (created by @mlflow.trace)
    span = mlflow.get_current_active_span()

    # Set the outputs of the span in accordance with the tracing schema
    outputs = [Document(page_content=doc, metadata={"doc_uri": uri}) for doc, uri in docs]
    span.set_outputs(outputs)

    # Return the original format for downstream usage
    return docs


# Example usage
user_query = "MLflow Tracing benefits"
retrieved_docs = retrieve_relevant_documents(user_query)

# Read path: Reconstructing the document list from the span outputs
trace_id = mlflow.get_last_active_trace_id()
trace = mlflow.get_trace(trace_id)
span = trace.search_spans(name="retrieve_relevant_documents")[0]
documents = [Document(**doc) for doc in span.outputs]

print(documents)

符合此结构,特别是包括page_content和相关metadatadoc_uri,将确保RETRIEVER跨度在 MLflow UI 中能够信息丰富地呈现,例如显示文档内容和提供链接,并且下游评估任务可以正确处理检索的上下文。

聊天完成和工具呼叫范围

类型 CHAT_MODELLLM 的范围用于表示与聊天完成 API 的交互(例如,OpenAI 的 聊天完成 API,或 Anthropic 的 messages API)。 这些范围还可以捕获模型提供给或使用的工具(函数)的相关信息。

由于提供程序的 API 可以具有不同的架构,因此对原始 LLM 调用本身的跨度输入和输出的格式没有严格的限制。 但是,若要启用丰富的 UI 功能(如聊天显示和工具调用可视化),并标准化数据进行评估,MLflow 定义了聊天消息和工具定义的特定属性。

有关如何使用上述实用工具函数以及如何使用函数 span.get_attribute() 检索这些函数的快速演示,请参阅以下示例:

import mlflow
from mlflow.entities.span import SpanType # Corrected from mlflow.entities.span import SpanType
from mlflow.tracing.constant import SpanAttributeKey
from mlflow.tracing import set_span_chat_messages, set_span_chat_tools

# example messages and tools
messages = [
    {
        "role": "system",
        "content": "please use the provided tool to answer the user's questions",
    },
    {"role": "user", "content": "what is 1 + 1?"},
]

tools = [
    {
        "type": "function",
        "function": {
            "name": "add",
            "description": "Add two numbers",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {"type": "number"},
                    "b": {"type": "number"},
                },
                "required": ["a", "b"],
            },
        },
    }
]


@mlflow.trace(span_type=SpanType.CHAT_MODEL)
def call_chat_model(messages, tools):
    # mocking a response
    response = {
        "role": "assistant",
        "tool_calls": [
            {
                "id": "123",
                "function": {"arguments": '{"a": 1,"b": 2}', "name": "add"},
                "type": "function",
            }
        ],
    }

    combined_messages = messages + [response]

    span = mlflow.get_current_active_span()
    set_span_chat_messages(span, combined_messages)
    set_span_chat_tools(span, tools)

    return response


call_chat_model(messages, tools)

trace = mlflow.get_last_active_trace()
span = trace.data.spans[0]

print("Messages: ", span.get_attribute(SpanAttributeKey.CHAT_MESSAGES))
print("Tools: ", span.get_attribute(SpanAttributeKey.CHAT_TOOLS))

后续步骤

继续您的旅程,并参考这些推荐的行动和教程。

参考指南

浏览有关相关概念的详细文档。