使用 Agent2Agent 代理构建 Google Chat 应用

本页介绍了如何构建可在 Google Chat 中运行的 Google Workspace 插件,以及如何与使用 Agent2Agent (A2A) 协议的 AI 智能体进行交互。 您可以使用 智能体开发套件 (ADK)开发智能体,并将其托管在 Vertex AI Agent Engine中。

AI 智能体能够自主感知环境、进行推理,并执行复杂的多步骤操作以实现既定目标。在本教程中,您将部署 LLM Auditor 多智能体示例 ,该示例使用 Gemini 和 Google 搜索基础知识来评论和修改事实。

LLM Auditor 多智能体示例(作为聊天应用)。

下图展示了架构和消息传递模式:

使用 A2A AI 智能体实现的聊天应用的架构。

在该图中,与使用 A2A 智能体实现的 Chat 应用交互的用户具有以下信息流:

  1. 用户通过私信或 Chat 聊天室向 Chat 应用发送消息。
  2. Chat 应用逻辑(在 Apps 脚本中实现或作为具有 HTTP 端点的 Web 服务器)接收并处理消息。
  3. 托管在 Vertex AI Agent Engine 中的 A2A 智能体接收并处理交互。
  4. (可选)Chat 应用或 AI 智能体可以与 Google Workspace 服务(例如日历或表格)或其他 Google 服务(例如 Google 地图或 YouTube)集成。
  5. Chat 应用使用 Google Chat API 异步发送响应,以传达 AI 智能体的进度。
  6. 响应会传递给用户。

目标

  • 设置环境。
  • 部署 A2A 智能体。
  • 部署 Chat 应用。
  • 配置 Chat 应用。
  • 测试 Chat 应用。

前提条件

设置环境

启用 Google Cloud API

在使用 Google API 之前,您需要在 Google Cloud 项目中启用它们。 您可以在单个 Google Cloud 项目中启用一个或多个 API。
  • 在 Google Cloud 控制台中,启用 Google Chat、Vertex AI 和 Cloud Resource Manager API。

    启用 API

配置 OAuth 权限请求页面

所有使用 OAuth 2.0 的应用都需要配置权限请求页面。通过配置应用的 OAuth 权限请求页面,您可以定义向用户和应用审核者显示的内容,还可以注册应用以便以后发布。

  1. 在 Google API 控制台中,依次点击“菜单”图标 > Google Auth 平台 > 品牌塑造

    前往“品牌塑造”

  2. 如果您已配置 Google Auth 平台,则可以在品牌塑造受众群体数据访问权限中配置以下 OAuth 权限请求页面设置。如果您看到一条消息,提示尚未配置 Google Auth 平台,请点击开始使用
    1. 应用信息 下的应用名称 中,输入应用的名称。
    2. 用户支持邮箱中,选择一个支持邮箱地址,供用户针对其同意情况与您联系。
    3. 点击下一步
    4. 受众群体 下,选择内部
    5. 点击下一步
    6. 联系信息下,输入一个邮箱地址,以便您接收有关项目变更的通知。
    7. 点击下一步
    8. 完成 部分,查看 Google API 服务用户数据政策,如果您同意,请选择我同意 Google API 服务:用户数据政策
    9. 点击继续
    10. 点击创建
  3. 目前,您可以跳过添加范围。 将来,当您创建供您的 Google Workspace 组织外部使用的应用时,必须将 用户类型 更改为 外部。然后, 添加应用所需的授权范围。如需了解详情,请参阅完整的 配置 OAuth 权限请求页面指南。

在 Google Cloud 控制台中创建服务账号

按照以下步骤创建具有 Vertex AI User 角色的新服务账号:

Google Cloud 控制台

  1. 在 Google Cloud 控制台中,依次点击“菜单”图标 > IAM 和管理 > 服务账号

    转到“服务账号”

    其余步骤会显示在 Google Cloud 控制台中。

  2. 选择 Google Cloud 项目。
  3. 点击创建服务账号
  4. 输入要在 Google Cloud 控制台中显示的服务账号名称。
  5. 如果您现在不想设置访问权限控制,请点击完成 以完成服务账号的创建过程。如需立即设置访问权限控制,请点击创建并继续 ,然后继续执行下一步。
  6. (可选)向您的服务账号分配角色,以授予对 Google Cloud 项目资源(除了 Google Workspace 资源之外)的访问权限。如需了解详情,请参阅管理对项目、文件夹和组织的访问权限
  7. 点击继续
  8. (可选)输入可以管理此服务账号并使用其执行操作的用户或群组。如需了解详情,请参阅服务账号模拟
  9. 点击完成 以完成服务账号的创建过程。

    记下服务账号的电子邮件地址。

gcloud CLI

  1. 创建服务账号:
    gcloud iam service-accounts create SERVICE_ACCOUNT_NAME \
      --display-name="SERVICE_ACCOUNT_NAME"
  2. (可选)向您的服务账号分配角色,以授予对 Google Cloud 项目资源(除了 Google Workspace 资源之外)的访问权限。如需了解详情,请参阅管理对项目、文件夹和组织的访问权限

服务账号会显示在服务账号页面上。

创建一个私钥

如需为服务账号创建并下载私钥,请按以下步骤操作:

  1. 在 Google Cloud 控制台中,依次点击“菜单”图标 > IAM 和管理 > 服务账号

    转到“服务账号”

    其余步骤会显示在 Google Cloud 控制台中。

  2. 选择 Google Cloud 项目。
  3. 点击要为其创建密钥的服务账号的电子邮件地址。
  4. 点击密钥 标签页。
  5. 点击添加密钥 下拉菜单,然后选择创建新密钥
  6. 选择 JSON 作为密钥类型 ,然后点击创建

    系统会为您生成新的公钥/私钥对,并将其作为服务账号密钥文件下载到您的 计算机。将下载的 JSON 文件另存为工作目录中的 credentials.json 。此文件是此密钥的唯一副本。下载密钥文件后,您无法再次下载。如需了解如何安全地存储 密钥,请参阅 管理服务账号密钥的最佳实践

如需详细了解服务账号,请参阅 Google Cloud IAM 文档中的服务账号

部署 A2A 智能体

  1. 如果您尚未执行此操作,请使用您的 Google Cloud 账号进行身份验证,并配置 Google Cloud CLI 以使用您的 Google Cloud 项目。

    gcloud auth application-default login
    gcloud config set project PROJECT_ID
    gcloud auth application-default set-quota-project PROJECT_ID

    PROJECT_ID 替换为您的云项目 ID。

  2. 使用此按钮下载 ADK 示例 GitHub 代码库:

    下载 adk-samples

  3. 在您偏好的本地开发环境中,提取下载的归档文件,然后打开 adk-samples/python/agents/llm-auditor 目录。

    unzip adk-samples-main.zip
    cd adk-samples-main/python/agents/llm-auditor
  4. 更新实现,以将 ADK 智能体部署为 A2A 远程智能体:

    1. pyproject.toml:在部署组中添加 ADK 和 A2A SDK 依赖项。

      apps-script/chat/a2a-ai-agent/llm-auditor/pyproject.toml
      [project]
      name = "llm-auditor"
      version = "0.1.0"
      description = "The LLM Auditor evaluates LLM-generated answers, verifies actual accuracy using the web, and refines the response to ensure alignment with real-world knowledge."
      authors = [
          { name = "Chun-Sung Ferng", email = "csferng@google.com" },
          { name = "Cyrus Rashtchian", email = "cyroid@google.com" },
          { name = "Da-Cheng Juan", email = "dacheng@google.com" },
          { name = "Ivan Kuznetsov", email = "ivanku@google.com" },
      ]
      license = "Apache License 2.0"
      readme = "README.md"
      
      [tool.poetry.dependencies]
      python = "^3.10"
      google-adk = "^1.0.0"
      google-cloud-aiplatform = { extras = [
          "adk",
          "agent-engines",
      ], version = "^1.93.0" }
      google-genai = "^1.9.0"
      pydantic = "^2.10.6"
      python-dotenv = "^1.0.1"
      
      [tool.poetry.group.dev]
      optional = true
      
      [tool.poetry.group.dev.dependencies]
      google-adk = { version = "^1.0.0", extras = ["eval"] }
      pytest = "^8.3.5"
      pytest-asyncio = "^0.26.0"
      
      [tool.poetry.group.deployment]
      optional = true
      
      [tool.poetry.group.deployment.dependencies]
      absl-py = "^2.2.1"
      google-adk = "^1.0.0"
      a2a-sdk = "^0.3.0"
      
      [build-system]
      requires = ["poetry-core>=2.0.0,<3.0.0"]
      build-backend = "poetry.core.masonry.api"
    2. deployment/deploy.py:将 ADK 应用部署替换为 A2A 智能体和卡片。

      apps-script/chat/a2a-ai-agent/llm-auditor/deployment/deploy.py
      # Copyright 2025 Google LLC
      #
      # Licensed under the Apache License, Version 2.0 (the "License");
      # you may not use this file except in compliance with the License.
      # You may obtain a copy of the License at
      #
      #     http://www.apache.org/licenses/LICENSE-2.0
      #
      # Unless required by applicable law or agreed to in writing, software
      # distributed under the License is distributed on an "AS IS" BASIS,
      # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      # See the License for the specific language governing permissions and
      # limitations under the License.
      
      """Deployment script for LLM Auditor."""
      
      import os
      
      from absl import app
      from absl import flags
      from dotenv import load_dotenv
      from llm_auditor.agent import root_agent
      import vertexai
      from vertexai import agent_engines
      
      # A2A wrapping
      from a2a.types import AgentSkill
      from google.adk.a2a.executor.a2a_agent_executor import A2aAgentExecutor
      from google.adk.runners import InMemoryRunner
      from vertexai.preview.reasoning_engines.templates.a2a import create_agent_card
      from vertexai.preview.reasoning_engines import A2aAgent
      
      FLAGS = flags.FLAGS
      flags.DEFINE_string("project_id", None, "GCP project ID.")
      flags.DEFINE_string("location", None, "GCP location.")
      flags.DEFINE_string("bucket", None, "GCP bucket.")
      flags.DEFINE_string("resource_id", None, "ReasoningEngine resource ID.")
      
      flags.DEFINE_bool("list", False, "List all agents.")
      flags.DEFINE_bool("create", False, "Creates a new agent.")
      flags.DEFINE_bool("delete", False, "Deletes an existing agent.")
      flags.mark_bool_flags_as_mutual_exclusive(["create", "delete"])
      
      
      def create() -> None:
          """Creates an agent engine for LLM Auditor."""
          agent_card = create_agent_card(
              agent_name=root_agent.name,
              description=root_agent.description,
              skills=[AgentSkill(
                  id='audit_llm_output',
                  name='Audit LLM Output',
                  description='Critiques and revises outputs from large language models.',
                  tags=['LLM', 'Audit', 'Revision'],
                  examples=[
                      'The earth is flat.',
                      'The capital of France is Berlin.',
                      'The last winner of the Super Bowl was the New England Patriots in 2020.',
                  ],
              )]
          )
          a2a_agent = A2aAgent(
              agent_card=agent_card,
              agent_executor_builder=lambda: A2aAgentExecutor(
                  runner=InMemoryRunner(
                      app_name=root_agent.name,
                      agent=root_agent,
                  )
              )
          )
          a2a_agent.set_up()
      
          remote_agent = agent_engines.create(
              a2a_agent,
              display_name=root_agent.name,
              requirements=[
                      "google-adk (>=0.0.2)",
                      "google-cloud-aiplatform[agent_engines] (>=1.88.0,<2.0.0)",
                      "google-genai (>=1.5.0,<2.0.0)",
                      "pydantic (>=2.10.6,<3.0.0)",
                      "absl-py (>=2.2.1,<3.0.0)",
                      "a2a-sdk>=0.3.22",
                      "uvicorn",
              ],
              # In-memory runner
              max_instances=1,
              env_vars ={
                  "NUM_WORKERS": "1"
              },
              extra_packages=["./llm_auditor"],
          )
          print(f"Created remote agent: {remote_agent.resource_name}")
      
      
      def delete(resource_id: str) -> None:
          remote_agent = agent_engines.get(resource_id)
          remote_agent.delete(force=True)
          print(f"Deleted remote agent: {resource_id}")
      
      
      def list_agents() -> None:
          remote_agents = agent_engines.list()
          TEMPLATE = '''
      {agent.name} ("{agent.display_name}")
      - Create time: {agent.create_time}
      - Update time: {agent.update_time}
      '''
          remote_agents_string = '\n'.join(TEMPLATE.format(agent=agent) for agent in remote_agents)
          print(f"All remote agents:\n{remote_agents_string}")
      
      def main(argv: list[str]) -> None:
          del argv  # unused
          load_dotenv()
      
          project_id = (
              FLAGS.project_id
              if FLAGS.project_id
              else os.getenv("GOOGLE_CLOUD_PROJECT")
          )
          location = (
              FLAGS.location if FLAGS.location else os.getenv("GOOGLE_CLOUD_LOCATION")
          )
          bucket = (
              FLAGS.bucket if FLAGS.bucket
              else os.getenv("GOOGLE_CLOUD_STORAGE_BUCKET")
          )
      
          print(f"PROJECT: {project_id}")
          print(f"LOCATION: {location}")
          print(f"BUCKET: {bucket}")
      
          if not project_id:
              print("Missing required environment variable: GOOGLE_CLOUD_PROJECT")
              return
          elif not location:
              print("Missing required environment variable: GOOGLE_CLOUD_LOCATION")
              return
          elif not bucket:
              print(
                  "Missing required environment variable: GOOGLE_CLOUD_STORAGE_BUCKET"
              )
              return
      
          vertexai.init(
              project=project_id,
              location=location,
              staging_bucket=f"gs://{bucket}",
          )
      
          if FLAGS.list:
              list_agents()
          elif FLAGS.create:
              create()
          elif FLAGS.delete:
              if not FLAGS.resource_id:
                  print("resource_id is required for delete")
                  return
              delete(FLAGS.resource_id)
          else:
              print("Unknown command")
      
      
      if __name__ == "__main__":
          app.run(main)
  5. 创建一个专用于 ADK 智能体的 Cloud Storage 存储分区。

    gcloud storage buckets create gs://CLOUD_STORAGE_BUCKET_NAME --project=PROJECT_ID --location=PROJECT_LOCATION

    替换以下内容:

    1. CLOUD_STORAGE_BUCKET_NAME 替换为您要使用的唯一存储分区名称。
    2. PROJECT_ID 替换为您的云项目 ID。
    3. PROJECT_LOCATION 替换为您的 云项目的位置。
  6. 设置以下环境变量:

    export GOOGLE_GENAI_USE_VERTEXAI=true
    export GOOGLE_CLOUD_PROJECT=PROJECT_ID
    export GOOGLE_CLOUD_LOCATION=PROJECT_LOCATION
    export GOOGLE_CLOUD_STORAGE_BUCKET=CLOUD_STORAGE_BUCKET_NAME

    替换以下内容:

    1. CLOUD_STORAGE_BUCKET_NAME 替换为您创建的存储分区的名称。
    2. PROJECT_ID 替换为您的云项目 ID。
    3. PROJECT_LOCATION 替换为您的 Cloud 项目的位置。
  7. 从虚拟环境安装和部署 ADK 智能体。

    python3 -m venv myenv
    source myenv/bin/activate
    poetry install --with deployment
    python3 deployment/deploy.py --create
  8. 检索智能体 ID。稍后在配置 Chat 应用时需要用到它。

    python3 deployment/deploy.py --list

创建和配置 Chat 应用项目

  1. 点击以下按钮以打开 A2A AI 智能体快速入门 Apps 脚本项目。

    打开项目

  2. 依次点击 概览 > 用于创建副本的图标 制作副本

  3. 在 Apps 脚本项目中, 依次点击 项目设置图标 项目设置 > 修改脚本属性 > 添加脚本属性 ,以添加以下脚本属性:

    1. REASONING_ENGINE_RESOURCE_NAME ,其中包含在之前的步骤中复制的 Vertex AI 智能体资源名称。
    2. SERVICE_ACCOUNT_KEY ,其中包含在之前的步骤中下载的服务账号的 JSON 密钥,例如 { ... }
  4. 点击保存脚本属性

  5. 在 Google API 控制台中,依次点击“菜单”图标 > IAM 和管理 > 设置

    前往“IAM 和管理”设置

  6. 项目编号 字段中,复制相应值。

  7. 在 Apps 脚本项目中, 点击 项目设置图标 项目设置

  8. Google Cloud Platform (GCP) 项目 下,点击 更改项目

  9. GCP 项目编号 中,粘贴在 之前的步骤中复制的 Google Cloud 项目编号。

  10. 点击设置项目 。云项目和 Apps 脚本项目现已连接。

创建测试部署

您需要此 Apps 脚本项目的部署 ID,以便在下一步中使用。

如需获取 Head 部署 ID,请执行以下操作:

  1. 在 Chat 应用 Apps 脚本项目中, 依次点击 部署 > 测试部署
  2. Head 部署 ID 下,点击 用于创建副本的图标 复制
  3. 点击完成

配置 Chat 应用

使用您的 Apps 脚本部署,按照以下步骤部署 Google Chat 应用以进行测试:

  1. API 控制台中,搜索 Google Chat API, 然后点击 Google Chat API
  2. 点击管理
  3. 点击配置 并设置 Chat 应用:

    1. 应用名称 字段中,输入 A2A Quickstart
    2. 头像网址 字段中,输入 https://developers.google.com/workspace/add-ons/images/quickstart-app-avatar.png
    3. 说明 字段中,输入 A2A Quickstart
    4. 功能 下,选择加入聊天室和群组对话
    5. 在连接设置下,选择 Apps 脚本项目
    6. 部署 ID 字段中,粘贴您之前复制的 Head 部署 ID。
    7. 在“可见性”下,选择您网域中的特定人员和群组,然后输入您的电子邮件地址。
  4. 点击保存

Chat 应用已准备好响应消息。

测试 Chat 应用

如需测试 Chat 应用,请打开与 Chat 应用的私信聊天室,然后发送消息:

  1. 使用您在将自己添加为受信任的测试人员时提供的 Google Workspace 账号打开 Google Chat。

    转到 Google Chat

  2. 点击 新对话
  3. 添加 1 位或多位用户 字段中,输入 Chat 应用的名称。
  4. 从结果中选择您的 Chat 应用。系统会打开一条私信。

  5. 在与应用来往的新私信中,输入 The Eiffel Tower was completed in 1900,然后按 enter

    Chat 应用会回复评论员修订员 子智能体的响应。

如需添加受信任的测试人员并详细了解如何测试互动功能,请参阅 测试 Google Chat 应用的互动功能

问题排查

当 Google Chat 应用或 卡片返回错误时, Chat 界面会显示一条消息,提示“出了点问题” 或“无法处理您的请求”。有时,Chat 界面 不会显示任何错误消息,但 Chat 应用或 卡片会产生意外结果;例如,卡片消息可能不会 显示。

虽然 Chat 界面中可能不会显示错误消息, 但当您为 Chat 应用启用错误日志记录功能后,系统会提供描述性错误消息和日志数据,帮助您修复错误。如需查看、 调试和修复错误方面的帮助,请参阅 排查和修复 Google Chat 错误

清理

为避免因本教程中使用的 资源导致您的 Google Cloud 账号产生费用,我们建议您删除 云项目。

  1. 在 Google API 控制台中,前往管理资源 页面。依次点击 菜单 > IAM 和管理 > 管理资源

    转到 Resource Manager

  2. 在项目列表中,选择要删除的项目,然后点击 删除 .
  3. 在对话框中输入项目 ID,然后点击关停 以删除 项目。