221 lines
7.2 KiB
Python
221 lines
7.2 KiB
Python
from __future__ import annotations
|
|
|
|
from yuxi.services import langfuse_service as svc
|
|
|
|
|
|
class _FakeLangfuseClient:
|
|
instances = []
|
|
|
|
def __init__(self, **kwargs):
|
|
self.kwargs = kwargs
|
|
self.scores = []
|
|
self.flush_count = 0
|
|
self.raise_on_score = False
|
|
self.__class__.instances.append(self)
|
|
|
|
def create_trace_id(self, *, seed: str | None = None) -> str:
|
|
return f"trace-{seed}"
|
|
|
|
def create_score(self, **kwargs) -> None:
|
|
if self.raise_on_score:
|
|
raise RuntimeError("score failed")
|
|
self.scores.append(kwargs)
|
|
|
|
def get_trace_url(self, *, trace_id: str | None = None) -> str | None:
|
|
if trace_id is None:
|
|
return None
|
|
return f"https://langfuse.local/trace/{trace_id}"
|
|
|
|
def flush(self) -> None:
|
|
self.flush_count += 1
|
|
|
|
|
|
class _FakeCallbackHandler:
|
|
def __init__(self, *, public_key=None, trace_context=None):
|
|
self.public_key = public_key
|
|
self.trace_context = trace_context
|
|
self.last_trace_id = None
|
|
|
|
|
|
def test_build_run_context_includes_trace_metadata(monkeypatch):
|
|
_FakeLangfuseClient.instances.clear()
|
|
monkeypatch.setenv("LANGFUSE_PUBLIC_KEY", "pk-test")
|
|
monkeypatch.setenv("LANGFUSE_SECRET_KEY", "sk-test")
|
|
monkeypatch.setenv("LANGFUSE_BASE_URL", "https://cloud.langfuse.example")
|
|
monkeypatch.delenv("LANGFUSE_ENABLED", raising=False)
|
|
monkeypatch.setattr(svc, "Langfuse", _FakeLangfuseClient)
|
|
monkeypatch.setattr(svc, "CallbackHandler", _FakeCallbackHandler)
|
|
svc.get_langfuse_client.cache_clear()
|
|
|
|
run_context = svc.build_run_context(
|
|
user_id="user-1",
|
|
thread_id="thread-1",
|
|
agent_id="agent-a",
|
|
request_id="req-1",
|
|
operation="agent_chat_stream",
|
|
backend_id="ChatbotAgent",
|
|
message_type="text",
|
|
username="alice",
|
|
login_user_id="alice-login",
|
|
department_id=7,
|
|
)
|
|
|
|
assert run_context.trace_id == "trace-req-1"
|
|
assert len(run_context.callbacks) == 1
|
|
assert run_context.callbacks[0].trace_context == {"trace_id": "trace-req-1"}
|
|
assert run_context.metadata["langfuse_user_id"] == "user-1"
|
|
assert run_context.metadata["langfuse_session_id"] == "thread-1"
|
|
assert run_context.metadata["backend_id"] == "ChatbotAgent"
|
|
assert run_context.metadata["department_id"] == "7"
|
|
assert run_context.tags == [
|
|
"yuxi",
|
|
"chat",
|
|
"agent_chat_stream",
|
|
"agent:agent-a",
|
|
"message_type:text",
|
|
]
|
|
|
|
|
|
def test_build_run_context_merges_evaluation_metadata_and_tags(monkeypatch):
|
|
monkeypatch.delenv("LANGFUSE_PUBLIC_KEY", raising=False)
|
|
monkeypatch.delenv("LANGFUSE_SECRET_KEY", raising=False)
|
|
svc.get_langfuse_client.cache_clear()
|
|
|
|
run_context = svc.build_run_context(
|
|
user_id="user-1",
|
|
thread_id="thread-1",
|
|
agent_id="agent-a",
|
|
request_id="req-1",
|
|
operation="agent_chat_stream",
|
|
extra_metadata={
|
|
"source": "agent_evaluation",
|
|
"feature": "agent_evaluation",
|
|
"evaluation": {"dataset_name": "agent-eval-smoke"},
|
|
},
|
|
extra_tags=["agent_evaluation", "dataset:agent-eval-smoke", "agent_evaluation"],
|
|
)
|
|
|
|
assert run_context.metadata["source"] == "agent_evaluation"
|
|
assert run_context.metadata["feature"] == "agent_evaluation"
|
|
assert run_context.metadata["evaluation"] == {"dataset_name": "agent-eval-smoke"}
|
|
assert run_context.tags == [
|
|
"yuxi",
|
|
"chat",
|
|
"agent_chat_stream",
|
|
"agent:agent-a",
|
|
"agent_evaluation",
|
|
"dataset:agent-eval-smoke",
|
|
]
|
|
|
|
|
|
def test_get_trace_info_prefers_handler_last_trace_id(monkeypatch):
|
|
_FakeLangfuseClient.instances.clear()
|
|
monkeypatch.setenv("LANGFUSE_PUBLIC_KEY", "pk-test")
|
|
monkeypatch.setenv("LANGFUSE_SECRET_KEY", "sk-test")
|
|
monkeypatch.setattr(svc, "Langfuse", _FakeLangfuseClient)
|
|
monkeypatch.setattr(svc, "CallbackHandler", _FakeCallbackHandler)
|
|
svc.get_langfuse_client.cache_clear()
|
|
|
|
run_context = svc.build_run_context(
|
|
user_id="user-1",
|
|
thread_id="thread-1",
|
|
agent_id="agent-a",
|
|
request_id="req-1",
|
|
operation="agent_chat_stream",
|
|
)
|
|
run_context.callbacks[0].last_trace_id = "trace-runtime"
|
|
|
|
trace_info = svc.get_trace_info(run_context)
|
|
|
|
assert trace_info == {
|
|
"langfuse_trace_id": "trace-runtime",
|
|
"langfuse_user_id": "user-1",
|
|
"langfuse_session_id": "thread-1",
|
|
}
|
|
|
|
|
|
async def test_get_trace_url_async_returns_trace_url(monkeypatch):
|
|
_FakeLangfuseClient.instances.clear()
|
|
monkeypatch.setenv("LANGFUSE_PUBLIC_KEY", "pk-test")
|
|
monkeypatch.setenv("LANGFUSE_SECRET_KEY", "sk-test")
|
|
monkeypatch.setattr(svc, "Langfuse", _FakeLangfuseClient)
|
|
monkeypatch.setattr(svc, "CallbackHandler", _FakeCallbackHandler)
|
|
svc.get_langfuse_client.cache_clear()
|
|
|
|
run_context = svc.build_run_context(
|
|
user_id="user-1",
|
|
thread_id="thread-1",
|
|
agent_id="agent-a",
|
|
request_id="req-1",
|
|
operation="agent_chat_stream",
|
|
)
|
|
run_context.callbacks[0].last_trace_id = "trace-runtime"
|
|
|
|
trace_url = await svc.get_trace_url_async(run_context)
|
|
|
|
assert trace_url == "https://langfuse.local/trace/trace-runtime"
|
|
|
|
|
|
def test_submit_user_feedback_score_creates_boolean_score(monkeypatch):
|
|
_FakeLangfuseClient.instances.clear()
|
|
monkeypatch.setenv("LANGFUSE_PUBLIC_KEY", "pk-test")
|
|
monkeypatch.setenv("LANGFUSE_SECRET_KEY", "sk-test")
|
|
monkeypatch.setattr(svc, "Langfuse", _FakeLangfuseClient)
|
|
monkeypatch.setattr(svc, "CallbackHandler", _FakeCallbackHandler)
|
|
svc.get_langfuse_client.cache_clear()
|
|
|
|
created = svc.submit_user_feedback_score(
|
|
trace_id="trace-1",
|
|
feedback_id=12,
|
|
message_id=34,
|
|
conversation_id=56,
|
|
uid="user-1",
|
|
rating="dislike",
|
|
reason="答案不准确",
|
|
)
|
|
|
|
client = _FakeLangfuseClient.instances[-1]
|
|
assert created is True
|
|
assert client.scores == [
|
|
{
|
|
"trace_id": "trace-1",
|
|
"score_id": "yuxi-message-feedback-12",
|
|
"name": "user-feedback",
|
|
"value": 0,
|
|
"data_type": "BOOLEAN",
|
|
"comment": "答案不准确",
|
|
"metadata": {
|
|
"source": "yuxi",
|
|
"feedback_id": 12,
|
|
"message_id": 34,
|
|
"conversation_id": 56,
|
|
"uid": "user-1",
|
|
"rating": "dislike",
|
|
},
|
|
}
|
|
]
|
|
assert client.flush_count == 1
|
|
|
|
|
|
def test_submit_user_feedback_score_returns_false_when_langfuse_fails(monkeypatch):
|
|
_FakeLangfuseClient.instances.clear()
|
|
monkeypatch.setenv("LANGFUSE_PUBLIC_KEY", "pk-test")
|
|
monkeypatch.setenv("LANGFUSE_SECRET_KEY", "sk-test")
|
|
monkeypatch.setattr(svc, "Langfuse", _FakeLangfuseClient)
|
|
monkeypatch.setattr(svc, "CallbackHandler", _FakeCallbackHandler)
|
|
svc.get_langfuse_client.cache_clear()
|
|
client = svc.get_langfuse_client()
|
|
client.raise_on_score = True
|
|
|
|
created = svc.submit_user_feedback_score(
|
|
trace_id="trace-1",
|
|
feedback_id=12,
|
|
message_id=34,
|
|
conversation_id=56,
|
|
uid="user-1",
|
|
rating="like",
|
|
)
|
|
|
|
assert created is False
|
|
assert client.flush_count == 0
|