《60天AI学习计划启动 | Day 36: 前端 Prompt 模板 & 配置化(可复用提示词系统》

Day 36:Prompt 实验台 & 前端 A/B 对比

学习目标

  • 同一个问题 下,快速对比多套 Prompt 的效果
  • 在前端配置/切换 Prompt 模板,收集主观评分
  • 打基础:后面可接“线上 A/B + 日志分析”

核心知识点

  • PromptVariant 抽象

    export interface PromptVariant {
      id: string
      name: string
      description?: string
      template: string        // "你是{{role}},请用{{lang}}回答:\n{{question}}"
    }
    
    export function renderPrompt(
      tpl: string,
      vars: Record<string, string>
    ): string {
      return tpl.replace(/{{(\w+)}}/g, (_, k) => vars[k] ?? '')
    }
    
  • 实验台基本交互

    • 输入区:一个 question
    • Prompt 列表:多个 PromptVariant,每个有「生成」按钮
    • 结果区:按 Prompt 展示 answer + 评分按钮(⭐1~5)

实战作业(附代码)

  • 作业 1:定义几套 Prompt 模板
export const PROMPT_VARIANTS: PromptVariant[] = [
  {
    id: 'base',
    name: '基础回答',
    template: '请简洁回答用户问题:\n\n{{question}}'
  },
  {
    id: 'detail',
    name: '详细解释',
    template:
      '你是专业讲解员,请分点详细说明,并给出示例。\n问题:{{question}}'
  },
  {
    id: 'frontend',
    name: '前端专家',
    template:
      '你是前端高级工程师(React/Vue/TS),用代码示例回答:\n{{question}}'
  }
]
  • 作业 2:React 实验台最小模型
import React, { useState } from 'react'
import { PROMPT_VARIANTS, renderPrompt, PromptVariant } from './promptCfg'

interface ResultItem {
  variantId: string
  prompt: string
  answer: string
  rating?: number
}

export const PromptLab: React.FC = () => {
  const [question, setQuestion] = useState('')
  const [results, setResults] = useState<ResultItem[]>([])
  const [loadingId, setLoadingId] = useState<string | null>(null)

  const runVariant = async (v: PromptVariant) => {
    if (!question.trim()) return
    const prompt = renderPrompt(v.template, { question: question.trim() })
    setLoadingId(v.id)
    try {
      const res = await fetch('/api/chat', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ prompt })
      })
      const data = await res.json()
      setResults(prev => [
        ...prev.filter(r => r.variantId !== v.id),
        { variantId: v.id, prompt, answer: data.answer ?? '' }
      ])
    } finally {
      setLoadingId(null)
    }
  }

  const setRating = (variantId: string, rating: number) => {
    setResults(prev =>
      prev.map(r => (r.variantId === variantId ? { ...r, rating } : r))
    )
  }

  return (
    <div style={{ display: 'flex', gap: 16 }}>
      <div style={{ flex: 1 }}>
        <h3>Prompt 实验台</h3>
        <textarea
          value={question}
          onChange={e => setQuestion(e.target.value)}
          placeholder="输入同一个问题,下面用不同 Prompt 测试"
          rows={4}
          style={{ width: '100%' }}
        />
        <ul>
          {PROMPT_VARIANTS.map(v => (
            <li key={v.id} style={{ marginTop: 8 }}>
              <strong>{v.name}</strong> - {v.description}
              <button
                onClick={() => runVariant(v)}
                disabled={!!loadingId}
                style={{ marginLeft: 8 }}
              >
                {loadingId === v.id ? '生成中…' : '生成'}
              </button>
            </li>
          ))}
        </ul>
      </div>
      <div style={{ flex: 1 }}>
        <h3>结果对比</h3>
        {results.map(r => (
          <div key={r.variantId} style={{ border: '1px solid #ccc', marginBottom: 8, padding: 8 }}>
            <div><strong>Variant:</strong> {r.variantId}</div>
            <div><strong>Answer:</strong></div>
            <pre style={{ whiteSpace: 'pre-wrap' }}>{r.answer}</pre>
            <div>
              评分:
              {[1,2,3,4,5].map(n => (
                <button
                  key={n}
                  onClick={() => setRating(r.variantId, n)}
                  style={{ color: r.rating && r.rating >= n ? 'gold' : '#999' }}
                >
                  ★
                </button>
              ))}
            </div>
          </div>
        ))}
      </div>
    </div>
  )
}
  • 作业 3:想收集的数据(可写在代码里作为注释)
// 日后可在调用接口时一并上传:variantId / question / rating
// 方便在后台统计:哪套 Prompt 对某类问题更好

明日学习计划预告(Day 37)

  • 主题:AI 聊天性能优化(大量消息 & 流式渲染)
  • 内容方向:
    • 只渲染最近 N 条 + 简单虚拟化
    • 流式内容合并更新(节流),减少重渲染次数
posted @ 2025-12-17 10:36  XiaoZhengTou  阅读(3)  评论(0)    收藏  举报