如何向集成添加标准测试
当为自己创建自定义类或在 LangChain 集成中发布时,添加标准测试以确保其按预期工作非常重要。本指南将向您展示如何为每种集成类型添加标准测试。
设置
首先,让我们安装 2 个依赖项
langchain-core
将定义我们要导入以定义自定义工具的接口。langchain-tests
将提供我们要使用的标准测试,以及运行它们所需的 pytest 插件。建议固定到最新版本:
由于新版本的 langchain-tests
中添加的测试可能会破坏您的 CI/CD 管道,我们建议固定 langchain-tests
的版本以避免意外更改。
- Poetry
- Pip
如果您遵循了之前的指南,您应该已经安装了这些依赖项!
poetry add langchain-core
poetry add --group test langchain-tests==<latest_version>
poetry install --with test
pip install -U langchain-core langchain-tests
# install current package in editable mode
pip install --editable .
添加和配置标准测试
langchain-tests
包中有 2 个命名空间
- 单元测试 (
langchain_tests.unit_tests
):旨在用于隔离测试组件,且无法访问外部服务 - 集成测试 (
langchain_tests.integration_tests
):旨在用于测试可以访问外部服务的组件(特别是组件旨在与之交互的外部服务)。
两种类型的测试都作为 pytest
基于类的测试套件 实现。
通过子类化每种类型的标准测试的基类(见下文),您将获得该类型的所有标准测试,并且可以覆盖测试套件用于配置测试的属性。
为了以与本指南相同的方式运行测试,我们建议在两个测试子目录下的测试文件中子类化这些类
tests/unit_tests
用于单元测试tests/integration_tests
用于集成测试
实施标准测试
在以下选项卡中,我们将展示如何为每种组件类型实施标准测试
- 聊天模型
- 向量存储
- 嵌入
- 工具
- 检索器
要为聊天模型配置标准测试,我们子类化 ChatModelUnitTests
和 ChatModelIntegrationTests
。在每个子类上,我们覆盖以下 @property
方法,以指定要测试的聊天模型和聊天模型的配置
属性 | 描述 |
---|---|
chat_model_class | 要测试的聊天模型的类 |
chat_model_params | 传递给聊天的参数 |
模型的构造函数 |
此外,聊天模型标准测试还测试一系列行为,从最基本的要求(生成对查询的响应)到可选功能,如多模态支持和工具调用。为了使测试运行成功
- 如果某个功能旨在由模型支持,则应通过测试;
- 如果某个功能不打算由模型支持,则应跳过。
“可选”功能的测试通过可以在测试模型子类上覆盖的一组属性来控制。
您可以在 单元测试 和 集成测试 的 API 参考中查看可配置功能的完整列表。
例如,要为图像输入启用集成测试,我们可以实现
@property
def supports_image_inputs(self) -> bool:
return True
在集成测试类上。
有关运行哪些测试、如何跳过每个测试以及每个测试的故障排除技巧的详细信息,请参见 API 参考。查看详细信息
单元测试示例
"""Test chat model integration."""
from typing import Type
from langchain_parrot_link.chat_models import ChatParrotLink
from langchain_tests.unit_tests import ChatModelUnitTests
class TestChatParrotLinkUnit(ChatModelUnitTests):
@property
def chat_model_class(self) -> Type[ChatParrotLink]:
return ChatParrotLink
@property
def chat_model_params(self) -> dict:
# These should be parameters used to initialize your integration for testing
return {
"model": "bird-brain-001",
"temperature": 0,
"parrot_buffer_length": 50,
}
集成测试示例
"""Test ChatParrotLink chat model."""
from typing import Type
from langchain_parrot_link.chat_models import ChatParrotLink
from langchain_tests.integration_tests import ChatModelIntegrationTests
class TestChatParrotLinkIntegration(ChatModelIntegrationTests):
@property
def chat_model_class(self) -> Type[ChatParrotLink]:
return ChatParrotLink
@property
def chat_model_params(self) -> dict:
# These should be parameters used to initialize your integration for testing
return {
"model": "bird-brain-001",
"temperature": 0,
"parrot_buffer_length": 50,
}
以下是如何为典型的向量存储配置标准测试(使用 ParrotVectorStore
作为占位符)
向量存储测试目前没有要配置的可选功能。
from typing import Generator
import pytest
from langchain_parrot_link.vectorstores import ParrotVectorStore
from langchain_core.vectorstores import VectorStore
from langchain_tests.integration_tests import VectorStoreIntegrationTests
class TestParrotVectorStore(VectorStoreIntegrationTests):
@pytest.fixture()
def vectorstore(self) -> Generator[VectorStore, None, None]: # type: ignore
"""Get an empty vectorstore for unit tests."""
store = ParrotVectorStore(self.get_embeddings())
# note: store should be EMPTY at this point
# if you need to delete data, you may do so here
try:
yield store
finally:
# cleanup operations, or deleting data
pass
配置测试包括为设置空向量存储和在测试运行结束后拆除向量存储实现 pytest fixtures。
Fixture | 描述 |
---|---|
vectorstore | 一个生成器,用于为单元测试生成空向量存储。向量存储在测试运行结束后被清理。 |
例如,下面是 Chroma 集成的 VectorStoreIntegrationTests
类
from typing import Generator
import pytest
from langchain_core.vectorstores import VectorStore
from langchain_tests.integration_tests.vectorstores import VectorStoreIntegrationTests
from langchain_chroma import Chroma
class TestChromaStandard(VectorStoreIntegrationTests):
@pytest.fixture()
def vectorstore(self) -> Generator[VectorStore, None, None]: # type: ignore
"""Get an empty vectorstore for unit tests."""
store = Chroma(embedding_function=self.get_embeddings())
try:
yield store
finally:
store.delete_collection()
pass
请注意,在初始 yield
之前,我们使用 embeddings 对象实例化向量存储。这是一个预定义的 “伪造”嵌入模型,它将为文档生成简短的任意向量。如果需要,您可以使用不同的嵌入对象。
在 finally
块中,我们调用将向量存储恢复到干净状态所需的任何特定于集成的逻辑。此逻辑在每次测试之间执行(例如,即使测试失败)。
有关运行哪些测试以及每个测试的故障排除技巧的详细信息,请参见 API 参考。
要为嵌入模型配置标准测试,我们子类化 EmbeddingsUnitTests
和 EmbeddingsIntegrationTests
。在每个子类上,我们覆盖以下 @property
方法,以指定要测试的嵌入模型和嵌入模型的配置
属性 | 描述 |
---|---|
embeddings_class | 要测试的嵌入模型的类 |
embedding_model_params | 传递给嵌入模型的构造函数的参数 |
有关运行哪些测试、如何跳过每个测试以及每个测试的故障排除技巧的详细信息,请参见 API 参考。查看详细信息
单元测试示例
"""Test embedding model integration."""
from typing import Type
from langchain_parrot_link.embeddings import ParrotLinkEmbeddings
from langchain_tests.unit_tests import EmbeddingsUnitTests
class TestParrotLinkEmbeddingsUnit(EmbeddingsUnitTests):
@property
def embeddings_class(self) -> Type[ParrotLinkEmbeddings]:
return ParrotLinkEmbeddings
@property
def embedding_model_params(self) -> dict:
return {"model": "nest-embed-001"}
集成测试示例
from typing import Type
from langchain_parrot_link.embeddings import ParrotLinkEmbeddings
from langchain_tests.integration_tests import EmbeddingsIntegrationTests
class TestParrotLinkEmbeddingsIntegration(EmbeddingsIntegrationTests):
@property
def embeddings_class(self) -> Type[ParrotLinkEmbeddings]:
return ParrotLinkEmbeddings
@property
def embedding_model_params(self) -> dict:
return {"model": "nest-embed-001"}
"""Test ParrotLink embeddings."""
from typing import Type
from langchain_parrot_link.embeddings import ParrotLinkEmbeddings
from langchain_tests.integration_tests import EmbeddingsIntegrationTests
class TestParrotLinkEmbeddingsIntegration(EmbeddingsIntegrationTests):
@property
def embeddings_class(self) -> Type[ParrotLinkEmbeddings]:
return ParrotLinkEmbeddings
@property
def embedding_model_params(self) -> dict:
return {"model": "nest-embed-001"}
要为工具配置标准测试,我们子类化 ToolsUnitTests
和 ToolsIntegrationTests
。在每个子类上,我们覆盖以下 @property
方法,以指定要测试的工具和工具的配置
属性 | 描述 |
---|---|
tool_constructor | 要测试的工具的构造函数,或实例化的工具。 |
tool_constructor_params | 传递给工具的参数(可选)。 |
tool_invoke_params_example | 传递给工具的 invoke 方法的参数示例。 |
如果您正在测试工具类并传递像 MyTool
这样的类给 tool_constructor
,您可以在 tool_constructor_params
中传递构造函数的参数。
如果您正在测试实例化的工具,您可以将实例化的工具传递给 tool_constructor
,并且不覆盖 tool_constructor_params
。
有关运行哪些测试、如何跳过每个测试以及每个测试的故障排除技巧的详细信息,请参见 API 参考。查看详细信息
from typing import Type
from langchain_parrot_link.tools import ParrotTool
from langchain_tests.unit_tests import ToolsUnitTests
class TestParrotMultiplyToolUnit(ToolsUnitTests):
@property
def tool_constructor(self) -> Type[ParrotTool]:
return ParrotTool
@property
def tool_constructor_params(self) -> dict:
# if your tool constructor instead required initialization arguments like
# `def __init__(self, some_arg: int):`, you would return those here
# as a dictionary, e.g.: `return {'some_arg': 42}`
return {}
@property
def tool_invoke_params_example(self) -> dict:
"""
Returns a dictionary representing the "args" of an example tool call.
This should NOT be a ToolCall dict - i.e. it should not
have {"name", "id", "args"} keys.
"""
return {"a": 2, "b": 3}
from typing import Type
from langchain_parrot_link.tools import ParrotTool
from langchain_tests.integration_tests import ToolsIntegrationTests
class TestParrotMultiplyToolIntegration(ToolsIntegrationTests):
@property
def tool_constructor(self) -> Type[ParrotTool]:
return ParrotTool
@property
def tool_constructor_params(self) -> dict:
# if your tool constructor instead required initialization arguments like
# `def __init__(self, some_arg: int):`, you would return those here
# as a dictionary, e.g.: `return {'some_arg': 42}`
return {}
@property
def tool_invoke_params_example(self) -> dict:
"""
Returns a dictionary representing the "args" of an example tool call.
This should NOT be a ToolCall dict - i.e. it should not
have {"name", "id", "args"} keys.
"""
return {"a": 2, "b": 3}
要为检索器配置标准测试,我们子类化 RetrieversUnitTests
和 RetrieversIntegrationTests
。在每个子类上,我们覆盖以下 @property
方法
属性 | 描述 |
---|---|
retriever_constructor | 要测试的检索器的类 |
retriever_constructor_params | 传递给检索器的构造函数的参数 |
retriever_query_example | 传递给检索器的 invoke 方法的查询示例 |
有关运行哪些测试以及每个测试的故障排除技巧的详细信息,请参见 API 参考。
from typing import Type
from langchain_parrot_link.retrievers import ParrotRetriever
from langchain_tests.integration_tests import (
RetrieversIntegrationTests,
)
class TestParrotRetriever(RetrieversIntegrationTests):
@property
def retriever_constructor(self) -> Type[ParrotRetriever]:
"""Get an empty vectorstore for unit tests."""
return ParrotRetriever
@property
def retriever_constructor_params(self) -> dict:
return {"k": 2}
@property
def retriever_query_example(self) -> str:
"""
Returns a str representing the "query" of an example retriever call.
"""
return "example query"
运行测试
您可以使用以下命令从项目根目录运行这些测试
- Poetry
- Pip
# run unit tests without network access
poetry run pytest --disable-socket --allow-unix-socket --asyncio-mode=auto tests/unit_tests
# run integration tests
poetry run pytest --asyncio-mode=auto tests/integration_tests
# run unit tests without network access
pytest --disable-socket --allow-unix-socket --asyncio-mode=auto tests/unit_tests
# run integration tests
pytest --asyncio-mode=auto tests/integration_tests
测试套件信息和故障排除
有关可用的标准测试套件的完整列表,以及有关包含哪些测试以及如何排除常见问题的信息,请参阅 标准测试 API 参考。
您可以在该 API 参考中列出的各个测试套件下查看故障排除指南。例如,此处是 ChatModelIntegrationTests.test_usage_metadata
的指南。