《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 条 + 简单虚拟化
- 流式内容合并更新(节流),减少重渲染次数

浙公网安备 33010602011771号