mcpField
A
analyzing-mlflow-session

analyzing-mlflow-session

github.com/mlflow测试与质量82966 次安装2 天前更新
代码仓库

关于 analyzing-mlflow-session

用于分析 MLflow traces 中多轮聊天会话的技能,帮助开发者高效重建对话、解读评估结果,并追溯问题轮次。

主要功能

  1. 01发现输入和输出结构
  2. 02提取会话 traces 的字段
  3. 03查看评估结果及其依据
  4. 04检查指定轮次的 spans
  5. 05将故障与应用代码关联

适用场景

  1. 01根据 traces 重建聊天对话
  2. 02定位错误开始的轮次
  3. 03调查多轮会话中的评估信号

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mlflow/skills --skill analyzing-mlflow-session

安装后在 Claude Code 中输入/analyzing-mlflow-session确认已加载。

附带文件scripts/discover_schema.shscripts/inspect_turn.sh

详细介绍

分析 MLflow 聊天会话

什么是会话?

会话将属于同一聊天对话或用户交互的多个跟踪记录归为一组。会话中的每条跟踪记录代表一个轮次:用户的输入和系统的响应。会话中的跟踪记录通过存储在跟踪记录元数据中的共享会话 ID 关联起来。

会话 ID 存储在跟踪记录元数据中,键为 mlflow.trace.session。此键包含点号,会影响筛选语法(见下文)。共享此键相同值的所有跟踪记录都属于同一会话。

重建对话

重建会话对话需要多个步骤:从第一条跟踪记录中发现输入/输出架构,然后在会话的所有跟踪记录中高效提取这些字段,最后按需检查特定轮次。不要为每个轮次获取完整跟踪记录——请改用搜索命令中的 --extract-fields。

**步骤 1:发现架构。**首先,找到会话中的一个跟踪记录 ID,然后获取其完整 JSON 以检查架构:

# Get the first trace in the session
mlflow traces search \
  --experiment-id <EXPERIMENT_ID> \
  --filter-string 'metadata.`mlflow.trace.session` = "<SESSION_ID>"' \
  --order-by "timestamp_ms ASC" \
  --extract-fields 'info.trace_id' \
  --output json \
  --max-results 1 > /tmp/first_trace.json

# Fetch the full trace (always outputs JSON, no --output flag needed)
mlflow traces get \
  --trace-id <TRACE_ID_FROM_ABOVE> > /tmp/trace_detail.json

找到根跨度——parent_span_id 等于 null(即没有父级)的跨度。这是跟踪记录中的顶层操作:

# Find the root span
jq '.data.spans[] | select(.parent_span_id == null)' /tmp/trace_detail.json

检查其 attributes 字典,找出存储用户输入和系统输出的键。这些键可能是:

  • MLflow 标准属性:mlflow.spanInputs 和 mlflow.spanOutputs(由 MLflow Python 客户端设置)
  • 自定义属性:通过 @mlflow.trace 或 mlflow.start_span() 设置并记录的应用专属自定义属性
  • 第三方 OTel 属性:遵循 GenAI Semantic Conventions、OpenInference 或其他插桩规范的键

这些值的结构也因应用而异(例如,query 字符串、messages 数组或包含多个字段的字典)。请检查实际属性值以了解其格式。

如果根跨度的输入/输出为空或缺失,它可能是一个包装跨度(例如,编排器或中间件),不会直接携带聊天轮次数据。在这种情况下,请检查它的直接子级——找到层级结构中最靠近顶层,且包含与聊天轮次对应的有效输入和输出的跨度:

以下示例假设跟踪记录来自 MLflow Python 客户端(该客户端将输入/输出存储在 mlflow.spanInputs/mlflow.spanOutputs 中),且相关跨度是根跨度的直接子级。实际情况中,相关跨度在层级结构中可能更深,其他客户端生成的跟踪记录也可能使用不同的属性键——请根据需要探索跨度树:

# Get the root span's ID
ROOT_ID=$(jq -r '.data.spans[] | select(.parent_span_id == null) | .span_id' /tmp/trace_detail.json)

# List immediate children of the root span with their inputs/outputs
jq --arg root "$ROOT_ID" '.data.spans[] | select(.parent_span_id == $root) | {name: .name, inputs: .attributes["mlflow.spanInputs"], outputs: .attributes["mlflow.spanOutputs"]}' /tmp/trace_detail.json

还要检查第一条跟踪记录的评估结果。会话级评估结果附加在会话中的第一条跟踪记录上——这些评估结果用于评估整个会话(例如,整体对话质量、多轮连贯性),并可能表明整个会话中某处存在问题,而不只是第一轮。第一条跟踪记录也可能包含针对该轮次的逐轮评估结果。

这两种评估结果都会显示在 .info.assessments 中。若评估结果的 metadata 字段中包含 mlflow.trace.session,则可识别为会话级评估结果:

# Show session-level assessments (exclude scorer errors)
jq '[.info.assessments[] | select(.feedback.error == null) | select(.metadata["mlflow.trace.session"]) | {name: .assessment_name, value: .feedback.value}]' /tmp/trace_detail.json

# Show per-turn assessments (exclude scorer errors)
jq '[.info.assessments[] | select(.feedback.error == null) | select(.metadata["mlflow.trace.session"] == null) | {name: .assessment_name, value: .feedback.value}]' /tmp/trace_detail.json

**评估错误不等于跟踪记录错误。**如果评估结果中有 feedback.error 字段,这表示评分器或评判器执行失败——并不表示跟踪记录本身有问题。使用评估结果识别跟踪记录问题时,请排除这些错误。

**解读评估值时,务必查看评估理由。**仅凭 value 可能会产生误解——例如,user_frustration 评估结果的 value: "no" 可能表示“未检测到用户挫败情绪”,也可能表示“挫败情绪检查未通过”(即确实存在挫败情绪),具体取决于评分器的配置。.rationale 字段是评估结果的顶层字段(不嵌套在 .feedback 下),用于解释该值在上下文中的含义。提取评估结果时,请一并包含评估理由:

jq '[.info.assessments[] | select(.feedback.error == null) | {name: .assessment_name, value: .feedback.value, rationale: .rationale}]' /tmp/trace_detail.json

步骤 2:提取所有会话跟踪记录。 确定哪些属性键存储输入和输出后,使用 --extract-fields 搜索会话中的所有跟踪记录,并提取这些字段及评估结果(有关为何将输出写入文件,请参阅处理 CLI 输出):

mlflow traces search \
  --experiment-id <EXPERIMENT_ID> \
  --filter-string 'metadata.`mlflow.trace.session` = "<SESSION_ID>"' \
  --order-by "timestamp_ms ASC" \
  --extract-fields 'info.trace_id,info.state,info.request_time,info.assessments,info.trace_metadata.`mlflow.traceInputs`,info.trace_metadata.`mlflow.traceOutputs`' \
  --output json \
  --max-results 100 > /tmp/session_traces.json

然后使用 bash 命令(例如 jq、wc、head)分析文件。

上面的 --extract-fields 示例使用跟踪元数据中的 mlflow.traceInputs/mlflow.traceOutputs — 请根据你在步骤 1 中发现的内容调整字段路径。

评估结果包含质量判断(例如正确性、相关性),无需详细阅读每条跟踪记录,就能指出哪些轮次存在问题。若要识别哪些轮次包含评估信号(排除评分器错误):

# List turns with their valid assessments (scorer errors filtered out)
jq '.traces[] | {
  trace_id: .info.trace_id,
  time: .info.request_time,
  state: .info.state,
  assessments: [.info.assessments[]? | select(.feedback.error == null) | {
    name: .assessment_name,
    value: .feedback.value
  }]
}' /tmp/session_traces.json

CLI 语法说明:

  • 所有 mlflow traces search 命令都必须指定 --experiment-id。否则命令会失败。
  • 过滤字符串和 extract-fields 中包含句点的元数据键必须用反引号括起来:metadata.`mlflow.trace.session`
  • Shell 引号:双引号内的反引号会被 bash 解释为命令替换(例如,bash 会尝试将 `mlflow.trace.session` 作为命令运行)。值中包含反引号时,外层字符串始终使用单引号。例如:--filter-string 'metadata.\mlflow.trace.session` = "value"'`
  • --max-results 默认值为 100,足以满足大多数会话的需要。对于较长的对话,可增加到 500(最大值)。如果返回了 500 条结果,请使用分页获取其余结果。

处理 CLI 输出

MLflow 跟踪输出可能很大,而 Claude Code 的 Bash 工具对管道命令的输出限制约为 30 KB。输出超过此阈值时,会被保存到文件,而不是通过管道传递,导致静默失败。

安全做法(始终有效):

# Step 1: Save to file
mlflow traces search \
  --experiment-id <EXPERIMENT_ID> \
  [...] \
  --output json > /tmp/output.json

# Step 2: Process the file
cat /tmp/output.json | jq '.traces[0].info.trace_id'
head -50 /tmp/output.json
wc -l /tmp/output.json

切勿直接通过管道传递 MLflow CLI 输出(例如,mlflow traces search ... | jq '.')。这可能会静默地不产生任何输出。始终先将输出重定向到文件,再对文件运行命令。

若要详细检查某个轮次(例如,确定问题轮次后),请获取其完整跟踪记录:

mlflow traces get --trace-id <TRACE_ID> > /tmp/turn_detail.json

与代码库关联

  • 会话 ID 分配:在代码库中搜索 mlflow.trace.session 的设置位置,以了解会话的创建方式 — 例如按用户登录、按浏览器标签页,或按明确的“新建对话”操作等。
  • 上下文窗口管理:查看应用如何构建每轮传递给 LLM 的消息历史记录。常见模式包括滑动窗口(最近 N 条消息)、对较早轮次进行摘要,或使用完整历史记录。此实现决定了模型能看到哪些上下文,也是多轮失败的常见根源。
  • 记忆和状态:有些应用会在消息历史记录之外跨轮次维护状态(例如提取出的实体、用户偏好、累积的工具结果)。搜索相关状态的存储方式以及在轮次之间传递的方式。

参考脚本

/scripts 子目录中包含每个分析步骤的即用型 bash 脚本。所有脚本都遵循上述输出处理规则(重定向到文件,然后再处理)。

  • scripts/discover_schema.sh <EXPERIMENT_ID> <SESSION_ID> — 查找会话中的第一条跟踪记录,获取其完整详情,并打印根 span 的属性键和输入/输出值。
  • scripts/inspect_turn.sh <TRACE_ID> — 获取指定跟踪记录,列出所有 span,突出显示错误 span,并显示评估结果。

示例:第 5 轮对话中回答错误

用户报告称,其聊天机器人在一段聊天对话的第 5 条消息中给出了错误回答。

1. 发现架构并重建对话。

获取会话中的第一条追踪记录,并检查根 span 的属性,以找出哪些键保存了输入和输出。在本例中,mlflow.spanInputs 包含用户查询,mlflow.spanOutputs 包含助手回答。随后搜索会话中的所有追踪记录,按时间顺序提取这些字段。检查提取出的输入和输出,可以确认第 5 轮的回答有误,并了解之前的轮次是否看起来正确。

2. 检查错误是否源于更早的轮次。

第 3 轮的回答包含一个事实性错误,但用户没有提出异议。第 4 轮基于这条错误信息展开,第 5 轮则进一步加剧了问题。根本原因在第 3 轮,而不是第 5 轮。

3. 将问题根源所在轮次作为单条追踪记录进行分析。

获取第 3 轮的完整追踪记录并进行分析——检查评估结果(如有)、遍历 span 树、查看检索器结果,并与代码关联。检索器返回了过时文档,导致回答错误。

4. 建议。

  • 修复检索器的数据源,排除或更新过时文档。
  • 添加逐轮评估,在错误传播到后续对话前将其检测出来。
  • 考虑实现对话级错误检测(例如,检查不同轮次回答的一致性)。

评论

支持 Markdown