集成测试用于验证 Agent 能否与模型 API 和外部服务正确协作。不同于使用伪实现和模拟对象的单元测试,集成测试会进行真实的网络调用,以确认组件能够协同工作、凭证有效,并且延迟表现可接受。 由于 LLM 响应具有非确定性,集成测试需要采用不同于传统软件测试的策略。本指南介绍如何为 Agent 组织、编写和运行集成测试。有关为 LangChain 本身贡献代码时使用的通用测试基础设施,请参阅贡献代码。

分离单元测试和集成测试

集成测试速度较慢,并且需要 API 凭证,因此请将它们与单元测试分开。这样可以让你在每次变更时运行快速的单元测试,并将集成测试留给 CI 或部署前检查。 使用文件命名约定分离集成测试。将集成测试文件命名为 *.int.test.ts,并配置 vitest,使其从默认运行中排除这些文件:
vitest.config.ts
向 package.json 添加脚本:
显式运行集成测试:

管理 API 密钥

集成测试需要真实 API 凭证。请从环境变量加载凭证,避免将密钥提交到源代码管理系统。 将 dotenv/config 添加为 vitest 设置文件,使环境变量自动从 .env 加载:
vitest.config.ts
.env
缺少密钥时跳过测试:
将 .env 添加到 .gitignore,避免提交凭证。在 CI 中,通过提供商的密钥管理机制注入 secrets,例如 GitHub Actions secrets。

断言结构,而不是内容

LLM 响应在不同运行之间会变化。请不要断言精确的输出字符串,而是验证响应的结构属性:消息类型、工具调用名称、参数形状和消息数量。
此示例使用自定义测试匹配器。请参阅下方部分了解设置方式和完整匹配器参考。
如需更严格的执行轨迹断言,请使用 AgentEvals 评估器。它支持 unordered 和 superset 等模糊匹配模式。

使用自定义测试匹配器

langchain 提供了自定义 vitest 匹配器,用于提高结构断言的可读性,并在失败时生成清晰的错误消息。请在设置文件中注册一次,之后它们就能在每个 expect() 调用中使用。

设置

添加一个 vitest 设置文件,用 LangChain 匹配器扩展 expect:
vitest.setup.ts
在 vitest 配置中引用该文件:
vitest.config.ts
TypeScript 类型会自动包含,因此无需额外配置自动补全。

检查消息类型

每个消息类都有对应的匹配器:toBeHumanMessage()、toBeAIMessage()、toBeSystemMessage() 和 toBeToolMessage()。不传参数时只检查类型,也可以传入字符串以同时匹配内容:
传入对象可匹配特定字段:

断言工具调用

以下三个匹配器可用于断言 AIMessage 上的工具调用:

断言工具消息

toHaveToolMessages() 接收完整消息数组,并按顺序检查其中的 ToolMessage 实例:

断言中断和结构化响应

toHaveBeenInterrupted() 检查 LangGraph interrupt 结果中是否存在 __interrupt__ 字段。传入一个值可匹配中断载荷:
toHaveStructuredResponse() 检查结果中是否存在 structuredResponse 字段。传入对象可匹配特定字段:

匹配器参考

降低成本和延迟

调用 LLM API 的集成测试会产生真实成本。以下做法有助于让测试套件保持快速且成本可控:
  • 使用较小的模型:对于只需要验证工具调用和响应结构的测试,使用 gemini-3.1-flash-lite 或等效模型。
  • 设置 maxTokens:限制响应长度,避免生成较长且昂贵的补全。
  • 限制测试范围:每个测试只测试一种行为。如果单轮测试足够,请避免串联多次 LLM 调用的端到端场景。
  • 选择性运行:使用上文中的测试分离方法,只在 CI 或部署前运行集成测试,而不是在每次保存文件时运行。

后续步骤

了解如何在 Evals 中使用确定性匹配或 LLM-as-judge 评估器评估 Agent 执行轨迹。