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:
@@ -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">Google、Anthropic、OpenAI 的 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 Card,Agent 之间可以相互发现,了解对方的能力和版本,实现互操作</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>SSE(Server-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 通过 SSE(Server-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">
|
||||
A2A(Agent-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 Card(Agent 名片)</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">SSE(Server-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 的 Agent、Anthropic 的 Agent、OpenAI 的 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">
|
||||
MCP(Model 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 应用可用(Claude、Cursor、Windsurf 等)</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>
|
||||
Reference in New Issue
Block a user