Opik 负载压测实战:用 tests_load 验证 Python SDK 的追踪摄取能力

发布时间:2026/9/14 15:49:59

Opik 负载压测实战:用 tests_load 验证 Python SDK 的追踪摄取能力 Opik 负载压测实战用 tests_load 验证 Python SDK 的追踪摄取能力【免费下载链接】comet-llmDebug, evaluate, and monitor your LLM applications, RAG systems, and agentic workflows with comprehensive tracing, automated evaluations, and production-ready dashboards.项目地址: https://gitcode.com/GitHub_Trending/co/comet-llm导读本文基于开源仓库 comet-llmOpik中的 tests_load/README.md 及其配套源码系统讲解如何对 Opik 的 Python SDK 与后端进行端到端负载压测。你将掌握 tests_load 目录的两级结构独立 CLI 脚本与 pytest 压测套件、10 个覆盖不同摄取形态的压测场景、统一的三阶段验证契约提交 → flush → 轮询校验以及如何通过--load-scale缩放压测规模、如何在本地 docker-compose 部署上手动复跑、如何在 CI 中按周自动执行并沉淀指标报告。读完即可在你的本地环境中复现全部压测流程。tests_load 目录的两层结构即席脚本与可调度套件tests_load目录将压测代码明确划分为两类职责不同、互不干扰tests/— 独立 CLI 脚本用于临时性、一次性的性能探测实验。它们不会被 pytest 收集适合快速手测某个具体问题。suite/target/— 由 pytest 驱动的压测套件既可在 CI 中按计划任务schedule运行也可手动触发。每个子目录针对一个被测系统当前只有python_sdk/未来的被测目标如 TypeScript SDK、仅后端等会以同级目录的形式加入例如suite/typescript_sdk/。这种“脚本探路、套件回归”的分层设计使得 ad-hoc 实验临时脚本与可重复的回归压测pytest 套件可以并存而不会互相污染。套件的完整实现位于 tests_load/suite/python_sdk/对应的 pytest 配置在 tests_load/pytest.ini。本地安装 Opik 并让 SDK 连接被测环境压测的首要前提是有一个可用的 Opik 后端。README 给出的标准做法是使用 docker-compose 部署本地实例对应 deployment/docker-compose/ 下的部署文件部署完成后Python SDK 的配置读取来源为环境变量或~/.opik.config对于本地 docker-compose 全栈安装需要把 SDK 指向前端代理地址export OPIK_URL_OVERRIDEhttp://localhost:5173/api/OPIK_URL_OVERRIDE是 SDK 读取的核心配置项之一它覆盖默认的 API 基地址。压测套件本身与运行环境无关——它只读取 shell 中已设置的OPIK_*环境变量配置工作由调用方负责。这意味着同一个套件可以无缝切换目标export OPIK_URL_OVERRIDEhttp://localhost:5173/api/ # 完整本地栈前端 后端 # export OPIK_URL_OVERRIDEhttp://localhost:8080 # 仅后端./opik.sh --backend # export OPIK_URL_OVERRIDEhttps://www.comet.com/opik/api/ OPIK_API_KEY... OPIK_WORKSPACE...Python SDK 压测套件四大摄取形态与十个场景suite/python_sdk/ 下的套件覆盖了四类摄取形态高条数、大负载、附件、突发/并发/时间分布外加数据集版本链。默认规模面向每周一次的定时压测而设计——而非 PR 检查——因此每个场景都能产生有意义的负载。可通过--load-scale缩小规模做本地冒烟测试。文件 / 场景默认规模test_ingestion_rate.py::test_many_traces_one_span_each10 万条 trace × 1 个嵌套 span约 100 B 负载test_ingestion_rate.py::test_many_spans_per_trace5 千条 trace × 50 个 span 25 万个 span约 100 B 负载test_heavy_payload.py::test_traces_with_one_megabyte_payload500 条 trace ×1 MB 入 1 MB 出≈ 1 GBtest_heavy_payload.py::test_spans_with_heavy_payload200 条 trace × 5 个 span ×500 KB 入 500 KB 出≈ 1 GBtest_attachments.py::test_traces_with_explicit_attachments500 条 trace × 2 个 × 50 KB 附件 ≈ 50 MB1 千次上传test_attachments.py::test_traces_with_implicit_attachments500 条 trace × 400 KB base64 数据块自动提取为附件test_bursts.py::test_burst_single_loop5 万条 trace紧循环、无思考间隔test_bursts.py::test_spread_over_time1 万条 trace均匀分布在 10 分钟内test_bursts.py::test_concurrent_writers_share_one_client30 线程 × 1 千条 trace 3 万条 trace共享一个 clienttest_dataset_items.py::test_dataset_insert_many_versions50 次顺序Dataset.insert()× 50 个 item × 约 4 KB 负载 2.5 千个 item、50 个版本高条数场景test_ingestion_rate.py该文件包含两个互为正交的吞吐场景源码位于 test_ingestion_rate.pytest_many_traces_one_span_each通过opik.track装饰器模拟“用户请求处理器handle_request调用一次下游服务downstream_call”的典型形态——每次调用产生一条带嵌套 span 的 trace。10 万条 trace × 1 span ≈ 20 万条观察数据。负载刻意保持 100 B 的小体积以便把压力集中在消息条数而非单条消息体积上。test_many_spans_per_trace改用opik.start_as_current_trace与opik.start_as_current_span上下文管理器模拟用户对 trace/span 生命周期有显式控制的场景。5 千条 trace × 50 span 25 万 span重点考验 span 批量发送与 trace/span 顺序保证。测试除了校验全部 trace id 落地还会抽查最后一条 trace 的 50 个 span是否全部可见且字段完整。大负载场景test_heavy_payload.py见 test_heavy_payload.py验证 MB 级 payload 下的链路吞吐test_traces_with_one_megabyte_payload每条 trace 的 input 与 output 各约 1 MB装饰器自动捕获函数入参与返回值等价于包装一个“长 prompt 进、长 completion 出”的 LLM 调用共约 1 GB 负载。test_spans_with_heavy_payload外层 trace 保持轻量约 1 KB内部 5 个 span 各携带约 500 KB 的 input/output总计约 1 GB。专门考验父 trace 轻、子 span 重时 span 批量发送的表现。附件场景test_attachments.pytest_attachments.py 覆盖两条附件上传路径显式附件在opik.track装饰的 handler 内通过opik.update_current_trace(attachments[...])为每条 trace 挂载 2 个 50 KB 的二进制附件压测 multipart 上传路径以及flush_tracker()对在途上传的协调契约。隐式附件handler 接收一个data:image/png;base64,~400 KB的 image 参数。由于嵌入的 base64 数据超过 SDK 的min_base64_embedded_attachment_size默认 250 KBSDK 的附件提取管线会自动识别并上传为附件无需用户显式操作——这正是多模态 LLM I/O 日志场景中最常见的路径。实现细节上_helpers.random_base64_png生成的是能被 SDK 提取管线识别的“伪 PNG”一是提取正则限定[A-Za-z0-9/]必须用标准 alphabet 的b64encode而非 url-safe 的-_变体二是解码端会做 MIME 嗅探跳过application/octet-stream与text/plain因此字节流必须以 PNG 魔数\x89PNG\r\n\x1a\n开头。魔数之后的字节全是随机噪声——测试并不渲染图片只验证提取/上传链路见 _helpers.py。突发与并发场景test_bursts.pytest_bursts.py 包含三种时间形态test_burst_single_loop单线程紧循环调用 5 万次opik.trackhandler仅保留套件共用的最小随机思考间隔0.5–2 ms由_helpers.think_time()提供。这个间隔足以避免并行运行多个重场景时压垮 docker-compose 栈又足够紧凑以持续占满 SDK 的进程内队列与批量 flusher。test_spread_over_time1 万条 trace 均匀铺在 600 秒窗口内约 17 trace/s 持续速率模拟中速生产负载并专门触发按时间间隔而非按批量大小触发的周期性 flush 路径。test_concurrent_writers_share_one_client30 个线程通过ThreadPoolExecutor同时调用同一个全局 Opik clientopik.track默认使用的那个每条调用经线程本地上下文获得独立 trace——完全等同于真实多线程服务器的用法。这是最可能暴露 batcher 竞态race的配置。数据集版本链场景test_dataset_items.pytest_dataset_items.py 是套件中最具“回归守门人”色彩的场景。每次Dataset.insert()调用都会在后端创建新版本后端通过 ClickHouse 的INSERT … SELECTCOPY_VERSION_ITEMS把上一版本的 item 快照进新版本。在多副本 ClickHouse 部署上该 SELECT 可能非确定性地返回短读截断新版本的行集随后每个后续版本都会基于被截断的基线级联放大损失。该测试通过 50 次顺序Dataset.insert()每次 50 个 item、约 4 KB/个并断言dataset.get_items()能完整回读全部 2.5 千个 item 来捕捉这类“元数据与存储不一致”问题items_total报 N 但流式返回更少。需要强调的是这类数据丢失是纯服务端问题单线程顺序 REST 调用即可触发但在单副本 localhost 上无法复现——因此该测试在多副本生产/预发环境跑通的价值在于提供绿色基线一旦出现短读即失败报警。每个测试的统一执行契约log → flush → verify → 指标落盘README 明确规定每个测试都遵循四个步骤记录请求的 trace/span涉及附件时一并上传调用opik.flush_tracker()轮询search_traces/search_spans/attachments.attachment_list直到预期数量的条目可见——只有每条数据都落库测试才算通过把各阶段耗时logging、flush、verify、total写入tests_load/.last_run/test_name.json。这套契约在 _helpers.py 中有完整的实现支撑Metrics一个极简的 key/value 记录器提供timer(label)上下文管理器记录各阶段耗时由metricsfixture 在 teardown 时写入REPORT_DIR即tests_load/.last_run/。写入的 JSON 同时会以日志形式输出便于 CI 汇总。verify_exact_trace_ids等待所有expected_ids落库并返回实际送达的 id 集合若超时仍有缺失则抛出带缺失样本的AssertionError——这能捕捉消息丢失如回归案例 OPIK-6444而不只是数量不足。verify_traces轮询search_traces默认 900 秒超时。在响应中通过exclude[input, output, metadata]排除大字段一是大幅减少高条数场景的回传数据量二是绕开 OPIK-6651附件提取的 trace 在流式返回时因 enrichment 路径读取不到workspaceName而失败的缺陷。name/end_time字段校验仍然执行。verify_spans_for_trace对指定 trace 轮询search_spans直至预期 span 数可见并断言name、end_time、input、output四个必需字段全部非空。verify_attachments轮询附件 REST 端点attachment_list直到数量达标。path查询参数是经 base64 编码的 base URL后端据此构建下载链接必须用标准b64encodealphabet 以匹配attachment/client.py与tests/e2e/verifiers.py的既有契约。安装与运行从冒烟测试到全量压测环境准备# 安装 Opik SDK本仓库源码安装或 pip install opik 使用已发布版本 pip install -e sdks/python # 安装套件专属依赖 pip install -r tests_load/suite/python_sdk/requirements.txt # 把 SDK 指向任意 Opik 实例 export OPIK_URL_OVERRIDEhttp://localhost:5173/api/ # 完整本地栈 # export OPIK_URL_OVERRIDEhttp://localhost:8080 # 仅后端./opik.sh --backend # export OPIK_URL_OVERRIDEhttps://www.comet.com/opik/api/ OPIK_API_KEY... OPIK_WORKSPACE...套件专属依赖由 tests_load/suite/python_sdk/requirements.txt 声明仅包含pytest、pytest-timeout、pytest-xdist——Opik SDK 本身单独安装避免混入版本耦合。串行 / 并行运行cd tests_load pytest suite/python_sdk # 串行 pytest suite/python_sdk -n auto --distworksteal # 经 pytest-xdist 并行关于并行度的取舍README 记录了明确的工程决策定时工作流固定使用-n 2 --distworksteal。因为-n auto在 ubuntu-latest 上是 4 个 worker在高负载摄取场景与其他重测试同时压同一个 docker-compose Opik 栈时会在 7 GB runner 上可靠地触发 OOM 杀掉进程。每个场景使用唯一 project 名_helpers.unique_project_name生成loadtest-scenario-时间戳-随机串因此 worker 隔离成立共享后端在并行下会看到有意义的并发负载这本身就是有价值的覆盖。pytest 配置的防呆设计tests_load/pytest.ini 中有几个值得关注的全局守卫testpaths suitepytest 默认只收集套件目录独立脚本tests/不会被误收。timeout 1200、timeout_method thread全局挂起守卫——任何单个场景运行超过 1200 秒即被杀并判失败避免死锁如 SDK 锁回归无声消耗整个工作流预算。最长合法场景是test_spread_over_timescale 1.0 时约 10 分钟1200 秒约留出 2 倍余量需要更紧上限的场景可用pytest.mark.timeout(...)覆盖。log_cli_level WARNING不输出 INFO 级别日志避免约 25 万 次 httpx 请求的INFO HTTP Request行在-n 2与 SDK 连接监控守护进程叠加时曾产生约 7 万行 traceback。每个测试的指标仍会写入.last_run/下的 JSON工作流 summary 步骤负责在运行页渲染它们。conftest.py中的_reset_opik_context_after_test自动 fixture 在测试结束后调用context_storage.clear_all()start_as_current_trace/start_as_current_span上下文管理器在进入时会获得context_storage的 project 名所有权但不释放若下一个测试用新的 project 跑opik.tracktrace 会静默落入泄漏的旧 project——该 fixture 正是为了中和这一跨测试污染见 conftest.py。用 --load-scale 缩放压测规模每个场景都接受一个规模乘数用于快速冒烟或加码长跑# 快速冒烟默认规模的约 10% pytest suite/python_sdk --load-scale 0.1 # 重负载5 倍默认规模 OPIK_LOAD_SCALE5 pytest suite/python_sdk该参数由 conftest.py 通过pytest_addoption注册默认值取环境变量OPIK_LOAD_SCALE缺省为 1.0随后以load_scalefixture 注入各测试。缩放是按场景类型各异的条数类场景直接对 trace/span 计数取整乘如 10 万 × 0.1 1 万test_spread_over_time则同时缩放时间窗口window_seconds max(1, int(600 * load_scale))保证均匀速率不随规模改变。CI 定时压测工作流每周自动跑 手动触发套件由 GitHub Actions 工作流 .github/workflows/load_tests.yml 驱动触发方式每周日 04:00 UTC 定时运行cron: 0 4 * * 0也可通过workflow_dispatch手动触发运行环境使用更大的 GitHub 托管 runnerubuntu-latest-m约 4 vCPU / 16 GB而非默认的 ubuntu-latest2 vCPU / 7 GB——最重的摄取场景在 7 GB 上偶发 OOM 杀掉 xdist worker额外内存余量正是为此执行流程checkout → Python 3.12 uv →./opik.sh --backend --port-mapping --build拉起全新 docker 化的 Opik 后端 → 安装 SDKuv pip install --system .与套件依赖 →pytest suite/python_sdk -n 2 --distworksteal --junitxml...结果沉淀一个内嵌 Python 脚本把.last_run/*.json渲染成包含 Test / Volume / Submit / Submit rate / Flush / Verify / Total / Delivered 各列的 Markdown 表格写入 job summary并附原始 JSON 供深挖.last_run/同时作为构建产物上传JUnit 报告经publish-unit-test-result-action发布为 “Load Test Results” 检查需checks: write权限失败排查失败时导出opik-backend-1容器日志为 artifact无论成败最终都会./opik.sh --stop清理环境。工作流内还预设了OPIK_ENABLE_LITELLM_MODELS_MONITORING、OPIK_SENTRY_ENABLE、OPIK_ANALYTICS_ENABLE为 False压测时关闭非必需的后台功能。独立 CLI 脚本即席性能探测tests/下的脚本保留用于 ad-hoc 实验不会被 pytest 收集依赖固定于 tests_load/requirements.txtopik、click、anthropic、datasets、pillow。现有五个脚本test_trace_span_ingestion.py — 记录 N 条 trace 并测量端到端延迟。它以 click 命令形式运行--num-traces控制规模默认 1000内部构造opik.track嵌套调用输出三段耗时日志写入耗时、trace 在 UI 可见的等待耗时、总耗时。这是最快了解“写多快、查多快”的入口。test_trace_span_retrieval.py — 在指定 project 内按日期范围检索 trace/span用于探测检索路径的吞吐。test_thread_ingestion.py — 记录带多条 trace 与 span 的 thread线程/会话数据。test_image_inference.py — 面向在线评测online-evaluation的图像生成推理探测。test_images_dataset_sample.py — 加载图像样本数据集供 playground / experiment 测试使用。此外 tests_load/tests/traces-local-v2-cutover/ 下还包含一套面向“本地 trace v2 切换”演练的独立脚本含seed_history.py、live_traffic.py、delete_traffic.py及各自的 README用于在迁移窗口前后灌入历史数据、打实时流量并清理属于专门的迁移验证工具。边界与注意事项环境无关性套件读取 shell 中设置的OPIK_*变量配置由调用方负责切换目标本地栈 / 仅后端 / Comet 云端只需改环境变量无需改动测试代码。单副本局限test_dataset_insert_many_versions针对的是多副本 ClickHouse 的COPY_VERSION_ITEMS短读截断在单副本 localhost 上不会复现——在那里它退化为“顺序版本链 完整回读”的常规回归覆盖。已知缺陷绕行verify_traces的字段排除列表是针对 OPIK-6651 的临时绕行verify_exact_trace_ids的存在则源于对 OPIK-6444 一类丢消息回归的守门需求。阅读源码时留意这些注释能帮助你理解每个断言为什么长成现在这样。延伸阅读套件入口与公共配置suite/python_sdk/、pytest.ini公共校验与数据生成工具suite/python_sdk/_helpers.py定时压测工作流.github/workflows/load_tests.yml本地部署入口opik.sh 与 deployment/docker-compose/被测 SDK 源码sdks/python【免费下载链接】comet-llmDebug, evaluate, and monitor your LLM applications, RAG systems, and agentic workflows with comprehensive tracing, automated evaluations, and production-ready dashboards.项目地址: https://gitcode.com/GitHub_Trending/co/comet-llm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/14 15:49:59

MiGPT 实操指南:把小爱音箱变成接上大模型的语音助手

MiGPT 实操指南:把小爱音箱变成接上大模型的语音助手 【免费下载链接】mi-gpt 🏠 将小爱音箱接入 ChatGPT 和豆包,改造成你的专属语音助手。 项目地址: https://gitcode.com/GitHub_Trending/mi/mi-gpt 如果你家里有一台小爱音箱&…

2026/9/14 15:49:59

基于Python的养老社区查询预约系统设计与实现全解析

最近好多准备做毕业设计的同学都在问同一个问题:“有没有一个既不算太难、又能把完整业务串起来的Python项目?”说实话,我特别理解这种焦虑——选题要是太偏算法,论文写得像天书;太简单吧,又怕撑不起一篇像…

2026/9/14 15:49:59

NodeXX:面向跨境金融的合规连接运行时

1. 项目概述:为什么是 NodeXX?连接全球价值“为什么是 NodeXX?连接全球价值”——这个标题乍看像一句口号,实则藏着三层硬核信息:第一层是技术选型的终极追问,“为什么是NodeXX而不是其他”;第二…

2026/9/14 16:35:07

电磁继电器多物理场动态仿真实战:从磁场建模到耦合求解

电磁继电器仿真,放在电磁场耦合仿真这个大类里,属于典型的"看着结构简单,一上手就踩坑"的项目。很多人一开始以为继电器嘛,就一个线圈加一个衔铁,磁路清楚、运动形式也不复杂,算个吸力、看个动作…

2026/9/14 16:35:07

医美行业数字化转型:智能客户画像与全渠道营销实践

1. 医美行业现状与核心痛点解析 医美行业经过十年高速发展,正面临转型阵痛期。根据我走访全国23家医美机构的实地调研数据,2023年行业平均获客成本已突破8000元/人,较2019年增长近300%。这种"高成本、低转化"的困境主要源于三大结构…

2026/9/14 16:35:07

基于微信小程序与协同过滤的外卖点餐个性化推荐系统毕设全解析

又到毕业设计季了,后台私信里咨询小程序类毕设的人明显多了起来。其中“基于微信小程序的个性化推荐外卖点餐系统”这个题目,我前前后后带过不少学生做完,自己也完整复现过两遍。说实话,这个题目选得挺聪明:技术栈主流…

2026/9/14 16:35:07

Netcat 实战速查指南:Linux/Unix 网络瑞士军刀核心用法

Netcat 实战速查指南:Linux/Unix 网络瑞士军刀核心用法 【免费下载链接】reference 面向开发者的技术速查清单(Cheat Sheets)集合,整理常见技术、工具与开发流程,帮助快速查阅关键信息,提高开发效率。 项…

2026/9/14 16:35:07

DeepSeek v4.1 Flash API Schema校验失败深度解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/14 16:30:06

Qdrant向量搜索引擎:原理、优化与应用实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/14 2:17:50

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/14 0:03:22

KCF目标跟踪算法与OTB工程实现:毕业设计实战解析

简介:这是一份基于KCF核相关滤波算法、融合尺度池与抗遮挡处理的目标检测跟踪MATLAB完整源码,主要面向计算机相关专业准备毕业设计、课程设计或期末大作业的学生,也适合需要项目实战练习的初学者。源码在OTB数据集上完成验证,能够…

2026/9/14 0:03:22

语音情感识别实战:Keras实现LSTM、CNN、SVM与MLP多模型对比

简介:面向语音情感识别入门与进阶开发者,这份基于Keras的项目源码完整实现了LSTM、CNN、SVM、MLP四种模型,兼容Python3.8与Keras/TensorFlow2环境。压缩包内含49个文件,大小约70.31MB,主体包括Python脚本、yaml/json配…

2026/9/14 11:59:31

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/14 13:53:59

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/14 11:22:57

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码