🚀 Vercel AI SDK 使用指南:工作流模式(Workflows)

8 阅读3分钟

为什么要使用工作流?

直接让 LLM “一步到位”往往会导致不稳定的输出。通过工作流模式,我们可以:

  • 分解复杂度:将大任务拆解为小步骤。
  • 提高可靠性:在步骤之间加入检查和重试机制。
  • 降低成本:简单的步骤使用小模型,复杂的步骤使用大模型。

AI SDK 总结了 5 种最常用的模式:顺序处理、路由、并行处理、编排者-执行者、评估-优化


1. 顺序处理 (Sequential Processing)

这是最基础的模式。上一步的输出作为下一步的输入,形成一条链。适合内容生成流水线或数据转换。

场景:写一段营销文案,然后检查质量,如果质量不达标则重写。

TypeScript

import { generateText, generateObject } from 'ai';
import { z } from 'zod';
import { anthropic } from '@ai-sdk/anthropic'; // 假设使用 Anthropic

async function generateMarketingCopy(input: string) {
  const model = anthropic('claude-3-5-sonnet-20240620');

  // 第一步:生成初稿
  const { text: copy } = await generateText({
    model,
    prompt: `为以下产品撰写有说服力的营销文案:${input}。注重利益点和情感共鸣。`,
  });

  // 第二步:质量检查 (结构化输出)
  const { object: qualityMetrics } = await generateObject({
    model,
    schema: z.object({
      hasCallToAction: z.boolean(), // 是否有号召性用语
      emotionalAppeal: z.number().min(1).max(10), // 情感分
      clarity: z.number().min(1).max(10), // 清晰度
    }),
    prompt: `评估这段文案:
    1. 是否包含号召性用语 (true/false)
    2. 情感吸引力 (1-10)
    3. 清晰度 (1-10)
    
    待评估文案:${copy}`,
  });

  // 第三步:根据检查结果决定是否重写 (条件逻辑)
  if (
    !qualityMetrics.hasCallToAction ||
    qualityMetrics.emotionalAppeal < 7 ||
    qualityMetrics.clarity < 7
  ) {
    const { text: improvedCopy } = await generateText({
      model,
      prompt: `重写这段文案,必须包含:
      ${!qualityMetrics.hasCallToAction ? '- 清晰的号召性用语' : ''}
      ${qualityMetrics.emotionalAppeal < 7 ? '- 更强的情感吸引力' : ''}
      ${qualityMetrics.clarity < 7 ? '- 提高清晰度和直接性' : ''}
      
      原文:${copy}`,
    });
    return { copy: improvedCopy, qualityMetrics, status: 'improved' };
  }

  return { copy, qualityMetrics, status: 'original' };
}

2. 路由 (Routing)

路由模式让 LLM 充当“交通指挥官”。它分析用户的意图,然后决定下一步由哪个模型处理,或者使用什么 Prompt。

场景:根据用户咨询的类型(退款、技术支持、一般问题),分配给不同的处理逻辑或不同大小的模型。

TypeScript

import { generateObject, generateText } from 'ai';
import { z } from 'zod';
import { openai } from '@ai-sdk/openai';

async function handleCustomerQuery(query: string) {
  const classifierModel = openai('gpt-4o'); // 智能分类用强模型

  // 第一步:分类查询意图
  const { object: classification } = await generateObject({
    model: classifierModel,
    schema: z.object({
      reasoning: z.string(),
      type: z.enum(['general', 'refund', 'technical']),
      complexity: z.enum(['simple', 'complex']),
    }),
    prompt: `对该客户查询进行分类:
    ${query}
    
    请确定:
    1. 查询类型 (general, refund, technical)
    2. 复杂度 (simple, complex)
    3. 分类理由`,
  });

  // 第二步:路由逻辑
  // 根据复杂度选择模型:简单问题用小模型省钱,复杂问题用大模型
  const targetModel = classification.complexity === 'simple'
    ? openai('gpt-4o-mini')
    : openai('gpt-4o');

  // 根据类型选择系统提示词 (System Prompt)
  const systemPrompts = {
    general: '你是一位专业的客服代表,处理一般性咨询。',
    refund: '你是一位专门处理退款的客服。请遵循公司政策并收集必要信息。',
    technical: '你是一位拥有深厚产品知识的技术支持专家。专注于清晰的分步故障排除。',
  };

  const { text: response } = await generateText({
    model: targetModel,
    system: systemPrompts[classification.type],
    prompt: query,
  });

  return { response, classification };
}

3. 并行处理 (Parallel Processing)

当任务包含多个相互独立的部分时,可以同时运行它们。这既提高了速度,又能让每个 Prompt 专注于单一职责。

场景:代码审查(Code Review)。同时从“安全性”、“性能”和“可维护性”三个维度进行审查,最后汇总。

TypeScript

import { generateText, generateObject } from 'ai';
import { z } from 'zod';
import { anthropic } from '@ai-sdk/anthropic';

async function parallelCodeReview(code: string) {
  const model = anthropic('claude-3-5-sonnet-20240620');

  // 使用 Promise.all 并行执行三个独立的审查任务
  const [securityReview, performanceReview, maintainabilityReview] = await Promise.all([
    generateObject({
      model,
      system: '你是代码安全专家。专注于识别漏洞、注入风险和认证问题。',
      schema: z.object({
        vulnerabilities: z.array(z.string()),
        riskLevel: z.enum(['low', 'medium', 'high']),
        suggestions: z.array(z.string()),
      }),
      prompt: `审查代码:${code}`,
    }),
    generateObject({
      model,
      system: '你是性能优化专家。专注于识别瓶颈、内存泄漏和优化机会。',
      schema: z.object({
        issues: z.array(z.string()),
        impact: z.enum(['low', 'medium', 'high']),
        optimizations: z.array(z.string()),
      }),
      prompt: `审查代码:${code}`,
    }),
    generateObject({
      model,
      system: '你是代码质量专家。专注于代码结构、可读性和最佳实践。',
      schema: z.object({
        concerns: z.array(z.string()),
        qualityScore: z.number().min(1).max(10),
        recommendations: z.array(z.string()),
      }),
      prompt: `审查代码:${code}`,
    }),
  ]);

  // 数据聚合
  const reviews = [    { ...securityReview.object, type: 'security' },    { ...performanceReview.object, type: 'performance' },    { ...maintainabilityReview.object, type: 'maintainability' },  ];

  // 最后一步:汇总报告
  const { text: summary } = await generateText({
    model,
    system: '你是技术负责人,负责汇总多份代码审查报告。',
    prompt: `将这些代码审查结果综合成一份简明的摘要,列出关键行动项:
    ${JSON.stringify(reviews, null, 2)}`,
  });

  return { reviews, summary };
}

4. 编排者-执行者 (Orchestrator-Worker)

这是处理复杂任务的强力模式。一个“编排者”模型负责制定计划(Plan),然后拆分出多个子任务,交给“执行者”模型去完成。

场景:实现一个新功能。编排者决定需要修改哪些文件,执行者分别去写每个文件的代码。

TypeScript

import { generateObject } from 'ai';
import { z } from 'zod';
import { anthropic } from '@ai-sdk/anthropic';

async function implementFeature(featureRequest: string) {
  const model = anthropic('claude-3-5-sonnet-20240620');

  // 1. 编排者 (Orchestrator):制定实施计划
  const { object: implementationPlan } = await generateObject({
    model,
    schema: z.object({
      files: z.array(
        z.object({
          purpose: z.string(),
          filePath: z.string(),
          changeType: z.enum(['create', 'modify', 'delete']),
        }),
      ),
      estimatedComplexity: z.enum(['low', 'medium', 'high']),
    }),
    system: '你是一位高级软件架构师,负责规划功能实现。',
    prompt: `分析此功能请求并制定实施计划:
    ${featureRequest}`,
  });

  // 2. 执行者 (Workers):根据计划并行执行
  const fileChanges = await Promise.all(
    implementationPlan.files.map(async (file) => {
      // 针对不同的修改类型,定制 System Prompt
      const workerSystemPrompt = {
        create: '你是实现新文件的专家,遵循最佳实践和项目模式。',
        modify: '你是修改现有代码的专家,保持一致性并避免回退。',
        delete: '你是安全删除代码的专家,确保不破坏现有功能。',
      }[file.changeType];

      const { object: change } = await generateObject({
        model,
        schema: z.object({
          explanation: z.string(),
          code: z.string(),
        }),
        system: workerSystemPrompt,
        prompt: `为 ${file.filePath} 实现变更以支持:
        ${file.purpose}
        
        考虑整体功能上下文:
        ${featureRequest}`,
      });

      return {
        file,
        implementation: change,
      };
    })
  );

  return {
    plan: implementationPlan,
    changes: fileChanges,
  };
}

5. 评估-优化循环 (Evaluator-Optimizer)

这是一种“自愈”模式。模型生成结果后,自己(或另一个模型)进行评估。如果不达标,则根据反馈进行优化,直到满足条件或达到最大重试次数。

场景:文学翻译。翻译 -> 评分 -> (如果不完美) 根据意见修正 -> 再次评分。

TypeScript

import { generateText, generateObject } from 'ai';
import { z } from 'zod';
import { anthropic } from '@ai-sdk/anthropic';

async function translateWithFeedback(text: string, targetLanguage: string) {
  const model = anthropic('claude-3-5-sonnet-20240620');
  
  let currentTranslation = '';
  let iterations = 0;
  const MAX_ITERATIONS = 3; // 防止死循环

  // 1. 初始翻译
  const { text: translation } = await generateText({
    model,
    system: '你是一位专业的文学翻译家。',
    prompt: `将此文本翻译成 ${targetLanguage},保留语气和文化细微差别:
    ${text}`,
  });

  currentTranslation = translation;

  // 2. 评估-优化 循环
  while (iterations < MAX_ITERATIONS) {
    // 评估当前翻译
    const { object: evaluation } = await generateObject({
      model,
      schema: z.object({
        qualityScore: z.number().min(1).max(10),
        preservesTone: z.boolean(),
        preservesNuance: z.boolean(),
        culturallyAccurate: z.boolean(),
        specificIssues: z.array(z.string()),
        improvementSuggestions: z.array(z.string()),
      }),
      system: '你是一位文学翻译评估专家。',
      prompt: `评估此翻译:
      
      原文:${text}
      翻译:${currentTranslation}
      
      请考虑:整体质量、语气保留、细微差别、文化准确性。`,
    });

    // 检查是否达到高质量标准
    if (
      evaluation.qualityScore >= 8 &&
      evaluation.preservesTone &&
      evaluation.preservesNuance &&
      evaluation.culturallyAccurate
    ) {
      break; // 质量达标,跳出循环
    }

    // 根据反馈生成改进后的翻译
    const { text: improvedTranslation } = await generateText({
      model,
      system: '你是一位专业的文学翻译家。',
      prompt: `根据以下反馈改进此翻译:
      ${evaluation.specificIssues.join('\n')}
      ${evaluation.improvementSuggestions.join('\n')}
      
      原文:${text}
      当前翻译:${currentTranslation}`,
    });

    currentTranslation = improvedTranslation;
    iterations++;
  }

  return {
    finalTranslation: currentTranslation,
    iterationsRequired: iterations,
  };
}

总结:如何选择?

模式适用场景核心优势
顺序处理只有一条路径的任务简单、易维护
路由输入类型多样的任务针对性强、可优化成本
并行处理任务可拆分独立的子任务速度快、多视角分析
编排者-执行者复杂、多步骤、动态子任务处理复杂系统工程能力强
评估-优化对质量要求极高的任务自我纠错、结果更可靠

Vercel AI SDK 通过 generateTextgenerateObject 这两个基础 API,配合 zod 的结构化能力,让实现这些高级模式变得非常简单(且类型安全!)。

希望这篇教程能帮你在项目中构建更强大的 AI Agent!🚀