Langfuse Seeder 测试数据生成系统完全指南:架构、三类数据形态与扩展实践
【免费下载链接】langfuse🪢 Open source AI engineering platform: LLM evals, observability, metrics, prompt management, playground, datasets. Integrates with OpenTelemetry, LangChain, OpenAI SDK, LiteLLM, and more. 🍊YC W23项目地址: https://gitcode.com/GitHub_Trending/la/langfuse
Langfuse Seeder System 是 Langfuse 仓库内置的一套测试数据生成系统,用于在 ClickHouse 与 PostgreSQL 中批量生成接近真实的 trace、observation、score 与数据集实验数据,服务于本地开发、调试、性能压测与演示场景。本文将以该系统的设计文档为核心,结合源码逐层拆解其架构、三种数据形态、双层生成模式(bulk / synthetic)、配置项与扩展方法论,帮助读者快速上手、按需定制属于自己的种子数据。
系统定位与整体架构
Seeder 系统解决的核心问题是:开发 Langfuse 前端、评估器、数据集实验等功能时,需要一个"看起来像生产环境"的数据集。手工造数据既慢又不真实,而真实业务数据又无法直接进入开发库。Seeder 通过一组相互协作的 TypeScript 模块,把"生成什么样的数据"与"如何高效写入 ClickHouse"彻底分离。
其核心文件全部位于 packages/shared/scripts/seeder/utils/ 目录下,文档中的架构树与实际文件一一对应:
seeder/utils/ ├── types.ts # 核心接口与类型(SeederMode、SeederOptions、FileContent) ├──>import { SeederOrchestrator } from "./seeder-orchestrator"; const orchestrator = new SeederOrchestrator(); // 完整播种(数据集实验 + 评估数据 + 合成数据 + 支持会话 / 框架 trace / 媒体 trace) await orchestrator.executeFullSeed(projectIds, { mode: "bulk", // 生成策略,见下文"两种生成模式" numberOfDays: 30, // 时间戳向前回退的天数 numberOfRuns: 3, // 每个数据集执行的实验轮数 }); // 单独生成某一类数据 await orchestrator.createDatasetExperimentData(projectIds, { mode: "bulk", numberOfDays: 30 }); await orchestrator.createEvaluationData(projectIds); await orchestrator.createSyntheticData(projectIds, { mode: "bulk", numberOfDays: 30 });其中projectIds是目标项目的 ID 数组。注意executeFullSeed(seeder-orchestrator.ts)并非只做文档中提到的三类数据,还会顺带生成三类补充数据,完整流程为:
createDatasetExperimentData()—— 数据集实验数据;createEvaluationData()—— 评估数据;createSyntheticData()—— 大规模合成数据;createSupportChatSessionTraces()—— 一条贴近真实的客服聊天会话 trace;createFrameworkTraces()—— 从真实框架导出 JSON 加载的框架 trace(LangGraph、OpenAI Agents、Pydantic AI 等);createMediaTestTraces()—— 用于测试 trace 详情页媒体渲染(图片 / PDF / 音频)的专用 trace。
每步执行完毕后,logStatistics()会对traces、scores、observations三张表按project_id做计数统计并以 ASCII 条形图输出(seeder-orchestrator.ts),方便快速核对写入量。
三种数据形态详解
1. 数据集实验数据(Dataset Experiment Data)
- 用途:基于真实数据集生成实验 trace,用于 A/B 测试与 prompt 对比、基于数据集的评估、prompt 测试;
- 环境(environment):
langfuse-prompt-experiment; - 结构:每个数据集条目(dataset item)对应一条 trace,trace 下挂载一个
GENERATION类型 observation,并附带 trace 级与 run 级两类 score; - ID 模式:
trace-dataset-{datasetName}-{itemIndex}-{projectId后8位}-{runNumber}(见 seed-helpers.ts)。
实现层面(data-generators.ts)会对特定数据集做输入输出模板化:例如demo-countries-dataset的条目会被翻译成"What is the capital of France?"/"The capital of France is Paris."这样的自然语言对。每个 observation 的 token 用量(输入 30–150、输出 10–80)与成本(约 $0.0001–0.01 区间)均为随机变化,成本经过 5 位小数舍入以保证精度(data-generators.ts)。数据集实验的分值与名称通过常量DATASET_SCORE_NAMES = ["score-1","score-2","score-3"]与DATASET_RUN_SCORE_NAMES控制,其中 run 级 score 会关联dataset_run_id形如demo-dataset-run-{runNumber}-{datasetName}-{projectId后8位}。
2. 评估数据(Evaluation Data)
- 用途:面向评估器(evaluator)配置的测试数据,用于评估器开发、分值校验与评估流程测试;
- 环境:
langfuse-evaluation; - 结构:每个评估器配置生成
EVAL_TRACE_COUNT = 100条 trace,每条 trace 挂载 10 个 observations(约 47%GENERATION、47%SPAN、其余EVENT),并恰好为每条 trace 生成一条 score; - ID 模式:
trace-eval-{evalTemplateId}-{projectId后8位}-{index}(注意实现中实际包含评估模板 ID,而非文档简写形式)。
评估 trace 的数据源头是 postgres-seed-constants.ts 中的SEED_EVALUATOR_CONFIGS:仓库内置了一个名为toxicity-job的 ACTIVE 评估任务(LLM_AS_JUDGE类型,使用gpt-5.4-mini,带temperature: 0.7等模型参数与变量映射),以及一个typescript-code-eval-template的代码评估器模板。createEvaluationData()(seeder-orchestrator.ts)会遍历所有SEED_EVALUATOR_CONFIGS生成对应数据,因此新增评估器配置即可自动扩充评估数据形态。
3. 合成数据(Synthetic Data)
- 用途:大规模真实感 trace 数据,用于压测、仪表盘演示与真实用量模拟;
- 环境:
default; - 结构:分层 trace,内含多种 observation 类型与 score;
- ID 模式:
trace-synthetic-{index}-{projectId后8位}。
合成数据同时覆盖新旧两代观测类型:约 80% 为传统类型(GENERATION/SPAN/EVENT),其余 20% 从AGENT、TOOL、CHAIN、RETRIEVER、EVALUATOR、EMBEDDING、GUARDRAIL中随机抽取,每种类型都有独立的名称池(见 clickhouse-seed-constants.ts,例如REALISTIC_TRACE_NAMES、REALISTIC_MODELS、REALISTIC_TOOL_NAMES)。观测之间通过parent_observation_id串联成链,形成父子层级。约 10% 的 trace 会走generateComprehensiveAIWorkflowTrace()(data-generators.ts),生成一条包含 AGENT → RETRIEVER → EMBEDDING → CHAIN → TOOL → GENERATION → EVALUATOR → GUARDRAIL 全链路的"AI Agent 综合工作流" trace,其中 GENERATION 观测还携带tool_definitions与tool_calls字段。Score 支持NUMERIC/CATEGORICAL/BOOLEAN三种类型,并有约 10% 概率挂到 observation 上(data-generators.ts)。
抽象架构:三层职责分离
系统通过三个核心类实现"生成逻辑、写入逻辑、编排逻辑"的完全解耦,文档明确给出了各层的修改边界:
DataGenerator(数据生成器)
负责生成上述三类数据的真实内容,是修改 ClickHouse 数据形态时的首选入口。它是一个私有构造函数的单例(getInstance()),并通过setFileContent()接收编排器注入的真实载荷。关键方法:
generateDatasetTrace()—— 根据数据集条目创建实验 trace;generateSyntheticTraces()—— 创建真实感合成 trace;generateEvaluationTraces()—— 创建评估导向 trace。
此外还包含generateSyntheticObservations()、generateSyntheticScores()、generateEvaluationObservations()、generateEvaluationScores()、generateDatasetObservation()、generateDatasetScore()、generateDatasetRunScore()等方法,以及一组私有随机工具(randomElement、randomBoolean、randomInt)和元数据构造器buildNestedSeedMetadata()(生成含customer.id、customer.plan、routing.queue、flags.beta等键的嵌套元数据,模拟真实业务标签体系)。
ClickHouseQueryBuilder(查询构建器)
构建并执行 ClickHouse 插入查询,文档强调"无需也不建议修改此文件"。它内部实现了完整的字符串转义(escapeString,先处理反斜杠再转义单引号,避免 JSON 夹具中的\"破坏 SQL)与嵌套元数据 Map 的 SQL 生成(buildNestedMetadataMapSql)。其 API 分两层:
executeXxxInsert()系列:面向小规模、需要精确控制的定制数据,直接复用packages/shared/src/server导出的createTracesCh/createObservationsCh/createScoresCh/createDatasetRunItemsCh;buildBulkXxxInsert()系列:面向超过 1000 条的大批量数据,生成基于 ClickHousenumbers()表函数与xxHash32哈希列的纯 SQLINSERT ... SELECT(clickhouse-builder.ts)。
SeederOrchestrator(编排器)
对外暴露createDatasetExperimentData/createEvaluationData/createSyntheticData/executeFullSeed四个主方法,职责包括:加载真实输入输出文件内容、协调生成与插入、错误恢复(任一插入失败即记录并抛出)、提供日志与统计。执行批量 SQL 时通过clickhouseClient().command()并设置wait_end_of_query: 1保证查询同步完成(seeder-orchestrator.ts)。
两种生成模式:bulk 与 synthetic
这是文档 Quick Start 之外必须补充的关键设计。在 types.ts 中,SeederMode定义了两种策略:
export type SeederMode = "bulk" | "synthetic"; // bulk: SQL 级生成,速度快、体量大(10 万条观测,默认) // synthetic: 内存级生成,速度较慢、结构更真实(1 千条观测) export const getTotalObservationsForMode = (mode: SeederMode): number => { return mode === "bulk" ? 100000 : 1000; }; export interface SeederOptions { mode: SeederMode; numberOfDays: number; numberOfRuns?: number; }createSyntheticData()的分支逻辑(seeder-orchestrator.ts)体现了两种模式的具体差异:
| 维度 | bulk(默认) | synthetic |
|---|---|---|
| 实现方式 | 纯 SQLnumbers()+ 哈希列 | 内存中逐条构造记录对象 |
| 观测总量 | 100,000(每项目) | 1,000(每项目) |
| 每 trace 观测数 | 15 | 15 |
| 每 trace 分数 | 10 | 10 |
| 插入路径 | executeQuery(bulkQuery) | executeTracesInsert / executeObservationsInsert / executeScoresInsert |
| 适用场景 | 压测、列表页性能、大屏演示 | 结构精细、便于人工核查的小数据集 |
bulk 模式的 SQL 蕴含大量"确定性技巧":时间戳以 UTC 午夜为锚点(anchorSeconds在 TS 侧计算,不依赖 ClickHouse 服务器时区),通过toDateTime(anchor - intDiv(number * spreadSeconds, count))让时间随行号均匀回退;行间差异全部来自对行号加盐后的xxHash32(toUInt64(...))哈希列h1–h4,从而保证同一天重复运行得到完全一致的数据,配合 ReplacingMergeTree 的去重键可做到原地覆盖而非产生重复行(这一点在 seeder 根目录 README.md 中被总结为"ClickHouse determinism rules")。此外 bulk 观测还通过h4 % 5将生成模型均匀分布到 5 个真实模型(gpt-5.4-mini、claude-haiku-4-5等),并支持传入真实 Postgres prompt 行,让约 10% 的 generation 正确挂载 prompt 徽章(伪造 ID 会破坏 PromptBadge 渲染,因此未传入时 prompt 字段保持 NULL)。
配置选项详解
文档给出的配置接口(SeederConfig)在现行源码中已演进为SeederOptions,核心字段如下:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
mode | "bulk" \| "synthetic" | 是 | 生成策略,直接决定观测总量(100,000 或 1,000) |
numberOfDays | number | 是 | 时间戳向前回退的天数,决定数据的时间跨度 |
numberOfRuns | number | 否 | 每个数据集执行的实验轮数,默认 1;多轮用于模拟多次实验对比 |
时间戳的生成逻辑为:以当前 UTC 日零点为锚,向前按numberOfDays * 86400秒均匀铺开。数据集实验数据中,run 内每个条目还会叠加 1–10 秒的随机偏移,制造真实的时间波动(data-generators.ts)。
扩展系统:六条修改路线
文档用一组 Checklist 给出了系统的扩展方法论,这里结合源码补充每条路线的具体落点:
新增数据类型(Adding New Data Types)
- 在 types.ts 添加接口(如
DatasetItemInput、FileContent的模式); - 在
DataGenerator添加生成方法(参照generateSyntheticTraces的模式,创建记录时统一使用createTrace/createObservation/createTraceScore/createDatasetRunItem工厂函数); - 在
ClickHouseQueryBuilder添加查询构建方法(小数据用executeXxxInsert,大数据用buildBulkXxxInsert); - 在
SeederOrchestrator添加编排方法,并视需要接入executeFullSeed流程; - 更新本文件(依赖关系文档)。
新增文件来源(Adding New File Sources)
- 在
SeederOrchestrator.loadFileContent()中追加文件路径(seeder-orchestrator.ts 已有对三个载荷文件"读取 → 截断 → 注入"的完整模板,注意大文件会被截断以控制测试数据体积); - 在
DataGenerator添加处理逻辑; - 需要时扩展
FileContent接口。
修改数据分布(Changing Data Distribution)
- 修改
DataGenerator中的生成方法(例如调整randomBoolean(0.3)的 user/session 关联概率、randomInt(20, 200)的 token 区间); - 更新 clickhouse-seed-constants.ts 中的名称/模型池常量;
- 先用小数据集验证(将
mode设为"synthetic"或减少观测数)。
修改 ID 生成(Changing ID Generation)
文档强调 ID 是跨库关联的"合同",修改前必须逐项核对:
- 检查所有按 ID 查询 ClickHouse 的位置;
- 检查PostgreSQL 外键引用(如
dataset_run_item_id、dataset_id); - 检查数据集 run item 与评估 trace 的创建逻辑;
- 执行:在 seed-helpers.ts 中一致性地更新
generateDatasetRunItemId、generateDatasetItemId、generateDatasetRunTraceId、generateEvalTraceId、generateEvalObservationId、generateEvalScoreId等函数。
值得注意的是,现有 ID 全部基于"名称 + 序号 + 项目 ID 后 8 位 + run 号"构造,不含日期——这是刻意设计,配合 UTC 日锚点时间戳,使同日重复运行可以原地覆盖数据。
修改环境名(Changing Environment Names)
- 检查所有按 environment 过滤的 ClickHouse 查询;
- 检查PostgreSQL 中 dataset 与 prompt 的 environment 字段;
- 检查前端环境过滤逻辑;
- 执行:同步更新两套系统中的常量。当前三个环境名分别为
langfuse-prompt-experiment(数据集实验)、langfuse-evaluation(评估)与default(合成数据)。
修改数据结构(Changing Data Structure)
- 检查ClickHouse 表结构兼容性(注意 clickhouse-builder.ts 中的注释:bulk INSERT 依赖位置列序,迁移新增列时必须保持 SELECT 列表与表结构同步);
- 检查PostgreSQL 表关系;
- 检查API 响应序列化;
- 执行:先改两边 schema 再改生成逻辑。
同时还要评估:新类型是否需要对应的 PostgreSQL 表、是否引入新的外键关系、UI 是否需要处理新数据类型——必要时规划数据库迁移。
文件依赖与数据常量
必备载荷文件
| 文件 | 用途 | 截断规则 |
|---|---|---|
| nested_json.json | 大体积嵌套 JSON,模拟结构化工具输出 | products数组截取前 3 项 |
| markdown.txt | Markdown 内容,模拟文档分析类输入 | 不截断 |
| chat_ml_json.json | ChatML 格式示例,模拟多轮对话 | messages数组截取前 4 条 |
这三个文件在loadFileContent()中加载并截断(seeder-orchestrator.ts);加载失败时降级为内置占位内容并输出 warning。合成数据中约 30% 的输入会使用重型 Markdown、其余使用 ChatML JSON,输出则约 30% 使用嵌套 JSON。
常量文件
- postgres-seed-constants.ts:数据集(
SEED_DATASETS,含国家首都、IPA 音标、数学运算等 7 个数据集)、文本与 ChatML prompt(SEED_TEXT_PROMPTS、SEED_CHAT_ML_PROMPTS)、prompt 版本(SEED_PROMPT_VERSIONS)、评估器模板与任务配置(SEED_EVALUATOR_TEMPLATES、SEED_EVALUATOR_CONFIGS)、EVAL_TRACE_COUNT = 100、默认 API Key 等; - clickhouse-seed-constants.ts:ClickHouse 侧的名称池与模型池(
REALISTIC_TRACE_NAMES、REALISTIC_MODELS、REALISTIC_AGENT_NAMES、REALISTIC_TOOL_NAMES、REALISTIC_CHAIN_NAMES、REALISTIC_RETRIEVER_NAMES、REALISTIC_EVALUATOR_NAMES、REALISTIC_EMBEDDING_NAMES、REALISTIC_GUARDRAIL_NAMES等)。
进阶:新一代场景式 CLI
如果目标是快速在本地堆出"能暴露前端问题的数据",可以直接使用新一代场景式 CLI(见 packages/shared/scripts/seeder/README.md):
pnpm run seed -- doctor # 诊断本地栈并给出修复命令 pnpm run seed -- list # 列出所有场景与参数(--json 供机器读取) pnpm run seed -- trace-tree --observations 5000 --breadth 1000 --v4 pnpm run seed -- many-traces --count 100000 --days 14 pnpm run seed -- long-session --traces 300 --observations-per-trace 8该 CLI 提供trace-tree(巨型分叉观测树)、agent-timeline(LangGraph 风格迭代 agent)、deep-chain(深链观测)、many-traces(bulk SQL 大规模列表)、outlier-traffic(带异常峰值的流量模拟)、support-agent(手写客服 Copilot 完整 trace)等十余种场景,公共参数包括--project、--environment、--seed(确定性种子)、--id-prefix、--dry-run与--json,运行末尾会输出可验证的 JSON 摘要与 UI 深链。其确定性与完整性保证(时间锚定、xxHash32加盐、uniqExact读回校验等)与本文介绍的utils/批量构建器一脉相承,二者共享clickhouse-builder.ts中的 bulk 构建逻辑。
结语
Langfuse Seeder 系统的设计精髓在于"生成与写入分离、定制与批量并存、确定性与真实感兼顾":DataGenerator负责内容的真实感,ClickHouseQueryBuilder负责写入的性能与正确性,SeederOrchestrator负责编排与容错;bulk模式用哈希驱动的 SQL 换取量级,synthetic模式用内存构造换取精细结构。无论你是要为本地产物填充演示数据、为评估器准备测试集,还是为压测构造十万级观测,都可以依据文档中的六条扩展路线,在明确的修改边界内快速定制属于你自己的种子数据。
【免费下载链接】langfuse🪢 Open source AI engineering platform: LLM evals, observability, metrics, prompt management, playground, datasets. Integrates with OpenTelemetry, LangChain, OpenAI SDK, LiteLLM, and more. 🍊YC W23项目地址: https://gitcode.com/GitHub_Trending/la/langfuse
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考