用 PostHog AI 可观测性定位失败 Trace:五类查询策略与实现原理
2026/9/14 5:16:53 网站建设 项目流程

用 PostHog AI 可观测性定位失败 Trace:五类查询策略与实现原理

【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog

在生产环境的 AI/LLM 应用中,"找出哪里出错了"是最高价值的工作——但大部分失败是沉默的:模型返回了干净的 HTTP 200、没有抛异常,但答案错误、跑题、忽略指令或误用工具。本文以 PostHog 仓库中exploring-ai-failures技能的查询参考文档 finding-traces.md 为主体,完整讲解发现失败 trace 的五类查询策略(code errors、metric outliers、分层抽样、既有 eval 峰值、失败模式计数),并深入到仓库的 MCP 工具实现与 ClickHouse 存储模型,帮你掌握一套可落地的"定位 → 阅读 → 归类 → 排序"排障工作流。

读完后,你将能:用 HogQL/SQL 按多种信号圈定可疑 trace;用 MCP 工具query-llm-traces-list/query-llm-trace拉取并逐条阅读 trace;最终产出一份基于真实阅读的、带深链的排序失败模式清单,直接支撑修 prompt、提 bug、排优先级或将头号模式转成自动 eval。

核心前提:查询只告诉你"打开哪些 trace",答案永远在阅读里

整份技能文档围绕一个不可省略的活动展开:阅读真实的 trace。exploring-ai-failures/SKILL.md 反复强调:查询只是选样手段,绝不是结论。如果你只按错误消息GROUP BY产出一张排名表就收工,你描述的是"响亮的少数"(抛异常的那部分),而错过了真正值得关心的沉默失败。

这个技能是自底向上的:失败模式从真实 trace 中涌现出来,而不是从一组预先决定的通用指标中推导出来。因此所有查询策略都有一个共同归宿——把选出的 trace 逐条读完(一个用例大约读 20–30 条),记录失败方式,再归并成带名字的失败模式(如"忽略了日期过滤"、"编造了政策"、"丢掉第二个问题")。

配套的 MCP 工具全景如下(来自 exploring-ai-failures/SKILL.md):

工具用途
posthog:query-llm-traces-list列出候选 trace——按错误过滤、按指标排序、按类型圈定范围
posthog:query-llm-trace完整读取一条 trace,看实际出了什么问题
posthog:execute-sql找指标极值、发现 trace 分类、统计失败模式
posthog:llma-evaluation-list找到既有 eval,其失败峰值可能暴露新模式
posthog:generate-app-url构造带区域与项目前缀的 trace/列表深链

数据模型基础:$ai_*事件与eventsvsai_events的拆分

所有查询都建立在标准 AI 事件属性之上。完整的属性 schema 见 events-and-properties.md,这里提炼与失败定位最相关的部分。

一条 AI trace 是事件树:$ai_trace(顶层容器)→$ai_span(逻辑分组,如 "RAG retrieval"、"tool execution")→$ai_generation(单次 LLM API 调用)与$ai_embedding(嵌入创建)。事件通过$ai_trace_id共享归属,用$ai_parent_id构建层级:

$ai_trace (id: "trace-1", $ai_trace_id: "trace-1") └── $ai_span (id: "span-1", $ai_trace_id: "trace-1", $ai_parent_id: "trace-1") └── $ai_generation (id: "gen-1", $ai_trace_id: "trace-1", $ai_parent_id: "span-1")

$ai_generation上承载了失败定位最常用的指标属性:

属性类型说明
$ai_modelstring模型标识(如gpt-4oclaude-sonnet-4-20250514
$ai_providerstring提供商名(如openaianthropic
$ai_input_tokensint输入 token 数
$ai_output_tokensint输出 token 数
$ai_total_cost_usdfloat总成本(USD)
$ai_latencyfloat生成耗时(秒)
$ai_http_statusintLLM API 的 HTTP 状态码
$ai_is_errorboolean该次生成是否出错
$ai_errorstring失败时的错误消息
$ai_tools_calledstringLLM 调用的工具名(逗号分隔)

关键约束:重量级内容不在events表上。$ai_input$ai_output_choices$ai_input_state$ai_output_state$ai_tools这些可能达到数 MB 的属性,存放在专用 ClickHouse 表posthog.ai_events上;events表只保留轻量元数据(token 数、成本、模型、provider、$ai_trace_id、延迟、错误标志)。因此本文所有 SQL 只作用于events的轻量属性,而阅读 trace 内容则交给 MCP 工具(它们内部替你读了posthog.ai_events)。

posthog.ai_eventsORDER BY (team_id, trace_id, timestamp)建表,访问路径是trace_id而非时间戳;行数据在保留期后(默认 30 天)会被丢弃,更早的 trace 将没有内容。当需要自己写 SQL 取重内容时,先按时间窗口在events上筛出 trace_id,再锚定trace_idai_events取数:

WITH matching_traces AS ( SELECT DISTINCT properties.$ai_trace_id AS trace_id FROM events WHERE event = '$ai_generation' AND timestamp >= now() - INTERVAL 7 DAY AND properties.$ai_model = 'gpt-4o' -- token/cost/model/ids 留在 events ) SELECT a.trace_id, a.span_id, a.model, a.input, a.output_choices FROM posthog.ai_events AS a WHERE a.trace_id IN (SELECT trace_id FROM matching_traces) ORDER BY a.trace_id, a.timestamp

第一步:发现 trace 分类(trace taxonomy)

不同用例的失败模式各不相同:支持聊天会幻觉政策、摘要器会丢掉关键点、agent 会循环或误用工具。把它们混在一起分析会平均掉信号,所以先圈定一个用例,再找它的过滤器($ai_trace_id前缀、feature property 或模型)。如果用户不清楚流量如何划分,先运行下面这条查询发现分类:

-- 按 trace-id 前缀约定分组(很多应用把 trace id 命名空间化为 "support:"、"summarize:" 等) SELECT splitByChar(':', coalesce(properties.$ai_trace_id, ''))[1] AS kind, count() AS n FROM events WHERE event = '$ai_generation' AND timestamp >= now() - INTERVAL 7 DAY GROUP BY kind ORDER BY n DESC

也可以按应用设置的任意 feature property 分组(ai_productagent_mode或自定义 tag),然后把下面每一条查询都收敛到这个切片上。

属性名($ai_is_error$ai_input_tokens等)是标准 AI 事件属性;但每个项目的自定义属性不同,动手前先用posthog:read-data-schema确认项目里实际存在的属性名与取值(这是 exploring-llm-traces/SKILL.md 的硬性要求),$ai_*内建字段除外。

策略一:代码错误(Code errors)——最便宜的第一轮扫描

对错误消息分组,快速看到错误类别分布:

SELECT properties.$ai_error AS error, count() AS n FROM events WHERE event = '$ai_generation' AND properties.$ai_is_error = 'true' AND timestamp >= now() - INTERVAL 7 DAY GROUP BY error ORDER BY n DESC

必须牢记的局限:这条查询只捕获异常与 API 失败。一条 trace 可以完全成功(没有$ai_is_error)但结果是错的——那些沉默失败要靠其他策略。它最合理的用途是"抓几条 trace 来读",而不是当作"问题清单"来汇报。相对而言,结构化输出或 tool-calling 管线用它会稍有用些,因为这类管线里部分失败确实会以 parse/schema 错误的形式浮出水面。

仓库后端还提供了更强的变体:错误在摄取时就被规范化。errors.sql 使用预计算的$ai_error_normalized属性(规范化的错误消息,实现在nodejs/src/ingestion/ai/errors/normalize-error.ts),按错误分组的同时聚合了 trace 数、各事件类型计数、会话数、用户数与首次/末次出现时间,并利用$ai_trace_id$ai_session_id$ai_is_error的物化列提升性能。当你想做错误聚类而非单纯计数时,这是直接可用的现成查询骨架。

策略二:指标极值(Metric outliers)——异常聚集在尾部

按某个指标排序,读两端:

SELECT properties.$ai_trace_id AS trace_id, properties.$ai_input_tokens AS in_tok, properties.$ai_output_tokens AS out_tok, properties.$ai_latency AS latency, properties.$ai_total_cost_usd AS cost FROM events WHERE event = '$ai_generation' AND timestamp >= now() - INTERVAL 7 DAY ORDER BY out_tok DESC -- 也可以换成 in_tok、latency、cost;以及 ASC 找截断/空输出 LIMIT 25

极值的典型含义:

极值形态常见原因
输出巨大失控/重复(runaway/repetition)
输出极小被截断或拒绝回答
输入巨大上下文膨胀或 prompt 塞得太满
延迟/成本极高低效或进入循环

对感兴趣的 trace,用query-llm-trace打开细读。

策略三:分层批次人工审阅(Stratified sample)——没有具体信号时的默认动作

当你没有任何具体信号时(最常见的情形),拉一个覆盖不同切片与不同结果(而非全是错误)的混合批次,逐条通读。这是默认动作,不是兜底方案。

先用列表工具取候选:

posthog:query-llm-traces-list { "dateRange": { "date_from": "-7d" }, "filterTestAccounts": true }

再逐条读取。query-llm-trace的唯一必填参数是traceId,传值来自列表结果中该 trace 的id字段——这一点在 ai_observability.ts 的工具定义里被明确约束(traceId描述为 "theidfield from a trace inquery-llm-traces-listresults"):

posthog:query-llm-trace { "traceId": "<id from a query-llm-traces-list result>" }

在一个用例上读大约 20–30 条,通常就能覆盖主要的失败模式。阅读过程中:用平实的语言记录每条 trace 哪里出了问题,同时记下该 trace 最早事件的时间戳(就在 trace 里和列表结果的createdAt里)——这个时间戳加 trace id 是后面构造可解析深链的全部材料,顺手记下能省掉一次来回。链式失败时记录第一个断掉的地方:根因通常引起下游症状,修掉根因症状自然消失。

需要更细的阅读手法时,可以参考 exploring-llm-traces/SKILL.md:浏览用detail: "summary"省上下文,确认工具参数、上下文内容、子 agent 行为时用detail: "full";结果太大落盘后,可用scripts/print_summary.pyscripts/print_timeline.pyscripts/extract_span.pyscripts/extract_conversation.pyscripts/search_traces.py等脚本解析。

query-llm-traces-list背后的两阶段查询实现见 example-llm-traces-list.md:先按属性过滤找到匹配的 trace_id(时间窗口 + 属性过滤放在这一阶段),再用这些 id 聚合出延迟、token、成本与错误计数。它刻意省略$ai_input$ai_output_choices等大字段——要拿这些内容必须走单条查询或直接锚定posthog.ai_events

策略四:既有 eval 的峰值(Existing-eval spikes)

如果项目已有运行中的 eval,其失败率的突增常常暴露新问题。找到 eval,用每日计数确认峰值,再读取失败的那批运行:

posthog:llma-evaluation-list { "enabled": true }
SELECT toDate(timestamp) AS day, count() AS fails FROM events WHERE event = '$ai_evaluation' AND properties.$ai_evaluation_id = '<uuid>' AND properties.$ai_evaluation_result = false AND timestamp >= now() - INTERVAL 30 DAY GROUP BY day ORDER BY day

这里$ai_evaluation事件、$ai_evaluation_id$ai_evaluation_result是 eval 运行结果事件的标准属性。深入阅读 eval 结果的方法由exploring-llm-evaluations技能覆盖(见 exploring-llm-evaluations/SKILL.md)。

策略五:统计失败模式(Counting failure modes)

在完成开放式记录与归并(Step 3)之后,对打标的 trace 做一次频率统计,把排名落到实处——例如按你写进 scratch 列表的标签计数,或者当模式能映射到某个属性时直接计数:

SELECT properties.$ai_model AS model, count() AS n FROM events WHERE event = '$ai_generation' AND properties.$ai_is_error = 'true' AND timestamp >= now() - INTERVAL 7 DAY GROUP BY model ORDER BY n DESC

换个属性($ai_provider$ai_tools_called$ai_http_status、自定义 tag)即可从不同维度验证模式的集中度。注意:这一统计应当基于你已经读过的那批 trace,而不是替代阅读——否则又落回"响亮的少数"陷阱。

把策略串成工作流:定位 → 阅读 → 归类 → 排序回交

四步工作流来自 exploring-ai-failures/SKILL.md,查询文档为 Step 2 提供弹药:

  1. Step 1 — 圈定一个用例:找到 trace 分类的过滤器(前缀、feature property、模型),后续所有查询收敛到这一个切片。
  2. Step 2 — 选择读哪些 trace:按手头信号从上面的策略里挑(可组合):code errors 最便宜但最不具代表性;metric outliers 捕捉失控/截断/膨胀/循环;单类型切片保证读到的 trace 共享分类;分层抽样是默认;eval 峰值从既有评估切入;高流量时可用聚类(exploring-llm-clusters)。
  3. Step 3 — 读一批(这是工作本身):用query-llm-trace逐条读 20–30 条,直到新 trace 不再带来新模式就停止(几十条,不是几千条)。不能GROUP BY或 grep 输出里的 "refusal" / "sorry" 字样来替代阅读——你还不知道要找的模式长什么样,阅读才是发现它们的方式。一条"查不出沉默失败"的 SQL 返回空,不是失败不存在的证据,而是"你必须去读"的信号。
  4. Step 4 — 排序、加链、交还用户:按在样本中出现的频率大致排序,输出简短的有名字的失败模式清单。每个模式主动附上一两条示例 trace 深链(不要等用户来要),请用户打开链接过目,再问他们下一步想聚焦哪个模式。你读过的 trace 也可能误读(看似幻觉的可能在上下文里是对的),所以不要把清单当作定论呈现。

陷阱提醒:不要对错误消息GROUP BY出一张排名表就收工。那张表只是"响亮的少数"。基于你从未打开过的错误/指标计数做出的排名,不是交付物——它只是"接下来该读什么"的指针。对沉默失败一无所获时,去读 trace,而不是回头汇报那些响亮的问题。

构造可解析的 UI 深链

query-llm-trace返回的_posthogUrl是现成的,直接回交即可;只有当你手握 id 但尚未打开时才自己拼链,且只用posthog:generate-app-url——不要手写 host 或/project/<id>/前缀:

  • Trace 列表generate-app-url {url: "/ai-observability/traces"}(然后过滤到你的用例)
  • 单条 tracegenerate-app-url {url: "/ai-observability/traces/{id}", params: {id: "<trace_id>"}}

trace 链接本身不带时间戳,所以要在任何回交的 URL 上追加?timestamp=<url_encoded_timestamp>(用 trace 最早事件的createdAt)——trace 页面靠它解析较旧的 trace,而这两个工具都无法表达它。生成出的链接会解析到正确的区域 host 与项目前缀(如https://us.posthog.com/project/<id>/ai-observability/traces/<trace_id>),用户即便不在目标项目上也能落在正确位置。

实操要点与注意事项

  • SQL 与query-*工具的分工:凡能映射到query-llm-traces-list的问题优先用工具——它们产出类型化、可保存的 insight,且内部替你读取posthog.ai_eventsexecute-sql留给工具表达不了的场景(多事件 join、CTE、窗口函数、先整形再取数)。路由规则详见 retrieving-data.md。
  • 永远带上dateRange:无时间范围的查询很慢。宽泛的列表查询用窄窗口(-30m-1h);按 trace id 或精确属性过滤的窄查询可以用宽窗口(-7d-30d)。
  • filterTestAccounts: true:检索时排除内部/测试流量;当用户给的是精确 URL 时要设false,避免目标 trace 被账号过滤隐藏。
  • 不要把$ai_is_error当重点:它是最响亮但也最无趣的信号;值得花时间的失败通常根本不会置这个标志。
  • 频率优先于完备性:目标是"发生最多的模式",不是穷举每种可能失败。
  • 内容过大时的安全姿势$ai_input$ai_input_state/$ai_output_state可能含数 MB 数据;MCP 查询用contentDetail: "preview""none""full"时落盘再分析。
  • 保留期意识posthog.ai_events默认只保留 30 天,更早 trace 无内容可读。

延伸阅读

  • exploring-ai-failures/SKILL.md——本查询文档所属的完整技能:工作流、工具表、陷阱与提示
  • exploring-ai-failures/references/finding-traces.md——本文主体查询参考(各策略 SQL/JSON 全集)
  • exploring-llm-traces/references/events-and-properties.md——$ai_*完整事件属性 schema 与events/ai_events列映射
  • exploring-llm-traces/SKILL.md——单条 trace 深度阅读机制
  • exploring-llm-traces/references/example-llm-traces-list.md——query-llm-traces-list的两阶段 SQL 实现
  • errors.sql——错误规范化后的聚类查询骨架
  • ai_observability.ts——MCP 工具定义(query-llm-traces-list/query-llm-trace的参数 schema 与 URL 模板)

【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询