如何将标准测试添加到集成中
当为自己创建自定义类或发布到LangChain集成中时,添加标准测试以确保其按预期工作非常重要。本指南将向您展示如何为每种集成类型添加标准测试。
设置
首先,让我们安装2个依赖项:
langchain-core
将定义我们想要导入的接口,以定义我们的自定义工具。langchain-tests
将提供我们想要使用的标准测试,以及运行这些测试所需的pytest插件。建议固定到最新版本:
因为在langchain-tests
的新版本中添加的测试可能会破坏您的CI/CD流水线,我们建议固定langchain-tests
的版本以避免意外的更改。
- 诗歌
- 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,用于设置一个空的向量存储,并在测试运行结束后拆除向量存储。
夹具 | 描述 |
---|---|
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
之前,我们使用一个嵌入对象实例化了向量存储。这是一个预定义的“假”嵌入模型,它将为文档生成短的、任意的向量。如果需要,您可以使用不同的嵌入对象。
在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"
运行测试
您可以从项目根目录运行以下命令来执行这些操作
- 诗歌
- 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
的指南。