Compare commits

...

39 Commits

Author SHA1 Message Date
William Fu-Hinthorn
b6d6274e96 simple 2023-10-26 11:50:11 -07:00
William Fu-Hinthorn
9b67effbd7 update tests 2023-10-26 11:35:18 -07:00
William Fu-Hinthorn
b1c3fa7e04 merge 2023-10-26 11:26:06 -07:00
William Fu-Hinthorn
267973c17f . 2023-09-28 21:27:14 -07:00
William Fu-Hinthorn
c0207edb36 ? 2023-09-28 17:04:47 -07:00
William Fu-Hinthorn
1b50c2b4a4 format 2023-09-28 16:36:36 -07:00
William Fu-Hinthorn
dba01d9d10 format 2023-09-28 16:27:57 -07:00
PaperMoose
dcbf9f9a3f synthetic-data: address wills comments 2023-09-28 16:24:08 -07:00
PaperMoose
23efd888ae Merge branch 'synthetic-data' of github.com:paperMoose/langchain into synthetic-data 2023-09-28 16:09:22 -07:00
PaperMoose
b9254fb046 synthetic-data: fixes issue with import from main file 2023-09-28 16:09:15 -07:00
PaperMoose
0b85d204c6 Merge branch 'master' into synthetic-data 2023-09-28 12:52:37 -07:00
PaperMoose
c4cdb5ed06 Merge branch 'master' into synthetic-data 2023-09-28 09:34:11 -07:00
PaperMoose
306a19c535 Merge branch 'master' into synthetic-data 2023-09-27 16:46:11 -07:00
PaperMoose
7153006e84 synthetic-data: adds useage notebook 2023-09-27 16:41:38 -07:00
PaperMoose
90663ff6d4 synthetic-data: moves things to experimental 2023-09-27 15:50:28 -07:00
PaperMoose
1bc0c90a6f Merge branch 'master' into synthetic-data 2023-09-26 19:17:41 -07:00
PaperMoose
4643aac017 synthetic-data: removes stray print statements 2023-09-26 19:08:33 -07:00
PaperMoose
b2ffc7b95d synthetic-data: fix linting 2023-09-26 18:46:57 -07:00
PaperMoose
7c09d42fb9 Merge branch 'synthetic-data' of github.com:paperMoose/langchain into synthetic-data 2023-09-26 17:39:08 -07:00
PaperMoose
ee0587db5b synthetic-data: fixes linting issues 2023-09-26 17:39:02 -07:00
PaperMoose
b42dc3cec0 Merge branch 'master' into synthetic-data 2023-09-18 18:37:05 -04:00
PaperMoose
f1700898ca Merge branch 'master' into synthetic-data 2023-09-18 13:33:31 -04:00
PaperMoose
87ba9cff3a Merge branch 'master' into synthetic-data 2023-09-15 21:07:50 -04:00
PaperMoose
8a10cfa56a synthetic-data: linting fixes 2023-09-15 18:55:10 -04:00
PaperMoose
2425a373ba Merge branch 'master' into synthetic-data 2023-09-15 14:26:57 -04:00
PaperMoose
f684240585 Merge branch 'master' into synthetic-data 2023-09-12 11:17:14 -07:00
PaperMoose
6df0644e6e Merge branch 'master' into synthetic-data 2023-09-11 16:02:11 -07:00
PaperMoose
ea04d8cd08 Merge branch 'synthetic-data' of github.com:paperMoose/langchain into synthetic-data 2023-09-11 15:48:58 -07:00
PaperMoose
f263fc18cc synthetic-data: fix 2023-09-11 15:48:49 -07:00
PaperMoose
a3173b3c86 Merge branch 'master' into synthetic-data 2023-09-11 10:00:13 -07:00
PaperMoose
252e619156 Merge branch 'master' into synthetic-data 2023-09-08 17:49:27 -07:00
PaperMoose
e8b5e7d03d Merge branch 'synthetic-data' of github.com:paperMoose/langchain into synthetic-data 2023-09-08 17:45:56 -07:00
PaperMoose
bb9fc2105a synthetic-data: linting and typing additions 2023-09-08 17:45:48 -07:00
PaperMoose
cc79c6f128 Merge branch 'master' into synthetic-data 2023-09-08 16:15:54 -07:00
PaperMoose
86430a41b7 synthetic-data: updates typing to use ChatOpenAI 2023-08-25 11:54:46 -04:00
PaperMoose
bef7f0478d synthetic-data: adds docstring useage examples, improves steerability of data gen, and likelihood of duplicates 2023-08-24 14:57:07 -04:00
PaperMoose
dc9870dad8 synthetic-data: updates 2023-08-18 12:11:44 -07:00
PaperMoose
d70f5735ec synthetic-data: adds fc 2023-08-17 18:10:24 -07:00
PaperMoose
18c4949fc3 synthetic-data: adds simple synthetic data gen 2023-08-16 16:58:19 -07:00
2 changed files with 173 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
import json
from typing import Any, Callable, Optional, Union
from langchain.evaluation.schema import StringEvaluator
from langchain.output_parsers.json import parse_json_markdown
class JsonEditDistanceEvaluator(StringEvaluator):
def __init__(
self,
string_distance: Optional[Callable[[str, str], float]] = None,
canonicalize: Optional[Callable[[Any], Any]] = None,
**kwargs: Any
) -> None:
super().__init__()
if string_distance is not None:
self._string_distance = string_distance
else:
try:
from rapidfuzz import distance as rfd # noqa: F401
except ImportError:
raise ImportError(
"The default string_distance operator for the "
" JsonEditDistanceEvaluator requires installation of "
"the rapidfuzz package. "
"Please install it with `pip install rapidfuzz`."
)
self._string_distance = rfd.DamerauLevenshtein.normalized_distance
if canonicalize is not None:
self._canonicalize = canonicalize
else:
self._canonicalize = lambda x: json.dumps(
x, separators=(",", ":"), sort_keys=True # eliminate whitespace
)
@property
def requires_input(self) -> bool:
return False
@property
def requires_reference(self) -> bool:
return True
@property
def evaluation_name(self) -> str:
return "json_edit_distance"
def _parse_json(self, node: Any) -> Union[dict, list, None, float, bool, int, str]:
if isinstance(node, str):
return parse_json_markdown(node)
return node
def _distance(self, a: Any, b: Any) -> float:
return self._string_distance(a, b)
def _evaluate_strings(
self,
prediction: str,
input: Optional[str] = None,
reference: Optional[str] = None,
**kwargs: Any
) -> dict:
parsed = self._canonicalize(self._parse_json(prediction))
label = self._canonicalize(self._parse_json(reference))
distance = self._distance(parsed, label)
return {"score": distance}

View File

@@ -0,0 +1,107 @@
import pytest
from langchain.evaluation.parsing.json_distance import JsonEditDistanceEvaluator
@pytest.fixture
def json_distance_evaluator() -> JsonEditDistanceEvaluator:
return JsonEditDistanceEvaluator()
def test_json_distance_evaluator_requires_input(
json_distance_evaluator: JsonEditDistanceEvaluator,
) -> None:
assert json_distance_evaluator.requires_input is False
def test_json_distance_evaluator_requires_reference(
json_distance_evaluator: JsonEditDistanceEvaluator,
) -> None:
assert json_distance_evaluator.requires_reference is True
def test_json_distance_evaluator_evaluation_name(
json_distance_evaluator: JsonEditDistanceEvaluator,
) -> None:
assert json_distance_evaluator.evaluation_name == "json_edit_distance"
def test_json_distance_evaluator_parse_json(
json_distance_evaluator: JsonEditDistanceEvaluator,
) -> None:
string = '{"a": 1}'
result = json_distance_evaluator._parse_json(string)
assert result == {"a": 1}
def test_json_distance_evaluator_evaluate_strings_simple_diff(
json_distance_evaluator: JsonEditDistanceEvaluator,
) -> None:
prediction = '{"a": 1}'
reference = '{"a": 2}'
result = json_distance_evaluator._evaluate_strings(
prediction=prediction, reference=reference
)
# Only 1 character flipped
pytest.approx(1 / 7, result["score"])
def test_json_distance_evaluator_evaluate_strings_complex_diff(
json_distance_evaluator: JsonEditDistanceEvaluator,
) -> None:
prediction = '{"a":1, "b": {"c": 2, "d": 3}}'
reference = '{"a": 1, "b": {"c": 2, "d": 4}}'
result = json_distance_evaluator._evaluate_strings(
prediction=prediction, reference=reference
)
# Only 1 character flipped
pytest.approx(1 / len(reference.replace(" ", "")), result["score"])
def test_json_distance_evaluator_evaluate_strings_list_diff(
json_distance_evaluator: JsonEditDistanceEvaluator,
) -> None:
prediction = '[{"a": 1, "b": 2}, {"a": 2, "b": 3}]'
reference = '[{"a": 1, "b": 2}, {"a": 2, "b": 4}]'
result = json_distance_evaluator._evaluate_strings(
prediction=prediction, reference=reference
)
# Again only 1 character flipped
pytest.approx(1 / len(reference.replace(" ", "")), result["score"])
def test_json_distance_evaluator_evaluate_strings_list_same(
json_distance_evaluator: JsonEditDistanceEvaluator,
) -> None:
prediction = '[{"a": 1, "b": 2}, {"a": 2, "b": 3}]'
reference = '[{"b": 2, "a": 1}, {"b": 3, "a": 2}]'
result = json_distance_evaluator._evaluate_strings(
prediction=prediction, reference=reference
)
assert result["score"] == 0
def test_json_distance_evaluator_evaluate_strings_list_diff_length(
json_distance_evaluator: JsonEditDistanceEvaluator,
) -> None:
prediction = '[{"a": 1, "b": 2}, {"a": 2, "b": 3}]'
reference = '[{"a": 1, "b": 2}]'
result = json_distance_evaluator._evaluate_strings(
prediction=prediction, reference=reference
)
pytest.approx(
len('{"a":2,"b":3}') / len(reference.replace(" ", "")), result["score"]
)
def test_json_distance_evaluator_evaluate_strings_custom_operator_equal() -> None:
"""Custom operator that returns 0.5 if strings are different."""
def custom_distance(a: str, b: str) -> float:
return 0.5 if a != b else 0.0
evaluator = JsonEditDistanceEvaluator(string_distance=custom_distance)
prediction = '{"a": "apple", "b": "banana"}'
reference = '{"a": "apple", "b": "berries"}'
result = evaluator._evaluate_strings(prediction=prediction, reference=reference)
assert result["score"] == 0.5