pytest-aitest:单元测试无法测试你的 MCP 服务器。AI 可以。

发布: (2026年2月13日 GMT+8 11:58)
9 分钟阅读
原文: Dev.to

I’m happy to help translate the article, but I need the full text you’d like translated. Could you please paste the content (excluding the source line you already provided) here? Once I have it, I’ll translate it into Simplified Chinese while preserving the formatting, markdown, and any code blocks or URLs.

我是这么硬着头皮学到的

我构建了两个 MCP 服务器——Excel MCP ServerWindows MCP Server。两者都有完善的测试套件,但一旦真实的 LLM 试图使用它们,就立刻崩溃。

我花了数周时间使用 GitHub Copilot 进行手动测试:打开聊天,输入提示,观察 LLM 选错工具,调整描述后再试。
有时设计根本就有问题,我追逐了好几周的“野鹅”,最后才意识到整个思路需要重新考虑。

失败模式总是相同的

#症状
1LLM 在 15 个听起来相似的选项中挑选了错误的工具
2当参数是 account 时,它传递了 {"account_id": "checking"}
3它完全忽略了系统提示
4它会询问用户 “Would you like me to do that?” 而不是直接执行

为什么? 因为我在测试 代码,而不是 AI 接口

对于 LLM 来说,你的 API 不仅仅是函数和类型——它是 工具描述、参数模式和系统提示。这才是模型实际读取的内容。

  • 没有编译器能捕获错误的工具描述。
  • 没有单元测试能验证 LLM 会选择正确的工具。
  • 如果你还注入了 Agent Skills——它们真的有帮助,还是会让情况更糟?LLM 真会按你想的那样表现吗?

(不,它们不会。)

介绍 pytest‑aitest

受 Dmytro Mykhaliev 的 agent‑benchmark 启发,pytest‑aitest 是一个 pytest 插件,让你能够在不新增任何 CLI 或语法的情况下编写 AI‑中心 的测试。它可以与现有的 fixtures、markers 以及 CI/CD 流程无缝配合。

工作原理

你的测试 就是一个提示。写下用户可能说的话,让 LLM 推断如何使用你的工具,然后对发生的事情进行断言。

# test_balance_query.py
from pytest_aitest import Agent, Provider, MCPServer

async def test_balance_query(aitest_run):
    agent = Agent(
        provider=Provider(model="azure/gpt-5-mini"),
        mcp_servers=[MCPServer(command=["python", "-m", "my_banking_server"])],
    )

    result = await aitest_run(agent, "What's my checking balance?")

    assert result.success
    assert result.tool_was_called("get_balance")

如果此测试失败,问题不在你的代码——而在你的 工具描述。LLM 未能弄清楚该调用哪个工具或传入什么参数。修改描述后重新运行。这就是 AI 接口的 TDD

async def test_transfer(aitest_run):
    result = await aitest_run(agent, "Move $200 from checking to savings")
    assert result.tool_was_called("transfer")

描述完善前后对比

# 前 — 过于模糊
@mcp.tool()
def transfer(from_acct: str, to_acct: str, amount: float) -> str:
    """Transfer money."""
# 后 — LLM 完全清楚该怎么做
@mcp.tool()
def transfer(from_account: str, to_account: str, amount: float) -> str:
    """Transfer money between accounts (checking, savings).
    Amount must be positive. Returns new balances for both accounts."""

再次运行——测试现在通过。

自动化故障分析

pytest‑aitest 不仅仅给出通过/失败的结果。它会启动 第二个 LLM,分析每一次失败并告诉你 为什么会失败以及如何改进。传统测试需要人工解释失败;这里 AI 为你完成这一步。

  • 报告会告诉你应该部署哪个模型,为什么它表现更好,以及需要修复的地方。
  • 它会分析成本效率、工具使用模式以及在所有配置下的提示有效性。
  • 未使用的工具?已标记。
  • 导致请求权限行为的提示?已解释。

查看完整示例报告 → (link placeholder)

比较配置

您可以针对相同的测试套件 测试多个配置

MODELS = ["gpt-5-mini", "gpt-4.1"]
PROMPTS = {"brief": "Be concise.", "detailed": "Explain your reasoning."}

AGENTS = [
    Agent(
        name=f"{model}-{prompt_name}",
        provider=Provider(model=f"azure/{model}"),
        mcp_servers=[banking_server],
        system_prompt=prompt,
    )
    for model in MODELS
    for prompt_name, prompt in PROMPTS.items()
]

@pytest.mark.parametrize("agent", AGENTS, ids=lambda a: a.name)
async def test_balance_query(aitest_run, agent):
    result = await aitest_run(agent, "What's my checking balance?")
    assert result.success

排行榜(通过率 → 成本)

Agent通过率Tokens成本
gpt-5-mini‑brief100 %747$0.002
gpt-4.1‑brief100 %560$0.008
gpt-5-mini‑detailed100 %1,203$0.004

部署方案: 使用 brief 提示的 gpt-5-mini —— 以最低成本实现 100 % 的通过率。

相同的模式同样适用于:

  • A/B 测试服务器版本(您的重构是否破坏了工具可发现性?)
  • 比较系统提示
  • 测量 Agent 技能的影响

基于会话的测试(对话流程)

真实用户不会只问一个问题;他们进行对话

@pytest.mark.session("banking-chat")
class TestBankingConversation:
    async def test_check_balance(self, aitest_run, agent):
        result = await aitest_run(agent, "What's my checking balance?")
        assert result.success

    async def test_transfer(self, aitest_run, agent):
        # Agent remembers we were talking about checking
        result = await aitest_run(agent, "Transfer $200 to savings")
        assert result.tool_was_called("transfer")

    async def test_verify(self, aitest_run, agent):
        # Agent remembers the transfer
        result = await aitest_run(agent, "What are my new balances?")
        assert result.success

测试共享会话历史,报告会展示完整的会话流程以及序列图。

谁受益?

受众好处
MCP 服务器作者验证 LLM 实际上能使用你的工具,而不仅仅是代码能运行
代理构建者找到通过你的测试套件的最便宜模型 + 提示组合
发布 AI 产品的团队在 CI/CD 中基于面向 LLM 的回归测试来控制部署
所有人通过 LiteLLM 与 100+ LLM 提供商合作 – Azure、OpenAI、Anthropic、Google、本地模型等。

TL;DR

测试是一个提示。LLM 是测试工具。报告告诉你需要修复什么。

传统测试验证你的代码是否工作pytest‑aitest 验证LLM 能够理解并使用你的代码。这两者不同,但都很重要。

pytest‑aitest

测试你的 AI 接口。 AI 分析你的结果。

一个用于 MCP 服务器、工具、提示和技能的测试驱动开发的 pytest 插件。先编写测试,让 AI 分析驱动你的设计。

为什么?

你的 MCP 服务器通过了所有单元测试。随后有 LLM 试图使用它时:

  • 选择了错误的工具,
  • 传入了垃圾参数,或
  • 忽略了你的系统提示。

因为你测试的是 代码,而不是 AI 接口

对于 LLM 来说,你的 API 包含:

  • 工具描述,
  • 架构,和
  • 提示

——而不是函数和类型。没有编译器能捕获错误的工具描述。没有 linter 能标记混乱的架构。传统测试无法验证它们。

工作原理

使用自然语言提示编写测试。Agent 将 LLM 与你的工具捆绑在一起——你对发生的事情进行断言:

from pytest_aitest import Agent, Provider, MCPServer

async def test_balance_query(aitest_run):
    agent = Agent(
        provider=Provider,
        # … configure your tools / server here …
    )
    # … write your natural‑language test here …

快速链接

欢迎贡献!开源且社区驱动。

0 浏览
Back to Blog

相关文章

阅读更多 »