基于A2A、ADK和MCP打造多代理AI应用:深度解析与实战代码

什么是A2A协议?

**A2A(代理到代理)**协议是由谷歌开发的一个开放协议,用于跨越组织或技术边界的代理之间的通信。

使用A2A,代理可以为最终用户完成任务,而无需共享内存、想法或工具。相反,代理会交换上下文、状态、指令和数据,这些数据以它们的原生模态存在。

  • 简单:重用现有标准
  • 企业级:认证、安全、隐私、追踪、监控
  • 异步优先:(非常)长运行任务和人工介入
  • 模态不可知:文本、音频/视频、表单、iframe等
  • 不透明执行:代理不必共享想法、计划或工具

A2A与MCP——关键区别

  • MCP能让企业API不依赖特定工具,还能很好地和大语言模型配合使用。
  • A2A允许分布式代理(使用ADK、LangChain、CrewAI等构建)无缝地相互交流。

A2A是代理的API,而MCP是工具的API

A2A协议——核心概念

A2A(代理到代理)协议围绕几个基本概念构建,这些概念使得代理之间的互操作性变得无缝。在本文中,我们将使用多代理旅行规划应用程序来更好地理解核心概念。

1. 基于任务的通信

代理之间的每次交互都被视为一个任务——一个具有明确开始和结束的清晰工作单元。这使得通信变得有结构且可追踪。示例:

基于任务的通信(请求)
{
  "jsonrpc": "2.0",
  "method": "tasks/send",
  "params": {
    "taskId": "20250615123456",
    "message": {
      "role": "user",
      "parts": [
        {
          "text": "Find flights from New York to Miami on 2025-06-15"
        }
      ]
    }
  },
  "id": "12345"
}
基于任务的通信(响应)
{
  "jsonrpc": "2.0",
  "id": "12345",
  "result": {
    "taskId": "20250615123456",
    "state": "completed",
    "messages": [
      {
        "role": "user",
        "parts": [
          {
            "text": "Find flights from New York to Miami on 2025-06-15"
          }
        ]
      },
      {
        "role": "agent",
        "parts": [
          {
            "text": "I found the following flights from New York to Miami on June 15, 2025:\n\n1. Delta Airlines DL1234: Departs JFK 08:00, Arrives MIA 11:00, $320\n2. American Airlines AA5678: Departs LGA 10:30, Arrives MIA 13:30, $290\n3. JetBlue B9101: Departs JFK 14:45, Arrives MIA 17:45, $275"
          }
        ]
      }
    ],
    "artifacts": []
  }
}
2. 代理发现

代理可以通过从标准位置(/.well-known/agent.json)读取其他代理的agent.json文件来自动发现其他代理的功能。无需手动设置。以下是一个代理卡示例:

  • 目的:公开可访问的发现端点
  • 位置:根据A2A协议的标准化网络可访问路径
  • 用途:由其他代理/客户端进行外部发现
  • 作用:启用自动代理发现
{
  "name": "Travel Itinerary Planner",
  "displayName": "Travel Itinerary Planner",
  "description": "An agent that coordinates flight and hotel information to create comprehensive travel itineraries",
  "version": "1.0.0",
  "contact": "code.aicloudlab@gmail.com",
  "endpointUrl": "http://localhost:8005",
  "authentication": {
    "type": "none"
  },
  "capabilities": ["streaming"],
  "skills": [
    {
      "name": "createItinerary",
      "description": "Create a comprehensive travel itinerary including flights and accommodations",
      "inputs": [
        {
          "name": "origin",
          "type": "string",
          "description": "Origin city or airport code"
        },
        {
          "name": "destination",
          "type": "string",
          "description": "Destination city or area"
        },
        {
          "name": "departureDate",
          "type": "string",
          "description": "Departure date in YYYY-MM-DD format"
        },
        {
          "name": "returnDate",
          "type": "string",
          "description": "Return date in YYYY-MM-DD format (optional)"
        },
        {
          "name": "travelers",
          "type": "integer",
          "description": "Number of travelers"
        },
        {
          "name": "preferences",
          "type": "object",
          "description": "Additional preferences like budget, hotel amenities, etc."
        }
      ],
      "outputs": [
        {
          "name": "itinerary",
          "type": "object",
          "description": "Complete travel itinerary with flights, hotels, and schedule"
        }
      ]
    }
  ]
}
3. 框架不可知的互操作性

A2A可以在不同的代理框架之间工作——比如ADK、CrewAI、LangChain——因此使用不同工具构建的代理仍然可以协同工作。

4. 多模态消息传递

A2A通过部件系统支持各种内容类型,允许代理在统一的消息格式内交换文本、结构化数据和文件。

5. 标准化消息结构

A2A使用干净的JSON-RPC风格来发送和接收消息,使得实现具有一致性和易于解析。

6. 技能和能力

代理会发布它们能做的事情(“技能”)——以及它们需要的输入和提供的输出——这样其他代理就知道如何与它们合作。示例:

// 技能声明在代理卡中
"skills": [
  {
    "name": "createItinerary",
    "description": "Creates a travel itinerary",
    "inputs": [
      {"name": "origin", "type": "string", "description": "Origin city or airport"},
      {"name": "destination", "type": "string", "description": "Destination city or airport"},
      {"name": "departureDate", "type": "string", "description": "Date of departure (YYYY-MM-DD)"},
      {"name": "returnDate", "type": "string", "description": "Date of return (YYYY-MM-DD)"}
    ]
  }
]

// 在消息中调用技能
{
  "role": "user",
  "parts": [
    {
      "text": "Create an itinerary for my trip from New York to Miami"
    },
    {
      "type": "data",
      "data": {
        "skill": "createItinerary",
        "parameters": {
          "origin": "New York",
          "destination": "Miami",
          "departureDate": "2025-06-15",
          "returnDate": "2025-06-20"
        }
      }
    }
  ]
}
7. 任务生命周期

每个任务都会经历明确定义的阶段:提交 → 正在处理 → 完成(或失败/取消)。我们总是可以追踪任务所处的状态。

8. 实时更新(流式传输)

长时间运行的任务可以使用服务器发送事件(SSE)流式传输更新,以便代理能够实时接收进度。

9. 推送通知

代理可以使用网络钩子主动通知其他代理任务更新,支持安全通信(JWT、OAuth等)。

10. 结构化表单

代理可以使用DataPart请求或提交结构化表单,这使得处理输入(如JSON或配置)变得简单。

架构

我们将使用相同的**旅行规划器**架构,扩展A2A + MCP协议。

下面的演示只是为了说明多个代理之间的A2A协议,仅供理解。

架构图

上图由作者提供

上述架构使用了模块化的多代理AI系统,其中每个代理都是独立可部署的,并使用谷歌的A2A(代理到代理)协议进行通信。

架构中的核心组件
  1. 用户界面层 — 向前端服务器发送HTTP请求
  2. 代理层 — 主代理、代理1和代理2之间的协调
  3. 协议层 — 代理之间的A2A协议通信
  4. 外部数据层 — 使用MCP访问外部API
代理角色:
  1. 行程规划代理 — 作为中央协调器 — 主代理,协调用户与专业代理之间的交互。
  2. 航班搜索代理 — 一个专门的代理,负责根据用户输入获取航班选项
  3. 酒店搜索代理 — 一个专门的代理,负责根据用户偏好获取酒店住宿
MCP在本项目中的实现:
航班搜索MCP服务器
  1. 连接:航班搜索(代理1)连接到MCP航班服务器
  2. 功能:连接到航班预订API和数据库
酒店搜索MCP服务器
  1. 连接:酒店搜索(代理2)连接到MCP酒店服务器
  2. 功能:连接到酒店预订系统和聚合器

代理通信流程

  1. 用户通过Streamlit UI提交旅行查询
  2. 旅行规划器解析查询以提取关键信息
  3. 旅行规划器向航班搜索代理请求航班信息
  4. 航班搜索代理通过调用MCP服务器返回可用航班
  5. 旅行规划器提取目的地详情
  6. 旅行规划器向酒店搜索代理请求酒店信息
  7. 酒店搜索代理返回住宿选项
  8. 旅行规划器将所有数据综合成一份完整的行程

实现

让我们深入了解一下如何使用ADK + MCP + Gemini AI构建这个多代理系统,将其分解为关键的实现步骤。

先决条件
  1. 安装Python 3.11+

  2. 通过API密钥访问谷歌**Gemini**生成式AI

  3. 一个有效的**SerpAPI密钥**

  4. 一个有效的**OpenAI GPT密钥**

项目文件夹结构
├── common
│   ├── __init__.py
│   ├── client
│   │   ├── __init__.py
│   │   ├── card_resolver.py
│   │   └── client.py
│   ├── server
│   │   ├── __init__.py
│   │   ├── server.py
│   │   ├── task_manager.py
│   │   └── utils.py
│   ├── types.py
│   └── utils
│       ├── in_memory_cache.py
│       └── push_notification_auth.py
├── flight_search_app
│   ├── a2a_agent_card.json
│   ├── agent.py
│   ├── main.py
│   ├── static
│   │   └── .well-known
│   │       └── agent.json
│   └── streamlit_ui.py
├── hotel_search_app
│   ├── README.md
│   ├── a2a_agent_card.json
│   ├── langchain_agent.py
│   ├── langchain_server.py
│   ├── langchain_streamlit.py
│   ├── static
│   │   └── .well-known
│   │       └── agent.json
│   └── streamlit_ui.py
└── itinerary_planner
    ├── __init__.py
    ├── a2a
    │   ├── __init__.py
    │   └── a2a_client.py
    ├── a2a_agent_card.json
    ├── event_log.py
    ├── itinerary_agent.py
    ├── itinerary_server.py
    ├── run_all.py
    ├── static
    │   └── .well-known
    │       └── agent.json
    └── streamlit_ui.py
步骤 1:设置虚拟环境

安装依赖项

# 设置虚拟环境
python -n venv .venv

# 激活虚拟环境
source .venv/bin/activate

# 安装依赖项
pip install fastapi uvicorn streamlit httpx python-dotenv pydantic
pip install google-generativeai google-adk langchain langchain-openai
步骤 2:安装MCP服务器包

mcp酒店服务器 — https://pypi.org/project/mcp-hotel-search/

mcp航班服务器 — https://pypi.org/project/mcp-flight-search/

# 安装mcp酒店搜索
pip install mcp-hotel-search

# 安装mcp航班搜索
pip install mcp-flight-search
步骤 3:设置Gemini、OpenAI、SerpAI的环境变量

设置上述先决条件中的环境变量

 GOOGLE_API_KEY=your_google_api_key
 OPENAI_API_KEY=your_openai_api_key
 SERP_API_KEY=your_serp_api_key
步骤 4:使用ADK作为MCP客户端设置航班搜索(代理)并使用Gemini 2.0 Flash

以下设置与上一篇文章中使用ADK的设置相同,但增加了A2A协议,并使用了从https://github.com/google/A2A/tree/main/samples/python/common中获取的可重用模块。

├── common/                          # 共享A2A协议组件
│   ├── __init__.py
│   ├── client/                      # 客户端实现
│   │   ├── __init__.py
│   │   └── client.py                # 基础A2A客户端
│   ├── server/                      # 服务器实现
│   │   ├── __init__.py
│   │   ├── server.py                # A2A服务器实现
│   │   └── task_manager.py          # 任务管理工具
│   └── types.py                     # A2A共享类型定义

代理结构

├── flight_search_app/               # 航班搜索代理(代理1)
│   ├── __init__.py
│   ├── a2a_agent_card.json          # 代理能力声明
│   ├── agent.py                     # ADK代理实现
│   ├── main.py                      # ADK服务器入口点Gemini LLM
│   └── static/                      # 静态文件
│       └── .well-known/             # 代理发现目录
│           └── agent.json           # 标准化代理发现文件

ADK代理实现作为MCP客户端从MCP服务器获取工具

from google.adk.agents.llm_agent import LlmAgent
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, StdioServerParameters

..
..
# 从MCP服务器获取工具
server_params = StdioServerParameters(
            command="mcp-flight-search",
            args=["--connection_type", "stdio"],
            env={"SERP_API_KEY": serp_api_key},)


tools, exit_stack = await MCPToolset.from_server(
            connection_params=server_params)
..
..

使用通用A2A服务器组件和类型以及谷歌ADK运行器、会话和代理定义ADK服务器入口点

from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.adk.agents import Agent
from .agent import get_agent_async

# 导入通用A2A服务器组件和类型
from common.server.server import A2AServer
from common.server.task_manager import InMemoryTaskManager
from common.types import (
    AgentCard,
    SendTaskRequest,
    SendTaskResponse,
    Task,
    TaskStatus,
    Message,
    TextPart,
    TaskState,
)


# --- 自定义航班搜索任务管理器 ---
class FlightAgentTaskManager(InMemoryTaskManager):
    """特定于ADK航班搜索代理的任务管理器。"""
    def __init__(self, agent: Agent, runner: Runner, session_service: InMemorySessionService):
        super().__init__()
        self.agent = agent
        self.runner = runner
        self.session_service = session_service
        logger.info("FlightAgentTaskManager初始化完成。")

...
...

使用代理卡创建A2A服务器实例

# --- 主执行块 ---
async def run_server():
    """初始化服务并启动A2AServer。"""
    logger.info("开始初始化航班搜索A2A服务器...")

    session_service = None
    exit_stack = None
    try:
        session_service = InMemorySessionService()
        agent, exit_stack = await get_agent_async()
        runner = Runner(
            app_name='flight_search_a2a_app',
            agent=agent,
            session_service=session_service,
        )

        # 创建特定的任务管理器
        task_manager = FlightAgentTaskManager(
            agent=agent,
            runner=runner,
            session_service=session_service
        )

        # 定义代理卡
        port = int(os.getenv("PORT", "8000"))
        host = os.getenv("HOST", "localhost")
        listen_host = "0.0.0.0"

        agent_card = AgentCard(
            name="Flight Search Agent (A2A)",
            description="根据用户查询提供航班信息。",
            url=f"http://{host}:{port}/",
            version="1.0.0",
            defaultInputModes=["text"],
            defaultOutputModes=["text"],
            capabilities={"streaming": False},
            skills=[
                {
                    "id": "search_flights",
                    "name": "Search Flights",
                    "description": "根据出发地、目的地和日期搜索航班。",
                    "tags": ["flights", "travel"],
                    "examples": ["Find flights from JFK to LAX tomorrow"]
                }
            ]
        )

        # 创建A2AServer实例
        a2a_server = A2AServer(
            agent_card=agent_card,
            task_manager=task_manager,
            host=listen_host,
            port=port
        )
        # 程序化配置Uvicorn
        config = uvicorn.Config(
            app=a2a_server.app, # 传递A2AServer的Starlette应用
            host=listen_host,
            port=port,
            log_level="info"
        )
        server = uvicorn.Server(config)
...
...

让我们启动航班搜索应用

启动航班搜索应用

步骤 5:使用LangChain作为MCP客户端设置酒店搜索(代理)并使用OpenAI(GPT-4o)
├── hotel_search_app/                # 酒店搜索代理(代理2)
│   ├── __init__.py
│   ├── a2a_agent_card.json          # 代理能力声明
│   ├── langchain_agent.py           # LangChain代理实现
│   ├── langchain_server.py          # 服务器入口点
│   └── static/                      # 静态文件
│       └── .well-known/             # 代理发现目录
│           └── agent.json           # 标准化代理发现文件

酒店搜索代理结构

使用OpenAI LLM的LangChain代理实现作为MCP客户端

from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_functions_agent
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_mcp_adapters.client import MultiServerMCPClient

# MCP客户端配置
MCP_CONFIG = {
    "hotel_search": {
        "command": "mcp-hotel-search",
        "args": ["--connection_type", "stdio"],
        "transport": "stdio",
        "env": {"SERP_API_KEY": os.getenv("SERP_API_KEY")},
    }
}

class HotelSearchAgent:
    """使用LangChain MCP适配器的酒店搜索代理。"""

    def __init__(self):
        self.llm = ChatOpenAI(model="gpt-4o", temperature=0)

    def _create_prompt(self):
        """创建带有自定义系统消息的提示模板。"""
        system_message = """你是一个有帮助的酒店搜索助手。
        """

        return ChatPromptTemplate.from_messages([
            ("system", system_message),
            ("human", "{input}"),
            MessagesPlaceholder(variable_name="agent_scratchpad"),
        ])
..
..
async def process_query(self, query):
...

            # 为此次查询创建MCP客户端
            async with MultiServerMCPClient(MCP_CONFIG) as client:
                # 从这个客户端实例获取工具
                tools = client.get_tools()

                # 创建提示
                prompt = self._create_prompt()

                # 使用这些工具创建代理
                agent = create_openai_functions_agent(
                    llm=self.llm,
                    tools=tools,
                    prompt=prompt
                )

                # 使用这些工具创建执行器
                executor = AgentExecutor(
                    agent=agent,
                    tools=tools,
                    verbose=True,
                    handle_parsing_errors=True,
                )

使用通用A2A服务器组件和类型,类似于步骤4,创建A2AServer实例

让我们启动酒店搜索应用(Langchain服务器)服务器入口点以调用MCP服务器

启动酒店搜索应用

步骤 6:使用A2A协议实现主机代理作为代理之间的协调器

行程规划器是上述旅行规划的核心组件,使用A2A协议在航班和酒店服务之间进行通信。

├── itinerary_planner/               # 旅行规划主机代理(代理3)
│   ├── __init__.py
│   ├── a2a/                         # A2A客户端实现
│   │   ├── __init__.py
│   │   └── a2a_client.py            # 航班和酒店代理的客户端
│   ├── a2a_agent_card.json          # 代理能力声明
│   ├── event_log.py                 # 事件记录工具
│   ├── itinerary_agent.py           # 主规划器实现
│   ├── itinerary_server.py          # FastAPI服务器
│   ├── run_all.py                   # 运行所有组件的脚本
│   ├── static/                      # 静态文件
│   │   └── .well-known/             # 代理发现目录
│   │       └── agent.json           # 标准化代理发现文件
│   └── streamlit_ui.py              # 主用户界面

A2A协议实现,使用航班和酒店API URL

  • 包含与其他服务通信的客户端代码
  • 实现了代理到代理协议
  • 包含调用航班和酒店搜索服务的模块
# A2A兼容代理API的根端点
FLIGHT_SEARCH_API_URL = os.getenv("FLIGHT_SEARCH_API_URL", "http://localhost:8000")
HOTEL_SEARCH_API_URL = os.getenv("HOTEL_SEARCH_API_URL", "http://localhost:8003")

class A2AClientBase:
    """通过根端点与A2A兼容代理通信的基础客户端。"""


    async def send_a2a_task(self, user_message: str, task_id: Optional[str] = None, agent_type: str = "generic") -> Dict[str, Any]:
    ...
    ....
        # 构造带有A2A方法和修正后的参数结构的JSON-RPC负载
        payload = {
            "jsonrpc": "2.0",
            "method": "tasks/send",
            "params": {
                "id": task_id,
                "taskId": task_id,
                "message": {
                    "role": "user",
                    "parts": [
                        {"type": "text", "text": user_message}
                    ]
                }
            },
            "id": task_id
        }

代理卡 — 描述代理能力、端点、认证要求和技能的JSON元数据文件。用于A2A协议中的服务发现

{
  "name": "Travel Itinerary Planner",
  "displayName": "Travel Itinerary Planner",
  "description": "一个协调航班和酒店信息以创建综合旅行行程的代理",
  "version": "1.0.0",
  "contact": "code.aicloudlab@gmail.com",
  "endpointUrl": "http://localhost:8005",
  "authentication": {
    "type": "none"
  },
  "capabilities": ["streaming"],
  "skills": [
    {
      "name": "createItinerary",
      "description": "创建包含航班和住宿的综合旅行行程",
      "inputs": [
        {
          "name": "origin",
          "type": "string",
          "description": "出发城市或机场代码"
        },
        {
          "name": "destination",
          "type": "string",
          "description": "目的地城市或地区"
        },
        {
          "name": "departureDate",
          "type": "string",
          "description": "出发日期,格式为YYYY-MM-DD"
        },
        {
          "name": "returnDate",
          "type": "string",
          "description": "返回日期,格式为YYYY-MM-DD(可选)"
        },
        {
          "name": "travelers",
          "type": "integer",
          "description": "旅行者数量"
        },
        {
          "name": "preferences",
          "type": "object",
          "description": "其他偏好,如预算、酒店设施等"
        }
      ],
      "outputs": [
        {
          "name": "itinerary",
          "type": "object",
          "description": "完整的旅行行程,包括航班、酒店和时间表"
        }
      ]
    }
  ]
}

行程代理 — 系统的核心主机代理,协调与航班和酒店搜索服务的通信,使用语言模型解析自然语言请求

import google.generativeai as genai # 直接使用SDK
..
..
from itinerary_planner.a2a.a2a_client import FlightSearchClient, HotelSearchClient

# 配置谷歌生成式AI SDK
genai.configure(api_key=api_key)

class ItineraryPlanner:
    """一个使用谷歌生成式AI SDK协调航班和酒店搜索代理以创建行程的规划器。"""

    def __init__(self):
        """初始化行程规划器。"""
        logger.info("使用谷歌生成式AI SDK初始化行程规划器")
        self.flight_client = FlightSearchClient()
        self.hotel_client = HotelSearchClient()

        # 使用SDK创建Gemini模型实例
        self.model = genai.GenerativeModel(
            model_name="gemini-2.0-flash",
        )
..
..

行程服务器 — 一个FastAPI服务器,暴露行程规划器的端点,处理传入的HTTP请求并将请求路由到行程代理

streamlit_ui — 使用Streamlit构建的用户界面,为旅行规划提供表单,并以用户友好的格式显示结果

最终演示

在每个终端中启动服务器代理

# 启动航班搜索代理 - 1端口8000
python -m flight_search_app.main

# 启动酒店搜索代理 - 2端口8003
python -m hotel_search_app.langchain_server

# 启动行程主机代理 - 端口8005
python -m itinerary_planner.itinerary_server

# 启动前端UI - 端口8501
streamlit run itinerary_planner/streamlit_ui.py

由主机代理发起任务ID的航班搜索日志

航班搜索日志

航班搜索日志

由主机代理发起任务的酒店搜索日志

酒店搜索日志

酒店搜索日志

行程规划器 — 主机代理的所有请求/响应

行程规划器日志

行程规划器日志

代理事件日志

代理事件日志

这个演示实现了**谷歌A2A协议**的核心原则,使代理能够以结构化、可互操作的方式进行通信。在上述演示中实现的组件如下:

  1. 代理卡 — 所有代理都暴露.well-known/agent.json文件用于发现。
  2. A2A服务器 — 每个代理都运行一个A2A服务器:flight_search_apphotel_search_appitinerary_planner
  3. A2A客户端itinerary_planner包含针对航班和酒店代理的专用A2A客户端。
  4. 任务管理 — 每个请求/响应都被建模为一个A2A任务,状态包括已提交、正在处理和已完成。
  5. 消息结构 — 使用标准的JSON-RPC格式,带有角色(用户/代理)和部件(主要是TextPart)。

以下组件在我们的演示中尚未实现,但可以扩展为企业级代理:

  1. 流式传输(SSE) — A2A支持服务器发送事件用于长时间运行的任务,但我们的演示使用简单的请求/响应,耗时不到3-5秒。
  2. 推送通知 — 尚未使用网络钩子更新机制。
  3. 复杂部件 — 只使用了TextPart。可以添加对DataPartFilePart等的支持,以实现更丰富的负载。
  4. 高级发现 — 实现了基本的.well-known/agent.json,但尚未实现高级认证、JWKS或授权流程。

A2A协议 — 官方文档

总结

在本文中,我们探索了如何使用可重用的A2A组件、ADK、LangChain和MCP构建一个功能齐全的多代理系统,用于旅行规划场景。通过结合这些开源工具和框架,我们的代理能够:

  • 使用A2A动态发现并调用彼此
  • 通过MCP以模型友好的方式连接到外部API
  • 使用现代框架,如ADKLangChain
  • 以异步方式通信,具有清晰的任务生命周期和结构化结果

这些原则可以扩展到更多领域,如零售、客户服务自动化、运营工作流以及AI辅助的企业工具。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI仙人掌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值