进阶主题

MCP 评估

使用 Evalite 和 AI SDK MCP 客户端评估 MCP 工具和工作流。

概述

评估(Evals)可帮助您验证 LLM 是否正确调用了您的 MCP 工具。本指南展示了如何使用 AI SDK MCP 客户端配合 Evalite 运行工具调用评估。

该方法保持库无关性,Evalite 仅作为示例运行器。您可以将这些模式适配到其他评估框架中。

提示词
使用 Evalite 为我的 Nuxt 应用 (@nuxtjs/mcp-toolkit) 设置 MCP 评估。

1. 安装依赖:pnpm add -D evalite vitest @ai-sdk/mcp ai
2. 在 package.json 中添加评估脚本:"eval": "evalite" 和 "eval:ui": "evalite watch"
3. 在 .env 中设置 AI 提供商 API 密钥和 MCP_URL=http://localhost:3000/mcp
4. 创建 test/mcp.eval.ts 并编写 evalite() 测试用例
5. 每个测试用例包含一个输入(自然语言提示词)和预期的工具调用(例如 [{ toolName: 'my-tool', input: { ... } }])
6. 使用 @ai-sdk/mcp 中的 experimental_createMCPClient 连接到 MCP 服务器
7. 使用 ai 中的 generateText 配合 MCP 工具测试工具选择
8. 使用 evalite/scorers 中的 toolCallAccuracy 进行评分
9. 先启动开发服务器 (pnpm dev),然后运行 pnpm eval 或 pnpm eval:ui 打开可视化界面

文档:https://mcp-toolkit.nuxt.dev/advanced/evals
如需查看实际示例,请参阅 nuxt.com MCP 评估

前置条件

  • 本地运行的 MCP 服务器(例如,启用模块后运行 pnpm dev
  • 模型提供商 API 密钥(AI Gateway、OpenAI 等)

设置

安装依赖

安装 Evalite、Vitest 和 AI SDK 相关包:

pnpm add -D evalite vitest @ai-sdk/mcp ai

添加评估脚本

将以下脚本添加到您的 package.json 中:

package.json
{
  "scripts": {
    "eval": "evalite",
    "eval:ui": "evalite watch"
  }
}

配置环境变量

创建一个 .env 文件,填入您的 AI 提供商密钥和 MCP 端点:

.env
# AI 提供商(AI Gateway 示例)
AI_GATEWAY_API_KEY=your_key

# 开发服务器暴露的 MCP 端点
MCP_URL=http://localhost:3000/mcp

编写您的第一个评估

test/ 目录中创建一个评估文件:

test/mcp.eval.ts
import { experimental_createMCPClient as createMCPClient } from '@ai-sdk/mcp'
import { generateText } from 'ai'
import { evalite } from 'evalite'
import { toolCallAccuracy } from 'evalite/scorers'

// AI Gateway 模型格式:provider/model-name
const model = 'openai/gpt-4o-mini'
const MCP_URL = process.env.MCP_URL ?? 'http://localhost:3000/mcp'

evalite('BMI Calculator', {
  data: async () => [
    {
      input: 'Calculate BMI for someone who weighs 70kg and is 1.75m tall',
      expected: [{ toolName: 'calculate-bmi', input: { weightKg: 70, heightM: 1.75 } }],
    },
  ],
  task: async (input) => {
    const mcp = await createMCPClient({ transport: { type: 'http', url: MCP_URL } })
    try {
      const result = await generateText({
        model,
        prompt: input,
        tools: await mcp.tools(),
      })
      return result.toolCalls ?? []
    }
    finally {
      await mcp.close()
    }
  },
  scorers: [({ output, expected }) => toolCallAccuracy({ actualCalls: output, expectedCalls: expected })],
})

运行评估

首先确保您的 MCP 服务器正在运行:

pnpm dev

然后在另一个终端中运行您的评估:

pnpm eval

或者启动 Evalite UI 以使用可视化界面:

pnpm eval:ui

UI 界面位于 http://localhost:3006,显示每次评估的追踪信息、评分、输入和输出。

项目结构

我们建议将评估文件放在项目根目录的 test/ 目录中:

your-project/
├── server/
│   └── mcp/
│       ├── tools/
│       │   └── calculate-bmi.ts
│       ├── resources/
│       └── prompts/
├── test/
│   └── mcp.eval.ts          # Your MCP eval tests
├── nuxt.config.ts
└── package.json
默认情况下,Evalite 会查找带有 .eval.ts 扩展名的文件。

编写高效的评估

测试工具选择

验证模型是否选择了正确的工具:

test/mcp.eval.ts
evalite('Tool Selection', {
  data: async () => [
    {
      input: 'List all available documentation pages',
      expected: [{ toolName: 'list-pages' }],
    },
    {
      input: 'Show me the installation guide',
      expected: [{ toolName: 'get-page', input: { path: '/getting-started/installation' } }],
    },
  ],
  task: async (input) => {
    const mcp = await createMCPClient({ transport: { type: 'http', url: MCP_URL } })
    try {
      const result = await generateText({
        model,
        prompt: input,
        tools: await mcp.tools(),
      })
      return result.toolCalls ?? []
    }
    finally {
      await mcp.close()
    }
  },
  scorers: [({ output, expected }) => toolCallAccuracy({ actualCalls: output, expectedCalls: expected })],
})

测试多步骤工作流

对于需要多次工具调用的工作流,请增加 maxSteps

test/mcp.eval.ts
evalite('Multi-Step Workflows', {
  data: async () => [
    {
      input: 'Find the installation page and show me its content',
      expected: [
        { toolName: 'list-pages' },
        { toolName: 'get-page', input: { path: '/getting-started/installation' } },
      ],
    },
  ],
  task: async (input) => {
    const mcp = await createMCPClient({ transport: { type: 'http', url: MCP_URL } })
    try {
      const result = await generateText({
        model,
        prompt: input,
        tools: await mcp.tools(),
        maxSteps: 5, // 允许多次工具调用
      })
      return result.toolCalls ?? []
    }
    finally {
      await mcp.close()
    }
  },
  scorers: [({ output, expected }) => toolCallAccuracy({ actualCalls: output, expectedCalls: expected })],
})

分组相关评估

按功能或工具类别组织评估:

test/mcp.eval.ts
// 文档工具
evalite('Documentation Tools', {
  data: async () => [
    { input: 'List all docs', expected: [{ toolName: 'list-pages' }] },
    { input: 'Get the intro page', expected: [{ toolName: 'get-page' }] },
  ],
  // ...
})

// API 工具
evalite('API Tools', {
  data: async () => [
    { input: 'Fetch user data', expected: [{ toolName: 'get-user' }] },
    { input: 'Create a new post', expected: [{ toolName: 'create-post' }] },
  ],
  // ...
})

提示

  • 保持提示词具体明确,以便模型选择预期的工具
  • 使用真实的输入,匹配用户提出请求的实际表达方式
  • 先从正常路径(happy-path)用例开始,然后再添加边界情况
  • 测试参数提取,在提示词中包含具体的值
  • 在部署前运行评估,以捕获工具行为中的回归问题