feat(ai-protocols): add MCP and A2A protocol demos and documentation

docs(ai-protocols): update AI protocols page with visual demos and detailed explanations
style(git-demos): improve responsive design and layout for git visualization components
refactor(ai-history): simplify and clean up demo components
chore: update config to register new AI protocol components
This commit is contained in:
sanbuphy
2026-02-22 18:26:19 +08:00
parent 4b83a4c23e
commit e5a5b9df5b
31 changed files with 5093 additions and 5333 deletions
@@ -0,0 +1,895 @@
<template>
<div class="a2a-detailed-demo">
<div class="demo-header">
<span class="title">A2A 内部实现</span>
<span class="subtitle">对等网络架构的通信细节</span>
</div>
<div class="intro-section">
<div class="section-title">A2A 可以做什么</div>
<p class="intro-text">
A2A 让多个 AI Agent 可以相互协作不再是单打独斗一个复杂任务可以分配给多个专业 Agent每个 Agent 做自己擅长的事
</p>
<div class="popular-uses">
<div class="use-item">
<div class="use-title">软件开发流水线</div>
<div class="use-desc">需求分析 Agent 代码 Agent 测试 Agent 部署 Agent</div>
</div>
<div class="use-item">
<div class="use-title">多厂商 Agent 集成</div>
<div class="use-desc">GoogleAnthropicOpenAI Agent 可以相互调用</div>
</div>
<div class="use-item">
<div class="use-title">企业工作流</div>
<div class="use-desc">HR Agent财务 Agent审批 Agent 协同处理业务流程</div>
</div>
<div class="use-item">
<div class="use-title">智能客服升级</div>
<div class="use-desc">接待 Agent 业务 Agent 人工 Agent 逐级转接</div>
</div>
<div class="use-item">
<div class="use-title">科研协作</div>
<div class="use-desc">文献 Agent 实验 Agent 分析 Agent 报告 Agent</div>
</div>
<div class="use-item">
<div class="use-title">自动化运维</div>
<div class="use-desc">监控 Agent 诊断 Agent 修复 Agent 通知 Agent</div>
</div>
</div>
</div>
<div class="usage-section">
<div class="section-title">如何使用 A2A</div>
<p class="usage-intro">
A2A 目前还在早期阶段主要由 Google 推动如果你想尝试 A2A需要开发支持 A2A 协议的 Agent 服务
</p>
<div class="usage-steps">
<div class="usage-step">
<div class="step-num">1</div>
<div class="step-content">
<div class="step-title">实现 Agent Card 端点</div>
<div class="step-desc">
在你的 Agent 服务中暴露 <code>/.well-known/agent.json</code>声明 Agent 的能力和版本
</div>
</div>
</div>
<div class="usage-step">
<div class="step-num">2</div>
<div class="step-content">
<div class="step-title">实现 A2A API</div>
<div class="step-desc">
实现 <code>agents/get</code><code>tasks/send</code><code>tasks/get</code> 等核心 API
</div>
</div>
</div>
<div class="usage-step">
<div class="step-num">3</div>
<div class="step-content">
<div class="step-title">部署并注册 Agent</div>
<div class="step-desc">
Agent 部署到服务器并在 Agent 注册表中登记让其他 Agent 可以发现它
</div>
</div>
</div>
</div>
<div class="usage-note">
<div class="note-title">当前状态</div>
<div class="note-content">
A2A 协议于 2025 4 月发布目前还在快速发展中Google 提供了参考实现但生态还在建设中建议关注 <a href="https://google.github.io/A2A" target="_blank">官方文档</a> 获取最新进展
</div>
</div>
</div>
<div class="demo-content">
<div class="flow-section">
<div class="flow-title">
通信流程5
</div>
<div class="flow-steps">
<div
v-for="(step, index) in a2aFlowSteps"
:key="index"
class="flow-step-item"
>
<div class="step-header" @click="toggleStep(index)">
<span class="step-num">{{ index + 1 }}</span>
<span class="step-name">{{ step.name }}</span>
<span class="step-arrow">{{ expandedStep === index ? '▼' : '▶' }}</span>
</div>
<div v-if="expandedStep === index" class="step-detail">
<div class="step-desc">{{ step.desc }}</div>
<div class="step-example">
<div class="example-title">{{ step.example.title }}</div>
<pre class="example-code"><code>{{ step.example.code }}</code></pre>
</div>
</div>
</div>
</div>
</div>
<details class="tech-details">
<summary class="tech-summary">
<span class="summary-text">技术深究Agent Card 名片格式</span>
</summary>
<div class="tech-content">
<div class="tech-intro">
Agent Card 是一个 JSON 文件通常放在 <code>/.well-known/agent.json</code> 路径
</div>
<div class="tech-section">
<div class="tech-title">Agent Card 示例</div>
<pre class="tech-code"><code>{{ agentCardExample }}</code></pre>
</div>
<div class="tech-note">
<span>通过 Agent CardAgent 之间可以相互发现了解对方的能力和版本实现互操作</span>
</div>
</div>
</details>
<details class="tech-details">
<summary class="tech-summary">
<span class="summary-text">技术深究HTTP + SSE 通信</span>
</summary>
<div class="tech-content">
<div class="tech-section">
<div class="tech-title">任务发送HTTP POST</div>
<pre class="tech-code"><code>{{ taskSendExample }}</code></pre>
</div>
<div class="tech-section">
<div class="tech-title">实时推送SSE</div>
<pre class="tech-code"><code>{{ sseExample }}</code></pre>
</div>
<div class="tech-note">
<span>SSEServer-Sent Events允许服务器主动推送消息适合长时任务的状态更新</span>
</div>
</div>
</details>
<details class="tech-details">
<summary class="tech-summary">
<span class="summary-text">技术深究A2A 核心 API</span>
</summary>
<div class="tech-content">
<div class="api-list">
<div v-for="(api, index) in a2aApis" :key="index" class="api-item">
<div class="api-method">
<span class="method-badge">{{ api.method }}</span>
<span class="method-name">{{ api.name }}</span>
</div>
<div class="api-desc">{{ api.desc }}</div>
</div>
</div>
</div>
</details>
<details class="tech-details">
<summary class="tech-summary">
<span class="summary-text">技术深究认证机制</span>
</summary>
<div class="tech-content">
<div class="auth-grid">
<div class="auth-card">
<div class="auth-header">
<span class="auth-name">API Key</span>
</div>
<div class="auth-desc">
简单的认证方式适合内部 Agent 通信
</div>
<pre class="auth-example"><code>{{ apiKeyExample }}</code></pre>
</div>
<div class="auth-card">
<div class="auth-header">
<span class="auth-name">OAuth 2.0</span>
</div>
<div class="auth-desc">
企业级认证支持令牌刷新和权限控制
</div>
<pre class="auth-example"><code>{{ oauthExample }}</code></pre>
</div>
</div>
</div>
</details>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const expandedStep = ref(0)
const toggleStep = (index) => {
expandedStep.value = expandedStep.value === index ? -1 : index
}
const a2aFlowSteps = [
{
name: '发现(agents/get',
desc: 'Agent 之间通过 HTTP 请求获取对方的 Agent Card,了解对方的能力和版本',
example: {
title: 'HTTP 请求',
code: `// Agent A 获取 Agent B 的 Agent Card
GET /.well-known/agent.json HTTP/1.1
Host: agent-b.company.com
// 响应
{
"name": "Code Agent",
"description": "专业代码生成 Agent",
"url": "https://agent-b.company.com",
"version": "1.0.0",
"capabilities": {
"streaming": true,
"pushNotifications": true
},
"skills": [
{"id": "code-gen", "name": "代码生成"},
{"id": "code-review", "name": "代码审查"}
]
}`
}
},
{
name: '发任务(tasks/send',
desc: 'Agent A 调用 tasks/send 向 Agent B 发送任务,包含任务ID、描述、上下文等',
example: {
title: 'HTTP POST',
code: `// Agent A 发送任务给 Agent B
POST /tasks/send HTTP/1.1
Content-Type: application/json
Authorization: Bearer xxx
{
"id": "task-12345",
"sessionId": "session-001",
"message": {
"role": "user",
"parts": [
{
"type": "text",
"text": "请帮我写一个登录 API"
},
{
"type": "resource",
"resource": "file:///specs/login.yaml"
}
]
}
}`
}
},
{
name: '执行(Task Processing',
desc: 'Agent B 接收任务后,可能调用自己的 LLM 或 MCP 工具来执行任务',
example: {
title: 'Agent B 内部处理',
code: `// Agent B 内部处理流程
1. 解析任务请求
2. 分析需要的技能(从 skills 中匹配)
3. 调用内部 LLM 生成代码
4. 可选:通过 MCP 调用外部工具验证代码
5. 生成最终结果
// 整个过程可能耗时较长,通过 SSE 推送进度`
}
},
{
name: '推送(SSE',
desc: 'Agent B 通过 SSEServer-Sent Events)实时推送任务进度和中间结果',
example: {
title: 'SSE 推送',
code: `// 服务器持续推送
event: taskProgress
data: {
"taskId": "task-12345",
"status": "processing",
"progress": 30,
"message": "正在生成登录逻辑..."
}
event: taskProgress
data: {
"taskId": "task-12345",
"status": "processing",
"progress": 60,
"message": "正在生成数据库操作..."
}
event: taskCompleted
data: {
"taskId": "task-12345",
"status": "completed",
"result": { ... }
}`
}
},
{
name: '返回结果(tasks/get',
desc: '任务完成后,Agent A 可以通过 tasks/get 获取最终结果',
example: {
title: 'HTTP GET',
code: `// Agent A 获取任务结果
GET /tasks/task-12345 HTTP/1.1
Authorization: Bearer xxx
// 响应
{
"id": "task-12345",
"status": "completed",
"result": {
"message": {
"role": "agent",
"parts": [
{
"type": "text",
"text": "登录 API 已生成..."
},
{
"type": "file",
"file": {
"name": "login.py",
"mimeType": "text/plain",
"uri": "file:///generated/login.py"
}
}
]
}
}
}`
}
}
]
const agentCardExample = `{
"name": "代码生成 Agent",
"description": "专业的前后端代码生成 Agent",
"url": "https://code-agent.company.com",
"version": "1.0.0",
"capabilities": {
"streaming": true,
"pushNotifications": true
},
"skills": [
{
"id": "frontend",
"name": "前端开发",
"description": "React/Vue/Angular"
},
{
"id": "backend",
"name": "后端开发",
"description": "Node/Python/Go"
}
],
"authentication": {
"schemes": ["Bearer", "OAuth2"]
}
}`
const taskSendExample = `POST /tasks/send HTTP/1.1
Host: agent-b.company.com
Content-Type: application/json
Authorization: Bearer {token}
{
"id": "task-001",
"message": {
"role": "user",
"parts": [{ "type": "text", "text": "写一个登录接口" }]
}
}`
const sseExample = `GET /tasks/task-001/sse HTTP/1.1
Authorization: Bearer {token}
event: progress
data: {"status": "processing", "progress": 50}
event: completed
data: {"status": "completed", "result": {...}}`
const a2aApis = [
{ method: 'GET', name: 'agents/get', desc: '获取指定 Agent 的 Agent Card,了解其能力' },
{ method: 'POST', name: 'tasks/send', desc: '发送任务给目标 Agent,同步等待结果' },
{ method: 'POST', name: 'tasks/sendSubscribe', desc: '发送任务并订阅 SSE 推送,实时获取进度' },
{ method: 'GET', name: 'tasks/get', desc: '根据任务 ID 获取任务状态和结果' },
{ method: 'GET', name: 'tasks/cancel', desc: '取消正在执行的任务' }
]
const apiKeyExample = `Authorization: Bearer sk-xxxxx
# 或
Authorization: ApiKey sk-xxxxx`
const oauthExample = `Authorization: Bearer {access_token}
# 支持刷新令牌
POST /oauth/token
{
"grant_type": "refresh_token",
"refresh_token": "xxx"
}`
</script>
<style scoped>
.a2a-detailed-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1rem;
}
.demo-header .icon {
font-size: 1.25rem;
}
.demo-header .title {
font-weight: bold;
font-size: 1rem;
}
.demo-header .subtitle {
color: var(--vp-c-text-2);
font-size: 0.85rem;
margin-left: 0.5rem;
}
.flow-section {
margin-bottom: 1rem;
}
.flow-title {
display: flex;
align-items: center;
gap: 0.3rem;
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 0.75rem;
}
.title-icon {
font-size: 1rem;
}
.flow-steps {
display: flex;
flex-direction: column;
gap: 0.4rem;
}
.flow-step-item {
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
overflow: hidden;
background: var(--vp-c-bg);
}
.step-header {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 0.75rem;
cursor: pointer;
background: var(--vp-c-bg-soft);
transition: background 0.2s;
}
.step-header:hover {
background: var(--vp-c-bg-alt);
}
.step-num {
width: 20px;
height: 20px;
border-radius: 50%;
background: #10b981;
color: white;
font-size: 0.7rem;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
flex-shrink: 0;
}
.step-name {
flex: 1;
font-size: 0.85rem;
font-weight: 500;
}
.step-arrow {
font-size: 0.7rem;
color: var(--vp-c-text-3);
}
.step-detail {
padding: 0.75rem;
border-top: 1px solid var(--vp-c-divider);
}
.step-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
margin-bottom: 0.5rem;
}
.step-example {
background: var(--vp-c-bg-soft);
border-radius: 6px;
padding: 0.5rem;
}
.example-title {
font-size: 0.7rem;
color: var(--vp-c-text-3);
margin-bottom: 0.3rem;
}
.example-code {
font-size: 0.7rem;
background: var(--vp-c-bg);
padding: 0.5rem;
border-radius: 4px;
overflow-x: auto;
white-space: pre-wrap;
word-break: break-all;
font-family: var(--vp-font-family-mono);
margin: 0;
line-height: 1.4;
}
.tech-details {
margin-bottom: 0.75rem;
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
overflow: hidden;
}
.tech-summary {
display: flex;
align-items: center;
gap: 0.4rem;
padding: 0.6rem 0.75rem;
cursor: pointer;
background: var(--vp-c-bg-soft);
font-size: 0.85rem;
font-weight: 500;
list-style: none;
}
.tech-summary::-webkit-details-marker {
display: none;
}
.summary-icon {
font-size: 0.9rem;
}
.tech-content {
padding: 0.75rem;
border-top: 1px solid var(--vp-c-divider);
background: var(--vp-c-bg);
}
.tech-intro {
font-size: 0.8rem;
color: var(--vp-c-text-2);
margin-bottom: 0.75rem;
padding: 0.5rem;
background: var(--vp-c-bg-soft);
border-radius: 4px;
}
.tech-intro code {
background: var(--vp-c-bg);
padding: 0.1rem 0.3rem;
border-radius: 3px;
font-size: 0.75rem;
}
.tech-section {
margin-bottom: 0.75rem;
}
.tech-title {
font-size: 0.8rem;
font-weight: 600;
color: var(--vp-c-text-1);
margin-bottom: 0.4rem;
}
.tech-code {
font-size: 0.7rem;
background: var(--vp-c-bg-soft);
padding: 0.5rem;
border-radius: 4px;
overflow-x: auto;
white-space: pre-wrap;
word-break: break-all;
font-family: var(--vp-font-family-mono);
margin: 0;
line-height: 1.4;
}
.tech-note {
display: flex;
align-items: flex-start;
gap: 0.3rem;
font-size: 0.75rem;
color: var(--vp-c-text-2);
padding: 0.5rem;
background: var(--vp-c-bg-soft);
border-radius: 4px;
}
.note-icon {
flex-shrink: 0;
}
.api-list {
display: flex;
flex-direction: column;
gap: 0.4rem;
}
.api-item {
padding: 0.4rem;
background: var(--vp-c-bg-soft);
border-radius: 4px;
}
.api-method {
display: flex;
align-items: center;
gap: 0.3rem;
margin-bottom: 0.2rem;
}
.method-badge {
font-size: 0.6rem;
background: #10b981;
color: white;
padding: 0.1rem 0.3rem;
border-radius: 3px;
font-family: var(--vp-font-family-mono);
}
.method-name {
font-size: 0.8rem;
font-weight: 600;
}
.api-desc {
font-size: 0.7rem;
color: var(--vp-c-text-2);
}
.auth-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.5rem;
}
.auth-card {
background: var(--vp-c-bg-soft);
border-radius: 6px;
padding: 0.5rem;
}
.auth-header {
display: flex;
align-items: center;
gap: 0.3rem;
margin-bottom: 0.3rem;
}
.auth-icon {
font-size: 0.9rem;
}
.auth-name {
font-size: 0.8rem;
font-weight: 600;
}
.auth-desc {
font-size: 0.7rem;
color: var(--vp-c-text-2);
margin-bottom: 0.4rem;
}
.auth-example pre {
font-size: 0.65rem;
background: var(--vp-c-bg);
padding: 0.4rem;
border-radius: 4px;
overflow-x: auto;
white-space: pre-wrap;
word-break: break-all;
font-family: var(--vp-font-family-mono);
margin: 0;
line-height: 1.3;
}
@media (max-width: 640px) {
.auth-grid {
grid-template-columns: 1fr;
}
}
.intro-section {
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--vp-c-divider);
}
.intro-section .section-title {
font-weight: 600;
font-size: 0.95rem;
color: var(--vp-c-text-1);
margin-bottom: 0.5rem;
}
.intro-section .intro-text {
font-size: 0.85rem;
color: var(--vp-c-text-2);
line-height: 1.5;
margin-bottom: 0.75rem;
}
.popular-uses {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.5rem;
}
.use-item {
padding: 0.5rem;
background: var(--vp-c-bg);
border-radius: 6px;
border-left: 3px solid var(--vp-c-brand);
}
.use-title {
font-weight: 600;
font-size: 0.75rem;
color: var(--vp-c-text-1);
margin-bottom: 0.2rem;
}
.use-desc {
font-size: 0.65rem;
color: var(--vp-c-text-2);
line-height: 1.3;
}
@media (max-width: 640px) {
.popular-uses {
grid-template-columns: 1fr;
}
}
.usage-section {
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--vp-c-divider);
}
.usage-section .section-title {
font-weight: 600;
font-size: 0.95rem;
color: var(--vp-c-text-1);
margin-bottom: 0.5rem;
}
.usage-intro {
font-size: 0.85rem;
color: var(--vp-c-text-2);
line-height: 1.5;
margin-bottom: 0.75rem;
}
.usage-intro code {
background: var(--vp-c-bg-alt);
padding: 0.1rem 0.3rem;
border-radius: 3px;
font-size: 0.8rem;
}
.usage-steps {
display: flex;
flex-direction: column;
gap: 0.6rem;
margin-bottom: 1rem;
}
.usage-step {
display: flex;
align-items: flex-start;
gap: 0.75rem;
padding: 0.75rem;
background: var(--vp-c-bg);
border-radius: 6px;
}
.usage-step .step-num {
display: flex;
align-items: center;
justify-content: center;
width: 1.5rem;
height: 1.5rem;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-size: 0.75rem;
font-weight: 600;
flex-shrink: 0;
}
.usage-step .step-content {
flex: 1;
}
.usage-step .step-title {
font-weight: 600;
font-size: 0.85rem;
color: var(--vp-c-text-1);
margin-bottom: 0.2rem;
}
.usage-step .step-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.usage-step .step-desc code {
background: var(--vp-c-bg-alt);
padding: 0.1rem 0.3rem;
border-radius: 3px;
font-size: 0.75rem;
}
.usage-note {
padding: 0.75rem;
background: var(--vp-c-bg);
border-radius: 6px;
border-left: 3px solid var(--vp-c-brand);
}
.note-title {
font-weight: 600;
font-size: 0.8rem;
color: var(--vp-c-text-1);
margin-bottom: 0.3rem;
}
.note-content {
font-size: 0.75rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.note-content a {
color: var(--vp-c-brand);
}
</style>
@@ -0,0 +1,221 @@
<template>
<div class="a2a-visual-demo">
<div class="section-title">A2A 是什么</div>
<div class="intro-text">
A2AAgent-to-Agent Protocol Google 2025 4 月推出的<strong>Agent 之间相互协作的通信标准</strong>它让不同厂商不同框架的 Agent 能够相互发现分配任务交换信息就像给 AI 世界装上了"对讲机"
</div>
<div class="section-title">核心概念</div>
<div class="concepts-grid">
<div class="concept">
<div class="concept-title">Agent CardAgent 名片</div>
<div class="concept-desc">每个 Agent 公开的元数据包括能力描述版本号端点地址等相当于人的"名片"</div>
</div>
<div class="concept">
<div class="concept-title">Task任务</div>
<div class="concept-desc">Agent 之间传递的工作单元可以包含多轮对话文件附件等</div>
</div>
<div class="concept">
<div class="concept-title">Message消息</div>
<div class="concept-desc">Agent 之间的通信内容支持文本文件语音等多模态</div>
</div>
<div class="concept">
<div class="concept-title">SSEServer-Sent Events</div>
<div class="concept-desc">服务器推送技术用于实时任务进度更新</div>
</div>
</div>
<div class="section-title">什么时候用 A2A</div>
<div class="use-cases">
<div class="use-case">
<div class="use-case-title">当需要多个 Agent 协作完成复杂任务时</div>
<div class="use-case-desc">一个 Agent 负责需求分析一个负责写代码一个负责测试各自发挥专长</div>
</div>
<div class="use-case">
<div class="use-case-title">当需要集成不同厂商的 Agent </div>
<div class="use-case-desc">Google AgentAnthropic AgentOpenAI Agent 需要相互协作</div>
</div>
<div class="use-case">
<div class="use-case-title">当需要任务委托和进度追踪时</div>
<div class="use-case-desc"> Agent 分配任务给专家 Agent并实时接收进度更新</div>
</div>
</div>
<div class="section-title">如何使用 A2A</div>
<div class="usage-steps">
<div class="step">
<div class="step-num">1</div>
<div class="step-content">
<div class="step-title">发布 Agent Card</div>
<div class="step-desc"> /.well-known/agent.json 路径暴露 Agent 的能力描述</div>
</div>
</div>
<div class="step">
<div class="step-num">2</div>
<div class="step-content">
<div class="step-title">发现 Agent</div>
<div class="step-desc">通过 agents/get API 获取其他 Agent 的名片了解其能力</div>
</div>
</div>
<div class="step">
<div class="step-num">3</div>
<div class="step-content">
<div class="step-title">发送任务</div>
<div class="step-desc">通过 tasks/send API 发送任务支持 SSE 接收进度更新</div>
</div>
</div>
<div class="step">
<div class="step-num">4</div>
<div class="step-content">
<div class="step-title">获取结果</div>
<div class="step-desc">任务完成后通过 tasks/get API 获取最终结果</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
</script>
<style scoped>
.a2a-visual-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
background: var(--vp-c-bg-soft);
padding: 1.25rem;
margin: 1rem 0;
}
.section-title {
font-weight: 600;
font-size: 1rem;
color: var(--vp-c-text-1);
margin-bottom: 0.75rem;
margin-top: 1.25rem;
}
.section-title:first-child {
margin-top: 0;
}
.intro-text {
font-size: 0.9rem;
color: var(--vp-c-text-2);
line-height: 1.6;
margin-bottom: 1rem;
}
.intro-text strong {
color: var(--vp-c-brand);
}
.concepts-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.6rem;
margin-bottom: 1rem;
}
.concept {
padding: 0.75rem;
background: var(--vp-c-bg);
border-radius: 6px;
}
.concept-title {
font-weight: 600;
font-size: 0.85rem;
color: var(--vp-c-text-1);
margin-bottom: 0.3rem;
}
.concept-desc {
font-size: 0.75rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.use-cases {
display: flex;
flex-direction: column;
gap: 0.6rem;
margin-bottom: 1rem;
}
.use-case {
padding: 0.75rem;
background: var(--vp-c-bg);
border-radius: 6px;
border-left: 3px solid var(--vp-c-brand);
}
.use-case-title {
font-weight: 600;
font-size: 0.85rem;
color: var(--vp-c-text-1);
margin-bottom: 0.3rem;
}
.use-case-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.usage-steps {
display: flex;
flex-direction: column;
gap: 0.6rem;
}
.step {
display: flex;
align-items: flex-start;
gap: 0.75rem;
padding: 0.75rem;
background: var(--vp-c-bg);
border-radius: 6px;
}
.step-num {
display: flex;
align-items: center;
justify-content: center;
width: 1.5rem;
height: 1.5rem;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-size: 0.75rem;
font-weight: 600;
flex-shrink: 0;
}
.step-content {
flex: 1;
}
.step-title {
font-weight: 600;
font-size: 0.85rem;
color: var(--vp-c-text-1);
margin-bottom: 0.2rem;
}
.step-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
@media (max-width: 640px) {
.concepts-grid {
grid-template-columns: 1fr;
}
}
</style>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,284 @@
<template>
<div class="mcp-visual-demo">
<div class="section-title">MCP 是什么</div>
<div class="intro-text">
MCPModel Context Protocol Anthropic 2024 11 月推出的<strong>AI 与外部工具连接的统一标准</strong>它让 AI 应用可以调用外部工具读取资源数据使用预定义提示就像给 AI 装上了"手""眼睛"
</div>
<div class="section-title">三大核心能力</div>
<div class="能力-table">
<div class="table-header">
<div class="col-能力">能力</div>
<div class="col-英文">英文</div>
<div class="col-作用">作用</div>
<div class="col-示例">示例</div>
</div>
<div class="table-row">
<div class="col-能力"><strong>工具</strong></div>
<div class="col-英文">Tools</div>
<div class="col-作用">AI 可以调用的功能</div>
<div class="col-示例">查询天气发送邮件调用 API</div>
</div>
<div class="table-row">
<div class="col-能力"><strong>资源</strong></div>
<div class="col-英文">Resources</div>
<div class="col-作用">AI 可以读取的数据</div>
<div class="col-示例">文件内容数据库记录配置信息</div>
</div>
<div class="table-row">
<div class="col-能力"><strong>提示</strong></div>
<div class="col-英文">Prompts</div>
<div class="col-作用">预定义的提示模板</div>
<div class="col-示例">代码审查模板写作模板</div>
</div>
</div>
<div class="section-title">什么时候用 MCP</div>
<div class="use-cases">
<div class="use-case">
<div class="use-case-title"> AI 需要执行实际操作时</div>
<div class="use-case-desc">AI 不仅要回答问题还要真正做事发送邮件操作文件调用第三方 API</div>
</div>
<div class="use-case">
<div class="use-case-title"> AI 需要访问私有数据时</div>
<div class="use-case-desc">读取本地文件查询数据库访问企业内部系统</div>
</div>
<div class="use-case">
<div class="use-case-title">当需要标准化工具接入时</div>
<div class="use-case-desc">一次开发多个 AI 应用可用ClaudeCursorWindsurf </div>
</div>
</div>
<div class="section-title">如何使用 MCP</div>
<div class="usage-steps">
<div class="step">
<div class="step-num">1</div>
<div class="step-content">
<div class="step-title">开发 MCP Server</div>
<div class="step-desc"> MCP 规范实现 Server提供 tools/resources/prompts</div>
</div>
</div>
<div class="step">
<div class="step-num">2</div>
<div class="step-content">
<div class="step-title">配置 AI 应用连接</div>
<div class="step-desc"> AI 应用中添加 MCP Server 配置本地或远程</div>
</div>
</div>
<div class="step">
<div class="step-num">3</div>
<div class="step-content">
<div class="step-title">AI 自动调用</div>
<div class="step-desc">AI 根据任务需求自动发现并调用合适的工具或读取资源</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
</script>
<style scoped>
.mcp-visual-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
background: var(--vp-c-bg-soft);
padding: 1.25rem;
margin: 1rem 0;
}
.section-title {
font-weight: 600;
font-size: 1rem;
color: var(--vp-c-text-1);
margin-bottom: 0.75rem;
margin-top: 1.25rem;
}
.section-title:first-child {
margin-top: 0;
}
.intro-text {
font-size: 0.9rem;
color: var(--vp-c-text-2);
line-height: 1.6;
margin-bottom: 1rem;
}
.intro-text strong {
color: var(--vp-c-brand);
}
.能力-table {
border: 1px solid var(--vp-c-divider);
border-radius: 6px;
overflow: hidden;
margin-bottom: 1rem;
}
.table-header {
display: flex;
background: var(--vp-c-bg-alt);
border-bottom: 1px solid var(--vp-c-divider);
font-weight: 600;
font-size: 0.8rem;
}
.table-row {
display: flex;
border-bottom: 1px solid var(--vp-c-divider);
font-size: 0.8rem;
}
.table-row:last-child {
border-bottom: none;
}
.col-能力 {
width: 15%;
padding: 0.5rem 0.6rem;
color: var(--vp-c-text-1);
}
.col-英文 {
width: 18%;
padding: 0.5rem 0.6rem;
color: var(--vp-c-text-2);
}
.col-作用 {
width: 32%;
padding: 0.5rem 0.6rem;
color: var(--vp-c-text-2);
}
.col-示例 {
width: 35%;
padding: 0.5rem 0.6rem;
color: var(--vp-c-text-3);
}
.use-cases {
display: flex;
flex-direction: column;
gap: 0.6rem;
margin-bottom: 1rem;
}
.use-case {
padding: 0.75rem;
background: var(--vp-c-bg);
border-radius: 6px;
border-left: 3px solid var(--vp-c-brand);
}
.use-case-title {
font-weight: 600;
font-size: 0.85rem;
color: var(--vp-c-text-1);
margin-bottom: 0.3rem;
}
.use-case-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.usage-steps {
display: flex;
flex-direction: column;
gap: 0.6rem;
}
.step {
display: flex;
align-items: flex-start;
gap: 0.75rem;
padding: 0.75rem;
background: var(--vp-c-bg);
border-radius: 6px;
}
.step-num {
display: flex;
align-items: center;
justify-content: center;
width: 1.5rem;
height: 1.5rem;
background: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-size: 0.75rem;
font-weight: 600;
flex-shrink: 0;
}
.step-content {
flex: 1;
}
.step-title {
font-weight: 600;
font-size: 0.85rem;
color: var(--vp-c-text-1);
margin-bottom: 0.2rem;
}
.step-desc {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
@media (max-width: 640px) {
.table-header,
.table-row {
flex-direction: column;
}
.col-能力,
.col-英文,
.col-作用,
.col-示例 {
width: 100%;
padding: 0.35rem 0.6rem;
}
.table-header {
display: none;
}
.table-row {
padding: 0.5rem 0;
}
.col-能力 {
font-size: 0.85rem;
padding-bottom: 0.2rem;
}
.col-英文 {
font-size: 0.75rem;
padding-top: 0;
padding-bottom: 0.2rem;
}
.col-作用 {
font-size: 0.8rem;
padding-top: 0;
padding-bottom: 0.2rem;
}
.col-示例 {
font-size: 0.75rem;
padding-top: 0;
}
}
</style>
@@ -0,0 +1,268 @@
<template>
<div class="protocol-comparison-demo">
<div class="demo-header">
<span class="title">MCP vs A2A</span>
<span class="subtitle">AI Agent 两大协议的定位差异</span>
</div>
<div class="intro-text">
想象你在一个<span class="highlight">大型商场</span>MCP 就像商场的"统一插座标准"让各种电器工具都能插上使用A2A 就像商场的"内部对讲系统"让不同店铺Agent之间可以协作
</div>
<div class="protocol-cards">
<div class="protocol-card mcp">
<div class="card-header">
<span class="card-title">MCP</span>
<span class="card-badge">工具连接</span>
</div>
<div class="card-fullname">Model Context Protocol</div>
<div class="card-desc">
AI 与外部工具数据源的连接协议让工具开发者写一次代码所有 AI 应用都能用
</div>
<div class="card-meta">
<div class="meta-item">
<span class="meta-label">发起方</span>
<span class="meta-value">Anthropic</span>
</div>
<div class="meta-item">
<span class="meta-label">发布时间</span>
<span class="meta-value">2024.11</span>
</div>
<div class="meta-item">
<span class="meta-label">架构</span>
<span class="meta-value">Client-Server</span>
</div>
<div class="meta-item">
<span class="meta-label">数据格式</span>
<span class="meta-value">JSON-RPC 2.0</span>
</div>
</div>
<div class="card-analogy">
<span class="analogy-label">类比</span>
<span class="analogy-text">USB-C 接口 统一各种设备的充电方式</span>
</div>
</div>
<div class="protocol-card a2a">
<div class="card-header">
<span class="card-title">A2A</span>
<span class="card-badge">Agent协作</span>
</div>
<div class="card-fullname">Agent-to-Agent Protocol</div>
<div class="card-desc">
Agent 之间的通信协议让不同厂商不同框架的 Agent 能够无缝协作
</div>
<div class="card-meta">
<div class="meta-item">
<span class="meta-label">发起方</span>
<span class="meta-value">Google</span>
</div>
<div class="meta-item">
<span class="meta-label">发布时间</span>
<span class="meta-value">2025.04</span>
</div>
<div class="meta-item">
<span class="meta-label">架构</span>
<span class="meta-value">Peer-to-Peer</span>
</div>
<div class="meta-item">
<span class="meta-label">数据格式</span>
<span class="meta-value">HTTP + JSON</span>
</div>
</div>
<div class="card-analogy">
<span class="analogy-label">类比</span>
<span class="analogy-text">企业微信 让同事之间可以发任务聊天</span>
</div>
</div>
</div>
<div class="info-box">
<strong>核心思想</strong>MCP A2A 不是竞争关系而是互补关系MCP 解决"AI 如何获取外部能力"A2A 解决"多个 AI 如何协作"
</div>
</div>
</template>
<script setup>
</script>
<style scoped>
.protocol-comparison-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon {
font-size: 1.25rem;
}
.demo-header .title {
font-weight: bold;
font-size: 1rem;
}
.demo-header .subtitle {
color: var(--vp-c-text-2);
font-size: 0.85rem;
margin-left: 0.5rem;
}
.intro-text {
color: var(--vp-c-text-2);
font-size: 0.9rem;
margin-bottom: 1rem;
line-height: 1.5;
}
.intro-text .highlight {
color: var(--vp-c-brand);
font-weight: 500;
}
.protocol-cards {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.75rem;
margin-bottom: 1rem;
}
.protocol-card {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 0.75rem;
background: var(--vp-c-bg);
}
.protocol-card.mcp {
border-left: 3px solid #3b82f6;
}
.protocol-card.a2a {
border-left: 3px solid #10b981;
}
.card-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.4rem;
}
.card-icon {
font-size: 1.25rem;
}
.card-title {
font-weight: bold;
font-size: 1.1rem;
}
.card-badge {
font-size: 0.7rem;
padding: 0.15rem 0.4rem;
border-radius: 4px;
margin-left: auto;
}
.protocol-card.mcp .card-badge {
background: rgba(59, 130, 246, 0.2);
color: #3b82f6;
}
.protocol-card.a2a .card-badge {
background: rgba(16, 185, 129, 0.2);
color: #10b981;
}
.card-fullname {
font-size: 0.75rem;
color: var(--vp-c-text-3);
margin-bottom: 0.4rem;
}
.card-desc {
font-size: 0.85rem;
color: var(--vp-c-text-2);
line-height: 1.4;
margin-bottom: 0.6rem;
}
.card-meta {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.4rem;
margin-bottom: 0.6rem;
padding: 0.5rem;
background: var(--vp-c-bg-soft);
border-radius: 6px;
}
.meta-item {
display: flex;
flex-direction: column;
gap: 0.1rem;
}
.meta-label {
font-size: 0.65rem;
color: var(--vp-c-text-3);
}
.meta-value {
font-size: 0.75rem;
color: var(--vp-c-text-1);
font-weight: 500;
}
.card-analogy {
display: flex;
align-items: center;
gap: 0.4rem;
padding: 0.4rem;
background: var(--vp-c-bg-alt);
border-radius: 6px;
}
.analogy-label {
font-size: 0.65rem;
color: var(--vp-c-text-3);
flex-shrink: 0;
}
.analogy-text {
font-size: 0.75rem;
color: var(--vp-c-text-2);
line-height: 1.3;
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
display: flex;
gap: 0.25rem;
align-items: flex-start;
}
.info-box .icon {
flex-shrink: 0;
}
@media (max-width: 640px) {
.protocol-cards {
grid-template-columns: 1fr;
}
}
</style>
@@ -0,0 +1,336 @@
<template>
<div class="protocol-workflow-demo">
<div class="demo-header">
<span class="title">MCP + A2A 协作流程</span>
<span class="subtitle">两者如何配合完成复杂任务</span>
</div>
<div class="intro-text">
想象你要<span class="highlight">装修房子</span>你需要设计师 Agent出方案工人专家 Agent施工还要从建材市场工具买材料A2A 让设计师和工人能协作MCP 让工人能买到材料
</div>
<div class="workflow-diagram">
<div class="user-node">
<span class="node-label">用户</span>
</div>
<div class="arrow"></div>
<div class="agent-node main">
<span class="node-label"> Agent</span>
<span class="node-role">需求分析</span>
</div>
<div class="arrow"></div>
<div class="a2a-badge">
<span class="badge-text">A2A</span>
</div>
<div class="agent-node expert">
<span class="node-label">专家 Agent</span>
<span class="node-role">执行任务</span>
</div>
<div class="arrow"></div>
<div class="mcp-badge">
<span class="badge-text">MCP</span>
</div>
<div class="tool-node">
<span class="node-label">外部工具</span>
<span class="node-role">API/数据库</span>
</div>
</div>
<div class="flow-steps">
<div class="flow-step">
<span class="step-num">1</span>
<span class="step-text">用户向主 Agent 提出需求"分析这个 GitHub 仓库"</span>
</div>
<div class="flow-step">
<span class="step-num">2</span>
<span class="step-text"> Agent 通过 <strong>A2A</strong> 委托专家 Agent 执行任务</span>
</div>
<div class="flow-step">
<span class="step-num">3</span>
<span class="step-text">专家 Agent 通过 <strong>MCP</strong> 调用外部工具获取数据</span>
</div>
<div class="flow-step">
<span class="step-num">4</span>
<span class="step-text">专家 Agent 通过 <strong>A2A</strong> 返回结果给主 Agent</span>
</div>
<div class="flow-step">
<span class="step-num">5</span>
<span class="step-text"> Agent 汇总结果回复用户</span>
</div>
</div>
<div class="legend">
<div class="legend-item">
<span class="legend-dot a2a"></span>
<span class="legend-text"><strong>A2A</strong>Agent Agent 通信</span>
</div>
<div class="legend-item">
<span class="legend-dot mcp"></span>
<span class="legend-text"><strong>MCP</strong>Agent 工具 通信</span>
</div>
</div>
<div class="info-box">
<strong>核心思想</strong>A2A 负责 Agent 之间的任务分配和协作MCP 负责 Agent 与外部工具的交互两者各司其职互补协作
</div>
</div>
</template>
<script setup>
</script>
<style scoped>
.protocol-workflow-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
background: var(--vp-c-bg-soft);
padding: 1rem;
margin: 1rem 0;
}
.demo-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.demo-header .icon {
font-size: 1.25rem;
}
.demo-header .title {
font-weight: bold;
font-size: 1rem;
}
.demo-header .subtitle {
color: var(--vp-c-text-2);
font-size: 0.85rem;
margin-left: 0.5rem;
}
.intro-text {
color: var(--vp-c-text-2);
font-size: 0.9rem;
margin-bottom: 1rem;
line-height: 1.5;
}
.intro-text .highlight {
color: var(--vp-c-brand);
font-weight: 500;
}
.workflow-diagram {
display: flex;
align-items: center;
justify-content: center;
gap: 0.4rem;
padding: 1rem;
background: var(--vp-c-bg);
border-radius: 8px;
margin-bottom: 1rem;
flex-wrap: wrap;
overflow-x: auto;
}
.user-node,
.agent-node,
.tool-node {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.2rem;
padding: 0.5rem 0.75rem;
border-radius: 8px;
background: var(--vp-c-bg-soft);
}
.user-node {
border: 1px dashed var(--vp-c-divider);
}
.agent-node.main {
border: 2px solid var(--vp-c-brand);
background: rgba(100, 108, 255, 0.1);
}
.agent-node.expert {
border: 2px solid #10b981;
background: rgba(16, 185, 129, 0.1);
}
.tool-node {
border: 1px solid var(--vp-c-divider);
}
.node-icon {
font-size: 1.25rem;
}
.node-label {
font-size: 0.75rem;
font-weight: 600;
color: var(--vp-c-text-1);
}
.node-role {
font-size: 0.65rem;
color: var(--vp-c-text-3);
}
.arrow {
color: var(--vp-c-text-3);
font-size: 1rem;
font-weight: bold;
}
.a2a-badge,
.mcp-badge {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.1rem;
padding: 0.3rem 0.5rem;
border-radius: 6px;
}
.a2a-badge {
background: rgba(16, 185, 129, 0.15);
}
.a2a-badge .badge-icon {
font-size: 0.9rem;
}
.a2a-badge .badge-text {
font-size: 0.6rem;
font-weight: 700;
color: #10b981;
}
.mcp-badge {
background: rgba(59, 130, 246, 0.15);
}
.mcp-badge .badge-icon {
font-size: 0.9rem;
}
.mcp-badge .badge-text {
font-size: 0.6rem;
font-weight: 700;
color: #3b82f6;
}
.flow-steps {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 1rem;
}
.flow-step {
display: flex;
align-items: flex-start;
gap: 0.5rem;
padding: 0.4rem 0.6rem;
background: var(--vp-c-bg);
border-radius: 6px;
}
.step-num {
width: 18px;
height: 18px;
border-radius: 50%;
background: var(--vp-c-brand);
color: white;
font-size: 0.7rem;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
font-weight: 600;
}
.step-text {
font-size: 0.8rem;
color: var(--vp-c-text-2);
line-height: 1.4;
}
.step-text strong {
color: var(--vp-c-brand);
}
.legend {
display: flex;
gap: 1rem;
margin-bottom: 0.75rem;
padding: 0.5rem;
background: var(--vp-c-bg);
border-radius: 6px;
justify-content: center;
}
.legend-item {
display: flex;
align-items: center;
gap: 0.3rem;
font-size: 0.75rem;
}
.legend-dot {
width: 10px;
height: 10px;
border-radius: 50%;
}
.legend-dot.a2a {
background: #10b981;
}
.legend-dot.mcp {
background: #3b82f6;
}
.legend-text {
color: var(--vp-c-text-2);
}
.legend-text strong {
color: var(--vp-c-text-1);
}
.info-box {
background: var(--vp-c-bg-alt);
padding: 0.75rem;
border-radius: 6px;
font-size: 0.85rem;
color: var(--vp-c-text-2);
display: flex;
gap: 0.25rem;
align-items: flex-start;
}
.info-box .icon {
flex-shrink: 0;
}
@media (max-width: 768px) {
.workflow-diagram {
justify-content: flex-start;
overflow-x: auto;
padding: 0.75rem;
}
.flow-steps {
gap: 0.4rem;
}
.flow-step {
padding: 0.3rem 0.5rem;
}
}
</style>