匠人学院 JR Academy学AI来匠人
匠人学院 JR Academy学AI来匠人

Follow Us

linkedinfacebooktwitterinstagramweiboyoutubebilibilitiktokxigua

We Accept

/image/layout/pay-paypal.png/image/layout/pay-visa.png/image/layout/pay-master-card.png/image/layout/pay-airwallex.png/image/layout/pay-alipay.png
EN

关于公司

关于我们元宇宙课堂新闻资讯匠人工作成为导师匠人导师联系我们匠人商店J3.Club

匠人资源

工作内推匠人活动1对1私教行业白皮书线上学习平台面试中心分享面试经验Internship会员中心

AI 工具

AI 工具箱考证匠 Cert Master求职匠 Job Hunter牛小匠 UniMate AI

AI 学习方向

全部学习方向AI EngineerContext EngineeringVibe CodingPrompt MasterAI BuilderAI 产品经理Python 入门

AI 应用提效

AI 办公提效AI 数据分析AI 财务AI 内容创作AI 视觉创作前端开发Hermes AgentOpenClaw 本地智能体

大学资源

墨尔本大学昆士兰大学新南威尔士大学悉尼大学莫那什大学阿德莱德大学RMITQUTUTS

少儿 AI 教育

Airbotix 少儿 AI 编程澳洲家长实用资料库NAPLAN 成绩单怎么看My School 学校数据指南悉尼私校学费 2026少儿编程课程与训练营

移民服务

澳洲移民技术移民189/190/491雇主担保482/186/494投资移民188/888英国移民美国移民加拿大移民

企业合作

P3职业孵化器Enterprise (EN)企业培训实习合作招聘合作申请合作

求职代理

岗位代投职位监控LinkedIn代运营LinkedIn人脉代加了解P3项目

匠人支持

FAQsTerms & ConditionsPrivacy PolicyCancellation & Refund PolicySite map

Top Categories

Web全栈班DevOps项目班数据工程全栈班数据分析项目班编程入门班Business Analyst实习算法集训营

求职就业

BA和产品经理实习数据科学实习数据分析实习Marketing实习简历修改面试指导导师指导VIP

地址

Level 10b, 144 Edward Street, Brisbane CBD(Headquarter)
Level 2, 171 La Trobe St, Melbourne VIC 3000
四川省成都市武侯区桂溪街道天府大道中段500号D5东方希望天祥广场B座45A13号
Business Hub, 155 Waymouth St, Adelaide SA 5000

联系方式

hello@jiangren.com.au0421-672-555

Disclaimer

footer-disclaimerfooter-disclaimer

JR Academy acknowledges Traditional Owners of Country throughout Australia and recognises the continuing connection to lands, waters and communities. We pay our respect to Aboriginal and Torres Strait Islander cultures; and to Elders past and present. Aboriginal and Torres Strait Islander peoples should be aware that this website may contain images or names of people who have since passed away.

匠人学院网站上的所有内容,包括课程材料、徽标和匠人学院网站上提供的信息,均受澳大利亚政府知识产权法的保护。严禁未经授权使用、销售、分发、复制或修改。违规行为可能会导致法律诉讼。通过访问我们的网站,您同意尊重我们的知识产权。JR Academy Pty Ltd 保留所有权利,包括专利、商标和版权。任何侵权行为都将受到法律追究。查看用户协议

© 2017-2026 JR Academy Pty Ltd. All rights reserved.

ABN 26621887572

首页/资源中心/文章详情
JR Academy · Blog职业洞察

Vercel AI SDK 实战指南 — 测试与可观测性:生产级 AI 应用的必修课

用 MockLanguageModelV4 写确定性单元测试,用 OpenTelemetry + Langfuse 监控生产环境每次模型调用的成本与延迟

发布日期2026-10-15
阅读时长3 分钟
作者

快速导航

  • 为什么 AI 应用需要特殊的测试策略
  • 测试工具安装
  • 用 MockLanguageModelV4 测试 generateText
  • 用 simulateReadableStream 测试流式输出
  • 测试结构化输出
  • 可观测性:用 OpenTelemetry 监控生产环境
  • 基础配置
  • 给每次 AI 调用打上标签
  • 接入 Langfuse(推荐)
  • 自定义 Telemetry(轻量版,无需 OpenTelemetry)
  • 实际项目建议

为什么 AI 应用需要特殊的测试策略

普通代码的单元测试逻辑很清晰:给定输入,断言输出。但 AI 应用面对三个麻烦:

  1. 非确定性:同样的 prompt 每次输出不一样
  2. 慢:调一次 GPT-4o 要 2-5 秒
  3. 贵:CI 跑 100 次测试可能花几美元 token 费用

Vercel AI SDK 内置了 mock 工具解决这三个问题——让测试快、便宜、可重复。

测试工具安装

# ai/test 是 ai 包的子路径,不需要额外安装
# 确保 ai 版本 >= 6.0
npm install ai

用 MockLanguageModelV4 测试 generateText

MockLanguageModelV4 让你控制模型的输出,不发任何真实 API 请求:

import { generateText } from 'ai';
import { MockLanguageModelV4 } from 'ai/test';

// 测试:验证函数能正确处理 AI 返回的内容
it('summarize() 应该返回摘要文本', async () => {
  const model = new MockLanguageModelV4({
    doGenerate: async () => ({
      content: [{ type: 'text', text: '这是一段自动生成的摘要内容。' }],
      finishReason: { unified: 'stop', raw: undefined },
      usage: {
        inputTokens: { total: 50, noCache: 50, cacheRead: undefined, cacheWrite: undefined },
        outputTokens: { total: 20, text: 20, reasoning: undefined },
      },
      warnings: [],
    }),
  });

  const { text } = await generateText({
    model,
    prompt: '请总结这篇文章:...',
  });

  expect(text).toBe('这是一段自动生成的摘要内容。');
});

doGenerate 完全控制返回内容,测试执行时间从 3 秒降到几毫秒。

用 simulateReadableStream 测试流式输出

流式响应需要模拟分块传输,simulateReadableStream 帮你构造:

import { streamText, simulateReadableStream } from 'ai';
import { MockLanguageModelV4 } from 'ai/test';

it('streamText 应该逐块输出文本', async () => {
  const model = new MockLanguageModelV4({
    doStream: async () => ({
      stream: simulateReadableStream({
        chunkDelayInMs: 0, // 测试时不需要延迟
        chunks: [
          { type: 'text-start', id: 'text-1' },
          { type: 'text-delta', id: 'text-1', delta: '你好' },
          { type: 'text-delta', id: 'text-1', delta: ',世界!' },
          { type: 'text-end', id: 'text-1' },
          {
            type: 'finish',
            finishReason: { unified: 'stop', raw: undefined },
            logprobs: undefined,
            usage: {
              inputTokens: { total: 10, noCache: 10, cacheRead: undefined, cacheWrite: undefined },
              outputTokens: { total: 5, text: 5, reasoning: undefined },
            },
          },
        ],
      }),
    }),
  });

  const result = streamText({ model, prompt: '打招呼' });
  const text = await result.text;

  expect(text).toBe('你好,世界!');
});

测试结构化输出

import { generateText, Output } from 'ai';
import { MockLanguageModelV4 } from 'ai/test';
import { z } from 'zod';

const RecipeSchema = z.object({
  name: z.string(),
  cookTime: z.number(),
  ingredients: z.array(z.string()),
});

it('结构化输出应该正确解析 JSON', async () => {
  const model = new MockLanguageModelV4({
    doGenerate: async () => ({
      content: [{
        type: 'text',
        text: JSON.stringify({
          name: '番茄炒蛋',
          cookTime: 10,
          ingredients: ['番茄', '鸡蛋', '盐'],
        }),
      }],
      finishReason: { unified: 'stop', raw: undefined },
      usage: {
        inputTokens: { total: 30, noCache: 30, cacheRead: undefined, cacheWrite: undefined },
        outputTokens: { total: 40, text: 40, reasoning: undefined },
      },
      warnings: [],
    }),
  });

  const { output } = await generateText({
    model,
    output: Output.object({ schema: RecipeSchema }),
    prompt: '给我一个番茄炒蛋的食谱',
  });

  expect(output.name).toBe('番茄炒蛋');
  expect(output.cookTime).toBe(10);
  expect(output.ingredients).toHaveLength(3);
});

可观测性:用 OpenTelemetry 监控生产环境

测试保证代码正确,可观测性保证生产环境不出意外。AI SDK 内置了 OpenTelemetry 支持,接入 Langfuse、LangSmith 等平台只需几行代码。

基础配置

npm install @ai-sdk/otel @opentelemetry/sdk-node

在应用入口(instrumentation.ts for Next.js,或 index.ts)注册:

import { registerTelemetry } from 'ai';
import { OpenTelemetry } from '@ai-sdk/otel';

// Next.js:放在 instrumentation.ts 的 register() 函数里
export async function register() {
  registerTelemetry(new OpenTelemetry());
}

给每次 AI 调用打上标签

const result = await generateText({
  model: openai('gpt-4o'),
  prompt: '...',
  telemetry: {
    functionId: 'user-onboarding-summary', // 标识这是哪个功能的调用
  },
});

// streamText 同样支持
const stream = streamText({
  model: openai('gpt-4o'),
  messages,
  telemetry: {
    functionId: 'chat-session',
  },
});

functionId 会出现在 Langfuse / LangSmith 的每条 trace 里,让你按功能筛选、比较不同版本的 prompt 效果。

接入 Langfuse(推荐)

Langfuse 是目前最流行的 LLM 可观测性平台,有免费自托管版:

npm install langfuse-vercel
import { registerTelemetry } from 'ai';
import { OpenTelemetry } from '@ai-sdk/otel';
import { LangfuseExporter } from 'langfuse-vercel';

registerTelemetry(
  new OpenTelemetry({
    exporter: new LangfuseExporter({
      publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
      secretKey: process.env.LANGFUSE_SECRET_KEY!,
      baseUrl: 'https://cloud.langfuse.com',
    }),
  })
);

配置好之后,每次 generateText / streamText 调用会自动上报:

  • 完整的 messages(输入/输出)
  • Token 用量和成本估算
  • 延迟(到第一个 token、总时长)
  • 工具调用详情
  • 错误信息

在 Langfuse 控制台就能看到每个用户、每个功能的 AI 调用明细,排查问题很方便。

自定义 Telemetry(轻量版,无需 OpenTelemetry)

如果你只想简单打日志,不想装 OTel,可以实现 Telemetry 接口:

import type { Telemetry } from 'ai';
import { registerTelemetry } from 'ai';

class ConsoleLogger implements Telemetry {
  async onStart(event: any) {
    console.log(`[AI] 开始调用: ${event.modelId}`);
  }

  async onStepEnd(event: any) {
    const { inputTokens, outputTokens } = event.usage;
    console.log(`[AI] 第 ${event.stepNumber} 步完成: in=${inputTokens.total} out=${outputTokens.total}`);
  }

  async onEnd(event: any) {
    const totalTokens = event.usage.inputTokens.total + event.usage.outputTokens.total;
    console.log(`[AI] 调用结束,总 tokens: ${totalTokens}`);
  }
}

registerTelemetry(new ConsoleLogger());

实际项目建议

测试分层:

单元测试(MockLanguageModelV4)
  → 验证业务逻辑:prompt 构造正确吗?返回值处理正确吗?
  → 运行时间:毫秒级,CI 全量跑

集成测试(真实 API,但用便宜模型)
  → 验证 prompt 能引导模型给出正确格式的回答
  → 每个核心 prompt 跑一次,用 Gemini Flash 省钱

生产监控(Langfuse / OpenTelemetry)
  → 追踪实际成本、延迟、错误率
  → 发现 prompt 退化(同一个输入,某次之后质量变差)

关键指标要盯:

  • P95 首 token 延迟(用户体感响应速度)
  • 每次调用平均 token 数(成本控制)
  • 工具调用失败率(Agent 健壮性)
  • finish_reason 分布(length 太多 = context 不够)

把这两章(MCP 集成 + 测试可观测性)加进你的项目,AI 功能才算真正生产就绪。

作者
一键分享或复制链接

相关学习资源

  • AI 学习中心
  • Prompt 工程入门
← 上一篇Vercel AI SDK 实战指南 — MCP 服务器集成:让 AI 连接任意外部工具下一篇 →Continue 实战手册:开源 AI 编程助手完全指南 — Continue 是什么:开源 AI 编程助手的自由之选

相关文章推荐

GitHub Copilot 实战指南 — 常见问题、定价与选型建议

2026-10-15

GitHub Copilot 实战指南 — 进阶玩法:Coding Agent、自定义指令与 MCP

2026-10-15

GitHub Copilot 实战指南 — 核心功能深度解析:补全、Chat 与 Agent Mode

2026-10-15

GitHub Copilot 实战指南 — 快速上手:注册免费版 + 第一次 AI 编程

2026-10-15

GitHub Copilot 实战指南 — GitHub Copilot 是什么:全球最大的 AI 编程助手

2026-10-15

Continue 实战手册:开源 AI 编程助手完全指南 — Continue 常见问题 FAQ:避坑指南与选型建议

2026-10-15
查看全部文章 →
JR Academy
全球华人学习 AI 第一站
训练营免费资源AI学习职业辅导
精选推荐
AI 职业影响地图
测测你的职业风险等级,查看转型路径与学习方向
热门工具
AI & 数据训练营
系统化课程 + 真实项目实战,快速提升竞争力
热门课程
1v1 就业辅导
资深导师一对一指导,简历优化 + 面试准备
职业辅导
企业内训定制
AI 技能培训方案,助力团队升级
企业服务
热门标签
Vibe CodingAI 编程CursorClaude求职攻略Prompt前端开发后端开发
订阅更新

获取最新 AI 学习资源、技术教程和求职攻略,直接送达邮箱。

我们尊重您的隐私,不会发送垃圾邮件