Skip to content

动态提示:如何根据输入选择不同模板?

在实际的 LLM 应用中,往往需要根据不同的输入条件选择不同的提示模板。这种动态选择机制能够显著提升应用的适应性和效果。LangChain V3 通过多种方式支持动态提示,使得开发者能够根据输入内容、用户特征或其他条件选择最合适的模板。本章将深入探讨动态提示的实现方式和应用场景。

动态提示的基本概念

动态提示是指根据输入或其他条件在运行时选择最合适提示模板的机制。这种机制能够:

  1. 提高准确性 - 为不同类型的输入选择最合适的提示
  2. 增强个性化 - 根据用户特征提供定制化的提示
  3. 优化性能 - 针对特定场景使用优化的提示模板
  4. 增加灵活性 - 适应多样化的使用场景

基于输入内容的动态选择

最常见的动态提示场景是根据输入内容选择不同的模板:

typescript
// 定义不同类型的提示模板
class DynamicPromptSelector extends Runnable<any, string> {
  private templates: Record<string, PromptTemplate>;
  private classifier: Runnable<any, string>;
  
  constructor(
    templates: Record<string, PromptTemplate>,
    classifier: Runnable<any, string>
  ) {
    super();
    this.templates = templates;
    this.classifier = classifier;
  }
  
  async invoke(input: any): Promise<string> {
    // 使用分类器确定输入类型
    const category = await this.classifier.invoke(input);
    
    // 根据分类结果选择模板
    const template = this.templates[category] || this.templates['default'];
    
    if (!template) {
      throw new Error(`未找到适用于类别 "${category}" 的模板`);
    }
    
    return await template.invoke(input);
  }
}

// 创建不同类型的模板
const mathTemplate = new PromptTemplate({
  template: "你是一个数学专家。请解决以下数学问题:\n{question}\n解题步骤:",
  inputVariables: ["question"]
});

const historyTemplate = new PromptTemplate({
  template: "你是一个历史学家。请回答以下历史问题:\n{question}\n历史背景:",
  inputVariables: ["question"]
});

const scienceTemplate = new PromptTemplate({
  template: "你是一个科学家。请解释以下科学问题:\n{question}\n科学原理:",
  inputVariables: ["question"]
});

const defaultTemplate = new PromptTemplate({
  template: "请回答以下问题:\n{question}",
  inputVariables: ["question"]
});

// 创建分类器
const classifier = new PromptTemplate({
  template: `请将以下问题分类到最合适的类别中:
类别选项:
1. 数学 (math)
2. 历史 (history)
3. 科学 (science)

问题: {question}

只回答类别名称:`,
  inputVariables: ["question"]
}).pipe(new ChatOpenAI()).pipe(new StringOutputParser());

// 创建动态提示选择器
const dynamicPrompt = new DynamicPromptSelector(
  {
    math: mathTemplate,
    history: historyTemplate,
    science: scienceTemplate,
    default: defaultTemplate
  },
  classifier
);

// 使用示例
const mathPrompt = await dynamicPrompt.invoke({
  question: "计算 2 的 10 次方"
});

const historyPrompt = await dynamicPrompt.invoke({
  question: "唐朝是哪个世纪建立的?"
});

基于用户特征的动态选择

动态提示也可以根据用户特征进行选择:

typescript
interface UserContext {
  userId: string;
  expertiseLevel: 'beginner' | 'intermediate' | 'advanced';
  preferredStyle: 'formal' | 'casual' | 'technical';
  language: string;
}

class UserAwarePromptSelector extends Runnable<any, string> {
  private baseTemplates: Record<string, string>;
  
  constructor(baseTemplates: Record<string, string>) {
    super();
    this.baseTemplates = baseTemplates;
  }
  
  async invoke(input: { question: string; userContext: UserContext }): Promise<string> {
    const { question, userContext } = input;
    
    // 根据用户特征构建个性化模板
    const personalizedTemplate = this.buildPersonalizedTemplate(
      this.baseTemplates.question,
      userContext
    );
    
    const template = new PromptTemplate({
      template: personalizedTemplate,
      inputVariables: ["question"]
    });
    
    return await template.invoke({ question });
  }
  
  private buildPersonalizedTemplate(baseTemplate: string, userContext: UserContext): string {
    let personalizedTemplate = baseTemplate;
    
    // 根据专业水平调整
    switch (userContext.expertiseLevel) {
      case 'beginner':
        personalizedTemplate = personalizedTemplate.replace(
          '{question}',
          '{question}\n请用简单易懂的语言解释,避免使用专业术语'
        );
        break;
      case 'intermediate':
        personalizedTemplate = personalizedTemplate.replace(
          '{question}',
          '{question}\n请提供中等深度的解释,可以使用一些专业术语'
        );
        break;
      case 'advanced':
        personalizedTemplate = personalizedTemplate.replace(
          '{question}',
          '{question}\n请提供深入的技术细节和专业分析'
        );
        break;
    }
    
    // 根据语言偏好调整
    if (userContext.language !== 'zh') {
      personalizedTemplate = `请用 ${userContext.language} 回答: ${personalizedTemplate}`;
    }
    
    // 根据风格偏好调整
    switch (userContext.preferredStyle) {
      case 'formal':
        personalizedTemplate += '\n请使用正式、专业的语言风格';
        break;
      case 'casual':
        personalizedTemplate += '\n请使用轻松、友好的语言风格';
        break;
      case 'technical':
        personalizedTemplate += '\n请使用技术性语言,可以包含代码示例';
        break;
    }
    
    return personalizedTemplate;
  }
}

// 使用示例
const userAwareSelector = new UserAwarePromptSelector({
  question: "请回答以下问题: {question}"
});

const promptForBeginner = await userAwareSelector.invoke({
  question: "什么是机器学习?",
  userContext: {
    userId: "user123",
    expertiseLevel: "beginner",
    preferredStyle: "casual",
    language: "中文"
  }
});

const promptForExpert = await userAwareSelector.invoke({
  question: "解释 Transformer 架构的注意力机制",
  userContext: {
    userId: "user456",
    expertiseLevel: "advanced",
    preferredStyle: "technical",
    language: "English"
  }
});

基于上下文的动态选择

动态提示还可以根据对话上下文进行选择:

typescript
interface ConversationContext {
  history: Array<{ role: string; content: string }>;
  currentTopic: string;
  conversationStage: 'opening' | 'exploration' | 'deep_dive' | 'conclusion';
}

class ContextAwarePromptSelector extends Runnable<any, string> {
  private stageTemplates: Record<string, PromptTemplate>;
  
  constructor(stageTemplates: Record<string, PromptTemplate>) {
    super();
    this.stageTemplates = stageTemplates;
  }
  
  async invoke(input: { 
    question: string; 
    context: ConversationContext 
  }): Promise<string> {
    const { question, context } = input;
    
    // 根据对话阶段选择模板
    let template = this.stageTemplates[context.conversationStage];
    
    // 如果当前主题有专门模板,则优先使用
    const topicTemplate = this.stageTemplates[`${context.conversationStage}_${context.currentTopic}`];
    if (topicTemplate) {
      template = topicTemplate;
    }
    
    // 如果没有找到合适的模板,使用默认模板
    if (!template) {
      template = this.stageTemplates['default'] || 
                 new PromptTemplate({
                   template: "{question}",
                   inputVariables: ["question"]
                 });
    }
    
    // 构建包含上下文的输入
    const templateInput = {
      question,
      history: this.formatHistory(context.history),
      topic: context.currentTopic,
      stage: context.conversationStage
    };
    
    return await template.invoke(templateInput);
  }
  
  private formatHistory(history: Array<{ role: string; content: string }>): string {
    return history
      .map(entry => `${entry.role}: ${entry.content}`)
      .join('\n');
  }
}

// 为不同阶段和主题创建模板
const contextAwareSelector = new ContextAwarePromptSelector({
  opening: new PromptTemplate({
    template: `开始新话题: {question}
请用友好的方式开启对话:`,
    inputVariables: ["question"]
  }),
  
  exploration: new PromptTemplate({
    template: `探索阶段问题: {question}
对话历史:
{history}

请基于历史继续探索这个话题:`,
    inputVariables: ["question", "history"]
  }),
  
  'deep_dive_technology': new PromptTemplate({
    template: `技术深度探讨: {question}
当前主题: {topic}
对话历史:
{history}

请提供深入的技术分析:`,
    inputVariables: ["question", "topic", "history"]
  }),
  
  conclusion: new PromptTemplate({
    template: `总结问题: {question}
对话历史:
{history}

请总结我们的讨论并提供关键要点:`,
    inputVariables: ["question", "history"]
  })
});

基于性能反馈的动态选择

动态提示还可以根据历史性能反馈进行优化:

typescript
interface TemplatePerformance {
  templateId: string;
  successRate: number;
  avgResponseTime: number;
  userSatisfaction: number;
}

class PerformanceBasedPromptSelector extends Runnable<any, string> {
  private templates: PromptTemplate[];
  private performanceData: Record<string, TemplatePerformance>;
  private performanceWeight: { 
    successRate: number; 
    responseTime: number; 
    satisfaction: number 
  };
  
  constructor(
    templates: PromptTemplate[],
    performanceWeight: { 
      successRate: number; 
      responseTime: number; 
      satisfaction: number 
    } = { successRate: 0.5, responseTime: 0.3, satisfaction: 0.2 }
  ) {
    super();
    this.templates = templates;
    this.performanceData = {};
    this.performanceWeight = performanceWeight;
    
    // 初始化性能数据
    templates.forEach((template, index) => {
      this.performanceData[`template_${index}`] = {
        templateId: `template_${index}`,
        successRate: 0.8,
        avgResponseTime: 2000,
        userSatisfaction: 4.0
      };
    });
  }
  
  async invoke(input: any): Promise<string> {
    // 根据性能数据选择最佳模板
    const bestTemplate = this.selectBestTemplate(input);
    const templateIndex = this.templates.indexOf(bestTemplate);
    
    return await bestTemplate.invoke(input);
  }
  
  private selectBestTemplate(input: any): PromptTemplate {
    // 计算每个模板的综合得分
    const scores = this.templates.map((template, index) => {
      const perfData = this.performanceData[`template_${index}`];
      if (!perfData) return { template, score: 0 };
      
      // 归一化各项指标
      const normalizedSuccess = perfData.successRate;
      const normalizedResponseTime = Math.max(0, 1 - (perfData.avgResponseTime / 5000));
      const normalizedSatisfaction = perfData.userSatisfaction / 5;
      
      // 计算加权得分
      const score = 
        normalizedSuccess * this.performanceWeight.successRate +
        normalizedResponseTime * this.performanceWeight.responseTime +
        normalizedSatisfaction * this.performanceWeight.satisfaction;
      
      return { template, score };
    });
    
    // 选择得分最高的模板
    const best = scores.reduce((prev, current) => 
      (prev.score > current.score) ? prev : current
    );
    
    return best.template;
  }
  
  // 更新性能数据的方法
  updatePerformance(templateId: string, success: boolean, responseTime: number, satisfaction: number): void {
    const perfData = this.performanceData[templateId];
    if (!perfData) return;
    
    // 更新成功率
    perfData.successRate = (perfData.successRate * 0.9) + (success ? 0.1 : 0);
    
    // 更新平均响应时间(指数移动平均)
    perfData.avgResponseTime = (perfData.avgResponseTime * 0.9) + (responseTime * 0.1);
    
    // 更新用户满意度
    perfData.userSatisfaction = (perfData.userSatisfaction * 0.9) + (satisfaction * 0.1);
  }
}

多维度动态选择系统

结合多种因素的综合动态提示系统:

typescript
interface DynamicPromptConfig {
  inputBased?: boolean;
  userBased?: boolean;
  contextBased?: boolean;
  performanceBased?: boolean;
}

class ComprehensiveDynamicPrompt extends Runnable<any, string> {
  private inputClassifier: Runnable<any, string>;
  private userProfiler: Runnable<any, string>;
  private contextAnalyzer: Runnable<any, string>;
  private templateRepository: Map<string, PromptTemplate>;
  private performanceTracker: PerformanceBasedPromptSelector;
  
  constructor(
    inputClassifier: Runnable<any, string>,
    userProfiler: Runnable<any, string>,
    contextAnalyzer: Runnable<any, string>,
    templates: PromptTemplate[]
  ) {
    super();
    this.inputClassifier = inputClassifier;
    this.userProfiler = userProfiler;
    this.contextAnalyzer = contextAnalyzer;
    this.templateRepository = new Map();
    this.performanceTracker = new PerformanceBasedPromptSelector(templates);
    
    // 初始化模板库
    templates.forEach((template, index) => {
      this.templateRepository.set(`template_${index}`, template);
    });
  }
  
  async invoke(input: any): Promise<string> {
    // 多维度分析
    const [inputType, userProfile, contextType] = await Promise.all([
      this.inputClassifier.invoke(input),
      this.userProfiler.invoke(input),
      this.contextAnalyzer.invoke(input)
    ]);
    
    // 构建模板选择键
    const templateKey = `${inputType}_${userProfile}_${contextType}`;
    
    // 尝试获取专门的模板
    let template = this.templateRepository.get(templateKey);
    
    // 如果没有专门模板,使用通用模板
    if (!template) {
      template = this.templateRepository.get(inputType) || 
                 this.templateRepository.get('default');
    }
    
    if (!template) {
      throw new Error('未找到合适的提示模板');
    }
    
    return await template.invoke(input);
  }
}

// 使用示例
const comprehensiveSelector = new ComprehensiveDynamicPrompt(
  // 输入分类器
  new PromptTemplate({
    template: "分类输入类型: {input}",
    inputVariables: ["input"]
  }).pipe(new ChatOpenAI()).pipe(new StringOutputParser()),
  
  // 用户画像器
  new PromptTemplate({
    template: "分析用户特征: {input}",
    inputVariables: ["input"]
  }).pipe(new ChatOpenAI()).pipe(new StringOutputParser()),
  
  // 上下文分析器
  new PromptTemplate({
    template: "分析上下文: {input}",
    inputVariables: ["input"]
  }).pipe(new ChatOpenAI()).pipe(new StringOutputParser()),
  
  // 模板集合
  [
    new PromptTemplate({
      template: "技术专家模式: {input}",
      inputVariables: ["input"]
    }),
    new PromptTemplate({
      template: "初学者友好模式: {input}",
      inputVariables: ["input"]
    })
  ]
);

实际应用示例:智能客服系统

让我们看一个完整的实际应用示例:

typescript
// 智能客服系统的动态提示选择器
class SmartCustomerServicePrompt extends Runnable<any, string> {
  private categoryTemplates: Record<string, PromptTemplate>;
  private priorityTemplates: Record<string, PromptTemplate>;
  private customerTierTemplates: Record<string, PromptTemplate>;
  
  constructor() {
    super();
    
    // 按问题类别分类的模板
    this.categoryTemplates = {
      technical: new PromptTemplate({
        template: `技术支持响应:
问题: {question}
客户ID: {customerId}
请提供详细的技术解决方案,并在必要时提供操作步骤:`,
        inputVariables: ["question", "customerId"]
      }),
      
      billing: new PromptTemplate({
        template: `账单问题响应:
问题: {question}
客户ID: {customerId}
账户信息: {accountInfo}
请仔细检查账单信息并提供清晰的解释:`,
        inputVariables: ["question", "customerId", "accountInfo"]
      }),
      
      general: new PromptTemplate({
        template: `一般咨询响应:
问题: {question}
客户ID: {customerId}
请提供友好且全面的回答:`,
        inputVariables: ["question", "customerId"]
      })
    };
    
    // 按优先级分类的模板
    this.priorityTemplates = {
      high: new PromptTemplate({
        template: `紧急问题处理:
问题: {question}
客户ID: {customerId}
优先级: 高
请立即处理并提供最快的解决方案:`,
        inputVariables: ["question", "customerId"]
      })
    };
    
    // 按客户等级分类的模板
    this.customerTierTemplates = {
      vip: new PromptTemplate({
        template: `VIP客户专属服务:
问题: {question}
客户ID: {customerId}
客户等级: VIP
请提供最高标准的服务和个性化解决方案:`,
        inputVariables: ["question", "customerId"]
      })
    };
  }
  
  async invoke(input: {
    question: string;
    customerId: string;
    category?: string;
    priority?: string;
    customerTier?: string;
    accountInfo?: any;
  }): Promise<string> {
    // 智能分类(如果没有提供分类信息)
    const category = input.category || await this.classifyQuestion(input.question);
    const priority = input.priority || 'normal';
    const customerTier = input.customerTier || await this.getCustomerTier(input.customerId);
    
    // 根据多个维度选择最佳模板
    let template = this.selectTemplate(category, priority, customerTier);
    
    // 构建模板输入
    const templateInput = {
      question: input.question,
      customerId: input.customerId,
      accountInfo: input.accountInfo ? JSON.stringify(input.accountInfo) : '无'
    };
    
    return await template.invoke(templateInput);
  }
  
  private async classifyQuestion(question: string): Promise<string> {
    // 使用 LLM 进行问题分类
    const classifier = new PromptTemplate({
      template: `将以下问题分类到最合适的类别中:
类别选项:
1. 技术问题 (technical)
2. 账单问题 (billing)
3. 一般咨询 (general)

问题: {question}

只回答类别代码:`,
      inputVariables: ["question"]
    }).pipe(new ChatOpenAI()).pipe(new StringOutputParser());
    
    return await classifier.invoke({ question });
  }
  
  private async getCustomerTier(customerId: string): Promise<string> {
    // 模拟客户等级查询
    // 实际应用中这里会查询数据库或调用 API
    const vipCustomers = ['cust_001', 'cust_002', 'cust_003'];
    return vipCustomers.includes(customerId) ? 'vip' : 'regular';
  }
  
  private selectTemplate(
    category: string, 
    priority: string, 
    customerTier: string
  ): PromptTemplate {
    // 优先级:客户等级 > 问题优先级 > 问题类别
    if (customerTier === 'vip' && this.customerTierTemplates.vip) {
      return this.customerTierTemplates.vip;
    }
    
    if (priority === 'high' && this.priorityTemplates.high) {
      return this.priorityTemplates.high;
    }
    
    return this.categoryTemplates[category] || this.categoryTemplates.general;
  }
}

// 使用示例
const smartPrompt = new SmartCustomerServicePrompt();

const prompt1 = await smartPrompt.invoke({
  question: "我无法登录我的账户",
  customerId: "cust_001"
});

const prompt2 = await smartPrompt.invoke({
  question: "我的账单金额似乎有误",
  customerId: "cust_123",
  accountInfo: {
    lastBillAmount: 99.99,
    currentBillAmount: 149.99
  }
});

总结

动态提示是构建智能、个性化 LLM 应用的重要技术。通过根据输入内容、用户特征、上下文和性能反馈等因素动态选择提示模板,可以显著提升应用的效果和用户体验。

关键要点包括:

  1. 多维度选择 - 可以基于输入内容、用户特征、上下文等多种因素进行选择
  2. 智能分类 - 使用 LLM 进行智能分类和分析
  3. 性能优化 - 根据历史性能数据优化模板选择
  4. 个性化体验 - 为不同用户提供定制化的提示
  5. 灵活扩展 - 支持复杂的多条件组合和优先级设置

动态提示机制使得 LangChain 应用能够适应各种复杂的使用场景,为用户提供更加精准和个性化的服务。

在下一章中,我们将探讨 LLM & ChatModel 的统一接口:BaseLanguageModel 抽象 generate, streamGenerate