Files
test-repo/docs/.vitepress/theme/components/appendix/ai-native-app/PromptDesignDemo.vue
T
sanbuphy 3af119a598 feat(appendix): 添加多个交互式演示组件,完善 AI/Infra 等章节内容
- 新增 Vibe Coding 全栈相关演示组件 (DeveloperSkillShift, FrontendTriad, BackendCore 等)
- 新增 RAG 相关组件 (RAGPipeline, ChunkingStrategy, Retrieval 等)
- 新增 Embedding & Vector 相关组件 (EmbeddingConcept, VectorSimilarity 等)
- 新增 AI Native App 设计组件 (AINativeArch, PromptDesign 等)
- 新增 Infrastructure as Code 组件 (IaCConcept, TerraformWorkflow 等)
- 新增 DNS & HTTPS 演示组件 (DnsResolution, HttpsHandshake 等)
- 新增 Model Finetuning 组件 (FinetuningPipeline 等)
- 更新多个章节的 markdown 内容,集成交互式演示
2026-02-24 18:22:58 +08:00

261 lines
9.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="prompt-demo">
<div class="header">
<div class="title">Prompt 工程实验室</div>
<div class="subtitle">修改 Prompt 结构观察输出质量的变化</div>
</div>
<div class="template-tabs">
<button
v-for="t in templates"
:key="t.id"
:class="['tab-btn', { active: currentTemplate === t.id }]"
@click="selectTemplate(t.id)"
>
<span>{{ t.icon }}</span>
<span>{{ t.name }}</span>
</button>
</div>
<div class="editor-grid">
<div class="editor-panel">
<div class="panel-label">System Prompt系统指令</div>
<textarea
v-model="systemPrompt"
class="prompt-input"
rows="3"
placeholder="设定 AI 的角色和行为规则..."
/>
<div class="panel-label">User Prompt用户输入</div>
<textarea
v-model="userPrompt"
class="prompt-input"
rows="3"
placeholder="用户的具体问题或指令..."
/>
<button class="run-btn" @click="runPrompt">
模拟生成
</button>
</div>
<div class="output-panel">
<div class="panel-label">模拟输出</div>
<div class="output-box">
<div v-if="isGenerating" class="generating">
<span class="dot-anim"></span> 生成中...
</div>
<div v-else-if="output" class="output-text">
{{ output }}
</div>
<div v-else class="output-placeholder">
点击"模拟生成"查看效果
</div>
</div>
<div v-if="output" class="quality-bar">
<div class="quality-label">输出质量评估</div>
<div class="quality-metrics">
<div
v-for="m in currentQuality"
:key="m.name"
class="metric"
>
<div class="metric-name">{{ m.name }}</div>
<div class="meter">
<div
class="meter-fill"
:style="{ width: m.score + '%', background: m.color }"
/>
</div>
<div class="metric-score">{{ m.score }}%</div>
</div>
</div>
</div>
</div>
</div>
<div class="tips-bar">
<span class="tips-label">💡 Prompt 技巧</span>
<span class="tips-text">{{ currentTip }}</span>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const templates = [
{ id: 'bad', icon: '❌', name: '模糊提问' },
{ id: 'basic', icon: '📝', name: '基础结构' },
{ id: 'good', icon: '✅', name: '最佳实践' }
]
const currentTemplate = ref('bad')
const systemPrompt = ref('')
const userPrompt = ref('')
const output = ref('')
const isGenerating = ref(false)
const templateData = {
bad: {
system: '',
user: '帮我写个介绍',
output: '好的,这是一个介绍:\n\n大家好,我是一个人,我喜欢很多东西。我觉得生活很有趣。谢谢大家。\n\n(输出模糊、缺乏方向、没有实际价值)',
quality: [
{ name: '相关性', score: 20, color: '#ef4444' },
{ name: '具体性', score: 10, color: '#ef4444' },
{ name: '可用性', score: 15, color: '#ef4444' }
],
tip: '没有 System Prompt,没有上下文,问题过于模糊 —— AI 只能猜测你的意图。'
},
basic: {
system: '你是一个技术文档写手。',
user: '帮我写一段关于 React 的介绍,大约100字。',
output: 'React 是由 Meta(原 Facebook)开发的开源 JavaScript 库,用于构建用户界面。它采用组件化开发模式和虚拟 DOM 技术,能够高效地更新和渲染页面。React 的声明式编程风格让开发者可以更直观地描述 UI 状态,广泛应用于现代 Web 开发中。',
quality: [
{ name: '相关性', score: 70, color: '#f59e0b' },
{ name: '具体性', score: 65, color: '#f59e0b' },
{ name: '可用性', score: 60, color: '#f59e0b' }
],
tip: '有了角色设定和基本约束(字数),输出质量明显提升,但仍缺少格式和受众定义。'
},
good: {
system: '你是一位资深前端技术博主。写作风格:简洁专业,善用类比。目标读者:编程初学者。输出格式:先用一句话总结,再展开说明,最后给出一个生活类比。',
user: '请介绍 React 是什么,以及为什么它如此流行。控制在150字以内。',
output: '一句话总结:React 是一个帮你高效搭建网页界面的 JavaScript 工具库。\n\n展开说明:React 由 Meta 团队开发,核心理念是"组件化"——把复杂页面拆成独立的小积木,每个积木管理自己的状态和外观。它的虚拟 DOM 机制能智能计算最小更新范围,避免不必要的页面重绘。\n\n生活类比:如果网页是一面乐高墙,React 就是那套标准化的乐高积木系统——你可以独立替换任何一块,而不用推倒重来。',
quality: [
{ name: '相关性', score: 95, color: '#10b981' },
{ name: '具体性', score: 90, color: '#10b981' },
{ name: '可用性', score: 95, color: '#10b981' }
],
tip: '角色 + 风格 + 受众 + 格式 + 约束 = 高质量输出。好的 Prompt 就是好的需求文档。'
}
}
const currentQuality = ref([])
const currentTip = computed(() => templateData[currentTemplate.value].tip)
const selectTemplate = (id) => {
currentTemplate.value = id
const data = templateData[id]
systemPrompt.value = data.system
userPrompt.value = data.user
output.value = ''
currentQuality.value = []
}
const runPrompt = async () => {
isGenerating.value = true
output.value = ''
currentQuality.value = []
await new Promise(r => setTimeout(r, 1200))
const data = templateData[currentTemplate.value]
output.value = data.output
currentQuality.value = data.quality
isGenerating.value = false
}
// Initialize
selectTemplate('bad')
</script>
<style scoped>
.prompt-demo {
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 12px;
padding: 20px;
margin: 20px 0;
}
.header { text-align: center; margin-bottom: 16px; }
.title {
font-size: 17px; font-weight: 700;
background: linear-gradient(120deg, #8b5cf6, var(--vp-c-brand));
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
}
.subtitle { font-size: 12px; color: var(--vp-c-text-2); margin-top: 4px; }
.template-tabs {
display: flex; gap: 8px; justify-content: center;
margin-bottom: 16px; flex-wrap: wrap;
}
.tab-btn {
display: flex; align-items: center; gap: 6px;
padding: 8px 14px; border: 1px solid var(--vp-c-divider);
border-radius: 20px; background: var(--vp-c-bg);
cursor: pointer; transition: all 0.2s; font-size: 13px;
}
.tab-btn:hover { background: var(--vp-c-bg-alt); }
.tab-btn.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
color: var(--vp-c-brand-dark);
}
.editor-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 12px;
}
.editor-panel, .output-panel {
background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider);
border-radius: 12px; padding: 14px;
}
.panel-label {
font-weight: 600; font-size: 12px; margin-bottom: 6px;
color: var(--vp-c-text-2);
}
.prompt-input {
width: 100%; padding: 10px; border: 1px solid var(--vp-c-divider);
border-radius: 8px; background: var(--vp-c-bg-soft);
font-size: 13px; line-height: 1.5; resize: vertical;
font-family: var(--vp-font-family-mono);
color: var(--vp-c-text-1); margin-bottom: 10px;
box-sizing: border-box;
}
.prompt-input:focus {
outline: none; border-color: var(--vp-c-brand);
}
.run-btn {
width: 100%; padding: 10px; background: var(--vp-c-brand);
color: white; border: none; border-radius: 8px;
font-size: 13px; cursor: pointer; transition: background 0.2s;
}
.run-btn:hover { background: var(--vp-c-brand-dark); }
.output-box {
background: var(--vp-c-bg-soft); border: 1px solid var(--vp-c-divider);
border-radius: 8px; padding: 14px; min-height: 120px;
font-size: 13px; line-height: 1.7;
}
.output-text { white-space: pre-wrap; color: var(--vp-c-text-1); }
.output-placeholder { color: var(--vp-c-text-3); text-align: center; padding: 30px 0; }
.generating { color: var(--vp-c-brand); text-align: center; padding: 30px 0; }
.dot-anim { animation: blink 1s infinite; }
@keyframes blink { 50% { opacity: 0.3; } }
.quality-bar { margin-top: 12px; }
.quality-label { font-weight: 600; font-size: 12px; margin-bottom: 8px; }
.quality-metrics { display: flex; flex-direction: column; gap: 6px; }
.metric { display: flex; align-items: center; gap: 8px; }
.metric-name { font-size: 11px; width: 50px; color: var(--vp-c-text-2); }
.meter {
flex: 1; height: 8px; background: var(--vp-c-bg-soft);
border-radius: 4px; overflow: hidden;
}
.meter-fill {
height: 100%; border-radius: 4px;
transition: width 0.6s ease;
}
.metric-score { font-size: 11px; font-weight: 600; width: 36px; text-align: right; }
.tips-bar {
margin-top: 16px; padding: 12px 16px;
background: var(--vp-c-brand-soft); border-radius: 6px; font-size: 13px;
}
.tips-label { font-weight: 600; color: var(--vp-c-brand-dark); }
.tips-text { color: var(--vp-c-text-1); }
</style>