趋近智
为LangChain链设置基本测试,涉及验证其结构完整性和预期流程。这种方法不同于评估LLM输出的质量,后者通常使用专门的评估方法。我们将使用流行的Python测试框架 pytest 和模拟技术,以便在测试期间将链与实际的LLM API调用隔离。
设想我们有一个简单的LangChain链,设计用于接收一段文本并将其总结为三个要点。它可能包含:
PromptTemplate 来指导LLM。OutputParser (也许是 SimpleJsonOutputParser 或自定义的)来构建要点。以下是我们链的结构,使用LangChain表达式语言(LCEL):
# 假设已导入必要的模块:ChatOpenAI, PromptTemplate, StrOutputParser, JsonOutputParser 等。
# 假设 OPENAI_API_KEY 已在环境变量中设置
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from operator import itemgetter
# 简化示例 - 实际链可能使用 JsonOutputParser 以获得更好的结构
prompt_template = ChatPromptTemplate.from_template(
"Summarize the following text into exactly three concise bullet points:\n\n{text}\n\nFormat the output as a numbered list."
)
model = ChatOpenAI(model="gpt-3.5-turbo") # 或您偏好的模型
output_parser = StrOutputParser() # 本示例的简单解析器
# 定义链
summary_chain = (
{"text": itemgetter("text")}
| prompt_template
| model
| output_parser
)
# 示例用法(不属于测试本身)
# input_text = "Large Language Models are transforming industries by enabling natural language interaction..."
# result = summary_chain.invoke({"text": input_text})
# print(result)
首先,请确保您已安装 pytest 和 pytest-mock:
pip install pytest pytest-mock langchain langchain_openai python-dotenv
我们将把测试组织在一个单独的文件中,例如 test_summary_chain.py。我们还需要一种安全管理API密钥的方法;使用环境变量(以及可能通过 python-dotenv 加载的 .env 文件用于本地测试)是常见做法。
在测试中直接调用LLM API会使测试变慢、成本高昂,并可能导致非确定性结果。对链结构进行单元和集成测试的主要思想是模拟LLM调用。我们希望验证我们的提示是否正确构建,并且链能适当地处理LLM的预期响应格式。
Python的内置 unittest.mock 库(或 pytest-mock 提供的 mocker fixture)非常适合此目的。
我们来创建 test_summary_chain.py:
import pytest
from unittest.mock import MagicMock # 用于创建模拟对象
from operator import itemgetter
# 假设您的链定义在名为 `summary_chain_module.py` 的文件中
from summary_chain_module import summary_chain, prompt_template, model, output_parser
# 测试提示模板格式化
def test_prompt_template_formatting():
"""验证提示模板是否正确插入文本。"""
sample_text = "This is sample input text."
expected_prompt_value = "Summarize the following text into exactly three concise bullet points:\n\nThis is sample input text.\n\nFormat the output as a numbered list."
# 创建一个等效的 RunnablePassthrough 用于测试模板部分
prompt_part = {"text": itemgetter("text")} | prompt_template
result = prompt_part.invoke({"text": sample_text})
# ChatPromptTemplate 的结果具有 'to_string()' 方法
assert result.to_string() == expected_prompt_value
# 使用模拟LLM测试整个链
def test_summary_chain_with_mock_llm(mocker): # 使用 pytest-mock 的 'mocker' fixture
"""验证链是否正确处理模拟的LLM响应。"""
sample_text = "This is the text to be summarized."
mock_llm_output = "1. First point.\n2. Second point.\n3. Third point."
# 模拟链中 'model' 实例的 'invoke' 方法
# 我们找到 'model' 在哪里使用(在 summary_chain_module 中)并在那里进行修补。
mock_model_invoke = mocker.patch('summary_chain_module.model.invoke')
mock_model_invoke.return_value = MagicMock(content=mock_llm_output) # 如果需要,模拟 AIMessage 结构,这里 StrOutputParser 直接期望字符串或带有 .content 的 AIMessage
# 调用实际的链
result = summary_chain.invoke({"text": sample_text})
# 断言提示已正确传递给模拟的模型
# 模拟函数第一次调用的第一个参数
call_args = mock_model_invoke.call_args[0][0]
expected_prompt = prompt_template.invoke({"text": sample_text})
assert call_args == expected_prompt
# 断言最终输出是经解析器处理的模拟LLM输出
assert result == mock_llm_output
# 测试输出解析器逻辑(如果它更复杂)
# 对于 StrOutputParser,没有太多可测试的,但如果使用 JsonOutputParser:
# def test_output_parser():
# mock_llm_response_content = '{"summary": ["Point 1", "Point 2", "Point 3"]}'
# # 假设 json_output_parser = JsonOutputParser(...)
# # parsed_output = json_output_parser.parse(mock_llm_response_content)
# # assert parsed_output == {"summary": ["Point 1", "Point 2", "Point 3"]}
导航到包含 test_summary_chain.py 的目录,并在终端中运行 pytest:
pytest
您应该会看到指示测试通过或失败的输出。
这些测试成功验证了:
test_prompt_template_formatting 确保我们的模板正确地整合了输入变量。test_summary_chain_with_mock_llm 确认输入通过提示模板流向(模拟的)模型,并且(模拟的)模型的输出由输出解析器正确处理。它检查链内的连接和数据流。请记住,这些测试不评估 mock_llm_output 是否是良好的摘要。这需要前面讨论过的评估策略,例如使用评估数据集,与参考摘要进行比较(例如ROUGE分数),或采用基于LLM的评估方法。
这种做法构成了测试的一个基本层面,确保您的链在进行更复杂的质量评估之前结构是健全的。它在开发周期的早期就能捕获逻辑、解析和组件集成中的错误。
简洁的语法。内置调试功能。从第一天起就可投入生产。
为 ApX 背后的 AI 系统而构建
这部分内容有帮助吗?
© 2026 ApX Machine Learning用心打造