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:
sanbuphy
2026-01-16 19:10:21 +08:00
parent c8567ce23f
commit 73f4788d7e
150 changed files with 19530 additions and 13401 deletions
@@ -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>
@@ -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>
@@ -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>