Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Fix LLMEvaluator serialization #7818

Merged
merged 2 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions haystack/components/evaluators/llm_evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from haystack import component, default_from_dict, default_to_dict
from haystack.components.builders import PromptBuilder
from haystack.components.generators import OpenAIGenerator
from haystack.utils import Secret, deserialize_secrets_inplace
from haystack.utils import Secret, deserialize_secrets_inplace, deserialize_type, serialize_type


@component
Expand Down Expand Up @@ -266,10 +266,12 @@ def to_dict(self) -> Dict[str, Any]:
:returns:
The serialized component as a dictionary.
"""
# Since we cannot currently serialize tuples, convert the inputs to a list.
inputs = [[name, serialize_type(type_)] for name, type_ in self.inputs]
return default_to_dict(
self,
instructions=self.instructions,
inputs=self.inputs,
inputs=inputs,
outputs=self.outputs,
examples=self.examples,
api=self.api,
Expand All @@ -287,6 +289,10 @@ def from_dict(cls, data: Dict[str, Any]) -> "LLMEvaluator":
:returns:
The deserialized component instance.
"""
data["init_parameters"]["inputs"] = [
(name, deserialize_type(type_)) for name, type_ in data["init_parameters"]["inputs"]
]

deserialize_secrets_inplace(data["init_parameters"], keys=["api_key"])
return default_from_dict(cls, data)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
fixes:
- |
Correctly serialize tuples and types in the init parameters of the `LLMEvaluator` component and its subclasses.
23 changes: 19 additions & 4 deletions test/components/evaluators/test_llm_evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
# SPDX-License-Identifier: Apache-2.0
from typing import List

import numpy as np
import pytest

from haystack import Pipeline
from haystack.components.evaluators import LLMEvaluator
from haystack.utils.auth import Secret

Expand Down Expand Up @@ -205,7 +205,7 @@ def test_to_dict_default(self, monkeypatch):
"api_key": {"env_vars": ["OPENAI_API_KEY"], "strict": True, "type": "env_var"},
"api": "openai",
"instructions": "test-instruction",
"inputs": [("predicted_answers", List[str])],
"inputs": [["predicted_answers", "typing.List[str]"]],
"outputs": ["score"],
"progress_bar": True,
"examples": [
Expand All @@ -223,7 +223,7 @@ def test_from_dict(self, monkeypatch):
"api_key": {"env_vars": ["OPENAI_API_KEY"], "strict": True, "type": "env_var"},
"api": "openai",
"instructions": "test-instruction",
"inputs": [("predicted_answers", List[str])],
"inputs": [["predicted_answers", "typing.List[str]"]],
"outputs": ["score"],
"examples": [
{"inputs": {"predicted_answers": "Football is the most popular sport."}, "outputs": {"score": 0}}
Expand Down Expand Up @@ -266,7 +266,7 @@ def test_to_dict_with_parameters(self, monkeypatch):
"api_key": {"env_vars": ["ENV_VAR"], "strict": True, "type": "env_var"},
"api": "openai",
"instructions": "test-instruction",
"inputs": [("predicted_answers", List[str])],
"inputs": [["predicted_answers", "typing.List[str]"]],
"outputs": ["custom_score"],
"progress_bar": True,
"examples": [
Expand All @@ -282,6 +282,21 @@ def test_to_dict_with_parameters(self, monkeypatch):
},
}

def test_serde(self, monkeypatch):
monkeypatch.setenv("OPENAI_API_KEY", "test-api-key")
pipeline = Pipeline()
component = LLMEvaluator(
instructions="test-instruction",
inputs=[("questions", List[str]), ("predicted_answers", List[List[str]])],
outputs=["score"],
examples=[
{"inputs": {"predicted_answers": "Football is the most popular sport."}, "outputs": {"score": 0}}
],
)
pipeline.add_component("evaluator", component)
serialized_pipeline = pipeline.dumps()
deserialized_pipeline = Pipeline.loads(serialized_pipeline)

def test_run_with_different_lengths(self, monkeypatch):
monkeypatch.setenv("OPENAI_API_KEY", "test-api-key")
component = LLMEvaluator(
Expand Down