关于 exploring-llm-traces
用于调查 PostHog 中 LLM 和 AI Agent 轨迹的技能,可查看事件树、输入、输出、错误和耗时。它引导先浏览摘要再深入检查,并提醒处理被省略或脱敏的数据。
主要功能
- 01搜索和列出 LLM 轨迹
- 02检查单条轨迹的事件树
- 03发现事件架构和属性值
- 04先查看摘要再读取完整轨迹
- 05使用 SQL 和脚本分析轨迹
适用场景
- 01根据 URL 排查轨迹或会话
- 02检查工具输入、输出和错误
- 03调查提供给 LLM 的上下文
- 04按已发现的事件属性查找轨迹
MCP 相关
使用 PostHog MCP 轨迹、架构和 SQL 工具搜索并检查 LLM 活动。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ posthog/ skills --skill exploring-llm-traces安装后在 Claude Code 中输入/exploring-llm-traces确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/events-and-properties.mdexample-llm-trace.mdexample-llm-traces-list.mdscripts/extract_conversation.pyextract_span.pyprint_summary.pyprint_timeline.pysearch_traces.pyshow_structure.py详细介绍
使用 MCP 工具探索 LLM 跟踪记录
PostHog 会将 LLM/AI Agent 活动记录为跟踪记录。每条跟踪记录都是由多个事件构成的树,表示一次 AI 交互——从顶层 Agent 调用到单个 LLM API 调用。
可用工具
| 工具 | 用途 |
|---|---|
posthog:query-llm-traces-list | 搜索并列出跟踪记录;可能返回包含多条跟踪记录的大型数据载荷 |
posthog:query-llm-trace | 根据 ID 获取单条跟踪记录及其完整事件树 |
posthog:read-data-schema | 在筛选前发现自定义事件/用户属性 |
posthog:execute-sql | 使用临时 SQL 进行复杂的跟踪记录分析 |
事件层级
完整架构请参阅事件参考。
$ai_trace (top-level container)
└── $ai_span (logical groupings, e.g. "RAG retrieval", "tool execution")
├── $ai_generation (individual LLM API call)
└── $ai_embedding (embedding creation)
事件通过 $ai_parent_id → 父级的 $ai_span_id 或 $ai_trace_id 进行关联。
工作流:从 URL 调试跟踪记录或会话
第 1 步 — 对 URL 分类
首先检查路径。不要把所有看起来像 UUID 的值都当作跟踪记录 ID。
/ai-observability/traces/<trace_id>或旧版/llm-analytics/traces/<trace_id>//llm-observability/traces/<trace_id>表示单条跟踪记录。使用posthog:query-llm-trace获取。/ai-observability/sessions/<session_id>或旧版/llm-analytics/sessions/<session_id>表示 AI 会话,而非跟踪记录。使用posthog:query-llm-traces-list,并按事件属性$ai_session_id筛选,以获取跟踪记录。
如果 URL 中包含 date_from / date_to 查询参数,请保留。
如果没有这些参数,但 URL 中包含 timestamp 查询参数,则使用该时间戳作为锚点,并围绕它查询一个绝对时间范围,例如从 timestamp - 36h 到 timestamp + 36h。
这样既能处理 UI 时间戳可能与存储的事件时间戳存在偏差的精确会话链接,又能将查询范围限定在合理区间内。
如果 URL 中既没有明确日期,也没有 timestamp,请使用 {"date_from": "-7d"} 这样的安全默认值。
对于精确的跟踪记录和会话 URL,请跳过对下文所用标准 $ai_* 字段的架构发现。这些是 AI 可观测性的内置字段,并非项目特定的自定义属性。
第 2 步 — 浏览跟踪记录摘要
浏览跟踪记录时,请明确设置 detail: "summary"。
这会返回事件元数据,并排除对话内容,
因此浏览时不会耗费上下文来处理提示词和输出。
为兼容现有调用方,省略 detail 仍会返回完整详情。
对于跟踪记录 URL,使用以下参数调用 posthog:query-llm-trace:
{
"traceId": "<trace_id>",
"detail": "summary",
"dateRange": { "date_from": "-7d" }
}
对于会话 URL,使用以下参数调用 posthog:query-llm-traces-list:
{
"detail": "summary",
"dateRange": { "date_from": "<timestamp_minus_36h>", "date_to": "<timestamp_plus_36h>" },
"filterTestAccounts": false,
"limit": 20,
"properties": [{ "type": "event", "key": "$ai_session_id", "value": ["<session_id>"], "operator": "exact" }]
}
如果 URL 中包含 date_from / date_to,请在会话查询中使用这些值。
如果 URL 中只有 timestamp,请根据该时间戳计算绝对日期范围,而不要使用 -1h 这样的相对范围。
对于精确 URL,请设置 filterTestAccounts: false,以免请求的跟踪记录被账户筛选器隐藏。
结果只包含跟踪记录和事件元数据。
提示词、输出、跨度状态、$ai_error 和 $ai_feedback_text 都会被省略,
其名称会与属性集一起列在 _summaryOmittedKeys 中。
带有 _detail: { "mode": "summary" } 的跟踪记录完全不包含对话内容。
使用 detail: "full" 读取内容。
结果中包含:
- 每个事件及其类型(
$ai_span、$ai_generation等) - 跨度名称(
$ai_span_name)——即工具/步骤名称 - 延迟、错误标记、使用的模型
- 通过
$ai_parent_id表示的父子关系 _posthogUrl——务必在回复中包含此项,以便用户点击链接访问 UI
第 3 步 — 读取调查所需的内容
选定一条追踪记录后,请先调用 posthog:query-llm-trace 并设置 detail: "full",然后再检查具体的工具参数、查看模型收到的上下文或搜索对话内容:
{
"traceId": "<trace_id>",
"detail": "full",
"dateRange": { "date_from": "-7d" }
}
使用原始 URL 或发现查询中的日期范围,而不要照搬示例范围。 保留相关属性筛选条件,以缩小读取范围。如果用户已经指出追踪记录且需要确切内容,可以直接请求完整详情。
两种模式都会限制响应大小。
在得出结论前,请检查省略和截断标记。
被丢弃的事件、列在 _summaryOmittedKeys 或 _redactedKeys 中的名称,
或摘要中缺失的关键词,都不能作为它们未出现在追踪记录中的证据。
如果完整详情仍被截断,请将查询范围缩小到相关事件,或打开 _posthogUrl 查看完整数据。
下文的被隐藏的属性也会介绍:这两种详情模式都会隐藏非 AI 负载属性。
第 4 步 — 使用脚本解析大型完整详情结果
当结果被保存到文件中(大型追踪记录包含完整的 $ai_input/$ai_output_choices)时,
请使用解析脚本进行探索。
先查看摘要,全面了解情况,然后再深入查看细节:
# 1. Overview: metadata, tool calls, final output, errors
python3 scripts/print_summary.py /path/to/persisted-file.json
# 2. Timeline: chronological event list with truncated I/O
python3 scripts/print_timeline.py /path/to/persisted-file.json
# 3. Drill into a specific span's full input/output
SPAN="tool_name" python3 scripts/extract_span.py /path/to/persisted-file.json
# 4. Full conversation with thinking blocks and tool calls
python3 scripts/extract_conversation.py /path/to/persisted-file.json
# 5. Search for a keyword across the returned properties
SEARCH="keyword" python3 scripts/search_traces.py /path/to/persisted-file.json
所有脚本都支持 MAX_LEN=N 环境变量来控制截断长度(0 = 不限)。
被隐藏的属性
这两个追踪工具仅返回 AI 负载。
只有 PostHog 分类体系定义的 $ai_* 属性会提供给你,
此外还包括 $ai_generation_id、$ai_cache_read_cost_usd、$ai_cache_creation_cost_usd、$ai_effort、
$session_id、$lib 和 $lib_version。
其他所有事件属性和所有用户属性在两种详情模式下都会被隐藏,
其名称会与属性集合一同列在 _redactedKeys 中。
$ai_base_url 和 $ai_request_url 返回时不包含查询字符串。
这包括项目自定义属性,例如 project_id 或 conversation_id。
被隐藏的属性在 PostHog 中不会发生变化。
它仍可在此处用作筛选条件,也可以在 PostHog UI 或通过 execute-sql 读取其值。
_redactedKeys 中的名称表示该属性存在于事件中,只是其值被隐藏。
search_traces.py 无法查找仅出现在被隐藏属性中的关键词。
调查模式
“Agent 是否正确使用了工具?”
- 找到工具调用对应的
$ai_span(查看$ai_span_name) - 检查
$ai_input_state— 传给工具的参数是什么? - 检查
$ai_output_state— 工具返回了什么? - 检查
$ai_is_error— 工具调用是否失败?
“上下文是否正确?” / “是否呈现了正确的文件?”
- 找到 LLM 做出决策时的
$ai_generation事件 - 检查
$ai_input— 这是 LLM 看到的完整消息历史 - 查看之前的
$ai_span事件,了解检索/搜索步骤 - 检查这些事件的
$ai_output_state— 检索到了哪些内容并传给了 LLM?
“子 Agent 是否正常工作?”
- 在结构概览中,找到作为其他 span 子项的 span(通过
$ai_parent_id) - 父 span 是编排器;子 span 是子 Agent 的步骤
- 检查每个子项的
$ai_output_state和$ai_is_error - 如果某个子 span 包含
$ai_generation事件,这些就是子 Agent 的 LLM 调用
“LLM 为什么会说 X?”
- 使用
search_traces.py查找文本出现的位置:SEARCH="the text" python3 scripts/search_traces.py FILE - 这会显示包含该文本的事件和属性路径
- 检查该次生成的
$ai_input,查看 LLM 在说出 X 之前收到了什么内容
构建 UI 链接
追踪工具会返回 _posthogUrl——务必将其展示给用户。
你也可以手动构建链接:
- 追踪详情:
https://app.posthog.com/ai-observability/traces/<trace_id>?timestamp=<url_encoded_timestamp>&event=<optional_event_id> - 带筛选条件的追踪列表:
query-llm-traces-list返回的_posthogUrl
timestamp 查询参数是必需的——使用追踪中最早事件的 createdAt,并进行 URL 编码(例如,timestamp=2026-04-01T19%3A39%3A20Z)。
展示调查结果时,务必附上相关的 PostHog URL,方便用户核实。
查找追踪
使用 posthog:query-llm-traces-list 并设置 detail: "summary" 来搜索和筛选追踪。
重要:切勿根据训练数据臆测事件名称、属性名称或属性值。
每个项目都会采集不同的自定义属性。对于开放式搜索和自定义筛选条件,在构建筛选条件之前,先调用
posthog:read-data-schema,了解项目数据中实际存在的属性和值。
例外情况是精确的 AI 可观测性追踪/会话 URL:直接使用内置的 $ai_trace_id / $ai_session_id
字段,无需发现架构。
先发现架构
筛选追踪之前,先了解可用数据:
- 确认 AI 事件存在——调用
posthog:read-data-schema并设置kind: "events",查找$ai_*事件 - 查找可筛选的属性——调用
posthog:read-data-schema并设置kind: "event_properties"和event_name: "$ai_generation"(或其他 AI 事件),查看采集了哪些属性 - 获取实际值——调用
posthog:read-data-schema并设置kind: "event_property_values"、event_name: "$ai_generation"和property_name: "$ai_model",查看实际使用的模型名称
只有完成上述步骤后,才能在 query-llm-traces-list 调用中构建属性筛选条件。
这对于 project_id、conversation_id、user_tier 等自定义属性尤为重要——这些属性因项目而异,不能靠猜测得出。
即使响应中不提供自定义属性的值,也可以用它作为筛选条件。
对于 $ai_* 属性,无需确认;但对于 email 这类其他属性,必须确认其是否属于某个人。
按筛选条件查找
posthog:query-llm-traces-list
{
"detail": "summary",
"dateRange": {"date_from": "-1h"},
"filterTestAccounts": true,
"limit": 20,
"properties": [
{"type": "event", "key": "$ai_model", "value": "gpt-4o", "operator": "exact"}
]
}
多个筛选条件会通过 AND 组合:
posthog:query-llm-traces-list
{
"detail": "summary",
"dateRange": {"date_from": "-1h"},
"filterTestAccounts": true,
"properties": [
{"type": "event", "key": "$ai_provider", "value": "anthropic", "operator": "exact"},
{"type": "event", "key": "$ai_is_error", "value": ["true"], "operator": "exact"}
]
}
你也可以按人员属性筛选(使用 read-data-schema 并设置 kind: "entity_properties" 和 entity: "person" 来发现这些属性):
posthog:query-llm-traces-list
{
"detail": "summary",
"dateRange": {"date_from": "-1h"},
"filterTestAccounts": true,
"properties": [
{"type": "person", "key": "email", "value": "@company.com", "operator": "icontains"}
]
}
按外部标识符查找
客户通常会将自己的 ID 存储为事件或人员属性。
使用 posthog:read-data-schema 发现现有哪些自定义属性,然后进行筛选:
- 调用
posthog:read-data-schema并设置kind: "event_properties"和event_name: "$ai_trace",查找自定义属性 - 查看返回的属性及其示例值
- 使用已发现的属性键和已知值构建筛选条件
posthog:query-llm-traces-list
{
"detail": "summary",
"dateRange": {"date_from": "-7d"},
"properties": [
{"type": "event", "key": "project_id", "value": "proj_abc123", "operator": "exact"}
]
}
如需更复杂的 SQL 模式,请阅读以下参考资料:
- 检索单条追踪 — 按 ID 获取单条追踪及其全部事件和属性(生成
TraceQueryHogQL) - 含聚合指标的追踪列表 — 两阶段查询:先查找追踪 ID,再获取聚合延迟、令牌数、费用和错误数
解析大型追踪结果
追踪工具的结果为 JSON。当结果过大而无法直接阅读时,Claude Code 会将其保存到文件中。 提取内容和搜索关键词时,请使用完整详情响应。 脚本无法恢复摘要中省略、属性包中未提供或因截断而丢失的内容。
已保存文件的格式
[{ "type": "text", "text": "{\"results\": [...], \"_posthogUrl\": \"...\"}" }]
追踪 JSON 结构
results (array for list, object for single trace)
├── id, traceName, createdAt, totalLatency, totalCost
├── inputState, outputState (trace-level state)
└── events[]
├── event ($ai_span | $ai_generation | $ai_embedding | $ai_metric | $ai_feedback)
├── id, createdAt
└── properties
├── $ai_span_name, $ai_latency, $ai_is_error
├── $ai_input_state, $ai_output_state (span tool I/O)
├── $ai_input, $ai_output_choices (generation messages)
├── $ai_model, $ai_provider
└── $ai_input_tokens, $ai_output_tokens, $ai_total_cost_usd
可用脚本
| 脚本 | 用途 | 用法 |
|---|---|---|
print_summary.py | 汇总列表/会话总数、追踪元数据、工具调用、错误和最终大模型输出 | python3 scripts/print_summary.py FILE |
print_timeline.py | 按时间顺序展示事件时间线和 I/O 摘要 | python3 scripts/print_timeline.py FILE |
extract_span.py | 按名称提取指定 span 的完整输入/输出 | SPAN="name" python3 scripts/extract_span.py FILE |
extract_conversation.py | 提取包含思考区块和工具调用的大模型消息 | python3 scripts/extract_conversation.py FILE |
search_traces.py | 在所有事件属性中查找关键词 | SEARCH="keyword" python3 scripts/search_traces.py FILE |
show_structure.py | 显示 JSON 键和类型,不显示值 | cat blob.json | python3 scripts/show_structure.py |
提示
- 始终设置
dateRange——不指定时间范围的查询速度很慢。对于宽泛的列表查询,使用较短的时间窗口(-30m、-1h);对于按追踪 ID 或特定属性值筛选的窄范围查询,可以使用较宽的时间窗口(-7d、-30d) - 回复中始终包含
_posthogUrl,方便用户点击查看 - span 上的
$ai_input_state/$ai_output_state包含工具调用的输入和输出 - generation 上的
$ai_input/$ai_output_choices包含完整的大模型对话,可能达到数 MB;如果结果已保存到文件,请使用解析脚本 - 在原始 SQL 中,大量内容(
$ai_input/$ai_output/$ai_output_choices/$ai_input_state/$ai_output_state/$ai_tools)只存在于posthog.ai_events表中,而不在events.properties中——有关列映射和以追踪 ID 为锚点的查询模式,请参阅事件参考 - 搜索时使用
filterTestAccounts: true排除内部/测试流量 $ai_trace事件不在events数组中——其数据通过追踪级别的inputState、outputState和traceName提供