ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

PostHog AI Observability:LLM Trace 事件模型与属性参考 —— 从 $ai_trace 到 posthog.ai_events 的完整数据地图

PostHog AI Observability:LLM Trace 事件模型与属性参考 —— 从 $ai_trace 到 posthog.ai_events 的完整数据地图 PostHog AI ObservabilityLLM Trace 事件模型与属性参考 —— 从 $ai_trace 到 posthog.ai_events 的完整数据地图【免费下载链接】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本文围绕 PostHog AI Observability 中 LLM/AI Agent 追踪的事件与属性体系展开完整讲解$ai_trace、$ai_span、$ai_generation、$ai_embedding四类事件的全部属性以及最关键的存储设计重量级 LLM 内容为何不在events表而在专门的 ClickHouse 表posthog.ai_events中。读完本文你将掌握 AI 可观测性事件的属性字典、events与ai_events的列映射关系、按trace_id锚定的单轨迹/批量 SQL 查询模式并能结合表结构源码理解保留期与索引设计。PostHog 将 LLM 与 Agent 活动捕获为trace轨迹每条 trace 是一棵事件树从顶层 Agent 调用一直下沉到每一次具体的 LLM API 请求。该参考文档是 exploring-llm-traces 技能 的核心参考文件供使用 MCP 工具调试 trace 时查阅事件 schema 与 SQL 模式。一、事件类型与属性字典AI 可观测性事件共四类构成trace → span → generation / embedding的层级$ai_trace (顶层容器) └── $ai_span (逻辑分组如 RAG retrieval、tool execution、routing) ├── $ai_generation (单次 LLM API 调用) └── $ai_embedding (向量嵌入生成)1.1$ai_trace—— 轨迹顶层容器顶层容器事件在所有子事件之后发出emitted last。属性类型说明$ai_trace_idstring唯一轨迹标识本轨迹内所有事件共享$ai_trace_namestring轨迹名称$ai_session_idstring将多条轨迹聚合为一个会话$ai_input_stateJSON轨迹开始时的应用状态可能非常大$ai_output_stateJSON轨迹结束时的应用状态可能非常大$ai_latencyfloat轨迹总耗时秒1.2$ai_span—— 轨迹内的逻辑分组表示轨迹内的一个逻辑步骤例如 “RAG retrieval”“tool execution”“routing”。属性类型说明$ai_trace_idstring父轨迹 ID$ai_span_idstring本 span 的唯一标识$ai_span_namestringspan 名称$ai_parent_idstring父 span 或 trace 的 ID$ai_latencyfloatspan 耗时秒$ai_input_stateJSON进入该 span 时的状态工具调用的入参$ai_output_stateJSON离开该 span 时的状态工具调用的返回1.3$ai_generation—— 单次 LLM API 调用每一次 chat completion 请求对应一条$ai_generation事件是属性最丰富的一类。属性类型说明$ai_trace_idstring父轨迹 ID$ai_parent_idstring父 span 或 trace 的 ID$ai_modelstring模型标识如 gpt-4o、claude-sonnet-4-20250514$ai_providerstring提供商名称如 openai、anthropic$ai_inputJSON array输入消息{role, content}对象数组可能非常大$ai_output_choicesJSON arrayLLM 响应{message: {role, content}}结构可能包含工具调用$ai_input_tokensint输入 token 数$ai_output_tokensint输出 token 数$ai_input_cost_usdfloat输入 token 成本USD$ai_output_cost_usdfloat输出 token 成本USD$ai_total_cost_usdfloat总成本USD$ai_latencyfloat本次生成耗时秒$ai_http_statusintLLM API 返回的 HTTP 状态码$ai_is_errorboolean本次生成是否出错$ai_errorstring出错时的错误信息$ai_base_urlstringLLM API 的 base URL$ai_tools_calledstringLLM 调用的工具名逗号分隔1.4$ai_embedding—— 向量嵌入生成文本到向量的嵌入创建事件。属性类型说明$ai_trace_idstring父轨迹 ID$ai_parent_idstring父 span 或 trace 的 ID$ai_modelstring嵌入模型标识$ai_providerstring提供商名称$ai_input_tokensint处理的 token 数$ai_total_cost_usdfloat总成本USD$ai_latencyfloat耗时秒二、重量级内容的存放位置events与posthog.ai_events这是整个数据模型中最容易踩坑的一点重量级 LLM 属性并不存储在events表的properties里而是作为原生列存放在专门的 ClickHouse 表posthog.ai_eventsHogQL 中引用为posthog.ai_events。events表只保留轻量元数据——token 计数、成本、模型、提供商、$ai_trace_id、延迟、错误标志等。2.1 列映射表重量级内容events属性名ai_events列名输入消息$ai_inputinput输出$ai_outputoutput输出 choices$ai_output_choicesoutput_choices输入状态$ai_input_stateinput_state输出状态$ai_output_stateoutput_state工具$ai_toolstools2.2 源码佐证写入链路上的属性剥离与原生列从源码结构看这一设计在表定义中有完整体现。ai_events 表结构定义 中明确order_by [team_id, trace_id, timestamp] partition_by toYYYYMM(drop_date) ttl drop_date而 dev 环境的完整表结构 揭示了两处关键实现细节properties列在物化视图写入时被主动剥离。ai_events_json_ws_mv物化视图在消费 Kafka topic 时用JSONExtractKeysAndValuesRaw重建properties并显式排除六个重量级键arrayFilter( x - ((x.1) NOT IN ($ai_input, $ai_output, $ai_output_choices, $ai_input_state, $ai_output_state, $ai_tools)), JSONExtractKeysAndValuesRaw(src.properties) )同时这六个字段被nullIf(JSONExtractRaw(src.properties, $ai_input), )提取为input、output、output_choices、input_state、output_state、tools原生列。也就是说即便ai_events表里也保留了properties字符串列其中也已经不再包含这些大字段——大字段只存在于原生列中。ai_events的retention_days默认值为 30column retention_days { type Int16 default 30 }drop_date toDate(timestamp) toIntervalDay(retention_days)作为 TTL 生效。这印证了参考文档的说法行在保留期默认 30 天后被丢弃超过保留期的 trace 在ai_events中已无内容。2.3 访问路径trace_id是索引键不是timestampposthog.ai_events的排序键是(team_id, trace_id, timestamp)因此trace_id才是高效访问路径而非timestamp。从表结构看辅助索引进一步佐证了各查询维度的设计意图trace_id、session_id、parent_id、span_id、model等列上建了bloom_filter索引event、is_error、provider上建了set索引见 ai_events 表定义中的 index 段。没有任何限制规定某个事件能携带哪些重量级列但典型形态是$ai_generation携带input/output_choices/tools嵌入事件携带input$ai_span和$ai_trace携带input_state/output_state。优先使用 MCP 工具posthog:query-llm-trace/posthog:query-llm-traces-list会替你读取posthog.ai_events。只有做自定义分析聚合、join、批量提取或已经在 SQL 层时才直接写下面的 SQL。三、SQL 查询模式3.1 单条 trace已知trace_id时直接读取当你已经持有trace_id例如来自 trace URL 或query-llm-traces-list的结果直接按trace_id过滤SELECT timestamp, span_id, event, model, input, output_choices FROM posthog.ai_events WHERE trace_id trace_id ORDER BY timestamp3.2 批量 / 分析场景两阶段查询时间窗口跨多条 trace先在带时间索引的events表上过滤拿到 trace ID再以trace_id为锚点从posthog.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注意注释中的关键点token、成本、模型、ID 这类轻量字段留在events上所以筛选条件如properties.$ai_model gpt-4o应该尽量在events这一侧完成ai_events只负责按trace_id回捞大字段。四、常见模式4.1 轨迹内事件的关联方式所有事件共享$ai_trace_id层级结构通过$ai_parent_id构建它指向父节点的$ai_span_id或$ai_trace_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)4.2 成本聚合成本只出现在$ai_generation和$ai_embedding事件上。对同一$ai_trace_id下的这两类事件求和$ai_total_cost_usd即得到整条轨迹的总成本。4.3 大属性警告以下属性可能包含兆字节级数据$ai_input—— 完整对话历史、system prompt$ai_input_state/$ai_output_state—— 应用状态快照因此通过 MCP 工具查询时使用contentDetail: preview或none使用contentDetail: full时把结果转储到文件再处理在原始 SQL 中这些内容只存在于posthog.ai_events的原生列而不在events.properties上。这正是 SKILL.md 反复强调的排查经验对events.properties.$ai_input/$ai_output_choices写 HogQL 返回空并不是数据缺失而是这些字段只存在于posthog.ai_events表上。当 full 详情的结果被持久化为文件后可用技能目录下的 解析脚本print_summary.py、print_timeline.py、extract_span.py、extract_conversation.py、search_traces.py做摘要、时间线、span 提取与关键词搜索。五、小结与适用边界属性字典四类事件的完整属性以本文第一节的表格为准$ai_generation是唯一携带成本与完整对话内容的事件$ai_embedding只携带输入 token 与成本。存储边界重量级字段input / output / output_choices / input_state / output_state / tools只在posthog.ai_events原生列上从物化视图源码可确认events与ai_events.properties两侧都被剥离轻量元数据token、成本、model、provider、trace_id、latency、错误标志留在events。查询边界单 trace 查询以trace_id为锚点跨时间窗口的批量分析采用 “events筛选 trace ID →ai_events回捞内容” 的两阶段模式。保留期限制ai_events行按默认 30 天保留期retention_days 30丢弃超期 trace 的重量级内容不可恢复做历史分析时必须考虑该窗口。优先工具常规 trace 检查优先走posthog:query-llm-trace/query-llm-traces-list直接 SQL 只留给聚合、join、批量提取等自定义场景。【免费下载链接】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),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进