OT-LLM质量分析

更新时间:
复制为 MD 格式

从 OT-Trace 数据中提取每次 LLM 调用的完整快照,经去重采样后自动完成 Prompt 与响应的质量评估及 Token 统计分析。

业务场景

AI Agent 应用中 LLM 调用是核心组件。本模板聚焦单次 LLM 调用(Span-LLM)粒度,支持以下分析场景:

  • 发现 Prompt 设计缺陷,例如 System Prompt 缺失、输入消息冗余等。

  • 识别异常响应,例如幻觉输出、格式错误、工具调用异常。

  • 分析 Token 使用效率和推理性能,例如输入输出 Token 比、每秒生成速率。

Pipeline 流程

本模板的 Pipeline 分为以下 4 个阶段,从原始 Trace 数据到 AI 质量评估依次处理。

阶段

节点

说明

Phase 1:数据组装

extend(extract)

从 OT-Trace Span 原始字段中提取 LLM 调用相关属性,包括 session_idrequest_modelinput_tokensoutput_tokens 等。

make-instance

spanid 聚合,将同一次 LLM 调用的多条 Span 记录合并为一行宽表。

extend(derive)

派生计算指标,包括 duration_ms(调用耗时)、tokens_per_sec(生成速率)、input_output_ratio(输入输出比)等。

where(filter)

过滤无效记录,仅保留模型名称非空且输入 Token 大于 0 的调用。

Phase 2:数据清洗

dedup-exact

full_text 字段精确去重,消除完全重复的 LLM 调用记录。

Phase 3:特征计算

doc-stats

full_text 进行文本统计,计算字符数、词数和行数。

Phase 4:采样 + AI 处理

sample

随机采样 50 条记录,控制后续 AI 评估的调用量。

llm-call(quality_eval)

调用 AI 模型对每条 LLM 调用进行质量评估,输出结构化评估结果。

调用质量评估Prompt模板

你是一位专业的 LLM 调用质量分析专家,擅长评估单次 LLM 调用的 Prompt 设计质量、响应效果和资源效率。

请根据以下评估维度,对这次 LLM 调用进行全面评估:

评估维度:

Prompt 质量: System Prompt 是否清晰定义了角色、约束和输出格式?用户输入是否提供了足够的上下文?(0-5分)
响应质量: LLM 输出是否准确、完整、切题?是否有幻觉或跑题?(0-5分)
Token 效率: 输入/输出 token 比例是否合理?是否存在冗余输入或过长输出?(0-5分)
延迟合理性: 根据 token 吞吐率(tok/s),推理性能是否在合理范围?(0-5分)
工具调用: 若涉及 tool_call,工具选择是否合理、参数是否正确?无工具调用则标记为 N/A。(0-5分或N/A)
评估参考:

Token 效率基准:input/output ratio 在 2:1 ~ 10:1 为合理范围
延迟基准:tokens_per_sec > 30 为优秀,15-30 为良好,< 15 需关注
若 has_tool_call=true,重点评估工具选择准确性
现在请评估以下 LLM 调用:

模型:{{request_model}} Token 使用:输入 {{input_tokens}} / 输出 {{output_tokens}} 性能指标:{{tokens_per_sec}} tok/s,耗时 {{duration_ms}} ms 工具调用:{{has_tool_call}} 调用详情: {{full_text}}

请输出JSON格式: { “prompt_quality”: {“score”: 分数, “reason”: “简短理由”}, “response_quality”: {“score”: 分数, “reason”: “简短理由”}, “token_efficiency”: {“score”: 分数, “reason”: “简短理由”}, “latency_rating”: {“score”: 分数, “reason”: “简短理由”}, “tool_usage”: {“score”: “分数或N/A”, “reason”: “简短理由”}, “overall_score”: 综合分数, “risk_flags”: [“风险标记1”, “风险标记2”], “optimization_suggestion”: “一句话优化建议” }

【重要】只输出纯JSON,不要添加任何markdown标记(如json或)。

完整配置

本模板提供 JSON 配置格式。关于 Pipeline 配置的基本概念和使用方式,请参见数据处理(Pipeline)

以下为完整的 Pipeline JSON 配置,可直接通过 API 创建。

{
  "name": "ot_llm_quality_analysis",
  "description": "OT-Trace Span-LLM 粒度:LLM 调用质量分析 — 从 Trace 数据提取所有 LLM 调用快照,去重采样后进行 Prompt/响应质量评估与文本统计",
  "source": {
    "type": "logstore",
    "logstore": {
      "project": "ali-pub-cn-hangzhou-staging-sls-admin",
      "logstore": "logstore-tracing",
      "query": "\"attributes.gen_ai.span.kind\": LLM"
    }
  },
  "pipeline": {
    "nodes": [
      {
        "id": "extract",
        "type": "extend",
        "parameters": {
          "session_id":       "\"attributes.gen_ai.session.id\"",
          "user_id":          "\"attributes.gen_ai.user.id\"",
          "framework":        "\"attributes.gen_ai.framework\"",
          "operation_name":   "\"attributes.gen_ai.operation.name\"",
          "provider":         "\"attributes.gen_ai.provider.name\"",
          "request_model":    "CASE WHEN \"attributes.gen_ai.request.model\" IS NOT NULL AND \"attributes.gen_ai.request.model\" != '' THEN \"attributes.gen_ai.request.model\" WHEN substr(spanname, 1, 4) = 'llm:' THEN substr(spanname, 5) WHEN substr(spanname, 1, 14) = 'llm_streaming_' THEN substr(spanname, 15) WHEN substr(spanname, 1, 9) = 'llm_call_' THEN substr(spanname, 10) WHEN substr(spanname, 1, 5) = 'chat ' THEN substr(spanname, 6) WHEN strpos(spanname, '.invoke') > 0 THEN substr(spanname, 1, strpos(spanname, '.invoke') - 1) ELSE spanname END",
          "system_prompt":    "\"attributes.gen_ai.system_instructions\"",
          "input_messages":   "\"attributes.gen_ai.input.messages\"",
          "output_messages":  "\"attributes.gen_ai.output.messages\"",
          "input_tokens":     "CAST(\"attributes.gen_ai.usage.input_tokens\" AS BIGINT)",
          "output_tokens":    "CAST(\"attributes.gen_ai.usage.output_tokens\" AS BIGINT)",
          "finish_reasons":   "\"attributes.gen_ai.response.finish_reasons\""
        }
      },
      {
        "id": "assemble",
        "type": "make-instance",
        "parameters": {
          "by": "spanid",
          "trace_id":         "any(traceid)",
          "service_name":     "any(servicename)",
          "span_name":        "any(spanname)",
          "duration_ns":      "max(duration)",
          "status_code":      "max(statuscode)",
          "span_time":        "first(__time__)",
          "session_id":       "any(session_id)",
          "user_id":          "any(user_id)",
          "framework":        "any(framework)",
          "operation_name":   "any(operation_name)",
          "provider":         "any(provider)",
          "request_model":    "any(request_model)",
          "system_prompt":    "first(system_prompt)",
          "input_messages":   "first(input_messages)",
          "output_messages":  "last(output_messages)",
          "input_tokens":     "sum(input_tokens)",
          "output_tokens":    "sum(output_tokens)",
          "finish_reasons":   "any(finish_reasons)"
        }
      },
      {
        "id": "derive",
        "type": "extend",
        "parameters": {
          "duration_ms":       "CAST(duration_ns AS DOUBLE) / 1000000.0",
          "tokens_per_sec":    "CASE WHEN CAST(duration_ns AS DOUBLE) > 0 THEN CAST(output_tokens AS DOUBLE) / (CAST(duration_ns AS DOUBLE) / 1000000000.0) ELSE 0.0 END",
          "input_output_ratio":"CASE WHEN CAST(output_tokens AS DOUBLE) > 0 THEN CAST(input_tokens AS DOUBLE) / CAST(output_tokens AS DOUBLE) ELSE 0.0 END",
          "has_tool_call":     "CASE WHEN finish_reasons LIKE '%tool_calls%' THEN 'true' ELSE 'false' END",
          "has_system_prompt": "CASE WHEN system_prompt IS NOT NULL AND system_prompt != '' THEN 'true' ELSE 'false' END",
          "full_text":         "concat('[', coalesce(request_model, '?'), '] ', coalesce(operation_name, 'chat'), chr(10), 'Tokens: ', coalesce(CAST(input_tokens AS VARCHAR), '?'), '→', coalesce(CAST(output_tokens AS VARCHAR), '?'), chr(10), 'Input: ', substr(coalesce(input_messages, ''), 1, 500), chr(10), 'Output: ', substr(coalesce(output_messages, ''), 1, 500))"
        }
      },
      {
        "id": "filter_valid",
        "type": "where",
        "parameters": {
          "filter": "(request_model IS NOT NULL AND request_model != '') AND (input_tokens IS NOT NULL AND input_tokens > 0)"
        }
      },
      {
        "id": "exact_dedup",
        "type": "dedup-exact",
        "parameters": {
          "field": "full_text"
        }
      },
      {
        "id": "text_stats",
        "type": "doc-stats",
        "parameters": {
          "field": "full_text"
        }
      },
      {
        "id": "downsample",
        "type": "sample",
        "parameters": {
          "n": 50
        }
      },
      {
        "id": "quality_eval",
        "type": "llm-call",
        "parameters": {
          "prompt": "@eval/llm-call-eval.md",
          "fields": "request_model,input_tokens,output_tokens,tokens_per_sec,duration_ms,has_tool_call,full_text",
          "format": "json",
          "as": "eval"
        }
      }
    ]
  },
  "sink": {
    "type": "dataset",
    "dataset": {
      "workspace": "inner-playground",
      "dataset": "ot_llm_quality_analysis"
    }
  },
  "executePolicy": {
    "mode": "run_once",
    "run_once": { "fromTime": 0, "toTime": 0 }
  }
}

字段说明

下表列出本模板涉及的主要字段及其来源。

extract 节点提取字段

字段名

原始属性

说明

session_id

attributes.gen_ai.session.id

会话 ID。

user_id

attributes.gen_ai.user.id

用户 ID。

framework

attributes.gen_ai.framework

AI 框架名称(如 LangChain、Semantic Kernel 等)。

operation_name

attributes.gen_ai.operation.name

操作类型(如 chat、completion 等)。

provider

attributes.gen_ai.provider.name

模型提供商名称。

request_model

attributes.gen_ai.request.model

请求的模型名称。支持从 Span 名称中自动提取(当属性字段为空时)。

system_prompt

attributes.gen_ai.system_instructions

系统指令(System Prompt)。

input_messages

attributes.gen_ai.input.messages

输入消息内容。

output_messages

attributes.gen_ai.output.messages

输出消息内容。

input_tokens

attributes.gen_ai.usage.input_tokens

输入 Token 数量。

output_tokens

attributes.gen_ai.usage.output_tokens

输出 Token 数量。

finish_reasons

attributes.gen_ai.response.finish_reasons

模型响应的结束原因。

derive 节点派生字段

字段名

类型

说明

duration_ms

DOUBLE

LLM 调用耗时(毫秒)。由 duration_ns 纳秒转换。

tokens_per_sec

DOUBLE

每秒生成 Token 数。计算公式:output_tokens / (duration_ns / 1e9)

input_output_ratio

DOUBLE

输入/输出 Token 比值。比值过高可能表示输入消息冗余。

has_tool_call

VARCHAR

是否包含工具调用。当 finish_reasons 包含 tool_calls 时为 true

has_system_prompt

VARCHAR

是否包含 System Prompt。

full_text

VARCHAR

拼接的完整文本摘要,用于去重和文本统计。格式为 [模型名] 操作类型\nTokens: 输入→输出\nInput: ...\nOutput: ...

定制建议

可以基于本模板进行以下定制调整。

定制项

修改方式

说明

数据源

修改 source.logstore 中的 projectlogstore

替换为实际的 OT-Trace 数据源。

采样数量

修改 sample.n 的值

控制 AI 评估的样本量。增大采样数会增加 AI 调用成本。

评估维度

自定义 prompts/llm-call-eval.md 中的评估提示词

调整 AI 质量评估的评分标准和评估维度。

去重策略

dedup-exact 后追加 dedup-fuzzy 节点

在精确去重基础上增加近似去重,进一步减少重复数据。

输出目标

修改 sink.dataset 中的 workspacedataset

替换为实际的数据集输出目标。