用 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-4o、claude-sonnet-4-20250514$ai_providerstring提供商名如openai、anthropic$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_events以ORDER BY (team_id, trace_id, timestamp)建表访问路径是trace_id而非时间戳行数据在保留期后默认 30 天会被丢弃更早的 trace 将没有内容。当需要自己写 SQL 取重内容时先按时间窗口在events上筛出 trace_id再锚定trace_id到ai_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_product、agent_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-listresultsposthog: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.py、scripts/print_timeline.py、scripts/extract_span.py、scripts/extract_conversation.py、scripts/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 提供弹药Step 1 — 圈定一个用例找到 trace 分类的过滤器前缀、feature property、模型后续所有查询收敛到这一个切片。Step 2 — 选择读哪些 trace按手头信号从上面的策略里挑可组合code errors 最便宜但最不具代表性metric outliers 捕捉失控/截断/膨胀/循环单类型切片保证读到的 trace 共享分类分层抽样是默认eval 峰值从既有评估切入高流量时可用聚类exploring-llm-clusters。Step 3 — 读一批这是工作本身用query-llm-trace逐条读 20–30 条直到新 trace 不再带来新模式就停止几十条不是几千条。不能用GROUP BY或 grep 输出里的 refusal / sorry 字样来替代阅读——你还不知道要找的模式长什么样阅读才是发现它们的方式。一条查不出沉默失败的 SQL 返回空不是失败不存在的证据而是你必须去读的信号。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 上追加?timestampurl_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或nonefull时落盘再分析。保留期意识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),仅供参考