Opik Python SDK 实战:用 opik_context.update_current_trace 在被追踪函数内动态更新当前 Trace

发布时间:2026/9/13 18:13:47
Opik Python SDK 实战:用 opik_context.update_current_trace 在被追踪函数内动态更新当前 Trace Opik Python SDK 实战用 opik_context.update_current_trace 在被追踪函数内动态更新当前 Trace【免费下载链接】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在 Opikcomet-llm的 Python SDK 中opik_context.update_current_trace是track追踪体系的核心上下文 API 之一。它允许你在被track装饰的函数执行过程中动态修改当前 trace 的name、input、output、metadata、tags、feedback_scores、thread_id、attachments和prompts。阅读本文后你将掌握该函数的完整参数语义、底层基于contextvars的上下文存储机制、静默降级与异常边界以及如何在多轮对话线程thread场景下用它把多条 trace 归组到同一会话。函数定位opik_context 模块的上下文 APIupdate_current_trace属于opik.opik_context模块实现于 sdks/python/src/opik/opik_context.py该模块为在已被追踪的函数内部访问和修改当前 span / trace 提供了一组 APIget_current_span_data()读取当前 span 数据副本get_current_trace_data()读取当前 trace 数据副本update_current_span()更新当前 spanupdate_current_trace()更新当前 trace本文主角get_distributed_trace_headers()生成跨节点分布式追踪请求头trace_context()内部使用的 trace 生命周期上下文管理器。官方文档入口位于 update_current_trace.rst其内容通过 Sphinx 的autofunction指令直接抽取源码 docstring 生成模块级说明与示例见 opik_context/index.rst。官方文档给出的最简用法如下from opik import opik_context, track track def my_function(): # 更新当前 trace 的 tags opik_context.update_current_trace(tags[my_tag])完整函数签名与参数说明该函数签名为见 opik_context.py 第 125-135 行def update_current_trace( name: Optional[str] None, input: Optional[Dict[str, Any]] None, output: Optional[Dict[str, Any]] None, metadata: Optional[Dict[str, Any]] None, tags: Optional[List[str]] None, feedback_scores: Optional[List[FeedbackScoreDict]] None, thread_id: Optional[str] None, attachments: Optional[List[Attachment]] None, prompts: Optional[List[prompt.BasePrompt]] None, ) - None:所有参数均为可选语义来自源码 docstring 并可直接用于生产代码参数类型说明nameOptional[str]重命名当前 traceinputOptional[Dict[str, Any]]覆盖 trace 的输入数据outputOptional[Dict[str, Any]]覆盖 trace 的输出数据metadataOptional[Dict[str, Any]]覆盖 trace 的元数据tagsOptional[List[str]]覆盖 trace 的标签列表feedback_scoresOptional[List[FeedbackScoreDict]]为该 trace 追加/记录反馈分数FeedbackScoreDict定义于 sdks/python/src/opik/types.pythread_idOptional[str]将多条 trace 归组进同一个 thread标识符由用户自定义且必须在单个 project 内唯一attachmentsOptional[List[Attachment]]上传到该 trace 的附件列表Attachment见 sdks/python/src/opik/api_objects/attachment.pypromptsOptional[List[prompt.BasePrompt]]记录该 trace 使用到的 Prompt 对象列表一个典型的反馈分数记录场景与 demo_data.py 中演示的文档一致from opik import track, opik_context track def llm_chain(input_text): # LLM chain code # ... # 在 trace 完成前记录用户反馈 opik_context.update_current_trace( feedback_scores[ {name: user_feedback, value: 1.0, reason: The response was helpful and accurate.} ] )源码级实现解析update_current_trace的完整实现opik_context.py 第 125-172 行只有三步核心逻辑值得逐行理解def update_current_trace(...) - None: if not tracing_runtime_config.is_tracing_active(): return if prompts is not None: prompts [p.__internal_api__to_info_dict__() for p in prompts] new_params { name: name, input: input, output: output, metadata: metadata, tags: tags, feedback_scores: feedback_scores, thread_id: thread_id, attachments: attachments, prompts: prompts, } current_trace_data context_storage.get_trace_data() if current_trace_data is None: raise exceptions.OpikException(There is no trace in the context.) current_trace_data.update(**new_params)三个关键行为点1. 追踪未激活时静默返回no-op。函数首行检查tracing_runtime_config.is_tracing_active()实现于 sdks/python/src/opik/tracing_runtime_config.py。当 SDK 处于禁用追踪模式例如opik.configure(..., disableTrue)或无有效的 Opik 配置时调用直接返回不抛异常。这使得同一份业务代码可以在有 Opik / 无 Opik两种部署下运行无需条件分支。该行为有专门的单元测试验证test_update_current_trace_noop_when_tracing_disabledtests/unit/opik_context/test_update_current_runtime.py。2. Prompt 对象被序列化为内部信息字典。传入的每个BasePrompt会经过__internal_api__to_info_dict__()转换把 Prompt 的 id 与版本提交commit等元信息固化为可上报的数据结构便于在 UI 中把 trace 关联回 Prompt Library 的具体版本。3. 上下文中没有 trace 时抛出 OpikException。如果调用处不在任何track作用域内即上下文存储中不存在TraceData函数不会静默吞掉错误而是抛出There is no trace in the context.异常同样有单测test_update_current_trace_error_when_tracing_enabled覆盖。与之形成对照的是update_current_span它在无 span 时抛出There is no span in the context.但不会因为没有 trace而报错——因为 span 可以独立存在而 trace 是更外层的容器。底层机制基于 contextvars 的上下文存储update_current_trace之所以能找到当前的 trace依赖 sdks/python/src/opik/context_storage.py 中的OpikContextStorage单例。其设计要点trace 数据存放在contextvars.ContextVar中_current_trace_data_context而不是普通全局变量。contextvars天然隔离线程与 asyncio 任务因此在多线程、异步并发请求下每个执行上下文各自持有独立的 trace 栈不会出现跨请求串线span 以不可变元组模拟栈_spans_data_stack_context存储Tuple[SpanData, ...]遵循取旧值 → 构造新值 → 整体 set的 create-new-set 模式保证并发下的安全源码类注释对此有专门说明get_trace_data()/set_trace_data()/pop_trace_data()提供对当前 trace 的读、写、弹出操作update_current_trace内部调用的正是context_storage.get_trace_data()然后直接对取出的TraceData对象执行update(**new_params)原地合并字段。也就是说update_current_trace修改的是内存中正在构造的TraceData对象真正的上报发生在 trace 生命周期结束时。与 update_current_span 的分工对比同文件中update_current_span第 59-122 行可以看出 SDK 的分工设计update_current_span作用于栈顶 span额外支持usage、model、provider、total_cost、error_info等 LLM 调用相关字段用于在 LLM 调用 span 上补充 token 用量与成本update_current_trace作用于外层 trace独有thread_id字段用于会话级归组不携带 usage/cost 字段这类信息属于 span 粒度。实践中常见组合在函数入口处update_current_trace(thread_id..., metadata...)做会话与业务归组在 LLM 调用 span 处update_current_span(usage...)补成本两者互不干扰。实战场景用 thread_id 把多轮对话归入同一线程thread_id是该函数区别于 span 更新 API 的最重要参数。仓库自带示例 examples/thread_with_image_attachment.py 展示了一个 3 轮视觉问答会话先thread_id str(uuid.uuid4())生成会话唯一标识再为每一轮对话分别创建 trace 并传入相同的thread_id使 Opik 前端能把三轮 trace 聚合进一个 thread 视图。在track场景中等价写法是import uuid from opik import track, opik_context SESSION_ID str(uuid.uuid4()) track def answer_user(question: str) - str: # 同一会话的所有 trace 都打上相同的 thread_id opik_context.update_current_trace(thread_idSESSION_ID) # ... 调用 RAG / LLM 生成回答 ... return ... answer_user(第一问) answer_user(第二问) # 与上一轮归入同一 thread需要注意 docstring 的约束thread_id必须在单个 project 内唯一因此用uuid4或用户体系的会话号是稳妥做法。该示例文件同时演示了attachments参数的另一用途——把图片附件挂到 trace 上供在线 LLM-as-judge 评估通过get_attachment抓取评分。生命周期视角修改何时生效理解update_current_trace的生效时机要结合 trace 的完整生命周期。trace_context上下文管理器opik_context.py 第 219-270 行是track内部为每个 trace 建立/销毁上下文的地方进入时通过context_storage.set_trace_data(trace_data)把TraceData放入contextvars函数体执行期间update_current_trace反复修改这个对象若函数体抛异常error_info_collector.collect(exception)会把错误信息收集到trace_data.error_info上并继续上抛退出时pop_trace_data()取出数据、init_end_time()补终点时间最后调用client.__internal_api__trace__(**trace_data.as_parameters)一次性上报。因此在track装饰的函数体内任何位置调用update_current_trace都来得及只要在函数返回之前但函数返回后上下文已被弹出再调用就会命中前述的OpikException。端到端测试 tests/e2e/test_tracing.py 中test_tracked_function__update_current_trace__with_attachments等用例验证了带附件、带反馈分数的更新确实能到达后端存储。使用边界与常见误区结合源码与测试可以总结出四条实用结论必须在track作用域内调用。裸调用会抛OpikException(There is no trace in the context.)这也是为什么它总出现在被装饰函数内部而不是模块顶层代码里单元测试 tests/unit/decorator/test_track_disabled_mode.py 覆盖了禁用模式下的静默行为。追踪禁用时是安全 no-op。is_tracing_active()为假时直接返回不抛错、不产生网络请求可放心写进库代码。参数是整体覆盖而非增量合并的浅合并语义。从实现看非 None 的参数通过TraceData.update(**new_params)写入传入的tags、metadata会替换对应字段而非逐个追加如需追加标签应先用opik_context.get_current_trace_data()读取副本、合并后再写回。成本、token 用量不属于 trace 级 API。如果你想在调用上补usage/total_cost应使用update_current_spantrace 级没有这些字段。相关资源索引实现源码sdks/python/src/opik/opik_context.pyupdate_current_trace位于 L125-L172上下文存储sdks/python/src/opik/context_storage.py模块文档apps/opik-documentation/python-sdk-docs/source/opik_context/index.rst、update_current_trace.rst、update_current_span.rst线程 附件实战示例sdks/python/examples/thread_with_image_attachment.py单元测试sdks/python/tests/unit/opik_context/test_update_current_runtime.py、sdks/python/tests/unit/decorator/test_tracker_outputs.py端到端测试sdks/python/tests/e2e/test_tracing.py、sdks/python/tests/e2e/test_feedback_scores.py【免费下载链接】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),仅供参考