Python v3 → v4
Python SDK v4 引入了**以 observation 为中心的数据模型**。在此模型中,关联属性(user_id、session_id、metadata、tags)传播到每个 observation,而非仅存在于 trace 上。这使得无需昂贵 join 的单表查询成为可能,显著提升了规模化时的查询性能。
这改变了你设置 trace 属性的方式:不再用 update_current_trace() 命令式地更新 trace 对象,而是使用 propagate_attributes()——一个上下文管理器,自动将属性应用于其作用域内创建的当前和所有子 observations。
v4 改变了默认的 OpenTelemetry 导出行为:Langfuse 不再默认导出所有 spans。如果你之前依赖非 LLM spans(HTTP、DB、队列、框架内部)被转发,请在升级前查看下面的第一个破坏性变更。
破坏性变更
智能默认 span 过滤取代导出全部行为
在以前的版本中,默认导出所有 OpenTelemetry spans 增加了来自基础设施和非 LLM 埋点(HTTP、DB、队列、框架内部)的 trace 噪声。为保持 traces 聚焦和有用,v4 引入了智能默认 span 过滤器。
默认情况下,如果满足以下任一条件,v4 导出 span:
- 该 span 由 Langfuse 创建(
langfuse-sdk) - 该 span 具有
gen_ai.*属性 - 该 span 埋点作用域匹配已知的 LLM 作用域前缀(例如
openinference、langsmith、haystack、litellm)
在 v4 之前,未被阻止的埋点作用域默认被导出。
保留 v4 之前的"导出全部"行为
from langfuse import Langfuse
langfuse = Langfuse(should_export_span=lambda span: True)
将自定义过滤器与默认行为组合
from langfuse import Langfuse
from langfuse.span_filter import is_default_export_span
langfuse = Langfuse(
should_export_span=lambda span: (
is_default_export_span(span)
or (
span.instrumentation_scope is not None
and span.instrumentation_scope.name.startswith("my_framework")
)
)
)
Python 兼容性说明:blocked_instrumentation_scopes 已弃用
blocked_instrumentation_scopes 在 v4 中仍然有效,但已弃用,并将在未来版本中移除。请迁移到 should_export_span。
使用 should_export_span 的等价拒绝列表行为:
from langfuse import Langfuse
from langfuse.span_filter import is_default_export_span
blocked = {"sqlite", "requests"}
langfuse = Langfuse(
should_export_span=lambda span: (
is_default_export_span(span)
and (
span.instrumentation_scope is None
or span.instrumentation_scope.name not in blocked
)
)
)
如果同时设置了 blocked_instrumentation_scopes 和 should_export_span,被阻止的作用域仍然胜出(硬否决)。
可能的 trace 树副作用及如何调试
当中间或父 spans 被丢弃而子 spans 仍被导出时,过滤可能会破坏 trace 树。如果 traces 显得断开,请启用 SDK 调试日志以检查被丢弃的 spans,然后在你的回调中将所需作用域加入允许列表。
- Python 调试模式:使用
Langfuse(debug=True)或设置LANGFUSE_DEBUG="True"。 - 参见 SDK 高级功能和针对不需要 spans 的 OpenTelemetry 故障排查。
update_current_trace() 分解为 3 个方法
在新模型中,关联属性(user_id、session_id、metadata、tags 和请求作用域的 environment)必须存在于每个 observation 上,而非仅在 trace 上。这就是它们移到 propagate_attributes() 的原因——一个上下文管理器,自动将这些属性应用于其作用域内创建的当前和所有子 observations。
v3:
langfuse.update_current_trace(
name="trace-name",
user_id="user-123",
session_id="session-abc",
version="1.0",
input={"query": "hello"},
output={"result": "world"},
metadata={"key": "value"},
tags=["tag1"],
public=True,
)
v4(分解):
from langfuse import observe, propagate_attributes, get_client
langfuse = get_client()
@observe()
def my_function():
# (a) Correlating attributes → propagate_attributes() context manager
with propagate_attributes(
trace_name="trace-name", # note: 'name' is now 'trace_name'
user_id="user-123",
session_id="session-abc",
version="1.0",
metadata={"key": "value"},
tags=["tag1"],
environment="staging",
):
result = call_llm("hello")
# (b) Trace I/O (deprecated, only for legacy trace-level LLM-as-a-judge configurations)
langfuse.set_current_trace_io(input={"query": "hello"}, output={"result": result})
# (c) Public flag
langfuse.set_current_trace_as_public()
关键差异:
| 属性 | v3 | v4 |
|---|---|---|
name |
update_current_trace(name=...) |
propagate_attributes(trace_name=...) |
user_id、session_id、tags、version |
update_current_trace(...) |
propagate_attributes(...) |
metadata |
update_current_trace(metadata=any) |
propagate_attributes(metadata=dict[str,str]) |
input、output |
update_current_trace(...) |
set_current_trace_io(...)(已弃用) |
public |
update_current_trace(public=True) |
set_current_trace_as_public() |
release |
update_current_trace(release=...) |
已移除——使用 LANGFUSE_RELEASE 环境变量 |
environment |
update_current_trace(environment=...) |
进程级环境使用 LANGFUSE_TRACING_ENVIRONMENT 或 Langfuse(environment=...)。请求作用域环境使用 propagate_attributes(environment=...)。 |
set_current_trace_io()已弃用,仅为与依赖 trace 输入/输出的 trace 级 LLM-as-a-judge 评估器向后兼容而存在。对于新代码,请直接在根 observation 上设置输入/输出。
span.update_trace() 分解为 3 个方法
相同的分解适用于 observation 级的 update_trace() 方法。
v3:
span.update_trace(
name="trace-name",
user_id="user-123",
session_id="session-abc",
input={"query": "hello"},
output={"result": "world"},
public=True,
)
v4:
from langfuse import get_client, propagate_attributes
langfuse = get_client()
with langfuse.start_as_current_observation(as_type="span", name="my-operation") as span:
with propagate_attributes(trace_name="trace-name", user_id="user-123", session_id="session-abc"):
result = call_llm("hello")
span.set_trace_io(input={"query": "hello"}, output={"result": result}) # deprecated
span.set_trace_as_public()
对于集成(LangChain、OpenAI),传入的 trace 属性现在仅传播到子节点——它们不会冒泡到 trace。
Public API 命名空间重映射(api.*)
在 v4 中,高性能 Public API 资源现在是默认值。v2 别名已被移除。
| v3 / 过渡名称 | v4 名称 |
|---|---|
langfuse.api.observations_v_2 |
langfuse.api.observations |
langfuse.api.score_v_2 |
langfuse.api.scores |
langfuse.api.metrics_v_2 |
langfuse.api.metrics |
langfuse.api.observations(旧版 v1) |
langfuse.api.legacy.observations_v1 |
langfuse.api.score(旧版 v1) |
langfuse.api.legacy.score_v1 |
langfuse.api.metrics(旧版 v1) |
langfuse.api.legacy.metrics_v1 |
如果你仍需要旧版 v1 行为,请切换到相应的 langfuse.api.legacy._v1 命名空间。
新的默认
langfuse.api.observations和langfuse.api.metrics方法指向 Observations v2 和 Metrics v2 端点,它们需要 Langfuse v4(Langfuse Cloud,或升级到 v4 的自托管服务器)。在自托管 Langfuse v3 上,请改用langfuse.api.legacy.observations_v1和langfuse.api.legacy.metrics_v1。参见自托管兼容性矩阵。
start_span() / start_generation() → start_observation()
Observations 是新模型中的主要概念。带 as_type 参数的统一 start_observation() API 取代了单独的方法。
| v3 | v4 |
|---|---|
langfuse.start_span(name="x") |
langfuse.start_observation(name="x") |
langfuse.start_as_current_span(name="x") |
langfuse.start_as_current_observation(name="x") |
langfuse.start_generation(name="x", model="gpt-4") |
langfuse.start_observation(name="x", as_type="generation", model="gpt-4") |
langfuse.start_as_current_generation(name="x", model="gpt-4") |
langfuse.start_as_current_observation(name="x", as_type="generation", model="gpt-4") |
span.start_span(name="x") |
span.start_observation(name="x") |
span.start_as_current_span(name="x") |
span.start_as_current_observation(name="x") |
span.start_generation(name="x") |
span.start_observation(name="x", as_type="generation") |
span.start_as_current_generation(name="x") |
span.start_as_current_observation(name="x", as_type="generation") |
DatasetItemClient.run() 已移除 → 使用 Experiment SDK
Experiment SDK(dataset.run_experiment())在底层处理实验属性的传播(运行元数据、数据集条目链接)。
v3:
for item in dataset.items:
with item.run(run_name="my-run", run_metadata={...}) as span:
result = my_llm(item.input)
span.update(output=result)
v4:
from langfuse import get_client
dataset = get_client().get_dataset("my-dataset")
def my_task(*, item, **kwargs):
return my_llm(item.input)
dataset.run_experiment(name="my-run", task=my_task)
DatasetItem 对象仍具有相同的数据属性(id、input、expected_output、metadata 等),但 run() 方法已移除。
LangChain CallbackHandler:update_trace 参数已移除
该 handler 现在在内部使用 propagate_attributes()。update_trace 参数不再存在——传递它会引发 TypeError。
v3:
from langfuse.langchain import CallbackHandler
handler = CallbackHandler(update_trace=True, trace_context={...})
v4:
handler = CallbackHandler(trace_context={...})
你仍然可以通过将 LangChain 调用包装在带
propagate_attributes()的外层 span 中来设置 trace 属性(user_id、session_id、tags等)。参见 v2 → v3 迁移指南中的 LangChain 集成示例或自定义 trace 属性文档。
已移除的类型
以下类型已从 langfuse.types 中移除:
| 已移除的类型 | 描述 |
|---|---|
TraceMetadata |
带 name、user_id、session_id、version、release、metadata、tags、public 的 TypedDict |
ObservationParams |
扩展 TraceMetadata 并带 observation 字段的 TypedDict |
MapValue、ModelUsage、PromptClient |
不再从 langfuse.types 重新导出,请改为从 langfuse.model 导入 |
放弃 Pydantic v1 支持
SDK 现在需要 Pydantic v2。如果你的应用仍使用 Pydantic v1,你必须使用 pydantic.v1 兼容性垫片。
校验变更
- 传播的
metadata:现在为dict[str, str],值限制为 200 字符(原来是Any)。非字符串值被强制转换为字符串。超过限制的值会被丢弃并发出警告。 user_id、session_id:作为最大长度 200 字符的字符串校验。超过限制的值会被丢弃并发出警告。
迁移清单
- 审计依赖非 LLM OpenTelemetry spans 的 traces/仪表盘:这些可能在 v4 默认过滤器下停止出现
- 如需要,设置
should_export_span=lambda span: True以保留 v4 之前的"导出所有 spans"行为 - 如果你仍使用
blocked_instrumentation_scopes,请在弃用被移除之前迁移到should_export_span组合 - 搜索
update_current_trace→ 拆分为propagate_attributes()+set_current_trace_io()(仅当依赖旧版 trace 级 LLM-as-a-judge 配置时)+set_current_trace_as_public() - 搜索
.update_trace(→ 在 observation 对象上做相同拆分 - 搜索
start_span/start_generation→ 替换为start_observation - 搜索
item.run(→ 替换为dataset.run_experiment() - 搜索
CallbackHandler(update_trace=→ 移除参数 - 验证 metadata 值为
dict[str, str],值 ≤200 字符 - 如果仍在 v1,将 Pydantic 升级到 v2
- 搜索
api.observations_v_2/api.score_v_2/api.metrics_v_2→ 替换为api.observations/api.scores/api.metrics - 搜索
api.observations/api.score/api.metrics上的旧版 v1 用法 → 移到api.legacy.observations_v1/api.legacy.score_v1/api.legacy.metrics_v1 - 如果你自托管 Langfuse v3,请使用
api.legacy.observations_v1和api.legacy.metrics_v1;默认的api.observations/api.metrics需要 Langfuse v4(参见自托管兼容性矩阵) - 移除任何剩余的
*_v_2别名引用(它们在 v4 中已被移除)