
PostHog AI 可观测性成本属性全解析$ai_total_cost_usd与 LLM 费用归因实战【免费下载链接】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 可观测性AI Observability功能为背景系统讲解 LLM 调用成本在事件上的落盘方式成本属性只存在于$ai_generation与$ai_embedding两类事件上、由模型与 Token 用量在摄取ingestion时推导而来且以$ai_total_cost_usd为唯一权威总额。读完本文你将掌握完整的成本属性 Schema、为何聚合时只能求和$ai_total_cost_usd而不能拆分组件、不同 Provider 缓存费用的口径差异、trace/evaluation 事件集的正确统计边界以及如何结合 PostHog 内置的 HogQL 查询与/ai-observability仪表盘做费用归因。本文主体源自仓库文档 cost-properties.md属于exploring-llm-costs技能包见 SKILL.md的核心参考之一并辅以仓库源码验证。成本属性总览一份完整的 Schema所有成本均以USD计在事件摄取时按模型 Provider Token 用量计算后写入事件属性。你不能手工设置这些成本值并期望它们长期有效——摄取管线会在每次事件到达时重新推导。成本只存在于两类事件上$ai_generation一次大模型生成调用含推理、工具调用、多模态内容生成$ai_embedding一次向量嵌入调用。完整属性表如下摘自 cost-properties.md属性所在事件含义$ai_total_cost_usdgeneration, embedding本次调用的总成本——权威总额做聚合请用它$ai_input_cost_usdgeneration, embedding输入 Token 对应的成本$ai_output_cost_usdgeneration, embedding输出 Token 对应的成本$ai_request_cost_usdgeneration, embedding每次请求的固定费用如 Anthropic 的 per-request fee通常为0$ai_web_search_cost_usdgeneration, embedding生成过程中网页搜索工具调用产生的成本通常为0$ai_audio_cost_usdgeneration模型按独立费率收取音频模态成本时使用通常为0$ai_image_cost_usdgeneration图像模态成本通常为0$ai_video_cost_usdgeneration视频模态成本通常为0$ai_input_tokensgeneration, embedding发送给模型的 Token 数跨所有模态合计$ai_output_tokensgeneration模型返回的 Token 数跨所有模态合计$ai_total_tokensgeneration, embedding输入 输出 Token 数$ai_cache_read_input_tokensgeneration由 Provider 提示词缓存命中的输入 Token 数$ai_cache_creation_input_tokensgeneration写入 Provider 提示词缓存的输入 Token 数$ai_reasoning_tokensgeneration推理模型的思考 Token按输出计费$ai_modelgeneration, embedding成本归因的主维度$ai_providergeneration, embedding次要归因维度openai、anthropic 等$ai_is_errorgeneration用于在成本汇总中排除/包含失败调用$ai_trace_id所有$ai_*事件将成本向上归集到 trace 层级$ai_session_id所有$ai_*事件将成本向上归集到 session 层级把一系列相关 trace 归为一组注意$ai_total_tokens与$ai_input_tokens$ai_output_tokens的差异前者同时出现在 generation 与 embedding 事件上而$ai_output_tokens只出现在 generation 上——嵌入调用没有输出 Token概念这一点在后续写聚合 SQL 时会影响sum()的取值。核心铁律永远求和$ai_total_cost_usd不要拆组件这是整份文档最重要的一条规则。在摄取时$ai_total_cost_usd input output request web_search再加上各模态成本如果只求$ai_input_cost_usd $ai_output_cost_usd会静默丢掉 request 与 web-search 费用——这两项对 Anthropic 的按请求收费和任何带工具tool增强的生成调用来说都是真实且非零的。UI 的成本单元格正是按如下方式计算的event IN ($ai_generation, $ai_embedding) 上的 $ai_total_cost_usd 求和写查询时请镜像这一口径。源码佐证UI 与后端都只聚合总额这一规则在仓库中有多处直接印证前端products/ai_observability/frontend/utils.ts中的costContextFromProperties()从事件属性构造CostContext时把totalCost设为props.$ai_total_cost_usd并先判断其类型是否为number非数字则返回undefined同时把 input/output/request/webSearch 作为旁路信息携带——但totalCost是唯一必填字段其它组件字段都可能缺失。仪表盘模板products/ai_observability/backend/dashboard_templates.py中内置的 Total cost (USD)、Cost per user (USD) 等 insight 图块其趋势查询math均为sum、math_property均为$ai_total_cost_usd事件过滤为$ai_generation。后端接口products/ai_observability/backend/api/personal_spend.py中的_fetch_summary()、_fetch_by_product()、_fetch_by_tool()、_fetch_by_model()、_fetch_by_day()等查询全部以sum(toFloat(properties.$ai_total_cost_usd))作为成本口径且事件集合固定为_event_in([$ai_generation, $ai_embedding])。从源码结构可以推断toFloat()转换意味着属性在 ClickHouse 中按字符串存储HogQL 聚合前需要显式类型转换这也是所有示例 SQL 都写toFloat(properties.$ai_total_cost_usd)的原因。缓存费用Provider 的两种报告口径提示词缓存prompt cache费用的归属因 Provider 而异直接求和$ai_input_cost_usd会得出误导性结论排他式exclusive报告缓存 Token不计入$ai_input_tokens。Anthropic 目前多数 SDK 采用此口径。这类 Provider 的缓存读/写花费也会体现在$ai_input_cost_usd之外因此仅看$ai_input_cost_usd会低估真实的输入侧花费。包含式inclusive报告缓存 Token已计入$ai_input_tokens。OpenAI 及多数其他 Provider 目前采用此口径缓存花费已打包进$ai_input_cost_usd。这个差异还随 SDK 版本变化——同一个 Provider 在不同 SDK 版本上可能切换口径。因此文档给出两个明确建议永远以$ai_total_cost_usd为权威总额它已经按事件实际采用的口径计算完毕无需你关心差异需要自己算缓存命中率时不要按 Provider 名硬编码而要按事件级标志$ai_cache_reporting_exclusive分支。缓存命中率公式按事件级标志分支仓库配套文档 cache-accounting.md 给出了可直接运行的 HogQL 配方posthog:execute-sql SELECT properties.$ai_model AS model, if(properties.$ai_cache_reporting_exclusive true, sum(toInt(properties.$ai_cache_read_input_tokens)) / nullIf(sum(toInt(properties.$ai_input_tokens)) sum(toInt(properties.$ai_cache_read_input_tokens)) sum(toInt(properties.$ai_cache_creation_input_tokens)), 0), sum(toInt(properties.$ai_cache_read_input_tokens)) / nullIf(sum(toInt(properties.$ai_input_tokens)), 0) ) AS cache_hit_rate FROM events WHERE event $ai_generation AND timestamp now() - INTERVAL 30 DAY GROUP BY model, properties.$ai_cache_reporting_exclusive关键点排他式真实输入总量 $ai_input_tokens $ai_cache_read_input_tokens $ai_cache_creation_input_tokens命中率 缓存读 / 该总量包含式$ai_input_tokens已含缓存命中率 缓存读 /$ai_input_tokensnullIf(..., 0)用于防止除零若某个模型混用了两种报告风格少见应在GROUP BY中加入$ai_cache_reporting_exclusive分别统计而不是用any()取其一。$ai_cache_reporting_exclusive是布尔标志由摄取管线在每条$ai_generation上自动探测并写入解析结果手动捕获时也可通过$ai_cache_reporting_exclusive: true|false覆盖。这份公式同样驱动着 breakdown-patterns.md 中输入 vs 输出 vs 缓存经济学配方的cache_hit_rate字段。事件集规则trace、span 与 evaluation 的成本边界trace 与 span 不承载可汇总的成本$ai_trace和$ai_span事件不携带用于汇总的成本。要获得一条 trace 的总成本正确做法是sum($ai_total_cost_usd) WHERE $ai_trace_id trace_id AND event IN ($ai_generation, $ai_embedding)需要注意的是部分 SDK 封装层会出于便利把$ai_total_cost_usd复制一份到$ai_trace事件上但查询执行器query runner仍然只对event IN ($ai_generation, $ai_embedding)做聚合——不要混用事件集否则会双重计数double-count。evaluation 事件默认不算入总额$ai_evaluation事件也会产出成本属性摄取时与$ai_generation、$ai_embedding一并计费但内置的/ai-observability汇总与查询执行器都不把它计入成本总额。处理原则如果用户只想要标准 LLM 花费保持event IN ($ai_generation, $ai_embedding)与 UI 对齐如果用户明确要求含评估的总花费则显式扩展事件过滤为event IN ($ai_generation, $ai_embedding, $ai_evaluation)并明确说明这是扩展口径。这条不混用事件集的纪律在 SKILL.md 的 Tips 中反复出现在$ai_span上求和得到的是 0$ai_trace上的复制值不可纳入汇总$ai_evaluation只在用户显式要求时才加入。源码佐证事件集合的固定写法products/ai_observability/backend/api/personal_spend.py中通过_event_in(events)构造event IN (...)过滤所有成本查询统一传入[$ai_generation, $ai_embedding]_fetch_by_tool()则额外限定equals(event, $ai_generation)工具调用只出现在生成事件上。这从后端实现上印证了成本聚合的事件集 generation embedding这一约定。用户维度distinct_id是规范维度distinct_id是规范的用户维度客户通常在 SDK 中设置它需要更丰富的按用户拆分时使用 person 属性例如email、company_tier写查询前先用posthog:read-data-schema工具发现项目里实际存在的自定义属性不要猜测属性名。有两个与用户统计相关的坑来自 SKILL.md Tips按用户汇总时排除distinct_id properties.$ai_trace_id的行——部分 SDK 在未设置用户时会把distinct_id默认成 trace ID想用 person 属性如email做过滤时事件行通过person_id关联 person 表读取属性HogQL 写法形如person.properties.email与 AI 可观测性 Users 标签页对events表的查询同构见 personal_spend.py 中_email_filter()的注释。实战一段可直接运行的总成本查询把上述规则落成一段标准查询模板来自 SKILL.mdposthog:execute-sql SELECT round(sum(toFloat(properties.$ai_total_cost_usd)), 4) AS total_cost_usd FROM events WHERE event IN ($ai_generation, $ai_embedding) AND timestamp now() - INTERVAL 30 DAY它同时体现了三条黄金规则聚合总额而非组件否则丢掉 request / web-search 费同时包含 generation 与 embedding漏掉 embedding 会静默少算嵌入调用单次便宜但规模大了很可观总是设置时间范围不带时间范围的成本查询会全表扫描 events 表。更多配方按天成本曲线、按模型/用户/trace/自定义维度拆分、单次调用成本分位数分布、输入 vs 输出 vs 缓存经济性见 breakdown-patterns.md成本为 0 或缺失时的排查路径与三条摄取计费路径预计算 passthrough、自定义单价 custom、自动模型匹配 openrouter/manual见 cost-sources.md其中$ai_cost_model_source是排障第一入口。总结PostHog 的 LLM 成本模型可以浓缩为几句话成本只写在$ai_generation与$ai_embedding事件上以$ai_total_cost_usd为唯一权威总额所有成本问题都是对这两类事件按$ai_total_cost_usd聚合后的分组、过滤与比较缓存口径按事件级标志$ai_cache_reporting_exclusive分支而非按 Provider 硬编码trace/span/evaluation 事件集各有明确的成本边界用户维度以distinct_id为准。这套约定在 UI 成本单元格、后端personal_spend接口与内置仪表盘模板中高度一致遵循它即可让自定义查询与官方展示口径永远对齐。【免费下载链接】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),仅供参考