feat: comprehensive documentation and demo updates
- Update READMEs and docs across multiple languages - Enhance interactive demos for Agent, LLM, VLM, Audio, Image Gen, Terminal, and Web Basics - Add new appendix sections for Database and IDE intros - Update VitePress config, theme, and utility scripts - Clean up unused assets and components
This commit is contained in:
@@ -1,59 +1,45 @@
|
||||
<!--
|
||||
AgentArchitectureDemo.vue
|
||||
Agent 架构“点哪看哪”:点击模块,右侧展示它负责什么 + 典型输入输出。
|
||||
-->
|
||||
<template>
|
||||
<div class="agent-architecture-demo">
|
||||
<div class="architecture-diagram">
|
||||
<div class="diagram-center">
|
||||
<div class="agent-core">🤖 Agent</div>
|
||||
<div class="arch">
|
||||
<div class="header">
|
||||
<div>
|
||||
<div class="title">Agent 由哪些模块拼起来?</div>
|
||||
<div class="subtitle">点一下模块,看它“负责什么”。</div>
|
||||
</div>
|
||||
|
||||
<div class="modules-container">
|
||||
<div
|
||||
v-for="(module, index) in modules"
|
||||
:key="module.name"
|
||||
class="module-card"
|
||||
:class="{ active: selectedModule === index }"
|
||||
@click="selectedModule = index"
|
||||
:style="getModulePosition(index)"
|
||||
>
|
||||
<div class="module-icon">{{ module.icon }}</div>
|
||||
<div class="module-name">{{ module.name }}</div>
|
||||
<div class="module-desc">{{ module.desc }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<svg class="connections">
|
||||
<line
|
||||
v-for="(module, index) in modules"
|
||||
:key="'line-' + index"
|
||||
x1="50%"
|
||||
y1="50%"
|
||||
x2="0"
|
||||
y2="0"
|
||||
:stroke="selectedModule === index ? 'var(--vp-c-brand)' : 'var(--vp-c-divider)'"
|
||||
stroke-width="2"
|
||||
:class="{ 'line-active': selectedModule === index }"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="module-details">
|
||||
<div class="detail-header">
|
||||
<span class="detail-icon">{{ modules[selectedModule].icon }}</span>
|
||||
<h3>{{ modules[selectedModule].name }}</h3>
|
||||
<div class="grid">
|
||||
<div class="diagram">
|
||||
<button
|
||||
v-for="m in modules"
|
||||
:key="m.id"
|
||||
:class="['node', { active: current.id === m.id }]"
|
||||
@click="current = m"
|
||||
>
|
||||
<span class="icon">{{ m.icon }}</span>
|
||||
<span class="name">{{ m.name }}</span>
|
||||
</button>
|
||||
|
||||
<div class="pipes">
|
||||
<div class="pipe">用户目标 → 计划 → 工具调用 → 结果 → 再计划…</div>
|
||||
<div class="pipe small">(记忆会贯穿整个过程)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-content">
|
||||
<p>{{ modules[selectedModule].description }}</p>
|
||||
<div class="panel">
|
||||
<div class="panel-title">{{ current.icon }} {{ current.name }}</div>
|
||||
<div class="panel-body">{{ current.desc }}</div>
|
||||
|
||||
<div class="code-example">
|
||||
<div class="code-title">💻 示例代码</div>
|
||||
<pre><code>{{ modules[selectedModule].code }}</code></pre>
|
||||
<div class="io">
|
||||
<div class="io-title">典型输入</div>
|
||||
<pre><code>{{ current.input }}</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="key-points">
|
||||
<div class="point-title">🎯 关键要点</div>
|
||||
<ul>
|
||||
<li v-for="point in modules[selectedModule].points" :key="point">{{ point }}</li>
|
||||
</ul>
|
||||
<div class="io">
|
||||
<div class="io-title">典型输出</div>
|
||||
<pre><code>{{ current.output }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,346 +49,104 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const selectedModule = ref(0)
|
||||
|
||||
const modules = [
|
||||
{
|
||||
name: 'Profile',
|
||||
icon: '👤',
|
||||
desc: '角色设定',
|
||||
description: 'Profile 定义了 Agent 的身份、角色、目标和约束条件。它决定了 Agent 的行为方式和能力范围。就像给演员设定角色一样,Profile 让 Agent 知道"我是谁"和"我应该做什么"。',
|
||||
code: `profile = {
|
||||
"name": "Web Researcher",
|
||||
"role": "网络搜索助手",
|
||||
"goal": "帮助用户搜索和总结网络信息",
|
||||
"constraints": [
|
||||
"只能使用公开信息",
|
||||
"必须注明信息来源",
|
||||
"不能访问付费内容"
|
||||
],
|
||||
"style": "专业、简洁、准确"
|
||||
}`,
|
||||
points: [
|
||||
'明确定义 Agent 的职责范围',
|
||||
'设定合理的目标和约束',
|
||||
'塑造 Agent 的沟通风格',
|
||||
'防止 Agent 超出权限范围'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Memory',
|
||||
id: 'llm',
|
||||
icon: '🧠',
|
||||
desc: '记忆系统',
|
||||
description: 'Memory 是 Agent 的"大脑",用于存储和检索信息。它包括短期记忆(当前对话)、长期记忆(持久化知识)和工作记忆(当前任务状态)。好的记忆系统能让 Agent 从历史经验中学习。',
|
||||
code: `memory = {
|
||||
# 短期记忆:当前对话
|
||||
"short_term": [
|
||||
{"role": "user", "content": "搜索 AI 文章"},
|
||||
{"role": "assistant", "content": "已找到 5 篇"}
|
||||
],
|
||||
|
||||
# 长期记忆:持久化知识
|
||||
"long_term": {
|
||||
"user_preferences": {...},
|
||||
"previous_tasks": [...]
|
||||
},
|
||||
|
||||
# 工作记忆:当前任务状态
|
||||
"working_memory": {
|
||||
"current_goal": "总结第 3 篇文章",
|
||||
"completed_steps": [1, 2],
|
||||
"pending_steps": [3, 4, 5]
|
||||
}
|
||||
}`,
|
||||
points: [
|
||||
'短期记忆:存储当前对话历史',
|
||||
'长期记忆:保存跨任务的知识',
|
||||
'工作记忆:追踪当前任务进度',
|
||||
'支持信息的快速检索和更新'
|
||||
]
|
||||
name: 'LLM(大脑)',
|
||||
desc: '负责理解目标、生成计划、选择动作、组织语言输出。',
|
||||
input: '用户目标 + 当前状态 + 可用工具列表',
|
||||
output: '下一步计划 / 工具调用参数 / 最终回答'
|
||||
},
|
||||
{
|
||||
name: 'Planning',
|
||||
icon: '📋',
|
||||
desc: '规划模块',
|
||||
description: 'Planning 负责将复杂任务分解为可执行的步骤。它能制定计划、调整策略、评估进度。好的规划能力是 Agent 完成复杂任务的关键。',
|
||||
code: `planning = {
|
||||
"goal": "搜索并总结 AI 文章",
|
||||
|
||||
"steps": [
|
||||
{
|
||||
"id": 1,
|
||||
"action": "web_search",
|
||||
"params": {"query": "AI 技术 2024"},
|
||||
"status": "completed"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"action": "filter_results",
|
||||
"params": {"top_n": 5},
|
||||
"status": "in_progress"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"action": "read_pages",
|
||||
"params": {"urls": [...]},
|
||||
"status": "pending"
|
||||
}
|
||||
],
|
||||
|
||||
"current_step": 2,
|
||||
"total_steps": 5
|
||||
}`,
|
||||
points: [
|
||||
'将复杂任务分解为小步骤',
|
||||
'动态调整执行计划',
|
||||
'跟踪每个步骤的执行状态',
|
||||
'支持并行和串行任务执行'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Action',
|
||||
id: 'tools',
|
||||
icon: '🔧',
|
||||
desc: '执行模块',
|
||||
description: 'Action 模块负责执行具体的操作,包括调用工具、修改文件、发送请求等。它是 Agent 与外部环境交互的接口,将"想法"转化为"行动"。',
|
||||
code: `action = {
|
||||
"tool": "web_search",
|
||||
"input": {
|
||||
"query": "AI 技术 2024",
|
||||
"max_results": 10,
|
||||
"time_range": "last_month"
|
||||
name: 'Tools(手脚)',
|
||||
desc: '负责真正“做事”:搜索、读写文件、调用 API、运行命令。',
|
||||
input: 'tool_name + input_schema 参数',
|
||||
output: '工具执行结果(文本/数据/文件变更)'
|
||||
},
|
||||
"output": {
|
||||
"status": "success",
|
||||
"results": [
|
||||
{
|
||||
"title": "...",
|
||||
"url": "...",
|
||||
"snippet": "..."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
# 可用工具
|
||||
tools = [
|
||||
"web_search", # 搜索引擎
|
||||
"read_page", # 读取网页
|
||||
"write_file", # 写入文件
|
||||
"run_code" # 执行代码
|
||||
]`,
|
||||
points: [
|
||||
'提供丰富的工具集',
|
||||
'处理工具调用的输入输出',
|
||||
'管理工具的权限和安全',
|
||||
'支持自定义工具扩展'
|
||||
]
|
||||
{
|
||||
id: 'memory',
|
||||
icon: '💾',
|
||||
name: 'Memory(记忆)',
|
||||
desc: '把“已经做过什么、得到什么结果”存起来,避免重复与跑偏。',
|
||||
input: '对话历史 / 工具结果 / 当前任务状态',
|
||||
output: '可检索的上下文(短期/长期/工作记忆)'
|
||||
},
|
||||
{
|
||||
id: 'planner',
|
||||
icon: '🧩',
|
||||
name: 'Planning(规划)',
|
||||
desc: '把大目标拆成小步骤,并在失败时改计划(计划不是一次性的)。',
|
||||
input: '目标 + 约束(预算/时间/安全) + 当前进度',
|
||||
output: '步骤清单 / 下一步动作 / 停止条件'
|
||||
},
|
||||
{
|
||||
id: 'guard',
|
||||
icon: '🛡️',
|
||||
name: 'Guardrails(护栏)',
|
||||
desc: '限制风险:权限白名单、预算上限、敏感操作确认、沙箱执行。',
|
||||
input: '请求执行的动作 + 安全策略',
|
||||
output: '允许/拒绝/要求确认 + 审计日志'
|
||||
}
|
||||
]
|
||||
|
||||
const getModulePosition = (index) => {
|
||||
const positions = [
|
||||
{ top: '0', left: '50%', transform: 'translate(-50%, -50%)' },
|
||||
{ top: '50%', right: '0', transform: 'translate(50%, -50%)' },
|
||||
{ bottom: '0', left: '50%', transform: 'translate(-50%, 50%)' },
|
||||
{ top: '50%', left: '0', transform: 'translate(-50%, -50%)' }
|
||||
]
|
||||
return positions[index]
|
||||
}
|
||||
const current = ref(modules[0])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.agent-architecture-demo {
|
||||
.arch {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
||||
.architecture-diagram {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 4/3;
|
||||
max-width: 600px;
|
||||
margin: 0 auto 32px;
|
||||
}
|
||||
|
||||
.diagram-center {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.agent-core {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
padding: 20px 30px;
|
||||
border-radius: 50%;
|
||||
font-weight: bold;
|
||||
font-size: 1.2rem;
|
||||
box-shadow: 0 4px 20px rgba(66, 153, 225, 0.4);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.modules-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.module-card {
|
||||
position: absolute;
|
||||
background: var(--vp-c-bg);
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
min-width: 140px;
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.module-card:hover {
|
||||
border-color: var(--vp-c-brand);
|
||||
transform: scale(1.05) !important;
|
||||
}
|
||||
.header { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
|
||||
.title { font-weight: 800; }
|
||||
.subtitle { color: var(--vp-c-text-2); font-size: 13px; }
|
||||
|
||||
.module-card.active {
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-bg-soft);
|
||||
box-shadow: 0 4px 20px rgba(66, 153, 225, 0.3);
|
||||
}
|
||||
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px; }
|
||||
|
||||
.module-icon {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.module-name {
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.module-desc {
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.connections {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.connections line {
|
||||
transition: stroke 0.3s;
|
||||
}
|
||||
|
||||
.line-active {
|
||||
stroke-width: 3;
|
||||
stroke-dasharray: 5, 5;
|
||||
animation: dash 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes dash {
|
||||
to {
|
||||
stroke-dashoffset: -10;
|
||||
}
|
||||
}
|
||||
|
||||
.module-details {
|
||||
.diagram {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
.node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 2px solid var(--vp-c-divider);
|
||||
gap: 10px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg);
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.detail-icon {
|
||||
font-size: 2rem;
|
||||
}
|
||||
.node.active { border-color: var(--vp-c-brand); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.06); }
|
||||
.icon { width: 28px; height: 28px; border-radius: 8px; display: grid; place-items: center; background: var(--vp-c-bg-soft); border: 1px solid var(--vp-c-divider); }
|
||||
.name { font-weight: 800; }
|
||||
|
||||
.detail-header h3 {
|
||||
margin: 0;
|
||||
color: var(--vp-c-brand);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
.pipes { margin-top: 6px; padding-top: 10px; border-top: 1px dashed var(--vp-c-divider); }
|
||||
.pipe { color: var(--vp-c-text-2); font-size: 13px; line-height: 1.5; }
|
||||
.pipe.small { font-size: 12px; color: var(--vp-c-text-3); }
|
||||
|
||||
.detail-content > p {
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.7;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.code-example {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.code-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #1e1e1e;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: 'Monaco', 'Courier New', monospace;
|
||||
font-size: 0.85rem;
|
||||
color: #d4d4d4;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.key-points {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
border-left: 4px solid var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.point-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.key-points ul {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.key-points li {
|
||||
padding: 4px 0;
|
||||
color: var(--vp-c-text-2);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.key-points li::before {
|
||||
content: '✓';
|
||||
position: absolute;
|
||||
left: -20px;
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: bold;
|
||||
}
|
||||
.panel { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 12px; padding: 12px; display: flex; flex-direction: column; gap: 10px; }
|
||||
.panel-title { font-weight: 800; }
|
||||
.panel-body { color: var(--vp-c-text-2); line-height: 1.6; }
|
||||
.io-title { font-weight: 700; margin-bottom: 6px; }
|
||||
pre { margin: 0; background: #0b1221; color: #e5e7eb; border-radius: 10px; padding: 12px; font-family: var(--vp-font-family-mono); font-size: 13px; overflow-x: auto; white-space: pre-wrap; }
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,490 +1,108 @@
|
||||
<!--
|
||||
AgentChallengesDemo.vue
|
||||
挑战不是“列清单”,而是“能感受到风险”:
|
||||
- 开关护栏(步数上限/预算/确认/沙箱)
|
||||
- 看风险分数怎么变化
|
||||
-->
|
||||
<template>
|
||||
<div class="agent-challenges-demo">
|
||||
<div class="challenges-grid">
|
||||
<div
|
||||
v-for="(challenge, index) in challenges"
|
||||
:key="challenge.title"
|
||||
class="challenge-card"
|
||||
:class="{ active: selectedChallenge === index }"
|
||||
@click="selectedChallenge = index"
|
||||
>
|
||||
<div class="challenge-icon">{{ challenge.icon }}</div>
|
||||
<div class="challenge-title">{{ challenge.title }}</div>
|
||||
<div class="challenge-level">
|
||||
<span
|
||||
v-for="i in challenge.difficulty"
|
||||
:key="i"
|
||||
class="difficulty-star"
|
||||
>⭐</span>
|
||||
</div>
|
||||
<div class="risk">
|
||||
<div class="header">
|
||||
<div>
|
||||
<div class="title">Agent 的挑战:没护栏就容易“翻车”</div>
|
||||
<div class="subtitle">打开这些护栏,风险会明显下降。</div>
|
||||
</div>
|
||||
<div class="score" :class="scoreClass">风险分数:{{ score }}/100</div>
|
||||
</div>
|
||||
|
||||
<div class="challenge-detail">
|
||||
<div class="detail-header">
|
||||
<span class="detail-icon">{{ challenges[selectedChallenge].icon }}</span>
|
||||
<h3>{{ challenges[selectedChallenge].title }}</h3>
|
||||
<div class="controls">
|
||||
<label class="toggle"><input type="checkbox" v-model="maxSteps" /> 最大迭代次数(防死循环)</label>
|
||||
<label class="toggle"><input type="checkbox" v-model="budget" /> 预算上限(防烧钱)</label>
|
||||
<label class="toggle"><input type="checkbox" v-model="confirm" /> 危险操作二次确认</label>
|
||||
<label class="toggle"><input type="checkbox" v-model="sandbox" /> 沙箱执行(隔离系统)</label>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<div class="card">
|
||||
<div class="k">常见风险</div>
|
||||
<ul>
|
||||
<li>重复尝试 → 死循环</li>
|
||||
<li>乱用工具 → 误删/误发</li>
|
||||
<li>外部内容注入 → 被带偏</li>
|
||||
<li>调用太多 → 成本失控</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="detail-sections">
|
||||
<div class="detail-section">
|
||||
<h4>📖 问题描述</h4>
|
||||
<p>{{ challenges[selectedChallenge].description }}</p>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<h4>💡 为什么困难?</h4>
|
||||
<ul>
|
||||
<li v-for="reason in challenges[selectedChallenge].reasons" :key="reason">
|
||||
{{ reason }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<h4>🔧 解决方案</h4>
|
||||
<div class="solutions">
|
||||
<div
|
||||
v-for="solution in challenges[selectedChallenge].solutions"
|
||||
:key="solution.title"
|
||||
class="solution-item"
|
||||
>
|
||||
<div class="solution-title">{{ solution.title }}</div>
|
||||
<div class="solution-desc">{{ solution.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<h4>📊 当前进展</h4>
|
||||
<div class="progress-item">
|
||||
<div class="progress-label">解决进度</div>
|
||||
<div class="progress-bar">
|
||||
<div
|
||||
class="progress-fill"
|
||||
:style="{ width: challenges[selectedChallenge].progress + '%' }"
|
||||
></div>
|
||||
</div>
|
||||
<div class="progress-value">{{ challenges[selectedChallenge].progress }}%</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<h4>🔗 相关资源</h4>
|
||||
<div class="resources">
|
||||
<a
|
||||
v-for="resource in challenges[selectedChallenge].resources"
|
||||
:key="resource.title"
|
||||
:href="resource.url"
|
||||
target="_blank"
|
||||
class="resource-link"
|
||||
>
|
||||
{{ resource.title }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="k">你现在开启了什么?</div>
|
||||
<div class="v">{{ enabledList }}</div>
|
||||
<div class="note">建议:最少也要有“最大步数 + 确认”。</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="k">一句话建议</div>
|
||||
<div class="v">{{ advice }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
const selectedChallenge = ref(0)
|
||||
const maxSteps = ref(true)
|
||||
const budget = ref(false)
|
||||
const confirm = ref(true)
|
||||
const sandbox = ref(false)
|
||||
|
||||
const challenges = [
|
||||
{
|
||||
title: '任务规划',
|
||||
icon: '📋',
|
||||
difficulty: 5,
|
||||
description: 'Agent 需要将复杂的用户任务分解为可执行的步骤,并动态调整计划。这要求 Agent 具备强大的推理能力和前瞻性思维。',
|
||||
reasons: [
|
||||
'任务分解需要深度理解用户意图',
|
||||
'长期规划容易偏离目标',
|
||||
'动态调整计划增加了复杂性',
|
||||
'缺乏反馈时难以评估进度'
|
||||
],
|
||||
solutions: [
|
||||
{
|
||||
title: '层次化规划',
|
||||
description: '将大任务分解为子任务,子任务再分解为具体步骤,形成层次结构。'
|
||||
},
|
||||
{
|
||||
title: '反思机制',
|
||||
description: '定期回顾已完成的步骤,评估计划的有效性,及时调整策略。'
|
||||
},
|
||||
{
|
||||
title: '外部记忆',
|
||||
description: '使用 todo.md 等文件记录计划,将目标保持在 Agent 的"视野"中。'
|
||||
}
|
||||
],
|
||||
progress: 40,
|
||||
resources: [
|
||||
{ title: 'ReAct 论文', url: 'https://arxiv.org/abs/2210.03629' },
|
||||
{ title: 'Tree of Thoughts', url: 'https://arxiv.org/abs/2305.10601' }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '上下文管理',
|
||||
icon: '🧠',
|
||||
difficulty: 5,
|
||||
description: 'Agent 在多次迭代中会积累大量上下文,如何有效管理、压缩和检索这些信息是一个巨大挑战。',
|
||||
reasons: [
|
||||
'上下文长度受限(128K-200K)',
|
||||
'长上下文会降低模型性能',
|
||||
'重要信息可能被"淹没"',
|
||||
'成本随长度线性增长'
|
||||
],
|
||||
solutions: [
|
||||
{
|
||||
title: 'KV 缓存优化',
|
||||
description: '保持前缀稳定,只追加不修改,提高缓存命中率,降低 90% 成本。'
|
||||
},
|
||||
{
|
||||
title: '外部记忆',
|
||||
description: '大内容写入文件系统,上下文只保留引用和路径。'
|
||||
},
|
||||
{
|
||||
title: '智能压缩',
|
||||
description: '使用摘要、选择性保留、语义压缩等技术减少上下文长度。'
|
||||
}
|
||||
],
|
||||
progress: 60,
|
||||
resources: [
|
||||
{ title: '上下文工程指南', url: '#' },
|
||||
{ title: 'Manus 最佳实践', url: '#' }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '工具使用',
|
||||
icon: '🔧',
|
||||
difficulty: 4,
|
||||
description: 'Agent 需要从众多工具中选择正确的工具,并正确调用它们。工具选择错误或调用失败都会导致任务失败。',
|
||||
reasons: [
|
||||
'工具数量多,选择困难',
|
||||
'工具参数复杂,容易出错',
|
||||
'工具调用失败需要恢复',
|
||||
'工具之间可能存在依赖关系'
|
||||
],
|
||||
solutions: [
|
||||
{
|
||||
title: 'Logits 遮蔽',
|
||||
description: '使用前缀限制模型只能调用特定工具,避免选择错误的工具。'
|
||||
},
|
||||
{
|
||||
title: '工具分组',
|
||||
description: '将工具按功能分类(如 browser_、shell_),便于选择和管理。'
|
||||
},
|
||||
{
|
||||
title: '错误恢复',
|
||||
description: '保留失败尝试在上下文中,让 Agent 从错误中学习。'
|
||||
}
|
||||
],
|
||||
progress: 70,
|
||||
resources: [
|
||||
{ title: 'Function Calling 指南', url: '#' },
|
||||
{ title: '工具设计最佳实践', url: '#' }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '记忆系统',
|
||||
icon: '💾',
|
||||
difficulty: 4,
|
||||
description: 'Agent 需要记住历史信息、学习经验、识别模式。设计一个高效的记忆系统对 Agent 的长期性能至关重要。',
|
||||
reasons: [
|
||||
'需要区分即时、短期、长期记忆',
|
||||
'信息检索和更新的效率',
|
||||
'记忆的准确性和相关性',
|
||||
'跨任务的知识迁移'
|
||||
],
|
||||
solutions: [
|
||||
{
|
||||
title: '三层记忆架构',
|
||||
description: '即时上下文(当前对话)+ 短期记忆(会话级)+ 长期记忆(持久化)。'
|
||||
},
|
||||
{
|
||||
title: '向量检索',
|
||||
description: '使用嵌入和向量数据库实现语义相似度检索。'
|
||||
},
|
||||
{
|
||||
title: '记忆整合',
|
||||
description: '定期将短期记忆中的重要信息转移到长期记忆。'
|
||||
}
|
||||
],
|
||||
progress: 50,
|
||||
resources: [
|
||||
{ title: 'RAG 技术', url: '#' },
|
||||
{ title: '向量数据库指南', url: '#' }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '错误处理',
|
||||
icon: '⚠️',
|
||||
difficulty: 3,
|
||||
description: 'Agent 在执行过程中会遇到各种错误:工具失败、网络超时、无效响应等。如何优雅地处理这些错误是一个挑战。',
|
||||
reasons: [
|
||||
'错误类型多样',
|
||||
'需要区分可恢复和不可恢复的错误',
|
||||
'错误可能级联传播',
|
||||
'重试策略需要优化'
|
||||
],
|
||||
solutions: [
|
||||
{
|
||||
title: '保留错误信息',
|
||||
description: '将失败的尝试保留在上下文中,让 Agent 学习并避免重复错误。'
|
||||
},
|
||||
{
|
||||
title: '重试机制',
|
||||
description: '对于可恢复的错误,实现指数退避的重试策略。'
|
||||
},
|
||||
{
|
||||
title: '回滚和恢复',
|
||||
description: '支持任务状态的保存和恢复,避免完全重新开始。'
|
||||
}
|
||||
],
|
||||
progress: 65,
|
||||
resources: [
|
||||
{ title: '错误处理最佳实践', url: '#' },
|
||||
{ title: '容错设计模式', url: '#' }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '安全防护',
|
||||
icon: '🛡️',
|
||||
difficulty: 5,
|
||||
description: 'Agent 具有执行能力,如果被恶意利用可能造成严重后果。提示注入、工具滥用、数据泄露都是需要防范的安全风险。',
|
||||
reasons: [
|
||||
'提示注入攻击难以检测',
|
||||
'Agent 可能被诱导执行危险操作',
|
||||
'敏感信息可能泄露',
|
||||
'攻击面广,难以全面防护'
|
||||
],
|
||||
solutions: [
|
||||
{
|
||||
title: '输入清理',
|
||||
description: '严格清理和验证用户输入,分离系统和用户消息。'
|
||||
},
|
||||
{
|
||||
title: '权限控制',
|
||||
description: '使用白名单限制工具访问,敏感操作需要二次确认。'
|
||||
},
|
||||
{
|
||||
title: '沙箱环境',
|
||||
description: '在隔离的沙箱中执行危险操作,限制资源访问。'
|
||||
},
|
||||
{
|
||||
title: '输出过滤',
|
||||
description: '过滤敏感信息,加密存储数据,定期审计日志。'
|
||||
}
|
||||
],
|
||||
progress: 55,
|
||||
resources: [
|
||||
{ title: 'AI 安全指南', url: '#' },
|
||||
{ title: 'OWASP LLM Top 10', url: '#' }
|
||||
]
|
||||
}
|
||||
]
|
||||
const score = computed(() => {
|
||||
let s = 85
|
||||
if (maxSteps.value) s -= 18
|
||||
if (budget.value) s -= 15
|
||||
if (confirm.value) s -= 22
|
||||
if (sandbox.value) s -= 18
|
||||
return Math.max(0, s)
|
||||
})
|
||||
|
||||
const scoreClass = computed(() => {
|
||||
if (score.value <= 35) return 'good'
|
||||
if (score.value <= 60) return 'mid'
|
||||
return 'bad'
|
||||
})
|
||||
|
||||
const enabledList = computed(() => {
|
||||
const items = []
|
||||
if (maxSteps.value) items.push('最大步数')
|
||||
if (budget.value) items.push('预算上限')
|
||||
if (confirm.value) items.push('二次确认')
|
||||
if (sandbox.value) items.push('沙箱')
|
||||
return items.length ? items.join('、') : '(都没开)'
|
||||
})
|
||||
|
||||
const advice = computed(() => {
|
||||
if (!maxSteps.value && !confirm.value) return '先加“最大步数”和“二次确认”,这是最低成本的安全感。'
|
||||
if (score.value <= 35) return '很稳了:可以开始做更复杂的任务,但记得加日志与监控。'
|
||||
if (score.value <= 60) return '还不错:建议再加预算或沙箱,避免极端情况。'
|
||||
return '风险偏高:建议优先补护栏,再让 Agent 真去执行。'
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.agent-challenges-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin: 24px 0;
|
||||
}
|
||||
.risk { border: 1px solid var(--vp-c-divider); border-radius: 12px; background: var(--vp-c-bg-soft); padding: 16px; margin: 20px 0; display: flex; flex-direction: column; gap: 12px; }
|
||||
.header { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; align-items: center; }
|
||||
.title { font-weight: 800; }
|
||||
.subtitle { color: var(--vp-c-text-2); font-size: 13px; }
|
||||
.score { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 999px; padding: 8px 12px; font-weight: 900; }
|
||||
.score.good { color: #22c55e; border-color: rgba(34, 197, 94, 0.4); }
|
||||
.score.mid { color: #f59e0b; border-color: rgba(245, 158, 11, 0.4); }
|
||||
.score.bad { color: #ef4444; border-color: rgba(239, 68, 68, 0.4); }
|
||||
|
||||
.challenges-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.controls { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 12px; padding: 10px 12px; display: flex; flex-wrap: wrap; gap: 12px; }
|
||||
.toggle { display: flex; gap: 8px; align-items: center; }
|
||||
input { accent-color: var(--vp-c-brand); }
|
||||
|
||||
.challenge-card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.challenge-card:hover {
|
||||
border-color: var(--vp-c-brand);
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 4px 20px rgba(66, 153, 225, 0.2);
|
||||
}
|
||||
|
||||
.challenge-card.active {
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-bg-soft);
|
||||
}
|
||||
|
||||
.challenge-icon {
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.challenge-title {
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 8px;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.challenge-level {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.difficulty-star {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.challenge-detail {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 2px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.detail-icon {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.detail-header h3 {
|
||||
margin: 0;
|
||||
color: var(--vp-c-brand);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.detail-sections {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.detail-section h4 {
|
||||
margin: 0 0 12px 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.detail-section p {
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.7;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.detail-section ul {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.detail-section li {
|
||||
padding: 4px 0;
|
||||
color: var(--vp-c-text-2);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.detail-section li::before {
|
||||
content: '•';
|
||||
position: absolute;
|
||||
left: -16px;
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.solutions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.solution-item {
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.solution-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.solution-desc {
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.progress-item {
|
||||
display: grid;
|
||||
grid-template-columns: 100px 1fr 60px;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.progress-label {
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: 24px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, var(--vp-c-brand), var(--vp-c-brand-light));
|
||||
border-radius: 12px;
|
||||
transition: width 0.5s ease;
|
||||
}
|
||||
|
||||
.progress-value {
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-brand);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.resources {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.resource-link {
|
||||
padding: 10px 20px;
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.resource-link:hover {
|
||||
background: var(--vp-c-brand-dark);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; }
|
||||
.card { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 12px; padding: 12px; }
|
||||
.k { font-weight: 900; margin-bottom: 6px; }
|
||||
.v { color: var(--vp-c-text-2); line-height: 1.6; }
|
||||
.note { margin-top: 6px; color: var(--vp-c-text-3); font-size: 12px; }
|
||||
ul { margin: 0; padding-left: 18px; color: var(--vp-c-text-2); line-height: 1.6; }
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,85 +1,38 @@
|
||||
<!--
|
||||
AgentFutureDemo.vue
|
||||
Agent 未来方向:点选趋势,看看“会带来什么变化”和“现在就能做的准备”。
|
||||
-->
|
||||
<template>
|
||||
<div class="agent-future-demo">
|
||||
<div class="future-intro">
|
||||
<h3>🚀 Agent 的未来展望</h3>
|
||||
<p>探索 Agent 技术的发展趋势和应用前景</p>
|
||||
<div class="future">
|
||||
<div class="header">
|
||||
<div>
|
||||
<div class="title">Agent 的未来:更稳、更强、更协作</div>
|
||||
<div class="subtitle">点一个趋势,看它意味着什么。</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline">
|
||||
<div class="timeline-line"></div>
|
||||
|
||||
<div
|
||||
v-for="(era, index) in timeline"
|
||||
:key="era.period"
|
||||
class="timeline-item"
|
||||
:class="{ active: selectedEra === index }"
|
||||
@click="selectedEra = index"
|
||||
<div class="chips">
|
||||
<button
|
||||
v-for="t in trends"
|
||||
:key="t.id"
|
||||
:class="['chip', { active: current.id === t.id }]"
|
||||
@click="current = t"
|
||||
>
|
||||
<div class="timeline-dot"></div>
|
||||
<div class="timeline-content">
|
||||
<div class="era-period">{{ era.period }}</div>
|
||||
<div class="era-title">{{ era.title }}</div>
|
||||
<div class="era-description">{{ era.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ t.label }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="era-details">
|
||||
<div class="detail-card">
|
||||
<h4>{{ timeline[selectedEra].title }} ({{ timeline[selectedEra].period }})</h4>
|
||||
<p class="era-detail-desc">{{ timeline[selectedEra].detailDescription }}</p>
|
||||
|
||||
<div class="era-features">
|
||||
<div class="features-title">🎯 关键特征</div>
|
||||
<div class="features-list">
|
||||
<div
|
||||
v-for="feature in timeline[selectedEra].features"
|
||||
:key="feature"
|
||||
class="feature-tag"
|
||||
>
|
||||
{{ feature }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="p-title">{{ current.label }}</div>
|
||||
<div class="p-body">{{ current.desc }}</div>
|
||||
<div class="grid">
|
||||
<div class="card">
|
||||
<div class="k">会带来什么?</div>
|
||||
<div class="v">{{ current.impact }}</div>
|
||||
</div>
|
||||
|
||||
<div class="era-applications">
|
||||
<div class="applications-title">💼 典型应用</div>
|
||||
<div class="applications-grid">
|
||||
<div
|
||||
v-for="app in timeline[selectedEra].applications"
|
||||
:key="app.name"
|
||||
class="app-item"
|
||||
>
|
||||
<div class="app-icon">{{ app.icon }}</div>
|
||||
<div class="app-name">{{ app.name }}</div>
|
||||
<div class="app-desc">{{ app.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="era-challenges">
|
||||
<div class="challenges-title">⚠️ 面临挑战</div>
|
||||
<ul>
|
||||
<li v-for="challenge in timeline[selectedEra].challenges" :key="challenge">
|
||||
{{ challenge }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="future-predictions">
|
||||
<h4>🔮 未来预测</h4>
|
||||
<div class="predictions-grid">
|
||||
<div
|
||||
v-for="(prediction, index) in predictions"
|
||||
:key="prediction.title"
|
||||
class="prediction-card"
|
||||
>
|
||||
<div class="prediction-icon">{{ prediction.icon }}</div>
|
||||
<div class="prediction-title">{{ prediction.title }}</div>
|
||||
<div class="prediction-desc">{{ prediction.description }}</div>
|
||||
<div class="prediction-time">预计实现:{{ prediction.timeline }}</div>
|
||||
<div class="card">
|
||||
<div class="k">你现在能做什么准备?</div>
|
||||
<div class="v">{{ current.prepare }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -89,435 +42,56 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const selectedEra = ref(3)
|
||||
|
||||
const timeline = [
|
||||
const trends = [
|
||||
{
|
||||
period: '2023-2024',
|
||||
title: '萌芽期',
|
||||
description: '单 Agent,简单工具调用',
|
||||
detailDescription: 'Agent 技术的起步阶段,主要是简单的单 Agent 系统,能够调用有限工具完成基础任务。这个阶段证明了 Agent 的可行性,但能力还比较有限。',
|
||||
features: [
|
||||
'单一 Agent 执行',
|
||||
'基础工具调用',
|
||||
'简单的任务规划',
|
||||
'有限的记忆能力'
|
||||
],
|
||||
applications: [
|
||||
{ icon: '💬', name: '聊天机器人', description: '增强型对话助手' },
|
||||
{ icon: '🔍', name: '搜索助手', description: '信息检索和汇总' },
|
||||
{ icon: '📝', name: '写作助手', description: '内容生成辅助' }
|
||||
],
|
||||
challenges: [
|
||||
'规划能力弱',
|
||||
'容易迷失目标',
|
||||
'上下文管理困难',
|
||||
'错误恢复能力差'
|
||||
]
|
||||
id: 'planning',
|
||||
label: '更强规划',
|
||||
desc: '把大目标拆成更合理的子任务,并能动态改计划。',
|
||||
impact: '更少跑题、更少漏步骤,复杂任务成功率更高。',
|
||||
prepare: '学会写“计划/检查点”,并把任务拆成可验收小块。'
|
||||
},
|
||||
{
|
||||
period: '2024-2025',
|
||||
title: '成长期',
|
||||
description: '多工具,复杂任务处理',
|
||||
detailDescription: 'Agent 开始能够处理更复杂的任务,使用多个工具,具备基本的规划能力。框架和工具日趋成熟,开始出现实际应用。',
|
||||
features: [
|
||||
'多工具协作',
|
||||
'层次化任务分解',
|
||||
'短期记忆管理',
|
||||
'基础的反思能力'
|
||||
],
|
||||
applications: [
|
||||
{ icon: '💻', name: '编程助手', description: '代码编写和调试' },
|
||||
{ icon: '📊', name: '数据分析', description: '自动化报告生成' },
|
||||
{ icon: '🌐', name: 'Web Agent', description: '网页自动化操作' }
|
||||
],
|
||||
challenges: [
|
||||
'长期规划困难',
|
||||
'记忆容量有限',
|
||||
'工具选择不准确',
|
||||
'安全风险增加'
|
||||
]
|
||||
id: 'memory',
|
||||
label: '更好记忆',
|
||||
desc: '长期记住偏好、事实与项目状态,跨任务复用。',
|
||||
impact: '更像长期同事:越用越懂你,重复工作更少。',
|
||||
prepare: '设计记忆结构:短期/长期/工作记忆,并做好隐私与脱敏。'
|
||||
},
|
||||
{
|
||||
period: '2025-2026',
|
||||
title: '成熟期',
|
||||
description: '多 Agent 协作,专业化分工',
|
||||
detailDescription: '多个专业化的 Agent 开始协作,每个 Agent 专注于特定领域。通过通信和协作完成复杂任务,形成 AI 团队。',
|
||||
features: [
|
||||
'多 Agent 协作',
|
||||
'专业化分工',
|
||||
'持久化记忆',
|
||||
'主动学习和改进'
|
||||
],
|
||||
applications: [
|
||||
{ icon: '👥', name: 'AI 团队', description: '协作完成复杂项目' },
|
||||
{ icon: '🔬', name: '研究助手', description: '自动化科研流程' },
|
||||
{ icon: '🏢', name: '企业助手', description: '业务流程自动化' }
|
||||
],
|
||||
challenges: [
|
||||
'Agent 间通信效率',
|
||||
'协作策略优化',
|
||||
'资源调度复杂',
|
||||
'责任归属问题'
|
||||
]
|
||||
id: 'multi',
|
||||
label: '多 Agent 协作',
|
||||
desc: '多个角色并行处理,再由协调者合并输出。',
|
||||
impact: '大任务并行化,质量更稳(研究/实现/评审分工)。',
|
||||
prepare: '先把“角色边界”和“交付格式”定义清楚。'
|
||||
},
|
||||
{
|
||||
period: '2026-2028',
|
||||
title: '进化期',
|
||||
description: '自主 Agent,持续学习',
|
||||
detailDescription: 'Agent 具备强大的自主学习和改进能力,能够从经验中学习,优化自己的行为。可以适应新环境,掌握新技能,实现真正的智能。',
|
||||
features: [
|
||||
'自主学习和优化',
|
||||
'跨任务知识迁移',
|
||||
'多模态理解',
|
||||
'情感和个性'
|
||||
],
|
||||
applications: [
|
||||
{ icon: '🤖', name: '个人助理', description: '全天候智能助手' },
|
||||
{ icon: '🎨', name: '创意专家', description: '艺术创作和设计' },
|
||||
{ icon: '🔬', name: '科学家', description: '独立开展研究' }
|
||||
],
|
||||
challenges: [
|
||||
'伦理和道德',
|
||||
'可控性和安全性',
|
||||
'社会接受度',
|
||||
'法律监管'
|
||||
]
|
||||
},
|
||||
{
|
||||
period: '2028+',
|
||||
title: '融合期',
|
||||
description: '人机共生,Agent 社会',
|
||||
detailDescription: 'Agent 深度融入人类社会,成为工作、生活不可或缺的伙伴。形成复杂的 Agent 社会,与人类共同创造价值。',
|
||||
features: [
|
||||
'人机深度融合',
|
||||
'Agent 社会形成',
|
||||
'集体智能涌现',
|
||||
'通用人工智能'
|
||||
],
|
||||
applications: [
|
||||
{ icon: '🌍', name: '全球协作', description: '跨区域 Agent 协作' },
|
||||
{ icon: '🧠', name: '知识网络', description: '全人类知识整合' },
|
||||
{ icon: '🚀', name: '创新引擎', description: '加速科技发展' }
|
||||
],
|
||||
challenges: [
|
||||
'人类身份认同',
|
||||
'社会结构变化',
|
||||
'AI 治理',
|
||||
'存在性风险'
|
||||
]
|
||||
id: 'safety',
|
||||
label: '更强安全护栏',
|
||||
desc: '更细的权限、确认与审计,降低工具滥用风险。',
|
||||
impact: '更容易上线到真实业务场景,减少事故。',
|
||||
prepare: '默认开启:最大步数、预算上限、危险操作确认、沙箱。'
|
||||
}
|
||||
]
|
||||
|
||||
const predictions = [
|
||||
{
|
||||
icon: '🧠',
|
||||
title: '通用 Agent',
|
||||
description: '能够处理几乎所有类型的任务,达到人类专家水平',
|
||||
timeline: '2027-2030'
|
||||
},
|
||||
{
|
||||
icon: '👥',
|
||||
title: 'Agent 社会',
|
||||
description: '数百万 Agent 协作工作,形成复杂的经济系统',
|
||||
timeline: '2028-2032'
|
||||
},
|
||||
{
|
||||
icon: '🔬',
|
||||
title: '科学突破',
|
||||
description: 'Agent 帮助人类在药物、材料、能源等领域取得重大突破',
|
||||
timeline: '2026-2028'
|
||||
},
|
||||
{
|
||||
icon: '🎨',
|
||||
title: '创意革命',
|
||||
description: 'Agent 在艺术、音乐、文学等创作领域达到大师水准',
|
||||
timeline: '2025-2027'
|
||||
},
|
||||
{
|
||||
icon: '🏥',
|
||||
title: '医疗革命',
|
||||
description: 'Agent 医生提供个性化、精准化的医疗服务',
|
||||
timeline: '2026-2029'
|
||||
},
|
||||
{
|
||||
icon: '🌍',
|
||||
title: '全球协作',
|
||||
description: 'Agent 打破语言和文化障碍,实现真正的全球协作',
|
||||
timeline: '2027-2030'
|
||||
}
|
||||
]
|
||||
const current = ref(trends[0])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.agent-future-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin: 24px 0;
|
||||
}
|
||||
.future { border: 1px solid var(--vp-c-divider); border-radius: 12px; background: var(--vp-c-bg-soft); padding: 16px; margin: 20px 0; display: flex; flex-direction: column; gap: 12px; }
|
||||
.header { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
|
||||
.title { font-weight: 800; }
|
||||
.subtitle { color: var(--vp-c-text-2); font-size: 13px; }
|
||||
|
||||
.future-intro {
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.chips { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
.chip { border: 1px solid var(--vp-c-divider); background: var(--vp-c-bg); padding: 8px 12px; border-radius: 999px; cursor: pointer; }
|
||||
.chip.active { border-color: var(--vp-c-brand); color: var(--vp-c-brand); box-shadow: 0 4px 12px rgba(0,0,0,0.08); }
|
||||
|
||||
.future-intro h3 {
|
||||
margin: 0 0 8px 0;
|
||||
color: var(--vp-c-brand);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.future-intro p {
|
||||
margin: 0;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.timeline {
|
||||
position: relative;
|
||||
padding: 20px 0;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.timeline-line {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 4px;
|
||||
background: linear-gradient(180deg, var(--vp-c-brand), var(--vp-c-brand-light));
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
position: relative;
|
||||
padding-left: 60px;
|
||||
padding-bottom: 24px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.timeline-item:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.timeline-item.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.timeline-dot {
|
||||
position: absolute;
|
||||
left: 6px;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: var(--vp-c-bg);
|
||||
border: 4px solid var(--vp-c-divider);
|
||||
border-radius: 50%;
|
||||
transition: all 0.3s;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.timeline-item.active .timeline-dot {
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-brand);
|
||||
box-shadow: 0 0 20px rgba(66, 153, 225, 0.5);
|
||||
}
|
||||
|
||||
.timeline-content {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.timeline-item.active .timeline-content {
|
||||
border-color: var(--vp-c-brand);
|
||||
box-shadow: 0 4px 20px rgba(66, 153, 225, 0.2);
|
||||
}
|
||||
|
||||
.era-period {
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.era-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.era-description {
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.era-details {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.detail-card h4 {
|
||||
margin: 0 0 12px 0;
|
||||
color: var(--vp-c-brand);
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.era-detail-desc {
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.7;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.era-features {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.features-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 12px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.features-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.feature-tag {
|
||||
padding: 6px 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 6px;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.era-applications {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.applications-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 12px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.applications-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.app-item {
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.app-icon {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.app-name {
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.app-desc {
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.era-challenges {
|
||||
padding: 16px;
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
border-left: 4px solid #ef4444;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.challenges-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
.era-challenges ul {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.era-challenges li {
|
||||
padding: 4px 0;
|
||||
color: var(--vp-c-text-2);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.era-challenges li::before {
|
||||
content: '⚠️';
|
||||
position: absolute;
|
||||
left: -20px;
|
||||
}
|
||||
|
||||
.future-predictions h4 {
|
||||
margin: 0 0 20px 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.predictions-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.prediction-card {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.prediction-card:hover {
|
||||
border-color: var(--vp-c-brand);
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 4px 20px rgba(66, 153, 225, 0.2);
|
||||
}
|
||||
|
||||
.prediction-icon {
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.prediction-title {
|
||||
font-weight: bold;
|
||||
font-size: 1.1rem;
|
||||
margin-bottom: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.prediction-desc {
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.prediction-time {
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: 600;
|
||||
}
|
||||
.panel { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 12px; padding: 12px; }
|
||||
.p-title { font-weight: 900; margin-bottom: 6px; }
|
||||
.p-body { color: var(--vp-c-text-2); line-height: 1.6; margin-bottom: 10px; }
|
||||
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 10px; }
|
||||
.card { background: var(--vp-c-bg-soft); border: 1px dashed var(--vp-c-divider); border-radius: 12px; padding: 10px; }
|
||||
.k { font-weight: 900; margin-bottom: 4px; }
|
||||
.v { color: var(--vp-c-text-2); line-height: 1.6; }
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,348 +1,117 @@
|
||||
<!--
|
||||
AgentLevelDemo.vue
|
||||
Agent 分级(L0-L5)交互:拖动等级,看到“能做什么/不能做什么/典型任务”。
|
||||
-->
|
||||
<template>
|
||||
<div class="agent-level-demo">
|
||||
<div class="levels-container">
|
||||
<div
|
||||
v-for="(level, index) in levels"
|
||||
:key="level.id"
|
||||
class="level-card"
|
||||
:class="{ active: selectedLevel === index }"
|
||||
@click="selectedLevel = index"
|
||||
>
|
||||
<div class="level-header">
|
||||
<div class="level-badge">{{ level.id }}</div>
|
||||
<div class="level-name">{{ level.name }}</div>
|
||||
</div>
|
||||
<div class="levels">
|
||||
<div class="header">
|
||||
<div>
|
||||
<div class="title">Agent 能力分级(从聊天到协作)</div>
|
||||
<div class="subtitle">拖动看看:等级越高,越像“能独立干活的同事”。</div>
|
||||
</div>
|
||||
<div class="badge">当前:{{ current.name }}</div>
|
||||
</div>
|
||||
|
||||
<div class="level-features">
|
||||
<div v-for="feature in level.features" :key="feature" class="feature-item">
|
||||
<span class="feature-icon">✓</span>
|
||||
{{ feature }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="level-example">
|
||||
<div class="example-label">典型应用</div>
|
||||
<div class="example-text">{{ level.example }}</div>
|
||||
</div>
|
||||
<div class="slider">
|
||||
<input type="range" min="0" max="5" step="1" v-model.number="level" />
|
||||
<div class="ticks">
|
||||
<span v-for="n in 6" :key="n">{{ n - 1 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="level-comparison">
|
||||
<h3>📊 能力对比</h3>
|
||||
|
||||
<div class="comparison-grid">
|
||||
<div class="comparison-item">
|
||||
<div class="item-label">工具使用</div>
|
||||
<div class="item-bar">
|
||||
<div
|
||||
class="bar-fill"
|
||||
:style="{ width: levels[selectedLevel].capabilities.tools + '%' }"
|
||||
></div>
|
||||
</div>
|
||||
<div class="item-value">{{ levels[selectedLevel].capabilities.tools }}%</div>
|
||||
</div>
|
||||
|
||||
<div class="comparison-item">
|
||||
<div class="item-label">规划能力</div>
|
||||
<div class="item-bar">
|
||||
<div
|
||||
class="bar-fill"
|
||||
:style="{ width: levels[selectedLevel].capabilities.planning + '%' }"
|
||||
></div>
|
||||
</div>
|
||||
<div class="item-value">{{ levels[selectedLevel].capabilities.planning }}%</div>
|
||||
</div>
|
||||
|
||||
<div class="comparison-item">
|
||||
<div class="item-label">自主性</div>
|
||||
<div class="item-bar">
|
||||
<div
|
||||
class="bar-fill"
|
||||
:style="{ width: levels[selectedLevel].capabilities.autonomy + '%' }"
|
||||
></div>
|
||||
</div>
|
||||
<div class="item-value">{{ levels[selectedLevel].capabilities.autonomy }}%</div>
|
||||
</div>
|
||||
|
||||
<div class="comparison-item">
|
||||
<div class="item-label">复杂度</div>
|
||||
<div class="item-bar">
|
||||
<div
|
||||
class="bar-fill"
|
||||
:style="{ width: levels[selectedLevel].capabilities.complexity + '%' }"
|
||||
></div>
|
||||
</div>
|
||||
<div class="item-value">{{ levels[selectedLevel].capabilities.complexity }}%</div>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div class="card">
|
||||
<div class="k">能做什么</div>
|
||||
<ul>
|
||||
<li v-for="x in current.can" :key="x">{{ x }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="level-description">
|
||||
<h4>{{ levels[selectedLevel].name }}</h4>
|
||||
<p>{{ levels[selectedLevel].description }}</p>
|
||||
|
||||
<div class="use-cases">
|
||||
<div class="use-case-title">🎯 适用场景</div>
|
||||
<ul>
|
||||
<li v-for="use in levels[selectedLevel].useCases" :key="use">{{ use }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="k">容易出的问题</div>
|
||||
<ul>
|
||||
<li v-for="x in current.risk" :key="x">{{ x }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="k">典型任务</div>
|
||||
<div class="v">{{ current.example }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
const selectedLevel = ref(2)
|
||||
const level = ref(2)
|
||||
|
||||
const levels = [
|
||||
{
|
||||
id: 'L0',
|
||||
name: '无工具',
|
||||
features: ['只能对话', '不能执行操作', '被动响应'],
|
||||
example: 'ChatGPT 聊天',
|
||||
description: '最基础的 LLM 应用,只能进行对话,无法执行任何实际操作。所有的"行动"都需要人工完成。',
|
||||
capabilities: { tools: 0, planning: 0, autonomy: 0, complexity: 10 },
|
||||
useCases: ['问答系统', '内容生成', '语言翻译']
|
||||
name: 'L0:纯对话',
|
||||
can: ['回答问题', '写文本/代码(但不执行)'],
|
||||
risk: ['只能“说”,不能“做”', '需要你手动分步骤'],
|
||||
example: '解释概念、写一段文案'
|
||||
},
|
||||
{
|
||||
id: 'L1',
|
||||
name: '单工具',
|
||||
features: ['使用一个固定工具', '有限的操作能力', '简单任务执行'],
|
||||
example: '代码解释器',
|
||||
description: '可以使用一个特定的工具来扩展能力,但工具选择是固定的,无法自主切换。',
|
||||
capabilities: { tools: 20, planning: 10, autonomy: 20, complexity: 30 },
|
||||
useCases: ['代码执行', '数据计算', '文件分析']
|
||||
name: 'L1:单工具',
|
||||
can: ['调用一个固定工具', '把结果解释给你'],
|
||||
risk: ['工具用错参数', '缺少复杂规划'],
|
||||
example: '只会查一次搜索/只会跑一次代码'
|
||||
},
|
||||
{
|
||||
id: 'L2',
|
||||
name: '多工具',
|
||||
features: ['可以选择多个工具', '工具切换能力', '灵活的任务处理'],
|
||||
example: 'Web Agent',
|
||||
description: '可以使用多个不同的工具,并能根据任务需要自主选择合适的工具。',
|
||||
capabilities: { tools: 60, planning: 30, autonomy: 40, complexity: 50 },
|
||||
useCases: ['网页浏览', '数据采集', '信息检索']
|
||||
name: 'L2:多工具',
|
||||
can: ['在多个工具间选择', '按需要组合调用'],
|
||||
risk: ['选择工具不稳', '权限与安全需要控制'],
|
||||
example: '搜索 + 打开网页 + 摘要'
|
||||
},
|
||||
{
|
||||
id: 'L3',
|
||||
name: '多步骤',
|
||||
features: ['复杂任务规划', '多步骤执行', '状态跟踪'],
|
||||
example: '数据分析 Agent',
|
||||
description: '能够将复杂任务分解为多个步骤,按照计划逐步执行,并跟踪整体进度。',
|
||||
capabilities: { tools: 70, planning: 60, autonomy: 60, complexity: 70 },
|
||||
useCases: ['数据分析', '报告生成', '工作流自动化']
|
||||
name: 'L3:多步骤执行',
|
||||
can: ['先计划后执行', '完成一串步骤', '记录中间结果'],
|
||||
risk: ['步骤漏/顺序错', '成本上升(更多调用)'],
|
||||
example: '读代码 → 改代码 → 跑测试 → 出报告'
|
||||
},
|
||||
{
|
||||
id: 'L4',
|
||||
name: '自主迭代',
|
||||
features: ['主动反思和改进', '从错误中学习', '策略调整'],
|
||||
example: '研究 Agent',
|
||||
description: '不仅能执行任务,还能主动反思结果,从错误中学习,不断优化自己的策略。',
|
||||
capabilities: { tools: 80, planning: 80, autonomy: 80, complexity: 85 },
|
||||
useCases: ['科学研究', '复杂问题求解', '自适应系统']
|
||||
name: 'L4:自我纠错',
|
||||
can: ['失败后换策略', '用检查点避免跑偏'],
|
||||
risk: ['可能反复尝试(需要上限)', '更依赖监控与日志'],
|
||||
example: '测试失败后自动定位并尝试修复'
|
||||
},
|
||||
{
|
||||
id: 'L5',
|
||||
name: '多 Agent 协作',
|
||||
features: ['Agent 间通信', '分工协作', '集体智能'],
|
||||
example: '企业级系统',
|
||||
description: '多个专业化的 Agent 协同工作,通过通信和协作完成单个 Agent 无法完成的复杂任务。',
|
||||
capabilities: { tools: 100, planning: 100, autonomy: 100, complexity: 100 },
|
||||
useCases: ['企业自动化', '软件开发团队', '智能组织']
|
||||
name: 'L5:多 Agent 协作',
|
||||
can: ['多个角色分工', '并行处理任务', '合并结果'],
|
||||
risk: ['协作成本更高', '需要清晰协议与仲裁机制'],
|
||||
example: '研究员找资料 + 工程师实现 + 编辑写总结'
|
||||
}
|
||||
]
|
||||
|
||||
const current = computed(() => levels[level.value])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.agent-level-demo {
|
||||
.levels {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
||||
.levels-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.level-card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.level-card:hover {
|
||||
border-color: var(--vp-c-brand);
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
|
||||
.level-card.active {
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-bg-soft);
|
||||
box-shadow: 0 4px 20px rgba(66, 153, 225, 0.2);
|
||||
}
|
||||
|
||||
.level-header {
|
||||
margin: 20px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.level-badge {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
padding: 4px 12px;
|
||||
border-radius: 6px;
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.header { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
|
||||
.title { font-weight: 800; }
|
||||
.subtitle { color: var(--vp-c-text-2); font-size: 13px; }
|
||||
.badge { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 999px; padding: 8px 12px; font-weight: 800; }
|
||||
|
||||
.level-name {
|
||||
font-weight: bold;
|
||||
font-size: 1.1rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
.slider { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 12px; padding: 10px 12px; }
|
||||
input[type='range'] { width: 100%; }
|
||||
.ticks { display: flex; justify-content: space-between; color: var(--vp-c-text-2); font-size: 12px; margin-top: 6px; }
|
||||
|
||||
.level-features {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.feature-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 0;
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.level-example {
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.example-label {
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.example-text {
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.level-comparison {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.level-comparison h3 {
|
||||
margin: 0 0 24px 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.comparison-grid {
|
||||
display: grid;
|
||||
gap: 20px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.comparison-item {
|
||||
display: grid;
|
||||
grid-template-columns: 100px 1fr 60px;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-label {
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.item-bar {
|
||||
height: 24px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bar-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, var(--vp-c-brand), var(--vp-c-brand-light));
|
||||
border-radius: 12px;
|
||||
transition: width 0.5s ease;
|
||||
}
|
||||
|
||||
.item-value {
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-brand);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.level-description {
|
||||
padding: 20px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 12px;
|
||||
border-left: 4px solid var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.level-description h4 {
|
||||
margin: 0 0 12px 0;
|
||||
color: var(--vp-c-brand);
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.level-description p {
|
||||
margin: 0 0 16px 0;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.use-cases {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.use-case-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.use-cases ul {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.use-cases li {
|
||||
padding: 4px 0;
|
||||
color: var(--vp-c-text-2);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.use-cases li::before {
|
||||
content: '•';
|
||||
position: absolute;
|
||||
left: -16px;
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: bold;
|
||||
}
|
||||
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; }
|
||||
.card { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 12px; padding: 12px; }
|
||||
.k { font-weight: 800; margin-bottom: 6px; }
|
||||
.v { color: var(--vp-c-text-2); line-height: 1.6; }
|
||||
ul { margin: 0; padding-left: 18px; color: var(--vp-c-text-2); line-height: 1.6; }
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,421 +1,117 @@
|
||||
<!--
|
||||
AgentTaskFlowDemo.vue
|
||||
任务执行流:像看“回放”一样看 Agent 一步步完成一个任务。
|
||||
-->
|
||||
<template>
|
||||
<div class="agent-task-flow-demo">
|
||||
<div class="task-input">
|
||||
<div class="input-label">🎯 用户任务</div>
|
||||
<div class="input-content">"搜索并总结最新的 AI 技术文章"</div>
|
||||
</div>
|
||||
|
||||
<div class="flow-timeline">
|
||||
<div class="timeline-line"></div>
|
||||
|
||||
<div
|
||||
v-for="(step, index) in steps"
|
||||
:key="index"
|
||||
class="timeline-item"
|
||||
:class="{ active: currentStep === index, completed: currentStep > index }"
|
||||
>
|
||||
<div class="timeline-dot"></div>
|
||||
<div class="timeline-content">
|
||||
<div class="step-number">步骤 {{ index + 1 }}</div>
|
||||
<div class="step-title">{{ step.title }}</div>
|
||||
<div class="step-description">{{ step.description }}</div>
|
||||
|
||||
<div v-if="step.code" class="step-code">
|
||||
<div class="code-label">执行代码</div>
|
||||
<pre><code>{{ step.code }}</code></pre>
|
||||
</div>
|
||||
|
||||
<div v-if="step.result" class="step-result">
|
||||
<div class="result-label">执行结果</div>
|
||||
<div class="result-content">{{ step.result }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow">
|
||||
<div class="header">
|
||||
<div>
|
||||
<div class="title">任务回放:Agent 怎么一步步做完?</div>
|
||||
<div class="subtitle">点步骤,看“工具调用”和“中间结果”。</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" @click="step = Math.max(0, step - 1)" :disabled="step === 0">上一步</button>
|
||||
<button class="btn primary" @click="step = Math.min(steps.length - 1, step + 1)" :disabled="step === steps.length - 1">下一步</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flow-controls">
|
||||
<button @click="prevStep" :disabled="currentStep === 0" class="control-btn">
|
||||
← 上一步
|
||||
</button>
|
||||
<button @click="togglePlay" class="control-btn primary">
|
||||
{{ isPlaying ? '⏸ 暂停' : '▶ 自动演示' }}
|
||||
</button>
|
||||
<button @click="nextStep" :disabled="currentStep === steps.length - 1" class="control-btn">
|
||||
下一步 →
|
||||
</button>
|
||||
<button @click="reset" class="control-btn">
|
||||
↺ 重置
|
||||
<div class="timeline">
|
||||
<button
|
||||
v-for="(s, i) in steps"
|
||||
:key="s.title"
|
||||
:class="['t', { active: i === step }]"
|
||||
@click="step = i"
|
||||
>
|
||||
<span class="n">{{ i + 1 }}</span>
|
||||
<span class="txt">{{ s.title }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flow-explanation">
|
||||
<div class="explanation-card">
|
||||
<h4>{{ steps[currentStep].title }}</h4>
|
||||
<p>{{ steps[currentStep].explanation }}</p>
|
||||
|
||||
<div class="tips">
|
||||
<div class="tip-icon">💡</div>
|
||||
<div>{{ steps[currentStep].tip }}</div>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div class="panel">
|
||||
<div class="panel-title">当前步骤</div>
|
||||
<div class="panel-body">{{ steps[step].desc }}</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel-title">工具调用(示意)</div>
|
||||
<pre><code>{{ steps[step].tool }}</code></pre>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel-title">结果(示意)</div>
|
||||
<pre><code>{{ steps[step].result }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onUnmounted } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const currentStep = ref(0)
|
||||
const isPlaying = ref(false)
|
||||
let playInterval = null
|
||||
const step = ref(0)
|
||||
|
||||
const steps = [
|
||||
{
|
||||
title: '理解任务',
|
||||
description: 'Agent 分析用户需求,明确目标',
|
||||
code: null,
|
||||
result: null,
|
||||
explanation: 'Agent 首先理解用户的意图,识别出这是一个需要搜索和总结的任务。它会分析关键词: "搜索"、"最新"、"AI 技术"、"文章"、"总结"。',
|
||||
tip: '好的任务理解是成功的一半。Agent 需要识别出核心需求和约束条件。'
|
||||
title: '理解目标',
|
||||
desc: '把用户需求拆成“可交付”的输出结构。',
|
||||
tool: 'LLM: parse_goal({ task, constraints, output_format })',
|
||||
result: '目标:找 3 篇文章;输出:标题 + 一句话总结(Markdown 列表)'
|
||||
},
|
||||
{
|
||||
title: '制定计划',
|
||||
description: '分解任务,制定执行步骤',
|
||||
code: `plan = [
|
||||
"搜索关键词:'AI 技术 2024'",
|
||||
"筛选前 5 篇文章",
|
||||
"阅读每篇文章摘要",
|
||||
"生成综合总结"
|
||||
]`,
|
||||
result: '✅ 计划已制定:4 个步骤',
|
||||
explanation: 'Agent 将复杂任务分解为可执行的小步骤。这个计划会动态调整,比如如果搜索结果质量不高,可能会重新搜索。',
|
||||
tip: '任务分解是 Agent 的核心能力。复杂任务必须拆解为可管理的步骤。'
|
||||
title: '搜索',
|
||||
desc: '先用搜索工具拿到候选链接。',
|
||||
tool: 'tool:web_search({ query: \"agent introduction\" })',
|
||||
result: '- link1\n- link2\n- link3\n- link4 ...'
|
||||
},
|
||||
{
|
||||
title: '执行搜索',
|
||||
description: '调用搜索工具,获取文章列表',
|
||||
code: `results = web_search(
|
||||
query="AI 技术 2024",
|
||||
max_results=10,
|
||||
time_range="last_month"
|
||||
)`,
|
||||
result: '✅ 找到 15 篇相关文章',
|
||||
explanation: 'Agent 调用 web_search 工具,使用合适的搜索关键词和参数。搜索结果会被保存到短期记忆中,供后续步骤使用。',
|
||||
tip: '工具调用需要选择合适的参数。Agent 会根据任务需求动态调整。'
|
||||
title: '读取页面',
|
||||
desc: '打开前三个链接,取出核心段落。',
|
||||
tool: 'tool:read_page({ url: link1/link2/link3 })',
|
||||
result: '每篇文章的核心段落(已截取)'
|
||||
},
|
||||
{
|
||||
title: '筛选结果',
|
||||
description: '根据相关性筛选最佳文章',
|
||||
code: `top_articles = filter_by_relevance(
|
||||
results,
|
||||
top_n=5,
|
||||
criteria=["date", "citations", "source"]
|
||||
)`,
|
||||
result: '✅ 筛选出 5 篇高质量文章',
|
||||
explanation: '不是所有搜索结果都有用。Agent 会根据日期、引用数、来源权威性等指标筛选出最有价值的文章。',
|
||||
tip: '信息筛选能力决定了 Agent 的输出质量。需要多维度的评估标准。'
|
||||
title: '压缩与整理',
|
||||
desc: '把每篇文章压缩成“一句话总结”,统一格式。',
|
||||
tool: 'LLM: summarize_each({ paragraphs, max_len: 25 })',
|
||||
result: '- 标题A:一句话…\n- 标题B:一句话…\n- 标题C:一句话…'
|
||||
},
|
||||
{
|
||||
title: '阅读内容',
|
||||
description: '读取并理解每篇文章的内容',
|
||||
code: `for article in top_articles:
|
||||
content = read_page(article.url)
|
||||
summary = extract_key_points(content)
|
||||
memory.store(article.id, summary)`,
|
||||
result: '✅ 已阅读 5 篇文章,提取关键信息',
|
||||
explanation: 'Agent 依次阅读每篇文章,提取关键信息并存储到记忆系统中。这样可以在生成总结时快速检索相关信息。',
|
||||
tip: '记忆管理很重要。只保留关键信息,避免上下文膨胀。'
|
||||
},
|
||||
{
|
||||
title: '生成总结',
|
||||
description: '综合所有信息,生成最终报告',
|
||||
code: `summary = generate_report(
|
||||
memories=memory.get_all(),
|
||||
format="markdown",
|
||||
style="concise"
|
||||
)
|
||||
|
||||
summary.add_references(top_articles)`,
|
||||
result: '✅ 总结已完成,包含 5 个参考文献',
|
||||
explanation: 'Agent 从记忆中检索所有关键信息,生成一份结构化的总结报告,并附上参考文献,确保信息的可追溯性。',
|
||||
tip: '输出质量取决于信息的整合能力。结构化输出更易读、更专业。'
|
||||
title: '自检与交付',
|
||||
desc: '检查是否满足“3 条 + 一句话 + 格式正确”,再输出。',
|
||||
tool: 'LLM: self_check({ checklist })',
|
||||
result: '✅ 满足要求;输出已就绪'
|
||||
}
|
||||
]
|
||||
|
||||
const nextStep = () => {
|
||||
if (currentStep.value < steps.length - 1) {
|
||||
currentStep.value++
|
||||
}
|
||||
}
|
||||
|
||||
const prevStep = () => {
|
||||
if (currentStep.value > 0) {
|
||||
currentStep.value--
|
||||
}
|
||||
}
|
||||
|
||||
const togglePlay = () => {
|
||||
isPlaying.value = !isPlaying.value
|
||||
if (isPlaying.value) {
|
||||
playInterval = setInterval(() => {
|
||||
if (currentStep.value < steps.length - 1) {
|
||||
currentStep.value++
|
||||
} else {
|
||||
currentStep.value = 0
|
||||
}
|
||||
}, 2500)
|
||||
} else {
|
||||
clearInterval(playInterval)
|
||||
}
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
currentStep.value = 0
|
||||
isPlaying.value = false
|
||||
clearInterval(playInterval)
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(playInterval)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.agent-task-flow-demo {
|
||||
.flow {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
||||
.task-input {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
margin-bottom: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
font-size: 0.9rem;
|
||||
opacity: 0.9;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.input-content {
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.flow-timeline {
|
||||
position: relative;
|
||||
padding: 20px 0;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.timeline-line {
|
||||
position: absolute;
|
||||
left: 24px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 4px;
|
||||
background: var(--vp-c-divider);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
position: relative;
|
||||
padding-left: 60px;
|
||||
padding-bottom: 32px;
|
||||
opacity: 0.5;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.timeline-item.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.timeline-item.completed {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.timeline-dot {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: var(--vp-c-bg);
|
||||
border: 4px solid var(--vp-c-divider);
|
||||
border-radius: 50%;
|
||||
transition: all 0.3s;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.timeline-item.active .timeline-dot {
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-brand);
|
||||
box-shadow: 0 0 20px rgba(66, 153, 225, 0.5);
|
||||
}
|
||||
|
||||
.timeline-item.completed .timeline-dot {
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.timeline-content {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.timeline-item.active .timeline-content {
|
||||
border-color: var(--vp-c-brand);
|
||||
box-shadow: 0 4px 20px rgba(66, 153, 225, 0.2);
|
||||
}
|
||||
|
||||
.step-number {
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.step-title {
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.step-description {
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.step-code {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.code-label {
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.step-code pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.step-code code {
|
||||
font-family: 'Monaco', 'Courier New', monospace;
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-1);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.step-result {
|
||||
background: rgba(66, 153, 225, 0.1);
|
||||
border-left: 4px solid var(--vp-c-brand);
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.result-label {
|
||||
font-size: 0.8rem;
|
||||
color: var(--vp-c-brand);
|
||||
margin-bottom: 4px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.result-content {
|
||||
color: var(--vp-c-text-1);
|
||||
font-family: monospace;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.flow-controls {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
justify-content: center;
|
||||
margin-bottom: 24px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.control-btn {
|
||||
padding: 10px 20px;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-1);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.control-btn:hover:not(:disabled) {
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-bg-soft);
|
||||
}
|
||||
|
||||
.control-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.control-btn.primary {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.control-btn.primary:hover:not(:disabled) {
|
||||
background: var(--vp-c-brand-dark);
|
||||
}
|
||||
|
||||
.flow-explanation {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.explanation-card h4 {
|
||||
margin: 0 0 12px 0;
|
||||
color: var(--vp-c-brand);
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.explanation-card p {
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.7;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.tips {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid var(--vp-c-brand);
|
||||
margin: 20px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
.header { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
|
||||
.title { font-weight: 800; }
|
||||
.subtitle { color: var(--vp-c-text-2); font-size: 13px; }
|
||||
.actions { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
.btn { border: 1px solid var(--vp-c-divider); background: var(--vp-c-bg); padding: 8px 12px; border-radius: 10px; cursor: pointer; }
|
||||
.btn.primary { border-color: var(--vp-c-brand); color: var(--vp-c-brand); }
|
||||
.btn:disabled { opacity: 0.6; cursor: not-allowed; }
|
||||
|
||||
.tip-icon {
|
||||
font-size: 1.5rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.timeline { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; }
|
||||
.t { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 12px; padding: 10px; display: flex; gap: 10px; align-items: center; cursor: pointer; text-align: left; }
|
||||
.t.active { border-color: var(--vp-c-brand); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.06); }
|
||||
.n { width: 26px; height: 26px; border-radius: 8px; display: grid; place-items: center; background: var(--vp-c-bg-soft); border: 1px solid var(--vp-c-divider); font-weight: 800; }
|
||||
.txt { font-weight: 800; }
|
||||
|
||||
.tips > div:last-child {
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.6;
|
||||
}
|
||||
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; }
|
||||
.panel { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 12px; padding: 12px; }
|
||||
.panel-title { font-weight: 700; margin-bottom: 6px; }
|
||||
.panel-body { color: var(--vp-c-text-2); line-height: 1.6; }
|
||||
pre { margin: 0; background: #0b1221; color: #e5e7eb; border-radius: 10px; padding: 12px; font-family: var(--vp-font-family-mono); font-size: 13px; overflow-x: auto; white-space: pre-wrap; }
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,372 +1,163 @@
|
||||
<!--
|
||||
AgentWorkflowDemo.vue
|
||||
Agent 核心循环(更像“先玩后讲”的演示):
|
||||
- 点步骤:看这一轮 Agent “在干什么”
|
||||
- 点“下一轮”:看它如何反复迭代直到完成
|
||||
-->
|
||||
<template>
|
||||
<div class="agent-workflow-demo">
|
||||
<div class="workflow-container">
|
||||
<div class="cycle-diagram">
|
||||
<div class="center-label">Agent 核心循环</div>
|
||||
|
||||
<div
|
||||
v-for="(step, index) in steps"
|
||||
:key="step.name"
|
||||
class="cycle-step"
|
||||
:class="{
|
||||
active: currentStep === index,
|
||||
completed: currentStep > index
|
||||
}"
|
||||
:style="getStepPosition(index)"
|
||||
>
|
||||
<div class="step-icon">{{ step.icon }}</div>
|
||||
<div class="step-name">{{ step.name }}</div>
|
||||
<div class="step-desc">{{ step.desc }}</div>
|
||||
</div>
|
||||
|
||||
<svg class="arrows" v-if="currentStep < steps.length">
|
||||
<circle cx="200" cy="200" r="130" fill="none" :stroke="arrowColor" stroke-width="2" stroke-dasharray="5,5">
|
||||
<animate
|
||||
v-if="isPlaying"
|
||||
attributeName="stroke-dashoffset"
|
||||
from="0"
|
||||
to="-20"
|
||||
dur="1s"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
</circle>
|
||||
</svg>
|
||||
<div class="workflow">
|
||||
<div class="header">
|
||||
<div>
|
||||
<div class="title">先玩一下:Agent 不是“聊天”,是“循环行动”</div>
|
||||
<div class="subtitle">它会反复:观察 → 计划 → 用工具 → 检查结果。</div>
|
||||
</div>
|
||||
|
||||
<div class="step-details">
|
||||
<div class="current-action">
|
||||
<div class="action-label">当前步骤</div>
|
||||
<div class="action-content">
|
||||
<span class="action-icon">{{ steps[currentStep]?.icon }}</span>
|
||||
<span class="action-text">{{ steps[currentStep]?.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step-explanation">
|
||||
<h4>{{ steps[currentStep]?.name }}</h4>
|
||||
<p>{{ steps[currentStep]?.detail }}</p>
|
||||
|
||||
<div v-if="currentStep > 0 && currentStep <= steps.length" class="example-box">
|
||||
<div class="example-title">📝 示例</div>
|
||||
<div class="example-content">{{ steps[currentStep]?.example }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn" @click="reset">重置</button>
|
||||
<button class="btn primary" @click="nextRound">下一轮 ({{ round }}/3)</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<button @click="prevStep" :disabled="currentStep === 0" class="control-btn">
|
||||
← 上一步
|
||||
</button>
|
||||
<button @click="togglePlay" class="control-btn primary">
|
||||
{{ isPlaying ? '⏸ 暂停' : '▶ 自动播放' }}
|
||||
</button>
|
||||
<button @click="nextStep" :disabled="currentStep === steps.length" class="control-btn">
|
||||
下一步 →
|
||||
</button>
|
||||
<button @click="reset" class="control-btn">
|
||||
↺ 重置
|
||||
<div class="cycle">
|
||||
<button
|
||||
v-for="s in steps"
|
||||
:key="s.id"
|
||||
:class="['step', { active: currentStep === s.id }]"
|
||||
@click="currentStep = s.id"
|
||||
>
|
||||
<span class="icon">{{ s.icon }}</span>
|
||||
<span class="name">{{ s.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="panels">
|
||||
<div class="panel">
|
||||
<div class="panel-title">任务</div>
|
||||
<div class="panel-body">
|
||||
帮我找 3 篇 “Agent” 入门文章,并输出:标题 + 一句话总结。
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel-title">这一轮发生了什么?</div>
|
||||
<div class="panel-body">{{ detail }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="log">
|
||||
<div class="log-title">Agent 运行日志(示意)</div>
|
||||
<pre><code>{{ logText }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
|
||||
const currentStep = ref(0)
|
||||
const isPlaying = ref(false)
|
||||
let playInterval = null
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
const steps = [
|
||||
{ id: 'observe', name: '观察', icon: '👀' },
|
||||
{ id: 'plan', name: '计划', icon: '🧩' },
|
||||
{ id: 'act', name: '行动', icon: '🔧' },
|
||||
{ id: 'check', name: '检查', icon: '✅' }
|
||||
]
|
||||
|
||||
const round = ref(1)
|
||||
const currentStep = ref('observe')
|
||||
|
||||
const scenarios = [
|
||||
{
|
||||
name: '感知',
|
||||
icon: '👁️',
|
||||
desc: 'Perceive',
|
||||
detail: 'Agent 从环境中接收信息,包括用户输入、文件内容、网页数据等。',
|
||||
example: '用户说:帮我搜索最新的 AI 文章'
|
||||
observe: '看到用户目标:要 3 篇入门文章 + 简短总结。',
|
||||
plan: '计划:1) 搜索关键词 2) 打开前几条 3) 抽取标题与要点。',
|
||||
act: '调用工具:web_search(query="agent introduction")。',
|
||||
check: '检查:结果里有 3 条可用链接,还缺“每条一句话总结”。'
|
||||
},
|
||||
{
|
||||
name: '决策',
|
||||
icon: '🤔',
|
||||
desc: 'Reason',
|
||||
detail: '分析当前状态,制定行动计划,选择合适的工具来完成任务。',
|
||||
example: '分析:需要搜索 → 应该使用 web_search 工具'
|
||||
observe: '拿到链接列表,准备逐条打开并提取要点。',
|
||||
plan: '计划:依次 read_page 3 次,把内容压缩成一句话。',
|
||||
act: '调用工具:read_page(url=...) × 3。',
|
||||
check: '检查:信息够了,但标题格式不统一,需要整理输出。'
|
||||
},
|
||||
{
|
||||
name: '行动',
|
||||
icon: '🔧',
|
||||
desc: 'Act',
|
||||
detail: '执行决策,调用工具,修改文件,发送请求等具体操作。',
|
||||
example: '执行:web_search("AI 文章 2024")'
|
||||
},
|
||||
{
|
||||
name: '观察',
|
||||
icon: '👀',
|
||||
desc: 'Observe',
|
||||
detail: '查看行动结果,评估是否达成目标,决定是继续还是结束。',
|
||||
example: '观察:找到 10 篇相关文章 → 继续阅读'
|
||||
observe: '材料齐全:标题 + 文章要点都已提取。',
|
||||
plan: '计划:统一格式,输出 Markdown 列表。',
|
||||
act: '组织输出:每条“标题 - 一句话总结”。',
|
||||
check: '完成:满足“3 条 + 一句话总结 + 可直接复制”。'
|
||||
}
|
||||
]
|
||||
|
||||
const arrowColor = computed(() => {
|
||||
if (currentStep.value === 0) return 'var(--vp-c-divider)'
|
||||
return 'var(--vp-c-brand)'
|
||||
const current = computed(() => scenarios[round.value - 1])
|
||||
|
||||
const detail = computed(() => current.value[currentStep.value])
|
||||
|
||||
const logText = computed(() => {
|
||||
const logs = []
|
||||
for (let i = 0; i < round.value; i++) {
|
||||
logs.push(`--- Round ${i + 1} ---`)
|
||||
logs.push(`OBS: ${scenarios[i].observe}`)
|
||||
logs.push(`PLAN: ${scenarios[i].plan}`)
|
||||
logs.push(`ACT: ${scenarios[i].act}`)
|
||||
logs.push(`CHECK: ${scenarios[i].check}`)
|
||||
logs.push('')
|
||||
}
|
||||
return logs.join('\n')
|
||||
})
|
||||
|
||||
const getStepPosition = (index) => {
|
||||
const positions = [
|
||||
{ top: '10%', left: '50%', transform: 'translateX(-50%)' }, // Top
|
||||
{ right: '10%', top: '50%', transform: 'translateY(-50%)' }, // Right
|
||||
{ bottom: '10%', left: '50%', transform: 'translateX(-50%)' }, // Bottom
|
||||
{ left: '10%', top: '50%', transform: 'translateY(-50%)' } // Left
|
||||
]
|
||||
return positions[index]
|
||||
}
|
||||
|
||||
const nextStep = () => {
|
||||
if (currentStep.value < steps.length) {
|
||||
currentStep.value++
|
||||
}
|
||||
}
|
||||
|
||||
const prevStep = () => {
|
||||
if (currentStep.value > 0) {
|
||||
currentStep.value--
|
||||
}
|
||||
}
|
||||
|
||||
const togglePlay = () => {
|
||||
isPlaying.value = !isPlaying.value
|
||||
if (isPlaying.value) {
|
||||
playInterval = setInterval(() => {
|
||||
if (currentStep.value < steps.length) {
|
||||
currentStep.value++
|
||||
} else {
|
||||
currentStep.value = 0
|
||||
}
|
||||
}, 2000)
|
||||
} else {
|
||||
clearInterval(playInterval)
|
||||
}
|
||||
const nextRound = () => {
|
||||
if (round.value >= 3) return
|
||||
round.value++
|
||||
currentStep.value = 'observe'
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
currentStep.value = 0
|
||||
isPlaying.value = false
|
||||
clearInterval(playInterval)
|
||||
round.value = 1
|
||||
currentStep.value = 'observe'
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(playInterval)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.agent-workflow-demo {
|
||||
.workflow {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
||||
.workflow-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 32px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.workflow-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.cycle-diagram {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
max-width: 400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.center-label {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-weight: bold;
|
||||
font-size: 1.1rem;
|
||||
color: var(--vp-c-brand);
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.cycle-step {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
transition: all 0.3s ease;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.cycle-step.active {
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-bg-soft);
|
||||
box-shadow: 0 0 20px rgba(66, 153, 225, 0.3);
|
||||
transform: scale(1.1) !important;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.cycle-step.completed {
|
||||
border-color: var(--vp-c-brand);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.step-icon {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.step-name {
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.step-desc {
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-2);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.arrows {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.step-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.current-action {
|
||||
padding: 20px;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
border-left: 4px solid var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.action-label {
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 8px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.action-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.step-explanation {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.step-explanation h4 {
|
||||
margin: 0 0 12px 0;
|
||||
color: var(--vp-c-brand);
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.step-explanation p {
|
||||
margin: 0 0 16px 0;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.example-box {
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.example-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.example-content {
|
||||
font-family: monospace;
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.controls {
|
||||
margin: 20px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.control-btn {
|
||||
padding: 10px 20px;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
.header { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
|
||||
.title { font-weight: 800; }
|
||||
.subtitle { color: var(--vp-c-text-2); font-size: 13px; }
|
||||
.actions { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
.btn { border: 1px solid var(--vp-c-divider); background: var(--vp-c-bg); padding: 8px 12px; border-radius: 10px; cursor: pointer; }
|
||||
.btn.primary { border-color: var(--vp-c-brand); color: var(--vp-c-brand); }
|
||||
|
||||
.cycle {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
.step {
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-1);
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
padding: 10px 12px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s;
|
||||
text-align: left;
|
||||
}
|
||||
.step.active { border-color: var(--vp-c-brand); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.06); }
|
||||
.icon { width: 28px; height: 28px; border-radius: 8px; display: grid; place-items: center; background: var(--vp-c-bg-soft); border: 1px solid var(--vp-c-divider); }
|
||||
.name { font-weight: 800; }
|
||||
|
||||
.control-btn:hover:not(:disabled) {
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-bg-soft);
|
||||
}
|
||||
.panels { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px; }
|
||||
.panel { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 12px; padding: 12px; }
|
||||
.panel-title { font-weight: 700; margin-bottom: 6px; }
|
||||
.panel-body { color: var(--vp-c-text-2); line-height: 1.6; }
|
||||
|
||||
.control-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.control-btn.primary {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.control-btn.primary:hover:not(:disabled) {
|
||||
background: var(--vp-c-brand-dark);
|
||||
border-color: var(--vp-c-brand-dark);
|
||||
}
|
||||
.log { background: var(--vp-c-bg); border: 1px dashed var(--vp-c-divider); border-radius: 12px; padding: 12px; }
|
||||
.log-title { font-weight: 700; margin-bottom: 8px; }
|
||||
pre { margin: 0; background: #0b1221; color: #e5e7eb; border-radius: 10px; padding: 12px; font-family: var(--vp-font-family-mono); font-size: 13px; overflow-x: auto; white-space: pre-wrap; }
|
||||
</style>
|
||||
|
||||
|
||||
+78
-509
@@ -1,529 +1,98 @@
|
||||
<!--
|
||||
FrameworkComparisonDemo.vue
|
||||
框架对比(更直观):选择关注点,表格高亮适配度。
|
||||
-->
|
||||
<template>
|
||||
<div class="framework-comparison-demo">
|
||||
<div class="framework-tabs">
|
||||
<button
|
||||
v-for="(framework, index) in frameworks"
|
||||
:key="framework.name"
|
||||
class="tab-btn"
|
||||
:class="{ active: selectedFramework === index }"
|
||||
@click="selectedFramework = index"
|
||||
>
|
||||
{{ framework.name }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="framework-content">
|
||||
<div class="framework-header">
|
||||
<div class="framework-icon">{{ frameworks[selectedFramework].icon }}</div>
|
||||
<div>
|
||||
<h3>{{ frameworks[selectedFramework].name }}</h3>
|
||||
<p class="framework-tagline">{{ frameworks[selectedFramework].tagline }}</p>
|
||||
</div>
|
||||
<div class="cmp">
|
||||
<div class="header">
|
||||
<div>
|
||||
<div class="title">主流框架对比(先看“适配度”)</div>
|
||||
<div class="subtitle">先选你的关注点,再看推荐。</div>
|
||||
</div>
|
||||
|
||||
<div class="framework-details">
|
||||
<div class="detail-section">
|
||||
<h4>✨ 特点</h4>
|
||||
<ul>
|
||||
<li v-for="feature in frameworks[selectedFramework].features" :key="feature">
|
||||
{{ feature }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<h4>🎯 适用场景</h4>
|
||||
<div class="scenarios">
|
||||
<div
|
||||
v-for="scenario in frameworks[selectedFramework].scenarios"
|
||||
:key="scenario"
|
||||
class="scenario-tag"
|
||||
>
|
||||
{{ scenario }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<h4>⚖️ 优缺点</h4>
|
||||
<div class="pros-cons">
|
||||
<div class="pros">
|
||||
<div class="pros-title">✅ 优点</div>
|
||||
<ul>
|
||||
<li v-for="pro in frameworks[selectedFramework].pros" :key="pro">{{ pro }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="cons">
|
||||
<div class="cons-title">❌ 缺点</div>
|
||||
<ul>
|
||||
<li v-for="con in frameworks[selectedFramework].cons" :key="con">{{ con }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<h4>📊 能力评分</h4>
|
||||
<div class="capabilities">
|
||||
<div
|
||||
v-for="(value, key) in frameworks[selectedFramework].scores"
|
||||
:key="key"
|
||||
class="capability-item"
|
||||
>
|
||||
<div class="capability-label">{{ key }}</div>
|
||||
<div class="capability-bar">
|
||||
<div class="bar-fill" :style="{ width: value + '%' }"></div>
|
||||
</div>
|
||||
<div class="capability-value">{{ value }}/100</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<h4>🔗 相关链接</h4>
|
||||
<div class="links">
|
||||
<a :href="frameworks[selectedFramework].website" target="_blank" class="link-item">
|
||||
🌐 官网
|
||||
</a>
|
||||
<a :href="frameworks[selectedFramework].github" target="_blank" class="link-item">
|
||||
💻 GitHub
|
||||
</a>
|
||||
<a :href="frameworks[selectedFramework].docs" target="_blank" class="link-item">
|
||||
📚 文档
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="focus">
|
||||
<button
|
||||
v-for="f in focuses"
|
||||
:key="f.id"
|
||||
:class="['chip', { active: focus === f.id }]"
|
||||
@click="focus = f.id"
|
||||
>
|
||||
{{ f.label }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="comparison-table">
|
||||
<h3>📋 快速对比</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>特性</th>
|
||||
<th v-for="fw in frameworks" :key="fw.name">{{ fw.name }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>学习曲线</td>
|
||||
<td v-for="fw in frameworks" :key="fw.name">{{ fw.learningCurve }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>社区规模</td>
|
||||
<td v-for="fw in frameworks" :key="fw.name">{{ fw.community }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>最佳用途</td>
|
||||
<td v-for="fw in frameworks" :key="fw.name">{{ fw.bestFor }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GitHub Stars</td>
|
||||
<td v-for="fw in frameworks" :key="fw.name">{{ fw.stars }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="table">
|
||||
<div class="row head">
|
||||
<div>框架</div>
|
||||
<div>上手</div>
|
||||
<div>可控</div>
|
||||
<div>多 Agent</div>
|
||||
<div>适合做什么</div>
|
||||
</div>
|
||||
<div v-for="fw in frameworks" :key="fw.name" :class="['row', { best: fw.name === best }]">
|
||||
<div class="name">{{ fw.name }}</div>
|
||||
<div>{{ fw.learn }}</div>
|
||||
<div>{{ fw.control }}</div>
|
||||
<div>{{ fw.multi }}</div>
|
||||
<div class="use">{{ fw.use }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rec">
|
||||
<div class="rec-title">此刻更推荐:{{ best }}</div>
|
||||
<div class="rec-body">{{ reason }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
const selectedFramework = ref(0)
|
||||
const focuses = [
|
||||
{ id: 'start', label: '快速上手' },
|
||||
{ id: 'control', label: '可控可调试' },
|
||||
{ id: 'team', label: '多 Agent 协作' }
|
||||
]
|
||||
|
||||
const focus = ref('control')
|
||||
|
||||
const frameworks = [
|
||||
{
|
||||
name: 'LangChain',
|
||||
icon: '🦜',
|
||||
tagline: '最流行的 LLM 应用开发框架',
|
||||
features: [
|
||||
'组件化设计,高度灵活',
|
||||
'丰富的集成(100+ 工具)',
|
||||
'LangGraph 专门用于构建 Agent',
|
||||
'支持多种 LLM 提供商',
|
||||
'活跃的社区和生态系统'
|
||||
],
|
||||
scenarios: ['需要高度定制', '企业级应用', '与现有系统集成', '快速原型开发'],
|
||||
pros: [
|
||||
'生态系统最完善',
|
||||
'文档齐全,示例丰富',
|
||||
'灵活性强',
|
||||
'社区支持好'
|
||||
],
|
||||
cons: [
|
||||
'学习曲线陡峭',
|
||||
'概念较多',
|
||||
'版本更新快',
|
||||
'有些抽象难以理解'
|
||||
],
|
||||
scores: {
|
||||
'灵活性': 95,
|
||||
'易用性': 70,
|
||||
'性能': 80,
|
||||
'文档': 90,
|
||||
'社区': 95
|
||||
},
|
||||
website: 'https://langchain.com',
|
||||
github: 'https://github.com/langchain-ai/langchain',
|
||||
docs: 'https://python.langchain.com',
|
||||
learningCurve: '⭐⭐⭐⭐',
|
||||
community: '⭐⭐⭐⭐⭐',
|
||||
bestFor: '通用 LLM 应用',
|
||||
stars: '95k+'
|
||||
},
|
||||
{
|
||||
name: 'AutoGen',
|
||||
icon: '🤖',
|
||||
tagline: '微软出品的 Agent 协作框架',
|
||||
features: [
|
||||
'多 Agent 协作',
|
||||
'Agent 之间可以对话',
|
||||
'强大的代码执行能力',
|
||||
'支持人类介入',
|
||||
'内置错误恢复'
|
||||
],
|
||||
scenarios: ['编程辅助', '多 Agent 协作', '数据分析', '代码审查'],
|
||||
pros: [
|
||||
'协作模式独特',
|
||||
'代码执行能力强',
|
||||
'微软支持',
|
||||
'易于调试'
|
||||
],
|
||||
cons: [
|
||||
'相对小众',
|
||||
'文档不够完善',
|
||||
'社区较小',
|
||||
'主要用于编程场景'
|
||||
],
|
||||
scores: {
|
||||
'灵活性': 75,
|
||||
'易用性': 80,
|
||||
'性能': 85,
|
||||
'文档': 70,
|
||||
'社区': 70
|
||||
},
|
||||
website: 'https://microsoft.github.io/autogen',
|
||||
github: 'https://github.com/microsoft/autogen',
|
||||
docs: 'https://microsoft.github.io/autogen/docs',
|
||||
learningCurve: '⭐⭐⭐',
|
||||
community: '⭐⭐⭐',
|
||||
bestFor: '多 Agent 编程',
|
||||
stars: '30k+'
|
||||
},
|
||||
{
|
||||
name: 'CrewAI',
|
||||
icon: '👥',
|
||||
tagline: '角色驱动的多 Agent 系统',
|
||||
features: [
|
||||
'角色驱动的 Agent 设计',
|
||||
'团队协作模式',
|
||||
'直观的任务定义',
|
||||
'支持复杂的协作流程',
|
||||
'易于理解和使用'
|
||||
],
|
||||
scenarios: ['内容创作', '研究团队', '营销团队', '业务流程自动化'],
|
||||
pros: [
|
||||
'概念易于理解',
|
||||
'角色设计直观',
|
||||
'协作流程清晰',
|
||||
'快速上手'
|
||||
],
|
||||
cons: [
|
||||
'生态相对较小',
|
||||
'定制性有限',
|
||||
'性能优化不足',
|
||||
'社区较小'
|
||||
],
|
||||
scores: {
|
||||
'灵活性': 70,
|
||||
'易用性': 90,
|
||||
'性能': 70,
|
||||
'文档': 80,
|
||||
'社区': 65
|
||||
},
|
||||
website: 'https://crewai.com',
|
||||
github: 'https://github.com/joaomdmoura/crewAI',
|
||||
docs: 'https://docs.crewai.com',
|
||||
learningCurve: '⭐⭐',
|
||||
community: '⭐⭐⭐',
|
||||
bestFor: '角色协作',
|
||||
stars: '12k+'
|
||||
},
|
||||
{
|
||||
name: 'AgentScope',
|
||||
icon: '🔭',
|
||||
tagline: '阿里开源的 Agent 框架',
|
||||
features: [
|
||||
'中文友好',
|
||||
'简单易用',
|
||||
'支持多模态',
|
||||
'分布式执行',
|
||||
'可视化调试'
|
||||
],
|
||||
scenarios: ['中文应用', '多模态 Agent', '分布式系统', '国内部署'],
|
||||
pros: [
|
||||
'中文文档完善',
|
||||
'国内部署友好',
|
||||
'上手简单',
|
||||
'多模态支持好'
|
||||
],
|
||||
cons: [
|
||||
'生态较新',
|
||||
'社区较小',
|
||||
'功能相对有限',
|
||||
'国际化不足'
|
||||
],
|
||||
scores: {
|
||||
'灵活性': 70,
|
||||
'易用性': 85,
|
||||
'性能': 75,
|
||||
'文档': 80,
|
||||
'社区': 60
|
||||
},
|
||||
website: 'https://github.com/modelscope/agentscope',
|
||||
github: 'https://github.com/modelscope/agentscope',
|
||||
docs: 'https://modelscope.github.io/agentscope',
|
||||
learningCurve: '⭐⭐',
|
||||
community: '⭐⭐',
|
||||
bestFor: '中文多模态',
|
||||
stars: '5k+'
|
||||
}
|
||||
{ name: 'LangChain / LangGraph', learn: '中', control: '高', multi: '中', use: '可控的工具调用、工作流、企业集成' },
|
||||
{ name: 'AutoGen', learn: '中', control: '中', multi: '高', use: '多 Agent 对话协作、编程/分析助手' },
|
||||
{ name: 'CrewAI', learn: '低', control: '中', multi: '高', use: '角色分工清晰的团队协作任务' }
|
||||
]
|
||||
|
||||
const best = computed(() => {
|
||||
if (focus.value === 'start') return 'CrewAI'
|
||||
if (focus.value === 'team') return 'AutoGen'
|
||||
return 'LangChain / LangGraph'
|
||||
})
|
||||
|
||||
const reason = computed(() => {
|
||||
if (focus.value === 'start') return '概念更直观(角色+任务),适合先跑通一个最小团队。'
|
||||
if (focus.value === 'team') return '多 Agent 对话与协作是强项,适合需要分工的场景。'
|
||||
return '把流程“画成图/写成步骤”,更利于调试、上线与长期维护。'
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.framework-comparison-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin: 24px 0;
|
||||
}
|
||||
.cmp { border: 1px solid var(--vp-c-divider); border-radius: 12px; background: var(--vp-c-bg-soft); padding: 16px; margin: 20px 0; display: flex; flex-direction: column; gap: 12px; }
|
||||
.header { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
|
||||
.title { font-weight: 800; }
|
||||
.subtitle { color: var(--vp-c-text-2); font-size: 13px; }
|
||||
.focus { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
.chip { border: 1px solid var(--vp-c-divider); background: var(--vp-c-bg); padding: 8px 12px; border-radius: 999px; cursor: pointer; }
|
||||
.chip.active { border-color: var(--vp-c-brand); color: var(--vp-c-brand); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); }
|
||||
|
||||
.framework-tabs {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.table { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 12px; overflow: hidden; }
|
||||
.row { display: grid; grid-template-columns: 1.4fr 0.8fr 0.8fr 0.9fr 2.1fr; gap: 10px; padding: 10px 12px; border-top: 1px solid var(--vp-c-divider); align-items: center; }
|
||||
.row.head { border-top: none; font-weight: 800; color: var(--vp-c-text-2); background: var(--vp-c-bg-soft); }
|
||||
.name { font-weight: 800; }
|
||||
.use { color: var(--vp-c-text-2); }
|
||||
.row.best { outline: 2px solid var(--vp-c-brand); outline-offset: -2px; background: rgba(0, 0, 0, 0.02); }
|
||||
|
||||
.tab-btn {
|
||||
padding: 12px 24px;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-1);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.tab-btn:hover {
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.tab-btn.active {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border-color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.framework-content {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.framework-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 2px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.framework-icon {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
.framework-header h3 {
|
||||
margin: 0 0 4px 0;
|
||||
color: var(--vp-c-brand);
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.framework-tagline {
|
||||
margin: 0;
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.framework-details {
|
||||
display: grid;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.detail-section h4 {
|
||||
margin: 0 0 12px 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.detail-section ul {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.detail-section li {
|
||||
padding: 4px 0;
|
||||
color: var(--vp-c-text-2);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.detail-section li::before {
|
||||
content: '•';
|
||||
position: absolute;
|
||||
left: -16px;
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.scenarios {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.scenario-tag {
|
||||
padding: 8px 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 6px;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.pros-cons {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.pros-cons {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.pros-title {
|
||||
color: #10b981;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.cons-title {
|
||||
color: #ef4444;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.capabilities {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.capability-item {
|
||||
display: grid;
|
||||
grid-template-columns: 80px 1fr 60px;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.capability-label {
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.capability-bar {
|
||||
height: 24px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.bar-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, var(--vp-c-brand), var(--vp-c-brand-light));
|
||||
border-radius: 12px;
|
||||
transition: width 0.5s ease;
|
||||
}
|
||||
|
||||
.capability-value {
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-brand);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.links {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.link-item {
|
||||
padding: 10px 20px;
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.link-item:hover {
|
||||
background: var(--vp-c-brand-dark);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.comparison-table {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.comparison-table h3 {
|
||||
margin: 0 0 20px 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
thead th {
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
color: var(--vp-c-text-1);
|
||||
border-bottom: 2px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
tbody td {
|
||||
padding: 12px;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
.rec { background: var(--vp-c-bg); border: 1px dashed var(--vp-c-divider); border-radius: 12px; padding: 12px; }
|
||||
.rec-title { font-weight: 800; margin-bottom: 6px; }
|
||||
.rec-body { color: var(--vp-c-text-2); line-height: 1.6; }
|
||||
</style>
|
||||
|
||||
|
||||
+101
-385
@@ -1,407 +1,123 @@
|
||||
<!--
|
||||
FrameworkSelectionDemo.vue
|
||||
框架选择小向导:回答 3 个问题,给出推荐 + 适配理由 + 你需要注意什么。
|
||||
-->
|
||||
<template>
|
||||
<div class="framework-selection-demo">
|
||||
<div class="selection-quiz">
|
||||
<h3>🤔 选择合适的 Agent 框架</h3>
|
||||
<p class="quiz-intro">回答几个问题,帮你找到最适合的框架!</p>
|
||||
|
||||
<div v-if="currentQuestion < questions.length" class="question-container">
|
||||
<div class="question-header">
|
||||
<span class="question-number">问题 {{ currentQuestion + 1 }}/{{ questions.length }}</span>
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" :style="{ width: ((currentQuestion + 1) / questions.length * 100) + '%' }"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="question-text">{{ questions[currentQuestion].question }}</h4>
|
||||
|
||||
<div class="options">
|
||||
<button
|
||||
v-for="(option, index) in questions[currentQuestion].options"
|
||||
:key="index"
|
||||
class="option-btn"
|
||||
@click="selectOption(index)"
|
||||
>
|
||||
{{ option.text }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="sel">
|
||||
<div class="header">
|
||||
<div>
|
||||
<div class="title">三问选框架</div>
|
||||
<div class="subtitle">目标:先跑通一个最小 Agent,再逐步增强。</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="recommendation">
|
||||
<div class="result-header">
|
||||
<div class="result-icon">🎯</div>
|
||||
<h4>推荐框架:{{ recommendedFramework }}</h4>
|
||||
</div>
|
||||
|
||||
<div class="result-description">
|
||||
{{ getRecommendationDescription() }}
|
||||
</div>
|
||||
|
||||
<div class="result-reasons">
|
||||
<div class="reasons-title">为什么推荐这个?</div>
|
||||
<ul>
|
||||
<li v-for="reason in getRecommendationReasons()" :key="reason">{{ reason }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="next-steps">
|
||||
<div class="steps-title">📚 下一步</div>
|
||||
<div class="step-links">
|
||||
<a :href="getFrameworkInfo().website" target="_blank" class="step-link">
|
||||
🌐 访问官网
|
||||
</a>
|
||||
<a :href="getFrameworkInfo().docs" target="_blank" class="step-link">
|
||||
📖 阅读文档
|
||||
</a>
|
||||
<a :href="getFrameworkInfo().github" target="_blank" class="step-link">
|
||||
💻 查看代码
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button @click="resetQuiz" class="restart-btn">
|
||||
↺ 重新选择
|
||||
</button>
|
||||
<div class="q">
|
||||
<div class="q-title">1) 你更在乎什么?</div>
|
||||
<div class="opts">
|
||||
<button v-for="o in q1" :key="o.id" :class="['opt', { active: a1 === o.id }]" @click="a1 = o.id">{{ o.label }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="q">
|
||||
<div class="q-title">2) 你的任务像哪种?</div>
|
||||
<div class="opts">
|
||||
<button v-for="o in q2" :key="o.id" :class="['opt', { active: a2 === o.id }]" @click="a2 = o.id">{{ o.label }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="q">
|
||||
<div class="q-title">3) 需要多 Agent 分工吗?</div>
|
||||
<div class="opts">
|
||||
<button v-for="o in q3" :key="o.id" :class="['opt', { active: a3 === o.id }]" @click="a3 = o.id">{{ o.label }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="result">
|
||||
<div class="r-title">推荐:{{ rec.name }}</div>
|
||||
<div class="r-body">{{ rec.reason }}</div>
|
||||
<div class="r-note"><strong>注意:</strong>{{ rec.note }}</div>
|
||||
<div class="r-next"><strong>下一步:</strong>{{ rec.next }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
const currentQuestion = ref(0)
|
||||
const answers = ref([])
|
||||
|
||||
const questions = [
|
||||
{
|
||||
question: '你的主要使用场景是什么?',
|
||||
options: [
|
||||
{ text: '🤖 编程和代码开发', scores: { LangChain: 2, AutoGen: 5, CrewAI: 2, AgentScope: 2 } },
|
||||
{ text: '📝 内容创作和文案', scores: { LangChain: 3, AutoGen: 1, CrewAI: 5, AgentScope: 3 } },
|
||||
{ text: '🔍 数据分析和研究', scores: { LangChain: 4, AutoGen: 4, CrewAI: 3, AgentScope: 3 } },
|
||||
{ text: '🌐 通用应用开发', scores: { LangChain: 5, AutoGen: 2, CrewAI: 3, AgentScope: 4 } }
|
||||
]
|
||||
},
|
||||
{
|
||||
question: '你更看重什么?',
|
||||
options: [
|
||||
{ text: '⚡ 快速上手', scores: { LangChain: 2, AutoGen: 3, CrewAI: 5, AgentScope: 4 } },
|
||||
{ text: '🔧 高度定制', scores: { LangChain: 5, AutoGen: 3, CrewAI: 2, AgentScope: 2 } },
|
||||
{ text: '👥 团队协作', scores: { LangChain: 3, AutoGen: 4, CrewAI: 5, AgentScope: 2 } },
|
||||
{ text: '📚 文档完善', scores: { LangChain: 5, AutoGen: 3, CrewAI: 3, AgentScope: 3 } }
|
||||
]
|
||||
},
|
||||
{
|
||||
question: '你的技术水平?',
|
||||
options: [
|
||||
{ text: '🌱 初学者', scores: { LangChain: 2, AutoGen: 2, CrewAI: 4, AgentScope: 5 } },
|
||||
{ text: '🌿 有一些经验', scores: { LangChain: 4, AutoGen: 3, CrewAI: 4, AgentScope: 4 } },
|
||||
{ text: '🌳 经验丰富', scores: { LangChain: 5, AutoGen: 4, CrewAI: 3, AgentScope: 3 } },
|
||||
{ text: '🏆 专家级别', scores: { LangChain: 5, AutoGen: 5, CrewAI: 3, AgentScope: 3 } }
|
||||
]
|
||||
},
|
||||
{
|
||||
question: '项目规模?',
|
||||
options: [
|
||||
{ text: '📦 个人项目', scores: { LangChain: 3, AutoGen: 3, CrewAI: 4, AgentScope: 5 } },
|
||||
{ text: '🏢 小团队项目', scores: { LangChain: 4, AutoGen: 4, CrewAI: 5, AgentScope: 3 } },
|
||||
{ text: '🏛️ 企业级应用', scores: { LangChain: 5, AutoGen: 3, CrewAI: 3, AgentScope: 2 } },
|
||||
{ text: '🌍 大规模分布式', scores: { LangChain: 4, AutoGen: 2, CrewAI: 2, AgentScope: 3 } }
|
||||
]
|
||||
},
|
||||
{
|
||||
question: '是否需要中文支持?',
|
||||
options: [
|
||||
{ text: '🇨🇳 非常重要', scores: { LangChain: 2, AutoGen: 2, CrewAI: 2, AgentScope: 5 } },
|
||||
{ text: '🌏 最好有', scores: { LangChain: 3, AutoGen: 2, CrewAI: 2, AgentScope: 4 } },
|
||||
{ text: '🌐 不重要', scores: { LangChain: 4, AutoGen: 4, CrewAI: 4, AgentScope: 2 } },
|
||||
{ text: '🚫 不需要', scores: { LangChain: 5, AutoGen: 5, CrewAI: 4, AgentScope: 2 } }
|
||||
]
|
||||
}
|
||||
const q1 = [
|
||||
{ id: 'easy', label: '快速上手' },
|
||||
{ id: 'stable', label: '可控可上线' },
|
||||
{ id: 'team', label: '团队协作' }
|
||||
]
|
||||
const q2 = [
|
||||
{ id: 'workflow', label: '有明确流程(步骤/图)' },
|
||||
{ id: 'chat', label: '偏对话与协商' },
|
||||
{ id: 'explore', label: '探索式试错' }
|
||||
]
|
||||
const q3 = [
|
||||
{ id: 'no', label: '不需要' },
|
||||
{ id: 'maybe', label: '可能需要' },
|
||||
{ id: 'yes', label: '必须需要' }
|
||||
]
|
||||
|
||||
const frameworkInfo = {
|
||||
LangChain: {
|
||||
website: 'https://langchain.com',
|
||||
docs: 'https://python.langchain.com',
|
||||
github: 'https://github.com/langchain-ai/langchain',
|
||||
description: 'LangChain 是最流行的 LLM 应用开发框架,拥有最完善的生态系统和社区支持。适合需要高度定制和集成的场景。',
|
||||
reasons: [
|
||||
'最强大的生态系统',
|
||||
'高度可定制',
|
||||
'丰富的集成选项',
|
||||
'活跃的社区支持'
|
||||
]
|
||||
},
|
||||
AutoGen: {
|
||||
website: 'https://microsoft.github.io/autogen',
|
||||
docs: 'https://microsoft.github.io/autogen/docs',
|
||||
github: 'https://github.com/microsoft/autogen',
|
||||
description: 'AutoGen 是微软开发的多 Agent 协作框架,特别擅长编程和代码相关任务。如果你需要多个 Agent 协作完成编程任务,这是最佳选择。',
|
||||
reasons: [
|
||||
'独特的协作模式',
|
||||
'强大的代码执行能力',
|
||||
'微软官方支持',
|
||||
'适合编程辅助场景'
|
||||
]
|
||||
},
|
||||
CrewAI: {
|
||||
website: 'https://crewai.com',
|
||||
docs: 'https://docs.crewai.com',
|
||||
github: 'https://github.com/joaomdmoura/crewAI',
|
||||
description: 'CrewAI 采用角色驱动的 Agent 设计,概念直观易懂。非常适合快速组建 AI 团队来完成内容创作、研究等任务。',
|
||||
reasons: [
|
||||
'直观的角色设计',
|
||||
'易于上手',
|
||||
'团队协作模式清晰',
|
||||
'适合快速原型开发'
|
||||
]
|
||||
},
|
||||
AgentScope: {
|
||||
website: 'https://github.com/modelscope/agentscope',
|
||||
docs: 'https://modelscope.github.io/agentscope',
|
||||
github: 'https://github.com/modelscope/agentscope',
|
||||
description: 'AgentScope 是阿里开源的 Agent 框架,中文友好,简单易用。特别适合国内开发者和需要中文支持的项目。',
|
||||
reasons: [
|
||||
'完善的中文文档',
|
||||
'国内部署友好',
|
||||
'上手非常简单',
|
||||
'多模态支持良好'
|
||||
]
|
||||
const a1 = ref('stable')
|
||||
const a2 = ref('workflow')
|
||||
const a3 = ref('maybe')
|
||||
|
||||
const rec = computed(() => {
|
||||
// Multi-agent first
|
||||
if (a3.value === 'yes' || a1.value === 'team') {
|
||||
if (a2.value === 'chat') {
|
||||
return {
|
||||
name: 'AutoGen',
|
||||
reason: '多 Agent 对话协作是强项,适合“互相讨论、分工协作”。',
|
||||
note: '先把角色边界写清楚,否则容易重复劳动或互怼。',
|
||||
next: '从 2 个 Agent 开始:研究员 + 执行者。'
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: 'CrewAI',
|
||||
reason: '角色+任务模型很直观,适合“分工明确”的团队工作流。',
|
||||
note: '先把输入/输出格式定死,避免多人输出难合并。',
|
||||
next: '先搭 2-3 个角色:Researcher/Writer/Reviewer。'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const recommendedFramework = computed(() => {
|
||||
const scores = { LangChain: 0, AutoGen: 0, CrewAI: 0, AgentScope: 0 }
|
||||
// Single-agent / controllable workflow
|
||||
if (a1.value === 'stable' || a2.value === 'workflow') {
|
||||
return {
|
||||
name: 'LangChain / LangGraph',
|
||||
reason: '更适合把 Agent 写成“可控流程”,便于调试、上线、加护栏。',
|
||||
note: '别一上来做大系统,先把 1 个工具调用跑通。',
|
||||
next: '用 LangGraph 画一个 3-5 节点的小图。'
|
||||
}
|
||||
}
|
||||
|
||||
answers.value.forEach((answerIndex, questionIndex) => {
|
||||
const optionScores = questions[questionIndex].options[answerIndex].scores
|
||||
Object.keys(optionScores).forEach(framework => {
|
||||
scores[framework] += optionScores[framework]
|
||||
})
|
||||
})
|
||||
|
||||
return Object.keys(scores).reduce((a, b) => scores[a] > scores[b] ? a : b)
|
||||
// Easy start
|
||||
return {
|
||||
name: 'CrewAI',
|
||||
reason: '上手快、概念直观,适合先做出一个“能跑”的 demo。',
|
||||
note: 'demo 能跑不代表可上线,后续要补安全与可观测。',
|
||||
next: '先做一个“研究+写作”的最小团队。'
|
||||
}
|
||||
})
|
||||
|
||||
const selectOption = (index) => {
|
||||
answers.value.push(index)
|
||||
if (currentQuestion.value < questions.length - 1) {
|
||||
currentQuestion.value++
|
||||
}
|
||||
}
|
||||
|
||||
const resetQuiz = () => {
|
||||
currentQuestion.value = 0
|
||||
answers.value = []
|
||||
}
|
||||
|
||||
const getRecommendationDescription = () => {
|
||||
return frameworkInfo[recommendedFramework.value].description
|
||||
}
|
||||
|
||||
const getRecommendationReasons = () => {
|
||||
return frameworkInfo[recommendedFramework.value].reasons
|
||||
}
|
||||
|
||||
const getFrameworkInfo = () => {
|
||||
return frameworkInfo[recommendedFramework.value]
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.framework-selection-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin: 24px 0;
|
||||
}
|
||||
.sel { border: 1px solid var(--vp-c-divider); border-radius: 12px; background: var(--vp-c-bg-soft); padding: 16px; margin: 20px 0; display: flex; flex-direction: column; gap: 12px; }
|
||||
.header { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
|
||||
.title { font-weight: 800; }
|
||||
.subtitle { color: var(--vp-c-text-2); font-size: 13px; }
|
||||
|
||||
.selection-quiz h3 {
|
||||
margin: 0 0 8px 0;
|
||||
color: var(--vp-c-brand);
|
||||
font-size: 1.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
.q { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 12px; padding: 12px; }
|
||||
.q-title { font-weight: 800; margin-bottom: 8px; }
|
||||
.opts { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
.opt { border: 1px solid var(--vp-c-divider); background: var(--vp-c-bg); padding: 8px 12px; border-radius: 999px; cursor: pointer; }
|
||||
.opt.active { border-color: var(--vp-c-brand); color: var(--vp-c-brand); box-shadow: 0 4px 12px rgba(0,0,0,0.08); }
|
||||
|
||||
.quiz-intro {
|
||||
text-align: center;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.question-container {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.question-header {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.question-number {
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 8px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: var(--vp-c-brand);
|
||||
border-radius: 4px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.question-text {
|
||||
margin: 0 0 24px 0;
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.option-btn {
|
||||
padding: 16px 20px;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
color: var(--vp-c-text-1);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
text-align: left;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.option-btn:hover {
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-bg);
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
.recommendation {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
padding: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.result-header {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.result-icon {
|
||||
font-size: 4rem;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.result-header h4 {
|
||||
margin: 0;
|
||||
color: var(--vp-c-brand);
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.result-description {
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.7;
|
||||
margin-bottom: 24px;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.result-reasons {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin-bottom: 24px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.reasons-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 12px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.result-reasons ul {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.result-reasons li {
|
||||
padding: 4px 0;
|
||||
color: var(--vp-c-text-2);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.result-reasons li::before {
|
||||
content: '✓';
|
||||
position: absolute;
|
||||
left: -20px;
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.next-steps {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.steps-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 12px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.step-links {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.step-link {
|
||||
padding: 12px 24px;
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.step-link:hover {
|
||||
background: var(--vp-c-brand-dark);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.restart-btn {
|
||||
padding: 12px 32px;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-1);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.restart-btn:hover {
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-bg-soft);
|
||||
}
|
||||
.result { background: var(--vp-c-bg); border: 1px dashed var(--vp-c-divider); border-radius: 12px; padding: 12px; }
|
||||
.r-title { font-weight: 900; margin-bottom: 6px; }
|
||||
.r-body { color: var(--vp-c-text-2); line-height: 1.6; margin-bottom: 6px; }
|
||||
.r-note, .r-next { color: var(--vp-c-text-2); line-height: 1.6; }
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user