A2A Protocol

A2A JS SDK 完整教程:快速入门指南

MILO
Share
A2A JS SDK 完整教程:快速入门指南

目录

  1. 什么是 A2A JS SDK?
  2. A2A JS 安装与设置
  3. A2A JS 核心概念
  4. 创建你的第一个 A2A JS 代理
  5. A2A JS 服务端开发
  6. A2A JS 客户端使用
  7. A2A JS 高级特性
  8. A2A JS 最佳实践
  9. A2A JS 故障排除

什么是 A2A JS SDK?

A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库,用于构建符合 Agent2Agent (A2A) 协议 的智能代理应用程序。这个 A2A JS 框架让开发者能够轻松创建能够相互通信和协作的智能代理系统。

A2A JS 的核心优势

  • 🚀 简单易用: A2A JS 提供直观的 API,让开发者能快速上手
  • 🔄 实时通信: 支持流式处理和服务端推送事件 (SSE)
  • 🛡️ 类型安全: 基于 TypeScript 构建,提供完整的类型支持
  • 🌐 跨平台: A2A JS 可在 Node.js 和浏览器环境中运行
  • 📡 标准协议: 完全实现 A2A 协议规范

A2A JS 安装与设置

安装 A2A JS SDK

使用 npm 安装 A2A JS SDK

npm install @a2a-js/sdk

或者使用 yarn:

yarn add @a2a-js/sdk

验证 A2A JS 安装

创建一个简单的测试文件来验证 A2A JS 是否正确安装:

import { A2AClient, AgentCard } from "@a2a-js/sdk";

console.log("A2A JS SDK 安装成功!");

A2A JS 核心概念

在开始使用 A2A JS 之前,了解以下核心概念很重要:

1. Agent Card (代理卡片)

A2A JS 中的每个代理都需要一个 Agent Card,它描述了代理的能力和接口:

import { AgentCard } from "@a2a-js/sdk";

const agentCard: AgentCard = {
  name: 'My A2A JS Agent',
  description: '使用 A2A JS SDK 构建的智能代理',
  url: 'http://localhost:3000/',
  provider: {
    organization: 'A2A JS Developers',
    url: 'https://example.com'
  },
  version: '1.0.0',
  capabilities: {
    streaming: true,
    pushNotifications: false,
    stateTransitionHistory: true,
  },
  skills: [{
    id: 'general_chat',
    name: '通用对话',
    description: '使用 A2A JS 进行通用对话',
    tags: ['chat', 'a2a-js'],
    examples: ['你好', '帮我解答问题']
  }]
};

2. Agent Executor (代理执行器)

A2A JS 的核心执行逻辑通过 AgentExecutor 实现:

import { AgentExecutor, RequestContext, IExecutionEventBus } from "@a2a-js/sdk";

class MyA2AJSExecutor implements AgentExecutor {
  async execute(
    requestContext: RequestContext,
    eventBus: IExecutionEventBus
  ): Promise<void> {
    // 你的 A2A JS 代理逻辑
    console.log("A2A JS 代理正在处理请求...");
  }

  async cancelTask(taskId: string, eventBus: IExecutionEventBus): Promise<void> {
    console.log(`A2A JS 取消任务: ${taskId}`);
  }
}

创建你的第一个 A2A JS 代理

让我们使用 A2A JS SDK 创建一个完整的代理示例:

步骤 1: 定义 A2A JS 代理卡片

import { AgentCard } from "@a2a-js/sdk";

const myAgentCard: AgentCard = {
  name: 'Hello World A2A JS Agent',
  description: '我的第一个 A2A JS 代理,用于学习 A2A JS SDK',
  url: 'http://localhost:3000/',
  provider: {
    organization: 'A2A JS Tutorial',
    url: 'https://example.com'
  },
  version: '1.0.0',
  capabilities: {
    streaming: true,
    pushNotifications: false,
    stateTransitionHistory: true,
  },
  defaultInputModes: ['text/plain'],
  defaultOutputModes: ['text/plain'],
  skills: [{
    id: 'hello_world',
    name: 'Hello World',
    description: 'A2A JS 示例技能:回复问候',
    tags: ['hello', 'greeting', 'a2a-js'],
    examples: [
      '你好',
      'Hello',
      '介绍一下 A2A JS'
    ],
    inputModes: ['text/plain'],
    outputModes: ['text/plain']
  }],
  supportsAuthenticatedExtendedCard: false,
};

步骤 2: 实现 A2A JS 执行器

import {
  AgentExecutor,
  RequestContext,
  IExecutionEventBus,
  Task,
  TaskState,
  TaskStatusUpdateEvent
} from "@a2a-js/sdk";
import { v4 as uuidv4 } from "uuid";

class HelloWorldA2AJSExecutor implements AgentExecutor {
  private cancelledTasks = new Set<string>();

  async cancelTask(taskId: string, eventBus: IExecutionEventBus): Promise<void> {
    this.cancelledTasks.add(taskId);
    console.log(`A2A JS 执行器取消任务: ${taskId}`);
  }

  async execute(
    requestContext: RequestContext,
    eventBus: IExecutionEventBus
  ): Promise<void> {
    const userMessage = requestContext.userMessage;
    const existingTask = requestContext.task;
    
    const taskId = existingTask?.id || uuidv4();
    const contextId = userMessage.contextId || existingTask?.contextId || uuidv4();

    console.log(`A2A JS 代理处理消息: ${userMessage.parts[0]?.text}`);

    // 创建新任务
    if (!existingTask) {
      const initialTask: Task = {
        kind: 'task',
        id: taskId,
        contextId: contextId,
        status: {
          state: TaskState.Submitted,
          timestamp: new Date().toISOString(),
        },
        history: [userMessage],
        metadata: userMessage.metadata,
        artifacts: [],
      };
      eventBus.publish(initialTask);
    }

    // 发布工作状态
    const workingUpdate: TaskStatusUpdateEvent = {
      kind: 'status-update',
      taskId: taskId,
      contextId: contextId,
      status: {
        state: TaskState.Working,
        message: {
          kind: 'message',
          role: 'agent',
          messageId: uuidv4(),
          parts: [{ kind: 'text', text: 'A2A JS 代理正在思考...' }],
          taskId: taskId,
          contextId: contextId,
        },
        timestamp: new Date().toISOString(),
      },
      final: false,
    };
    eventBus.publish(workingUpdate);

    // 模拟处理时间
    await new Promise(resolve => setTimeout(resolve, 1000));

    // 检查取消状态
    if (this.cancelledTasks.has(taskId)) {
      const cancelledUpdate: TaskStatusUpdateEvent = {
        kind: 'status-update',
        taskId: taskId,
        contextId: contextId,
        status: {
          state: TaskState.Canceled,
          timestamp: new Date().toISOString(),
        },
        final: true,
      };
      eventBus.publish(cancelledUpdate);
      return;
    }

    // 生成响应
    const userText = userMessage.parts[0]?.text || '';
    let responseText = '';
    
    if (userText.toLowerCase().includes('hello') || userText.includes('你好')) {
      responseText = `你好!欢迎使用 A2A JS SDK!我是用 A2A JS 构建的智能代理。`;
    } else if (userText.toLowerCase().includes('a2a js')) {
      responseText = `A2A JS SDK 是一个强大的 JavaScript 库,用于构建智能代理应用程序!`;
    } else {
      responseText = `我是一个 A2A JS 代理,收到了你的消息:"${userText}"。感谢使用 A2A JS SDK!`;
    }

    // 发布最终结果
    const finalUpdate: TaskStatusUpdateEvent = {
      kind: 'status-update',
      taskId: taskId,
      contextId: contextId,
      status: {
        state: TaskState.Completed,
        message: {
          kind: 'message',
          role: 'agent',
          messageId: uuidv4(),
          parts: [{ kind: 'text', text: responseText }],
          taskId: taskId,
          contextId: contextId,
        },
        timestamp: new Date().toISOString(),
      },
      final: true,
    };
    eventBus.publish(finalUpdate);
  }
}

步骤 3: 启动 A2A JS 服务器

import express from 'express';
import {
  A2AExpressApp,
  DefaultRequestHandler,
  InMemoryTaskStore
} from "@a2a-js/sdk";

const taskStore = new InMemoryTaskStore();
const agentExecutor = new HelloWorldA2AJSExecutor();

const requestHandler = new DefaultRequestHandler(
  myAgentCard,
  taskStore,
  agentExecutor
);

const appBuilder = new A2AExpressApp(requestHandler);
const expressApp = appBuilder.setupRoutes(express(), '');

const PORT = process.env.PORT || 3000;
expressApp.listen(PORT, () => {
  console.log(`A2A JS 代理服务器启动在 http://localhost:${PORT}`);
  console.log(`A2A JS 代理卡片: http://localhost:${PORT}/.well-known/agent.json`);
  console.log('按 Ctrl+C 停止 A2A JS 服务器');
});

A2A JS 服务端开发

任务存储

A2A JS 提供了内存任务存储,你也可以实现自定义存储:

import { TaskStore, Task } from "@a2a-js/sdk";

class CustomA2AJSTaskStore implements TaskStore {
  private tasks = new Map<string, Task>();

  async getTask(taskId: string): Promise<Task | undefined> {
    console.log(`A2A JS 获取任务: ${taskId}`);
    return this.tasks.get(taskId);
  }

  async setTask(task: Task): Promise<void> {
    console.log(`A2A JS 保存任务: ${task.id}`);
    this.tasks.set(task.id, task);
  }

  async deleteTask(taskId: string): Promise<void> {
    console.log(`A2A JS 删除任务: ${taskId}`);
    this.tasks.delete(taskId);
  }
}

中间件支持

A2A JS 基于 Express.js,支持所有标准中间件:

import cors from 'cors';
import express from 'express';

const app = express();

// A2A JS 服务器中间件配置
app.use(cors());
app.use(express.json());

// 自定义 A2A JS 日志中间件
app.use((req, res, next) => {
  console.log(`A2A JS 请求: ${req.method} ${req.path}`);
  next();
});

A2A JS 客户端使用

基础客户端操作

import { A2AClient, MessageSendParams } from "@a2a-js/sdk";
import { v4 as uuidv4 } from "uuid";

const client = new A2AClient("http://localhost:3000");

async function testA2AJSClient() {
  console.log("测试 A2A JS 客户端...");
  
  const messageParams: MessageSendParams = {
    message: {
      messageId: uuidv4(),
      role: "user",
      parts: [{ kind: "text", text: "你好,A2A JS!" }],
      kind: "message"
    },
    configuration: {
      blocking: true,
      acceptedOutputModes: ['text/plain']
    }
  };

  try {
    const response = await client.sendMessage(messageParams);
    
    if (response.error) {
      console.error("A2A JS 客户端错误:", response.error);
      return;
    }

    console.log("A2A JS 响应:", response.result);
  } catch (error) {
    console.error("A2A JS 通信错误:", error);
  }
}

testA2AJSClient();

A2A JS 流式处理

A2A JS 支持实时流式通信:

import { A2AClient, TaskStatusUpdateEvent } from "@a2a-js/sdk";

async function streamA2AJSResponse() {
  const client = new A2AClient("http://localhost:3000");
  
  console.log("开始 A2A JS 流式处理...");
  
  const streamParams = {
    message: {
      messageId: uuidv4(),
      role: "user",
      parts: [{ kind: "text", text: "使用 A2A JS 进行流式对话" }],
      kind: "message"
    }
  };

  try {
    const stream = client.sendMessageStream(streamParams);
    
    for await (const event of stream) {
      if (event.kind === 'task') {
        console.log(`A2A JS 任务创建: ${event.id}`);
      } else if (event.kind === 'status-update') {
        const statusEvent = event as TaskStatusUpdateEvent;
        console.log(`A2A JS 状态更新: ${statusEvent.status.state}`);
        
        if (statusEvent.status.message?.parts[0]?.text) {
          console.log(`A2A JS 消息: ${statusEvent.status.message.parts[0].text}`);
        }
        
        if (statusEvent.final) {
          console.log("A2A JS 流式处理完成");
          break;
        }
      }
    }
  } catch (error) {
    console.error("A2A JS 流式处理错误:", error);
  }
}

A2A JS 高级特性

工件处理

A2A JS 支持工件(Artifacts)的创建和管理:

import { TaskArtifactUpdateEvent } from "@a2a-js/sdk";

// 在 AgentExecutor 中发布工件
const artifactUpdate: TaskArtifactUpdateEvent = {
  kind: 'artifact-update',
  taskId: taskId,
  contextId: contextId,
  artifact: {
    artifactId: "a2a-js-example",
    name: "A2A JS 示例文件",
    parts: [{ 
      text: `# A2A JS 生成的内容\n\n这是使用 A2A JS SDK 生成的示例文件。`
    }],
  },
  append: false,
  lastChunk: true,
};
eventBus.publish(artifactUpdate);

安全配置

A2A JS 代理配置安全选项:

const secureAgentCard: AgentCard = {
  name: 'Secure A2A JS Agent',
  description: '安全的 A2A JS 代理',
  // ... 其他配置
  securitySchemes: {
    apiKey: {
      type: 'apiKey',
      name: 'X-API-Key',
      in: 'header'
    }
  },
  security: [{
    apiKey: []
  }]
};

A2A JS 最佳实践

1. 错误处理

A2A JS 应用中实施全面的错误处理:

class RobustA2AJSExecutor implements AgentExecutor {
  async execute(requestContext: RequestContext, eventBus: IExecutionEventBus) {
    try {
      // A2A JS 执行逻辑
      await this.processRequest(requestContext, eventBus);
    } catch (error) {
      console.error("A2A JS 执行错误:", error);
      
      // 发布错误状态
      const errorUpdate: TaskStatusUpdateEvent = {
        kind: 'status-update',
        taskId: requestContext.task?.id || uuidv4(),
        contextId: requestContext.userMessage.contextId || uuidv4(),
        status: {
          state: TaskState.Failed,
          message: {
            kind: 'message',
            role: 'agent',
            messageId: uuidv4(),
            parts: [{ kind: 'text', text: 'A2A JS 处理时发生错误,请稍后重试。' }],
          },
          timestamp: new Date().toISOString(),
        },
        final: true,
      };
      eventBus.publish(errorUpdate);
    }
  }
}

2. 性能优化

优化你的 A2A JS 应用性能:

// 使用连接池优化 A2A JS 客户端
const client = new A2AClient("http://localhost:3000", {
  keepAlive: true,
  timeout: 30000
});

// A2A JS 代理响应缓存
class CachedA2AJSExecutor implements AgentExecutor {
  private cache = new Map<string, string>();
  
  async execute(requestContext: RequestContext, eventBus: IExecutionEventBus) {
    const userText = requestContext.userMessage.parts[0]?.text || '';
    const cacheKey = `a2a-js-${userText}`;
    
    // 检查 A2A JS 缓存
    if (this.cache.has(cacheKey)) {
      console.log("A2A JS 使用缓存响应");
      // 返回缓存的响应
    }
    
    // 处理新请求并缓存结果
  }
}

3. 日志记录

A2A JS 应用添加详细的日志记录:

import { createLogger, format, transports } from 'winston';

const a2aJSLogger = createLogger({
  level: 'info',
  format: format.combine(
    format.timestamp(),
    format.printf(({ timestamp, level, message }) => {
      return `[A2A JS] ${timestamp} ${level}: ${message}`;
    })
  ),
  transports: [
    new transports.Console(),
    new transports.File({ filename: 'a2a-js.log' })
  ]
});

// 在 A2A JS 代码中使用
a2aJSLogger.info('A2A JS 代理启动成功');
a2aJSLogger.error('A2A JS 处理错误', { error: errorDetails });

A2A JS 故障排除

常见问题解决

1. A2A JS 连接问题

// 检查 A2A JS 服务器连接
async function checkA2AJSConnection() {
  try {
    const client = new A2AClient("http://localhost:3000");
    const response = await fetch("http://localhost:3000/.well-known/agent.json");
    
    if (response.ok) {
      console.log("A2A JS 服务器连接正常");
    } else {
      console.error("A2A JS 服务器响应异常:", response.status);
    }
  } catch (error) {
    console.error("A2A JS 连接失败:", error);
  }
}

也可以尝试如下方法:

2. A2A JS 类型错误

确保正确导入 A2A JS 类型:

// 正确的 A2A JS 类型导入
import {
  AgentCard,
  AgentExecutor,
  A2AClient,
  Task,
  TaskState,
  Message,
  MessageSendParams
} from "@a2a-js/sdk";

3. A2A JS 性能调试

// A2A JS 性能监控
class PerformanceA2AJSExecutor implements AgentExecutor {
  async execute(requestContext: RequestContext, eventBus: IExecutionEventBus) {
    const startTime = Date.now();
    console.log(`A2A JS 开始处理: ${startTime}`);
    
    try {
      // 你的 A2A JS 逻辑
      await this.processRequest(requestContext, eventBus);
    } finally {
      const endTime = Date.now();
      console.log(`A2A JS 处理完成,耗时: ${endTime - startTime}ms`);
    }
  }
}

总结

A2A JS SDK 是构建智能代理应用程序的强大工具。通过本教程,你已经学习了:

  • A2A JS 的核心概念和架构
  • 如何创建和配置 A2A JS 代理
  • A2A JS 服务端和客户端开发
  • A2A JS 的高级特性和最佳实践
  • A2A JS 应用的故障排除方法

现在你可以开始构建自己的 A2A JS 应用程序了!记住,A2A JS SDK 提供了丰富的功能来帮助你创建强大、可扩展的智能代理系统。

如需更多 A2A JS 资源和示例,请访问:

开始你的 A2A JS 开发之旅吧!🚀