Files

238 lines
8.7 KiB
Vue
Raw Permalink Normal View History

<template>
<div class="arch-demo">
<div class="header">
<div class="title">传统应用 vs AI 原生应用</div>
<div class="subtitle">切换视图对比两种架构的核心差异</div>
</div>
<div class="toggle-bar">
<button
:class="['toggle-btn', { active: mode === 'traditional' }]"
@click="mode = 'traditional'"
>
<span>🏗</span>
<span>传统应用</span>
</button>
<button
:class="['toggle-btn', { active: mode === 'ai-native' }]"
@click="mode = 'ai-native'"
>
<span>🤖</span>
<span>AI 原生应用</span>
</button>
</div>
<div class="arch-grid">
<div class="stack">
<div class="stack-title">{{ currentArch.label }}</div>
<div
v-for="(layer, idx) in currentArch.layers"
:key="idx"
:class="['layer', { highlight: selectedLayer === idx }]"
:style="{ borderLeftColor: layer.color }"
@click="selectedLayer = idx"
>
<div class="layer-icon">{{ layer.icon }}</div>
<div class="layer-info">
<div class="layer-name">{{ layer.name }}</div>
<div class="layer-desc">{{ layer.brief }}</div>
</div>
</div>
</div>
<div class="detail-panel">
<div v-if="selectedLayer !== null" class="detail-content">
<div class="detail-title">
{{ currentArch.layers[selectedLayer].icon }}
{{ currentArch.layers[selectedLayer].name }}
</div>
<div class="detail-desc">
{{ currentArch.layers[selectedLayer].detail }}
</div>
<div class="detail-example">
<div class="example-label">典型技术</div>
<div class="tech-tags">
<span
v-for="t in currentArch.layers[selectedLayer].techs"
:key="t"
class="tech-tag"
>{{ t }}</span>
</div>
</div>
</div>
<div v-else class="detail-placeholder">
👆 点击左侧层级查看详情
</div>
</div>
</div>
<div class="comparison-bar">
<span class="compare-label">💡 核心区别</span>
<span class="compare-text">{{ mode === 'traditional'
? '传统应用的逻辑由开发者用 if/else 硬编码,行为完全确定。'
: 'AI 原生应用的核心逻辑由模型驱动,行为具有概率性,需要全新的设计思维。' }}</span>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const mode = ref('traditional')
const selectedLayer = ref(0)
const architectures = {
traditional: {
label: '传统应用架构',
layers: [
{
icon: '🖥️', name: '前端 UI', color: '#3b82f6',
brief: '用户界面与交互',
detail: '基于确定性的表单、按钮、页面路由。用户操作触发固定的业务流程,所有交互路径在开发时已经确定。',
techs: ['React', 'Vue', 'HTML/CSS']
},
{
icon: '⚙️', name: '业务逻辑层', color: '#8b5cf6',
brief: '硬编码的规则引擎',
detail: '开发者用 if/else、switch/case 编写所有业务规则。每一条路径都需要人工预设,无法处理规则之外的情况。',
techs: ['Node.js', 'Java', 'Python']
},
{
icon: '🗄️', name: '数据存储', color: '#06b6d4',
brief: '结构化数据管理',
detail: '关系型数据库存储结构化数据,Schema 固定。数据的读写遵循严格的 CRUD 模式。',
techs: ['MySQL', 'PostgreSQL', 'Redis']
},
{
icon: '🔌', name: 'API 接口', color: '#10b981',
brief: '固定的请求/响应',
detail: '每个 API 端点返回确定性的结果。相同的输入永远产生相同的输出,行为完全可预测。',
techs: ['REST', 'GraphQL', 'gRPC']
}
]
},
'ai-native': {
label: 'AI 原生应用架构',
layers: [
{
icon: '💬', name: '自然语言交互层', color: '#f59e0b',
brief: '对话式 + 流式输出',
detail: '用户通过自然语言表达意图,系统以流式方式逐步生成响应。交互不再是固定的表单,而是开放式的对话。',
techs: ['Streaming UI', 'Markdown 渲染', 'SSE']
},
{
icon: '🧠', name: '模型推理层', color: '#ef4444',
brief: 'LLM 驱动的决策引擎',
detail: '核心逻辑不再是 if/else,而是由大语言模型根据 Prompt 和上下文进行推理。输出具有概率性,同样的输入可能产生不同的结果。',
techs: ['GPT-4', 'Claude', 'Prompt 工程']
},
{
icon: '🔗', name: '编排与工具层', color: '#8b5cf6',
brief: 'Agent 编排 + 工具调用',
detail: '模型可以调用外部工具(搜索、数据库、API)来获取实时信息。编排层负责管理多步推理、工具选择和结果整合。',
techs: ['LangChain', 'Function Calling', 'RAG']
},
{
icon: '📦', name: '上下文管理层', color: '#06b6d4',
brief: '向量数据库 + 记忆系统',
detail: '使用向量数据库存储和检索非结构化知识。通过 Embedding 将文本转化为语义向量,实现基于含义的搜索而非关键词匹配。',
techs: ['Pinecone', 'ChromaDB', 'Embedding']
},
{
icon: '🛡️', name: '安全与护栏层', color: '#10b981',
brief: '输出过滤 + 幻觉检测',
detail: 'AI 输出不可完全信任,需要护栏机制:内容过滤、事实核查、幻觉检测、敏感信息脱敏等。这是传统应用不需要的全新层级。',
techs: ['Guardrails', '内容审核', '事实校验']
}
]
}
}
const currentArch = computed(() => architectures[mode.value])
</script>
<style scoped>
.arch-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, var(--vp-c-brand), #f59e0b);
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
}
.subtitle { font-size: 12px; color: var(--vp-c-text-2); margin-top: 4px; }
.toggle-bar {
display: flex; gap: 8px; justify-content: center; margin-bottom: 16px;
}
.toggle-btn {
display: flex; align-items: center; gap: 6px;
padding: 8px 18px; border: 1px solid var(--vp-c-divider);
border-radius: 20px; background: var(--vp-c-bg);
cursor: pointer; transition: all 0.2s; font-size: 13px;
}
.toggle-btn:hover { background: var(--vp-c-bg-alt); }
.toggle-btn.active {
border-color: var(--vp-c-brand);
background: var(--vp-c-brand-soft);
color: var(--vp-c-brand-dark);
}
.arch-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 12px;
}
.stack {
background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider);
border-radius: 12px; padding: 12px;
display: flex; flex-direction: column; gap: 8px;
}
.stack-title { font-weight: 700; font-size: 14px; margin-bottom: 4px; }
.layer {
display: flex; align-items: center; gap: 10px;
padding: 10px 12px; border-radius: 8px;
border: 1px solid var(--vp-c-divider);
border-left: 3px solid; background: var(--vp-c-bg);
cursor: pointer; transition: all 0.2s;
}
.layer:hover { background: var(--vp-c-bg-alt); }
.layer.highlight {
border-color: var(--vp-c-brand);
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
}
.layer-icon { font-size: 20px; flex-shrink: 0; }
.layer-name { font-weight: 600; font-size: 13px; }
.layer-desc { font-size: 11px; color: var(--vp-c-text-2); margin-top: 2px; }
.detail-panel {
background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider);
border-radius: 12px; padding: 16px;
}
.detail-title { font-weight: 700; font-size: 15px; margin-bottom: 10px; }
.detail-desc { color: var(--vp-c-text-2); line-height: 1.7; font-size: 13px; margin-bottom: 12px; }
.example-label { font-weight: 600; font-size: 12px; margin-bottom: 6px; }
.tech-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.tech-tag {
padding: 3px 10px; border-radius: 12px; font-size: 11px;
background: var(--vp-c-brand-soft); color: var(--vp-c-brand-dark);
border: 1px solid var(--vp-c-brand-dimm);
}
.detail-placeholder {
color: var(--vp-c-text-3); text-align: center; padding: 40px 0; font-size: 13px;
}
.comparison-bar {
margin-top: 16px; padding: 12px 16px;
background: var(--vp-c-brand-soft); border-radius: 6px; font-size: 13px;
}
.compare-label { font-weight: 600; color: var(--vp-c-brand-dark); }
.compare-text { color: var(--vp-c-text-1); }
</style>