Langfuse · 模型、采集与存储
本页覆盖:Trace 模型、采集入口、鉴权限流、存储与保留。每条事实链到固定提交(f75c661d)。回到 Langfuse 总览。
1. Trace / Observation 模型、类型、层级、Token 与成本
1.1 Trace 与 Observation 的领域对象
TraceDomain是前后端共用的 Zod 对象(packages/shared/src/domain/traces.tsL12-L30,permalink)。- Trace 字段包括
id、name、timestamp、environment、tags、bookmarked、public、release、version、input、output、metadata、sessionId、userId、projectId(同上范围)。 ObservationType有SPAN、EVENT、GENERATION、AGENT、TOOL、CHAIN、RETRIEVER、EVALUATOR、EMBEDDING、GUARDRAIL共 10 种(packages/shared/src/domain/observations.tsL5-L17,permalink)。ObservationSchema用可空traceId指向 Trace,用可空parentObservationId指向父 Observation(packages/shared/src/domain/observations.tsL55-L65,permalink)。- Observation 还带
level、statusMessage、模型、用量、成本、promptId、promptName、promptVersion、工具定义与工具调用(packages/shared/src/domain/observations.tsL66-L100,permalink)。 EventsObservationSchema在 Observation 上附加userId、sessionId、traceName、release、tags、bookmarked、public、isRootObservation(packages/shared/src/domain/observations.tsL116-L125,permalink)。- 根 Observation 的判定是没有
parentObservationId,或isAppRoot === true(packages/shared/src/eventsTable.tsL44-L50,permalink)。 - 在 SQL 里,根行条件是
parent_span_id = '' OR is_app_root = true(packages/shared/src/eventsTable.tsL4-L7,permalink)。
1.2 层级
- ClickHouse
events_full用trace_id、span_id、parent_span_id表示同一条 Trace 里的 span 树(packages/shared/clickhouse/migrations/canonical/0039_create_events_full.up.sqlL4-L6,permalink)。 - 同一行带
trace_name、is_app_root、session_id、user_id、tags(packages/shared/clickhouse/migrations/canonical/0039_create_events_full.up.sqlL16-L24,permalink)。 - 从 events 聚合 Trace 时,
id取trace_id,timestamp取min(start_time)(packages/shared/src/server/queries/clickhouse-sql/event-query-builder.tsL528-L535,permalink)。 - Trace 的
input、output、metadata、bookmarked取parent_span_id = ''的最新event_ts行(packages/shared/src/server/queries/clickhouse-sql/event-query-builder.tsL541-L558,permalink)。 - Trace 级聚合 level 按 ERROR、WARNING、DEFAULT、DEBUG 的优先级取最高(
packages/shared/src/server/queries/clickhouse-sql/event-query-builder.tsL566-L567,permalink)。 eventsTracesAggregation的注释写明:按trace_id把 events 重新聚成 Trace,并称这是迁到只用 events 表之前的临时做法(packages/shared/src/server/queries/clickhouse-sql/query-fragments.tsL103-L128,permalink)。- 旧
traces表独立存在,初始建表使用ReplacingMergeTree(event_ts, is_deleted),按toYYYYMM(timestamp)分区(packages/shared/clickhouse/migrations/canonical/0001_traces.up.sqlL1-L23,permalink)。
1.3 采集事件类型
- 采集事件类型包含
trace-create、span-create/update、generation-create/update、event-create、score-create、sdk-log、dataset-run-item-create,以及 agent、tool、chain、retriever、evaluator、embedding、guardrail 的 create(packages/shared/src/server/ingestion/types.tsL319-L339,permalink)。 observation-create与observation-update被标成仅为兼容保留的旧类型(packages/shared/src/server/ingestion/types.tsL336-L338,permalink)。- Generation 在 Span 字段上增加
model、usage、costDetails、promptName、promptVersion(packages/shared/src/server/ingestion/types.tsL513-L540,permalink)。 promptName与promptVersion必须同时出现或同时为空(packages/shared/src/server/ingestion/types.tsL535-L539,permalink)。
1.4 模型匹配、Token 计数、成本
- 模型定义存在 Postgres
Model表,含matchPattern、单价、tokenizerId、tokenizerConfig,可按项目覆盖(packages/shared/prisma/schema.prismaL912-L932,permalink)。 - 价格拆成
Price(按usageType)和PricingTier(含priority、isDefault、conditions)(packages/shared/prisma/schema.prismaL955-L969,permalink)。 findModel先查本地缓存,再查 Redis 缓存,最后查库(packages/shared/src/server/ingestion/modelMatch.tsL44,permalink)。- Worker 对有
provided_model_name的观测调用findModel,否则不匹配模型(worker/src/services/IngestionService/index.tsL1363,permalink)。 - 价格档按条件匹配:条件可对
usageDetails的键做正则求和比较,也可比较modelParameters或metadata的值(packages/shared/src/server/pricing-tiers/matcher.tsL18-L30,permalink)。 - Worker 调
matchPricingTier选出价格档,再算成本(worker/src/services/IngestionService/index.tsL1411,permalink)。 - 只有在「用户没给 usage、没给 cost、模型已匹配、level 不是 ERROR、不是 AI Gateway 生成」时才做本地 tokenize(
worker/src/services/IngestionService/index.tsL1491-L1497,permalink)。 - 用户给了任一成本点后,不再计算其他成本点,直接用用户提供的值(
worker/src/services/IngestionService/index.tsL1713-L1716,permalink)。 - 未提供成本时,按
usageUnits的键逐项匹配价格并相乘(worker/src/services/IngestionService/index.tsL1740-L1743,permalink)。 - 本地 tokenizer 有
openai(tiktoken)和claude两种(worker/src/features/tokenisation/usage.tsL51-L57,permalink)。 - events 路径的成本与用量按 span 做
sum/sumMap聚合成 Trace 总量(packages/shared/src/server/queries/clickhouse-sql/event-query-builder.tsL549-L565,permalink)。 - 价格档与模型管理有独立 tRPC 路由
models(web/src/server/api/root.tsL99,permalink)和页面/project/[projectId]/models(web/src/pages/project/[projectId]/models.tsxL1,permalink)。 - 公共 API 有
/api/public/models目录下的路由(web/src/pages/api/public/models/index.tsL1,permalink)。
2. 采集:legacy ingestion、公共 API、OTLP、SDK、队列、批处理、限流、鉴权
2.1 入口
- 入口
POST /api/public/ingestion接收{ batch, metadata },先做权限、限流和格式校验,再异步处理(web/src/pages/api/public/ingestion.tsL56-L70,permalink)。 - 请求体上限是 4.5mb(
web/src/pages/api/public/ingestion.tsL48-L54,permalink)。 - 用量超阈值时 ingestion 被拒绝(
web/src/pages/api/public/ingestion.tsL127,permalink)。 - 在
events_only下,该端点只接受score-create(web/src/pages/api/public/ingestion.tsL295-L297,permalink)。 - 被拒绝的非 score 事件返回 400,并提示改用 v4 SDK 或 OTLP,或临时把写入模式设成
dual(web/src/pages/api/public/ingestion.tsL311-L345,permalink)。 - Legacy REST 还有
POST /api/public/traces、spans、events、generations;它们把 body 包成 ingestion 事件再走同一管线(web/src/pages/api/public/traces/index.tsL39-L64,permalink、web/src/pages/api/public/spans.tsL18-L38,permalink、web/src/pages/api/public/events.tsL16-L33,permalink、web/src/pages/api/public/generations.tsL19-L35,permalink)。 - 这些 legacy 写接口在
events_only下被拒绝(web/src/pages/api/public/traces/index.tsL45-L47,permalink)。 - OTLP 入口是
POST /api/public/otel/v1/traces,权限traces:create,限流资源ingestion(web/src/pages/api/public/otel/v1/traces/index.tsL26-L33,permalink)。 - OTLP 路由关闭 bodyParser,自行读 body,并支持 gzip(
web/src/pages/api/public/otel/v1/traces/index.tsL20-L24,permalink)。 - OTLP 路由读取
x-langfuse-ingestion-version头,并和 SDK 名称、版本一起交给processOtelIngestion(web/src/pages/api/public/otel/v1/traces/index.tsL96,permalink)。 - OTLP metrics 端点
POST /api/public/otel/v1/metrics的处理函数是空函数fn: async () => {}(web/src/pages/api/public/otel/v1/metrics/index.tsL18,permalink)。 - SDK 自身代码不在本仓库;仓库只读取 SDK 头(
x-langfuse-sdk-name、x-langfuse-sdk-version、x-langfuse-ingestion-version)来决定写入路径(worker/src/queues/otelIngestionQueue.tsL60-L100,permalink)。 - 另有媒体上传入口
POST /api/public/media,限流资源media-upload(web/src/pages/api/public/media/index.tsL19,permalink)。
2.2 鉴权与限流
- 公共 API 支持 Basic 认证(公钥加私钥,完整 scope)和 Bearer 认证(只有公钥,受限 scope)(
web/src/features/public-api/server/apiAuth.tsL92,permalink、web/src/features/public-api/server/apiAuth.tsL215,permalink)。 - API Key 有
PROJECT与ORGANIZATION两种 scope(web/src/features/public-api/server/apiAuth.tsL183,permalink)。 - 限流用
rate-limiter-flexible的RateLimiterRedis,按「组织、套餐、资源」分桶(web/src/features/public-api/server/RateLimitService.tsL47-L50,permalink)。 - 自托管和没有 Redis 时不限流(
web/src/features/public-api/server/RateLimitService.tsL48,permalink)。 - 限流资源有
ingestion、media-upload、public-api、public-api-metrics、public-api-v2-metrics、prompts、datasets、annotation-queues、trace-delete、score-delete等(packages/shared/src/interfaces/rate-limits.tsL4,permalink)。 - 限流出错时 ingestion 选择放行(fail open)(
web/src/pages/api/public/ingestion.tsL158,permalink)。 - score 事件要求
scores:create,其余事件要求traces:create(web/src/pages/api/public/ingestion.tsL384-L390,permalink)。
2.3 队列与 Worker
processEventBatch先按 ingestion schema 校验,再把sdk-log记日志后丢出后续处理(packages/shared/src/server/ingestion/processEventBatch.tsL168-L200,permalink)。- 校验通过的事件按实体 id 分组上传到 S3,S3 失败则中止,不再入队(
packages/shared/src/server/ingestion/processEventBatch.tsL276-L332,permalink)。 - S3 成功后,每组事件按
projectId-eventBodyId分片写入IngestionQueue(packages/shared/src/server/ingestion/processEventBatch.tsL328-L346,permalink)。 - 队列名包括
ingestion-queue、otel-ingestion-queue、trace-upsert、batch-export-queue、event-propagation-queue、monitor-queue、webhook-queue、data-retention-queue等(packages/shared/src/server/queues.tsL406-L446,permalink)。 - 入队延迟默认 15 秒,分片数默认 1(
packages/shared/src/env.tsL217-L223,permalink)。 - Worker 消费
IngestionQueue:先查 Redis 去重键,再读 S3 事件文件(worker/src/queues/ingestionQueue.tsL85,permalink)。 IngestionService.mergeAndWrite按事件类型分流到 trace、observation、score 三条处理函数(worker/src/services/IngestionService/index.tsL238-L268,permalink)。- 处理结果写入
ClickhouseWriter的内存队列,批量写 ClickHouse(worker/src/services/ClickhouseWriter/index.tsL61-L63,permalink)。 - 批大小默认 1000,写间隔默认 1000 ms,最大重试次数默认 3(
worker/src/env.tsL181-L192,permalink)。 - OTLP 数据先上传 S3,再进
OtelIngestionQueue,分片键是projectId-fileKey(packages/shared/src/server/otel/OtelIngestionProcessor.tsL330-L342,permalink)。 - Worker 的 OTLP 处理器
processOtelEvents对每个 span 调createEventRecord,再writeEventRecord(worker/src/features/otel-ingestion/processOtelEvents.tsL110,permalink、worker/src/features/otel-ingestion/processOtelEvents.tsL154,permalink)。 writeEventRecord直接把记录加入events_full的写队列,events_core由物化视图填充(worker/src/services/IngestionService/index.tsL509-L512,permalink)。- 是否直写 events 表由下面四条规则按序决定:请求头、环境变量、SDK 版本 scope、组织创建日期截止线(
worker/src/queues/otelIngestionQueue.tsL310-L322,permalink)。 - SDK scope 规则:Python SDK ≥ 4.0.0,或 JS SDK ≥ 5.0.0(
worker/src/queues/otelIngestionQueue.tsL65-L66,permalink)。 - 一条 OTLP span 可能同时生成
trace-create事件,body 含public、tags、environment、input、output(packages/shared/src/server/otel/OtelIngestionProcessor.tsL1140-L1161,permalink)。 is_app_root来自 OTel 属性,值为true或"true"时为真(packages/shared/src/server/otel/OtelIngestionProcessor.tsL1175-L1178,permalink)。- 旧路径里,观测处理会在缺 Trace 时生成包装 Trace 记录(
worker/src/services/IngestionService/index.tsL1121,permalink)。
2.4 事件批处理与暂存表
observations_batch_staging表有TTL toDateTime(s3_first_seen_timestamp) + INTERVAL 48 HOUR(packages/shared/clickhouse/migrations/canonical/0038_create_observations_batch_staging.up.sqlL50,permalink)。- Worker 有独立的
EventPropagationQueue(worker/src/app.tsL715,permalink)。 - 传播任务把
observations_batch_staging与 traces 连接后插入events_full(worker/src/features/eventPropagation/handleEventPropagationJob.tsL159,permalink)。
2.5 其他采集路径
- 采集管线按
trace-create事件在 Worker 里写 Trace,同时对带session_id的 Trace 往 Postgrestrace_sessions插入稀疏行(worker/src/services/IngestionService/index.tsL882-L894,permalink)。 - 采集侧环境名会被规范化,空值或非法字符落到默认环境(
packages/shared/src/server/ingestion/types.tsL304-L317,permalink)。
3. 存储:ClickHouse、Postgres、对象存储、保留策略
3.1 ClickHouse 表
- 旧
traces表按project_id、toDate(timestamp)、id排序(packages/shared/clickhouse/migrations/canonical/0001_traces.up.sqlL28-L32,permalink)。 - 旧
traces表的input与output使用ZSTD(3)(packages/shared/clickhouse/migrations/canonical/0001_traces.up.sqlL13-L14,permalink)。 - 旧
observations表以trace_id关联 Trace,并有parent_observation_id、type、start_time、end_time(packages/shared/clickhouse/migrations/canonical/0002_observations.up.sqlL3-L10,permalink)。 - 旧
scores表同样是ReplacingMergeTree(event_ts, is_deleted),按toYYYYMM(timestamp)分区(packages/shared/clickhouse/migrations/canonical/0003_scores.up.sqlL22-L23,permalink)。 scores后续增加了session_id(packages/shared/clickhouse/migrations/canonical/0012_add_session_id_column_scores.up.sqlL1,permalink)、dataset_run_id(packages/shared/clickhouse/migrations/canonical/0017_add_run_id_column_scores.up.sqlL1,permalink),并把trace_id改成可空(packages/shared/clickhouse/migrations/canonical/0014_scores_modify_nullable_trace_id_column.up.sqlL1,permalink)。events_full使用ReplacingMergeTree(event_ts, is_deleted),按toYYYYMM(start_time)分区,主键是project_id、分钟级start_time、xxHash32(trace_id)(packages/shared/clickhouse/migrations/canonical/0039_create_events_full.up.sqlL112-L115,permalink)。events_full带全文索引,覆盖input、output的小写形式以及metadata_values、metadata_names(packages/shared/clickhouse/migrations/canonical/0039_create_events_full.up.sqlL108-L110,permalink)。events_core引擎与排序键同events_full(packages/shared/clickhouse/migrations/canonical/0040_create_events_core.up.sqlL113-L116,permalink)。- 物化视图
events_core_mv从events_full写入events_core,并把input、output、metadata value 截到 200 个字符(packages/shared/clickhouse/migrations/canonical/0041_create_events_core_mv.up.sqlL39-L42,permalink)。 - 读取时
truncated为 true 读events_core,否则读events_full(packages/shared/src/server/queries/clickhouse-sql/query-fragments.tsL97,permalink)。 observations_batch_staging是 48 小时 TTL 的暂存表(packages/shared/clickhouse/migrations/canonical/0038_create_observations_batch_staging.up.sqlL50,permalink)。dataset_run_items_rmt存数据集运行项,排序键project_id, dataset_id, dataset_run_id, id(packages/shared/clickhouse/migrations/canonical/0024_dataset_run_items.up.sqlL1,permalink、packages/shared/clickhouse/migrations/canonical/0024_dataset_run_items.up.sqlL36,permalink)。blob_storage_file_log记录 S3 事件文件,取代了旧的event_log表(packages/shared/clickhouse/migrations/canonical/0011_add_blob_storage_file_log.up.sqlL1,permalink、packages/shared/clickhouse/migrations/canonical/0044_drop_event_log.up.sqlL1,permalink)。- 迁移
0028、0029删除了traces_null以及按 7 天、30 天、全量划分的聚合表(packages/shared/clickhouse/migrations/canonical/0029_drop_traces_null_and_amt_tables.up.sqlL1,permalink)。 events_full加了name、trace_name等列的 ngram 索引(packages/shared/clickhouse/migrations/canonical/0049_add_events_name_ngram_indexes.up.sqlL3,permalink)。- 迁移
0049的注释写明events_full按月分区且没有表级 TTL(packages/shared/clickhouse/migrations/canonical/0049_add_events_name_ngram_indexes.up.sqlL1,permalink)。 - 迁移文件分 canonical 模板,按集群与非集群两种方式渲染(模板里有
{CLICKHOUSE_CLUSTER_CLAUSE}占位,见packages/shared/clickhouse/migrations/canonical/0039_create_events_full.up.sqlL1,permalink)。 - OTLP 直写路径下,Worker 通过
writeEventRecord把 span 写进events_full(worker/src/services/IngestionService/index.tsL509-L512,permalink);score 仍写scores表(worker/src/services/IngestionService/index.tsL799,permalink)。 - 登录时 session 的
v4BetaEnabled在events_only下恒为 true;在dual下还要求「Cloud 或开启LANGFUSE_MIGRATION_V4_ALLOW_PREVIEW_OPT_IN」且用户库里的 flag 为 true(web/src/server/auth.tsL844-L847,permalink)。
3.2 Postgres 表
- Postgres 里没有 Trace 与 Observation 表;只有
TraceSession(packages/shared/prisma/schema.prismaL501-L513,permalink)。 Project带retentionDays与hasTraces(packages/shared/prisma/schema.prismaL139,permalink)。- 观测相关的 Postgres 模型有:
Model/Price/PricingTier、Dashboard/DashboardWidget、TableViewPreset/DefaultView、Monitor、Action/Trigger/Automation、AnnotationQueue*、ScoreConfig、Evaluator/JobConfiguration/EvaluationRule/JobExecution、BatchExport/BatchAction、Media、BlobStorageIntegration、AuditLog、PendingDeletion、Comment(各model声明见packages/shared/prisma/schema.prismaL1630,permalink、packages/shared/prisma/schema.prismaL1892,permalink、packages/shared/prisma/schema.prismaL1488,permalink、packages/shared/prisma/schema.prismaL1964,permalink)。 Comment.objectType可以是TRACE、OBSERVATION、SESSION、PROMPT(packages/shared/prisma/schema.prismaL751-L756,permalink)。AuditLog无外键约束,保证审计记录保留(packages/shared/prisma/schema.prismaL980,permalink)。
3.3 对象存储
- 采集的原始事件先写 S3 再入队(
packages/shared/src/server/ingestion/processEventBatch.tsL276-L332,permalink;桶由LANGFUSE_S3_EVENT_UPLOAD_BUCKET配置,见packages/shared/src/env.tsL312,permalink)。 - OTLP 的
resourceSpans以 JSON 文件写入 S3 的otel/<projectId>/...路径(packages/shared/src/server/otel/OtelIngestionProcessor.tsL331,permalink)。 - 媒体桶由
LANGFUSE_S3_MEDIA_UPLOAD_BUCKET配置(packages/shared/src/env.tsL325,permalink)。 - Postgres
Media表按sha256Hash去重,记录bucketPath、contentType、contentLength、上传状态(packages/shared/prisma/schema.prismaL1488-L1507,permalink)。 TraceMedia把媒体关联到projectId、traceId、field;ObservationMedia再关联observationId(packages/shared/prisma/schema.prismaL1516-L1528,permalink、packages/shared/prisma/schema.prismaL1531-L1543,permalink)。- 媒体关联来源有
CLIENT_UPLOAD、INGESTION_MEDIA_EXTRACTION、INGESTION_FIELD_OVERFLOW等(packages/shared/prisma/schema.prismaL1509-L1514,permalink)。 - OTLP 处理器里有
processOtelMedia,把 span 里的媒体抽取后上传(worker/src/features/otel-ingestion/processOtelEvents.tsL19,permalink)。 - 客户可配置
BlobStorageIntegration,把数据按频率导出到自己的 S3/Azure/GCS 桶(packages/shared/prisma/schema.prismaL1335-L1365,permalink)。 - 导出文件格式、导出模式、数据源是可选项:
fileType、exportMode、exportSource、compressed(packages/shared/prisma/schema.prismaL1353,permalink)。 - Worker 目录
worker/src/features/blobstorage实现导出,并有BlobStorageIntegrationQueue与处理队列(worker/src/app.tsL630,permalink)。 - 批量导出(用户在表格里点导出)的文件落在 S3 批量导出桶,由
BatchExport队列处理(worker/src/app.tsL352,permalink)。
3.4 保留策略与删除
- 项目级保留天数是
Project.retentionDays(packages/shared/prisma/schema.prismaL139,permalink)。 - 保留任务由
DataRetentionQueue调度、DataRetentionProcessingQueue执行(packages/shared/src/server/queues.tsL433,permalink)。 - 处理任务先读项目当前
retentionDays,已关闭则不删(worker/src/ee/dataRetention/handleDataRetentionProcessingJob.tsL31,permalink)。 - 处理任务按截止日期删除 traces、observations、scores,并删媒体(
worker/src/ee/dataRetention/handleDataRetentionProcessingJob.tsL154,permalink)。 - 另有批量保留清理器,覆盖
traces、observations、scores、events_full、events_core五张表(worker/src/features/batch-data-retention-cleaner/index.tsL23-L30,permalink)。 deleteEventsOlderThanDays提供按天数删除 events 的仓储函数(packages/shared/src/server/repositories/events.tsL2568,permalink)。- 另有媒体保留清理器(
worker/src/features/media-retention-cleaner/index.tsL26,permalink)。 - Trace 删除先写 Postgres
PendingDeletion,延迟LANGFUSE_TRACE_DELETE_DELAY_MS后再删 ClickHouse(packages/shared/src/server/traceDeletionProcessor.tsL55,permalink、packages/shared/src/server/traceDeletionProcessor.tsL31,permalink)。 - 数据保留属于企业能力,处理代码放在
worker/src/ee/dataRetention(worker/src/ee/dataRetention/handleDataRetentionSchedule.tsL1,permalink);项目设置接口要求data-retention权益(web/src/features/projects/server/projectsRouter.tsL158,permalink)。