项目文件夹

文件
2026-07-13 13:22:34 +08:00

137 行
4.5 KiB
Python

import json
from dataclasses import dataclass
from unittest import mock
import pytest
from mlflow.entities.trace import Trace
from mlflow.entities.trace_info import TraceInfo
from mlflow.entities.trace_location import TraceLocation
from mlflow.entities.trace_state import TraceState
from mlflow.genai.judges.utils.tool_calling_utils import _process_tool_calls
from mlflow.types.llm import ChatMessage, ToolCall
@pytest.fixture
def mock_trace():
trace_info = TraceInfo(
trace_id="test-trace",
trace_location=TraceLocation.from_experiment_id("0"),
request_time=1234567890,
state=TraceState.OK,
)
return Trace(info=trace_info, data=None)
def _make_tool_call(call_id, name, arguments="{}"):
return ToolCall(
id=call_id,
function={"name": name, "arguments": arguments},
)
def test_process_tool_calls_success(mock_trace):
tool_call = _make_tool_call("call_123", "test_tool", '{"arg": "value"}')
with mock.patch(
"mlflow.genai.judges.tools.registry._judge_tool_registry.invoke"
) as mock_invoke:
mock_invoke.return_value = {"result": "success"}
result = _process_tool_calls(tool_calls=[tool_call], trace=mock_trace)
assert len(result) == 1
assert isinstance(result[0], ChatMessage)
assert result[0].role == "tool"
assert result[0].tool_call_id == "call_123"
assert result[0].name == "test_tool"
assert json.loads(result[0].content) == {"result": "success"}
def test_process_tool_calls_with_error(mock_trace):
tool_call = _make_tool_call("call_456", "failing_tool")
with mock.patch(
"mlflow.genai.judges.tools.registry._judge_tool_registry.invoke"
) as mock_invoke:
mock_invoke.side_effect = RuntimeError("Tool execution failed")
result = _process_tool_calls(tool_calls=[tool_call], trace=mock_trace)
assert len(result) == 1
assert result[0].role == "tool"
assert result[0].tool_call_id == "call_456"
assert "Error: Tool execution failed" in result[0].content
def test_process_tool_calls_multiple(mock_trace):
tool_call_1 = _make_tool_call("call_1", "tool_1")
tool_call_2 = _make_tool_call("call_2", "tool_2")
with mock.patch(
"mlflow.genai.judges.tools.registry._judge_tool_registry.invoke"
) as mock_invoke:
mock_invoke.side_effect = [{"result": "first"}, {"result": "second"}]
result = _process_tool_calls(tool_calls=[tool_call_1, tool_call_2], trace=mock_trace)
assert len(result) == 2
assert result[0].tool_call_id == "call_1"
assert result[1].tool_call_id == "call_2"
assert json.loads(result[0].content) == {"result": "first"}
assert json.loads(result[1].content) == {"result": "second"}
def test_process_tool_calls_with_dataclass(mock_trace):
@dataclass
class ToolResult:
status: str
count: int
tool_call = _make_tool_call("call_789", "dataclass_tool")
with mock.patch(
"mlflow.genai.judges.tools.registry._judge_tool_registry.invoke"
) as mock_invoke:
mock_invoke.return_value = ToolResult(status="ok", count=42)
result = _process_tool_calls(tool_calls=[tool_call], trace=mock_trace)
assert len(result) == 1
assert result[0].role == "tool"
content = json.loads(result[0].content)
assert content == {"status": "ok", "count": 42}
def test_process_tool_calls_with_string_result(mock_trace):
tool_call = _make_tool_call("call_str", "string_tool")
with mock.patch(
"mlflow.genai.judges.tools.registry._judge_tool_registry.invoke"
) as mock_invoke:
mock_invoke.return_value = "Plain string result"
result = _process_tool_calls(tool_calls=[tool_call], trace=mock_trace)
assert len(result) == 1
assert result[0].role == "tool"
assert result[0].content == "Plain string result"
def test_process_tool_calls_mixed_success_and_error(mock_trace):
tool_call_1 = _make_tool_call("call_success", "success_tool")
tool_call_2 = _make_tool_call("call_error", "error_tool")
with mock.patch(
"mlflow.genai.judges.tools.registry._judge_tool_registry.invoke"
) as mock_invoke:
mock_invoke.side_effect = [{"result": "success"}, RuntimeError("Failed")]
result = _process_tool_calls(tool_calls=[tool_call_1, tool_call_2], trace=mock_trace)
assert len(result) == 2
assert result[0].tool_call_id == "call_success"
assert json.loads(result[0].content) == {"result": "success"}
assert result[1].tool_call_id == "call_error"
assert "Error: Failed" in result[1].content