AI Agents系列:如何使用 ADK + MCP + Gemini AI 构建这个多代理系统

架构

我们将使用与 [旅行规划器]在这里插入图片描述
相同的架构,并在此基础上扩展 A2A + MCP 协议。

下面的演示只是为了说明 A2A 协议在多个代理之间的通信,仅用于说明目的。

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

核心组件

  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. 功能:连接到酒店预订系统和聚合器

代理通信流程

以下是使用 Mermaid 语法绘制的流程图,描述了用户通过 Streamlit UI 提交旅行查询并生成完整行程的过程:

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

流程图说明:

  1. 用户通过 Streamlit UI 提交旅行查询:用户在前端界面输入旅行需求。
  2. 旅行规划器解析查询以提取关键信息:旅行规划器解析用户输入,提取出发地、目的地、日期等关键信息。
  3. 旅行规划器向航班搜索代理请求航班信息:旅行规划器将关键信息发送给航班搜索代理。
  4. 航班搜索代理通过调用 MCP 服务器返回可用航班:航班搜索代理查询航班信息并返回结果。
  5. 旅行规划器提取目的地详细信息:旅行规划器从航班信息中提取目的地相关细节。
  6. 旅行规划器向酒店搜索代理请求酒店信息:旅行规划器将目的地信息发送给酒店搜索代理。
  7. 酒店搜索代理返回住宿选项:酒店搜索代理查询酒店信息并返回结果。
  8. 旅行规划器将所有数据综合成一个完整的行程:旅行规划器整合航班和酒店信息,生成完整的行程。

这个流程图清晰地展示了从用户输入到生成完整行程的整个过程。

实现

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

准备工作

  1. 安装 Python 3.11+

2. 获取谷歌 Gemini 生成式 AI 的 API 密钥

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

第一步:设置虚拟环境

安装依赖项

# 设置虚拟环境
python -m venv .venv # 激活虚拟环境
source .venv/bin/activate# 安装依赖项
pip install fastapi uvicorn streamlit httpx python-dotenv pydantic
pip install google-generativeai google-adk langchain langchain-openai

第二步:安装 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

第三步:设置 Gemini、OpenAI、SerpAI 的环境变量

设置上面准备工作中提到的环境变量

 GOOGLE_API_KEY=your_google_api_key
 OPENAI_API_KEY=your_openai_api_key
 SERP_API_KEY=your_serp_api_key

第四步:使用 ADK 设置航班搜索(代理)作为 MCP 客户端,使用 Gemini 2.0 Flash

使用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           # 标准化代理发现文件

4.1 使用 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)
..
..

4.2 使用通用 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 初始化完成。")...
...

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

# --- 主执行块 ---

async def run_server():
"""初始化服务并启动航班搜索 A2A 服务器。"""
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)
...
...

4.4 让我们启动航班搜索应用

第五步:使用 LangChain 配置酒店搜索代理作为 MCP 客户端,并使用 OpenAI(GPT-4o)作为 LLM

├── hotel_search_app/                # 酒店搜索代理(代理 2)
│   ├── __init__.py
│   ├── a2a_agent_card.json          # 代理能力声明
│   ├── langchain_agent.py           # LangChain 代理实现
│   ├── langchain_server.py          # 服务器入口点
│   └── static/                      # 静态文件
│       └── .well-known/             # 代理发现目录
│           └── agent.json           # 标准化代理发现文件

图片由作者提供

5.1. LangChain 代理 实现作为 MCP 客户端,使用 OpenAI LLM 作为语言模型

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,
                )

5.2 使用通用 A2A 服务器组件和类型创建 A2AServer 实例


# 直接使用底层代理
from hotel_search_app.langchain_agent import get_agent, HotelSearchAgent # 导入通用 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 HotelAgentTaskManager(InMemoryTaskManager):
    """特定于酒店搜索代理的任务管理器。"""
    def __init__(self, agent: HotelSearchAgent):
        super().__init__()
        self.agent = agent # HotelSearchAgent 实例
        logger.info("HotelAgentTaskManager 初始化完成。")    async def on_send_task(self, request: SendTaskRequest) -> SendTaskResponse:
        """通过调用代理的 process_query 处理 tasks/send 请求。"""
        task_params = request.params
        task_id = task_params.id
        user_message_text = None        logger.info(f"HotelAgentTaskManager 正在处理任务 {task_id}")# --- 主执行块 ---
async def run_server():
    """初始化服务并启动酒店搜索 A2A 服务器。"""
    logger.info("开始酒店搜索 A2A 服务器初始化...")        agent_instance: Optional[HotelSearchAgent] = None
    try:
        agent_instance = await get_agent()
        if not agent_instance:
             raise RuntimeError("初始化 HotelSearchAgent 失败")        # 创建特定的任务管理器
        task_manager = HotelAgentTaskManager(agent=agent_instance)                # 定义代理卡片
        port = int(os.getenv("PORT", "8003")) # 默认端口 8003
        host = os.getenv("HOST", "localhost")
        listen_host = "0.0.0.0"        agent_card = AgentCard(
            name="Hotel Search Agent (A2A)",
            description="根据位置、入住/退房日期和客人数量提供酒店信息。",
            url=f"http://{host}:{port}/",
            version="1.0.0",
            defaultInputModes=["text"],
            defaultOutputModes=["text"],
            capabilities={"streaming": False},
            skills=[
                {
                    "id": "search_hotels",
                    "name": "Search Hotels",
                    "description": "根据位置、入住/退房日期和客人数量搜索酒店。",
                    "tags": ["hotels", "travel", "accommodation"],
                    "examples": ["Find hotels in London from July 1st to July 5th for 2 adults"]
                }
            ]
        )        # 创建 A2AServer 实例,不使用 endpoint 参数
        a2a_server = A2AServer(
            agent_card=agent_card,
            task_manager=task_manager,
            host=listen_host,
            port=port
        )        config = uvicorn.Config(
            app=a2a_server.app, # 传递 A2AServer 的 Starlette 应用
            host=listen_host,
            port=port,
            log_level="info"
        )

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

第六步:实现宿主代理作为代理之间的协调者,使用 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              # 主用户界面

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

  • 包含与服务通信的客户端代码
  • 实现 Agent-to-Agent 协议
  • 包含调用航班和酒店搜索服务的模块
# 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
        }

6.2 行程规划代理卡片

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": "包含航班、酒店和行程的完整旅行行程"
        }
      ]
    }
  ]
}

6.3 使用谷歌生成式 AI SDK 的行程代理

为了简化演示,这里使用了 GenAI SDK(也可以使用 ADK、CrewAI 或其他框架)

行程代理 是系统的中央宿主代理,它协调与航班和酒店搜索服务的通信,并使用语言模型解析自然语言请求。

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",
        )
..
..

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

from fastapi import FastAPI, HTTPException, Requestfrom itinerary_planner.itinerary_agent import ItineraryPlanner@app.post("/v1/tasks/send")
async def send_task(request: TaskRequest):
    """处理 A2A tasks/send 请求。"""
    global planner        if not planner:
        raise HTTPException(status_code=503, detail="规划器未初始化")        try:
        task_id = request.taskId                # 提取用户的消息
        user_message = None
        for part in request.message.get("parts", []):
            if "text" in part:
                user_message = part["text"]
                break                if not user_message:
            raise HTTPException(status_code=400, detail="请求中未找到文本消息")                # 根据查询生成行程
        itinerary = await planner.create_itinerary(user_message)                # 创建 A2A 响应
        response = {
            "task": {
                "taskId": task_id,
                "state": "completed",
                "messages": [
                    {
                        "role": "user",
                        "parts": [{"text": user_message}]
                    },
                    {
                        "role": "agent",
                        "parts": [{"text": itinerary}]
                    }
                ],
                "artifacts": []
            }
        }                return response

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

...
...

# API 端点

API_URL = "http://localhost:8005/v1/tasks/send"def generate_itinerary(query: str):
"""向行程规划器 API 发送查询。"""
try:
task_id = "task-" + datetime.now().strftime("%Y%m%d%H%M%S") payload = {
"taskId": task_id,
"message": {
"role": "user",
"parts": [
{
"text": query
}
]
}
} # 将用户查询和请求记录到事件日志
log_user_query(query)
log_itinerary_request(payload) response = requests.post(
API_URL,
json=payload,
headers={"Content-Type": "application/json"}
)
response.raise_for_status() result = response.json() # 提取代理的响应消息
agent_message = None
for message in result.get("task", {}).get("messages", []):
if message.get("role") == "agent":
for part in message.get("parts", []):
if "text" in part:
agent_message = part["text"]
break
if agent_message:
break
..
..
...

第七步:最终演示

在每个终端中,按照以下方式启动服务器代理,正如下面的演示所看到的那样:

# 启动航班搜索代理 - 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_app、hotel_search_app 和 itinerary_planner
  3. A2A 客户端 —— 行程规划器包含了针对航班和酒店代理的专用 A2A 客户端。
  4. 任务管理 —— 每个请求/响应都被建模为一个 A2A 任务,状态包括已提交、正在处理和已完成。
  5. 消息结构 —— 使用标准的 JSON-RPC 格式,包含角色(用户/代理)和部分(主要是 TextPart)。

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

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

A2A 协议 —— 官方文档

总结

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

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

同样的原理可以扩展到更多领域,如零售、客户服务自动化、操作工作流以及 AI 辅助的企业工具。

感谢Arjun Prabhulal的分享https://medium.com/ai-cloud-lab/building-multi-agent-ai-app-with-googles-a2a-agent2agent-protocol-adk-and-mcp-a-deep-a94de2237200

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AI仙人掌

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

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

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

打赏作者

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

抵扣说明:

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

余额充值