Source code for langchain.evaluation.embedding_distance.base

"""使用嵌入向量比较两个模型输出的链条。"""
from enum import Enum
from typing import Any, Dict, List, Optional

import numpy as np
from langchain_core.callbacks.manager import (
    AsyncCallbackManagerForChainRun,
    CallbackManagerForChainRun,
    Callbacks,
)
from langchain_core.embeddings import Embeddings
from langchain_core.pydantic_v1 import Field, root_validator

from langchain.chains.base import Chain
from langchain.evaluation.schema import PairwiseStringEvaluator, StringEvaluator
from langchain.schema import RUN_KEY


def _embedding_factory() -> Embeddings:
    """创建一个嵌入对象。
返回:
    Embeddings:创建的嵌入对象。
"""
    # Here for backwards compatibility.
    # Generally, we do not want to be seeing imports from langchain community
    # or partner packages in langchain.
    try:
        from langchain_openai import OpenAIEmbeddings
    except ImportError:
        try:
            from langchain_community.embeddings.openai import OpenAIEmbeddings
        except ImportError:
            raise ImportError(
                "Could not import OpenAIEmbeddings. Please install the "
                "OpenAIEmbeddings package using `pip install langchain-openai`."
            )
    return OpenAIEmbeddings()


[docs]class EmbeddingDistance(str, Enum): """嵌入距离度量。 属性: COSINE: 余弦距离度量。 EUCLIDEAN: 欧氏距离度量。 MANHATTAN: 曼哈顿距离度量。 CHEBYSHEV: 切比雪夫距离度量。 HAMMING: 汉明距离度量。""" COSINE = "cosine" EUCLIDEAN = "euclidean" MANHATTAN = "manhattan" CHEBYSHEV = "chebyshev" HAMMING = "hamming"
class _EmbeddingDistanceChainMixin(Chain): """共享功能,用于嵌入距离评估器。 属性: embeddings (Embeddings): 用于将输出向量化的嵌入对象。 distance_metric (EmbeddingDistance): 用于比较嵌入的距离度量标准。""" embeddings: Embeddings = Field(default_factory=_embedding_factory) distance_metric: EmbeddingDistance = Field(default=EmbeddingDistance.COSINE) @root_validator(pre=False) def _validate_tiktoken_installed(cls, values: Dict[str, Any]) -> Dict[str, Any]: """验证TikTok库是否已安装。 参数: values(Dict[str, Any]):要验证的值。 返回: Dict[str, Any]:已验证的值。 """ embeddings = values.get("embeddings") types_ = [] try: from langchain_openai import OpenAIEmbeddings types_.append(OpenAIEmbeddings) except ImportError: pass try: from langchain_community.embeddings.openai import OpenAIEmbeddings types_.append(OpenAIEmbeddings) except ImportError: pass if not types_: raise ImportError( "Could not import OpenAIEmbeddings. Please install the " "OpenAIEmbeddings package using `pip install langchain-openai`." ) if isinstance(embeddings, tuple(types_)): try: import tiktoken # noqa: F401 except ImportError: raise ImportError( "The tiktoken library is required to use the default " "OpenAI embeddings with embedding distance evaluators." " Please either manually select a different Embeddings object" " or install tiktoken using `pip install tiktoken`." ) return values class Config: """允许嵌入物不经验证。""" arbitrary_types_allowed: bool = True @property def output_keys(self) -> List[str]: """返回链的输出键。 返回: List[str]:输出键。 """ return ["score"] def _prepare_output(self, result: dict) -> dict: parsed = {"score": result["score"]} if RUN_KEY in result: parsed[RUN_KEY] = result[RUN_KEY] return parsed def _get_metric(self, metric: EmbeddingDistance) -> Any: """获取给定度量名称的度量函数。 参数: metric (EmbeddingDistance): 度量名称。 返回: Any: 度量函数。 """ metrics = { EmbeddingDistance.COSINE: self._cosine_distance, EmbeddingDistance.EUCLIDEAN: self._euclidean_distance, EmbeddingDistance.MANHATTAN: self._manhattan_distance, EmbeddingDistance.CHEBYSHEV: self._chebyshev_distance, EmbeddingDistance.HAMMING: self._hamming_distance, } if metric in metrics: return metrics[metric] else: raise ValueError(f"Invalid metric: {metric}") @staticmethod def _cosine_distance(a: np.ndarray, b: np.ndarray) -> np.ndarray: """计算两个向量之间的余弦距离。 参数: a (np.ndarray): 第一个向量。 b (np.ndarray): 第二个向量。 返回: np.ndarray: 余弦距离。 """ try: from langchain_community.utils.math import cosine_similarity except ImportError: raise ImportError( "The cosine_similarity function is required to compute cosine distance." " Please install the langchain-community package using" " `pip install langchain-community`." ) return 1.0 - cosine_similarity(a, b) @staticmethod def _euclidean_distance(a: np.ndarray, b: np.ndarray) -> np.floating: """计算两个向量之间的欧几里德距离。 参数: a (np.ndarray): 第一个向量。 b (np.ndarray): 第二个向量。 返回: np.floating: 欧几里德距离。 """ return np.linalg.norm(a - b) @staticmethod def _manhattan_distance(a: np.ndarray, b: np.ndarray) -> np.floating: """计算两个向量之间的曼哈顿距离。 参数: a (np.ndarray): 第一个向量。 b (np.ndarray): 第二个向量。 返回: np.floating: 曼哈顿距离。 """ return np.sum(np.abs(a - b)) @staticmethod def _chebyshev_distance(a: np.ndarray, b: np.ndarray) -> np.floating: """计算两个向量之间的切比雪夫距离。 参数: a (np.ndarray): 第一个向量。 b (np.ndarray): 第二个向量。 返回: np.floating: 切比雪夫距离。 """ return np.max(np.abs(a - b)) @staticmethod def _hamming_distance(a: np.ndarray, b: np.ndarray) -> np.floating: """计算两个向量之间的汉明距离。 参数: a(np.ndarray):第一个向量。 b(np.ndarray):第二个向量。 返回: np.floating:汉明距离。 """ return np.mean(a != b) def _compute_score(self, vectors: np.ndarray) -> float: """根据距离度量计算得分。 参数: vectors (np.ndarray): 输入向量。 返回: float: 计算得分。 """ metric = self._get_metric(self.distance_metric) score = metric(vectors[0].reshape(1, -1), vectors[1].reshape(1, -1)).item() return score
[docs]class EmbeddingDistanceEvalChain(_EmbeddingDistanceChainMixin, StringEvaluator): """使用嵌入距离来评分预测和参考之间的语义差异。 示例: >>> chain = EmbeddingDistanceEvalChain() >>> result = chain.evaluate_strings(prediction="Hello", reference="Hi") >>> print(result) {'score': 0.5}""" @property def requires_reference(self) -> bool: """返回链是否需要引用。 返回: 布尔值:如果需要引用,则为True,否则为False。 """ return True @property def evaluation_name(self) -> str: return f"embedding_{self.distance_metric.value}_distance" @property def input_keys(self) -> List[str]: """返回链的输入键。 返回: List[str]:输入键。 """ return ["prediction", "reference"] def _call( self, inputs: Dict[str, Any], run_manager: Optional[CallbackManagerForChainRun] = None, ) -> Dict[str, Any]: """计算预测和参考之间的得分。 参数: inputs(Dict[str, Any]):输入数据。 run_manager(Optional[CallbackManagerForChainRun],可选): 回调管理器。 返回: Dict[str, Any]:计算得分。 """ vectors = np.array( self.embeddings.embed_documents([inputs["prediction"], inputs["reference"]]) ) score = self._compute_score(vectors) return {"score": score} async def _acall( self, inputs: Dict[str, Any], run_manager: Optional[AsyncCallbackManagerForChainRun] = None, ) -> Dict[str, Any]: """异步计算预测和参考值的得分。 参数: inputs(Dict[str, Any]):输入数据。 run_manager(AsyncCallbackManagerForChainRun,可选): 回调管理器。 返回: Dict[str, Any]:计算得分。 """ embedded = await self.embeddings.aembed_documents( [inputs["prediction"], inputs["reference"]] ) vectors = np.array(embedded) score = self._compute_score(vectors) return {"score": score} def _evaluate_strings( self, *, prediction: str, reference: Optional[str] = None, callbacks: Callbacks = None, tags: Optional[List[str]] = None, metadata: Optional[Dict[str, Any]] = None, include_run_info: bool = False, **kwargs: Any, ) -> dict: """评估预测和参考之间的嵌入距离。 参数: prediction (str): 第一个模型的输出字符串。 reference (str): 参考字符串(必填) callbacks (Callbacks, optional): 要使用的回调。 **kwargs (Any): 附加关键字参数。 返回: dict: 包含以下内容的字典: - score: 两个预测之间的嵌入距离。 """ result = self( inputs={"prediction": prediction, "reference": reference}, callbacks=callbacks, tags=tags, metadata=metadata, include_run_info=include_run_info, ) return self._prepare_output(result) async def _aevaluate_strings( self, *, prediction: str, reference: Optional[str] = None, callbacks: Callbacks = None, tags: Optional[List[str]] = None, metadata: Optional[Dict[str, Any]] = None, include_run_info: bool = False, **kwargs: Any, ) -> dict: """异步评估预测和参考之间的嵌入距离。 参数: prediction(str):第一个模型的输出字符串。 reference(str):第二个模型的输出字符串。 callbacks(Callbacks,可选):要使用的回调。 **kwargs(Any):额外的关键字参数。 返回: dict:包含以下内容的字典: - score:两个预测之间的嵌入距离。 """ result = await self.acall( inputs={"prediction": prediction, "reference": reference}, callbacks=callbacks, tags=tags, metadata=metadata, include_run_info=include_run_info, ) return self._prepare_output(result)
[docs]class PairwiseEmbeddingDistanceEvalChain( _EmbeddingDistanceChainMixin, PairwiseStringEvaluator ): """使用嵌入距离来评估两个预测之间的语义差异。 示例: >>> chain = PairwiseEmbeddingDistanceEvalChain() >>> result = chain.evaluate_string_pairs(prediction="Hello", prediction_b="Hi") >>> print(result) {'score': 0.5}""" @property def input_keys(self) -> List[str]: """返回链的输入键。 返回: List[str]:输入键。 """ return ["prediction", "prediction_b"] @property def evaluation_name(self) -> str: return f"pairwise_embedding_{self.distance_metric.value}_distance" def _call( self, inputs: Dict[str, Any], run_manager: Optional[CallbackManagerForChainRun] = None, ) -> Dict[str, Any]: """计算两个预测的得分。 参数: inputs(Dict[str, Any]):输入数据。 run_manager(CallbackManagerForChainRun,可选): 回调管理器。 返回: Dict[str, Any]:计算得分。 """ vectors = np.array( self.embeddings.embed_documents( [inputs["prediction"], inputs["prediction_b"]] ) ) score = self._compute_score(vectors) return {"score": score} async def _acall( self, inputs: Dict[str, Any], run_manager: Optional[AsyncCallbackManagerForChainRun] = None, ) -> Dict[str, Any]: """异步计算两个预测的得分。 参数: inputs(Dict[str, Any]):输入数据。 run_manager(AsyncCallbackManagerForChainRun,可选): 回调管理器。 返回: Dict[str, Any]:计算得分。 """ embedded = await self.embeddings.aembed_documents( [inputs["prediction"], inputs["prediction_b"]] ) vectors = np.array(embedded) score = self._compute_score(vectors) return {"score": score} def _evaluate_string_pairs( self, *, prediction: str, prediction_b: str, callbacks: Callbacks = None, tags: Optional[List[str]] = None, metadata: Optional[Dict[str, Any]] = None, include_run_info: bool = False, **kwargs: Any, ) -> dict: """评估两个预测之间的嵌入距离。 参数: prediction (str): 第一个模型的输出字符串。 prediction_b (str): 第二个模型的输出字符串。 callbacks (Callbacks, optional): 要使用的回调。 tags (List[str], optional): 应用于跟踪的标签。 metadata (Dict[str, Any], optional): 应用于元数据的元数据。 **kwargs (Any): 其他关键字参数。 返回: dict: 包含以下内容的字典: - score: 两个预测之间的嵌入距离。 """ result = self( inputs={"prediction": prediction, "prediction_b": prediction_b}, callbacks=callbacks, tags=tags, metadata=metadata, include_run_info=include_run_info, ) return self._prepare_output(result) async def _aevaluate_string_pairs( self, *, prediction: str, prediction_b: str, callbacks: Callbacks = None, tags: Optional[List[str]] = None, metadata: Optional[Dict[str, Any]] = None, include_run_info: bool = False, **kwargs: Any, ) -> dict: """异步评估两个预测之间的嵌入距离 参数: prediction (str): 第一个模型的输出字符串。 prediction_b (str): 第二个模型的输出字符串。 callbacks (Callbacks, optional): 要使用的回调。 tags (List[str], optional): 应用于跟踪的标签 metadata (Dict[str, Any], optional): 应用于跟踪的元数据 **kwargs (Any): 附加关键字参数。 返回: dict: 包含以下内容的字典: - score: 两个预测之间的嵌入距离。 """ result = await self.acall( inputs={"prediction": prediction, "prediction_b": prediction_b}, callbacks=callbacks, tags=tags, metadata=metadata, include_run_info=include_run_info, ) return self._prepare_output(result)