fix:Jev 观测改为 evaluator,会话视图不再被 JSON 分类结果占位
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"""一次大屏图调用的 Langfuse 追踪
|
||||
|
||||
不属于处理管道的任一步。把图调用收成可过滤的 trace,并把 Jev 记成当前节点下的 generation
|
||||
不属于处理管道的任一步。把图调用收成可过滤的 trace,并把 Jev 记成当前节点下的 evaluator
|
||||
每轮调用单独记录,首次请求与澄清恢复通过 session 关联,不修改业务状态
|
||||
"""
|
||||
|
||||
@@ -100,7 +100,7 @@ def _screen_trace(payload, thread_id, session_id, user_id=None):
|
||||
|
||||
# 明确回调所属项目,避免进程中存在多个客户端时跳过追踪
|
||||
handler = CallbackHandler(public_key=os.getenv("LANGFUSE_PUBLIC_KEY"))
|
||||
# 在当前异步上下文执行回调,手动记录的 Jev generation 才会挂到所属节点。
|
||||
# 在当前异步上下文执行回调,手动记录的 Jev 观测才会挂到所属节点。
|
||||
handler.run_inline = True
|
||||
resume = isinstance(payload, Command) and payload.resume is not None
|
||||
trace_input = (
|
||||
@@ -162,9 +162,10 @@ def _run_output(state: dict[str, Any]) -> dict[str, Any]:
|
||||
|
||||
@contextmanager
|
||||
def observe_decision(request: Any) -> Iterator[Any]:
|
||||
"""在当前节点下面记一次 Jev 调用,yield 的是 generation,未追踪时是 None
|
||||
"""在当前节点下面记一次 Jev 调用,yield 的是观测对象,未追踪时是 None
|
||||
|
||||
TypeSafe 不走 LangChain callback,所以要手记。类型必须是 generation,面板才能算模型和 token
|
||||
TypeSafe 不走 LangChain callback,所以要手记。类型不能是 generation:会话视图只用 generation
|
||||
拼对话,且只显示最浅的一条对话线,Jev 比 agent 的模型调用浅,用 generation 会把真正的对话挤掉
|
||||
只有图回调已经挂上当前 span 时才记。没有父 span 就跳过,避免 Jev 单独变成一条 trace
|
||||
这里不吞异常:失败时标 ERROR 后原样抛出,调用方的 DecisionError 类型不变
|
||||
"""
|
||||
@@ -177,7 +178,7 @@ def observe_decision(request: Any) -> Iterator[Any]:
|
||||
name = "classify-intent" if set(request.decisions) == {"intent"} else "run-decision"
|
||||
# 复用本应用已经选定的客户端
|
||||
with client.start_as_current_observation(
|
||||
as_type="generation",
|
||||
as_type="evaluator",
|
||||
name=name,
|
||||
model=model,
|
||||
input={
|
||||
@@ -187,11 +188,11 @@ def observe_decision(request: Any) -> Iterator[Any]:
|
||||
},
|
||||
"state": request.state,
|
||||
},
|
||||
) as generation:
|
||||
) as observation:
|
||||
try:
|
||||
yield generation
|
||||
yield observation
|
||||
except Exception as error:
|
||||
generation.update(
|
||||
observation.update(
|
||||
level="ERROR",
|
||||
status_message=str(error),
|
||||
metadata=_error_metadata(error),
|
||||
@@ -199,29 +200,26 @@ def observe_decision(request: Any) -> Iterator[Any]:
|
||||
raise
|
||||
|
||||
|
||||
def record_decision(generation: Any, response: Any) -> None:
|
||||
"""把成功的 Jev 结果写回刚才那条 generation
|
||||
def record_decision(observation: Any, response: Any) -> None:
|
||||
"""把成功的 Jev 结果写回刚才那条观测
|
||||
|
||||
generation 为 None 表示这次没追踪,直接返回,不影响判断结果
|
||||
observation 为 None 表示这次没追踪,直接返回,不影响判断结果
|
||||
只写选项、置信度和 token。不写原始 HTTP 响应
|
||||
"""
|
||||
if generation is None:
|
||||
if observation is None:
|
||||
return
|
||||
usage: dict[str, int] = {}
|
||||
# evaluator 没有 model/usage 字段,模型和 token 只能放 metadata
|
||||
metadata = {"model": response.model, "request_id": response.request_id or ""}
|
||||
if response.usage.input_tokens is not None:
|
||||
usage["input_tokens"] = response.usage.input_tokens
|
||||
metadata["input_tokens"] = str(response.usage.input_tokens)
|
||||
if response.usage.output_tokens is not None:
|
||||
usage["output_tokens"] = response.usage.output_tokens
|
||||
metadata["output_tokens"] = str(response.usage.output_tokens)
|
||||
|
||||
generation.update(
|
||||
model=response.model,
|
||||
observation.update(
|
||||
output={
|
||||
name: _result_summary(result) for name, result in response.results.items()
|
||||
},
|
||||
usage_details=usage or None,
|
||||
metadata={
|
||||
"request_id": response.request_id or "",
|
||||
},
|
||||
metadata=metadata,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user