1. 始める前に
Gemini Enterprise とは何ですか?
Gemini Enterprise は、あらゆる従業員がすべてのワークフローで最先端の Google AI を利用できる高度なエージェント プラットフォームです。これにより、チームは 1 つの安全な環境で AI エージェントを発見、作成、共有、実行できるようになります。
- 高度なモデルにアクセスする: ユーザーは、Gemini などの Google の最も強力なマルチモーダル AI にすぐにアクセスして、複雑なビジネス上の課題に取り組むことができます。
- 専門のエージェントを活用する: このスイートには、調査、コーディング、メモ取り用の Google エージェントがすぐに使用できる状態で含まれており、すぐに価値を提供できます。
- すべての従業員が活用できる: ノーコードとプロコードのオプションにより、すべての部門のスタッフがワークフローの自動化のための独自のカスタム エージェントを構築して管理できます。
- エージェントをデータにグラウンディングする: エージェントを社内データやサードパーティ アプリケーションに安全に接続し、コンテキストに沿った正確な回答を生成できます。
- 一元化されたガバナンス: 管理者は、すべてのエージェント アクティビティを可視化して監査し、組織が厳格なセキュリティとコンプライアンスの基準を満たしていることを確認できます。
- エコシステムで拡張: このプラットフォームは、パートナー アプリケーションとサービス プロバイダの広範なネットワークと統合され、さまざまなシステムにわたって自動化を拡張します。
Google Workspace とは
Google Workspace は、個人、学校、企業向けに設計されたクラウドベースの生産性とコラボレーションのソリューションです。
- コミュニケーション: ビジネス用メールサービス(Gmail)、ビデオ会議(Meet)、チーム メッセージング(Chat)。
- コンテンツ作成: ドキュメントの作成(ドキュメント)、スプレッドシートの作成(スプレッドシート)、プレゼンテーションの作成(スライド)を行うためのツール。
- 整理: 共有カレンダー(カレンダー)とデジタル メモ(Keep)。
- ストレージ: ファイルを安全に保存、共有できる一元化されたクラウド スペース(ドライブ)。
- 管理: ユーザーとセキュリティ設定を管理するための管理ツール(Workspace 管理コンソール)。
どのようなカスタム統合ですか?
Google Workspace と Gemini Enterprise は、強力なフィードバック ループを形成します。Workspace はリアルタイムのデータとコラボレーション コンテキストを提供し、Gemini Enterprise はインテリジェントなワークフローの自動化に必要なモデル、エージェントによる推論、オーケストレーションを提供します。
- スマートな接続性: Google が管理するデータストア、API、MCP サーバー(Google が管理するものとカスタムのもの)により、エージェントは Workspace データに安全かつシームレスにアクセスし、ユーザーに代わってアクションを実行できます。
- カスタム エージェント: ノーコード デザイナーまたはプロコード フレームワークを使用して、管理者が管理する Workspace のデータとアクションに基づいて、特殊なエージェントを構築できます。
- ネイティブ統合: Workspace アドオンは、専用の UI コンポーネントまたはバックグラウンド プロセスを介して、AI システムと Chat や Gmail などのアプリケーション間のギャップを埋めます。これにより、エージェントはユーザーの状況を正確に把握し、即座にコンテキストに応じたサポートを提供できます。
Google Workspace の堅牢な生産性エコシステムと Gemini Enterprise の高度なエージェント機能を組み合わせることで、組織は、チームが日常的に使用しているツール内で複雑なワークフローを自動化する、データに基づいたカスタム AI エージェントを通じて、業務を変革できます。
前提条件
ご自身の環境で手順をすべて行うには、次のものが必要です。
- Google Cloud と Python の基礎知識。
- 課金が有効になっており、自分がオーナーの Google Cloud プロジェクト。既存のプロジェクトで課金が有効になっていることを確認するには、プロジェクトの課金ステータスを確認するをご覧ください。プロジェクトを作成して課金管理を設定するには、Google Cloud プロジェクトを作成するをご覧ください。プロジェクトの所有権を変更するには、プロジェクト メンバーの管理またはプロジェクトの所有権の変更をご覧ください。
- Gemini Enterprise Standard / Plus エディションが有効になっている。Gemini Enterprise のエディションを比較するには、Gemini Enterprise のエディションの比較をご覧ください。Gemini Enterprise のライセンスをお持ちでない場合は、次のステップでトライアル ライセンスを作成できます。
- Google Chat へのアクセス権を持ち、スマート機能がオンになっている Business または Enterprise の Google Workspace アカウント。
- Google Cloud プロジェクト用に Google Cloud CLI がインストールされ、初期化されていること。
- Python 3.11 以降がインストールされている。公式の Python ウェブサイトの手順をご覧ください。
作成するアプリの概要
この Codelab では、Google Workspace と緊密に統合された Gemini Enterprise AI エージェントを使用して 3 つのソリューションを構築します。データ、アクション、UI とのやり取りに使用できるアーキテクチャ パターンについて説明します。
ノーコード カスタム エージェント
このエージェントを使用すると、ユーザーは自然言語でデータを検索し、Workspace のアクションを実行できます。次の要素に依存します。
- モデル: Gemini。
- データとアクション: Google Workspace(カレンダー、Gmail、ドライブ、NotebookLM)用の Gemini Enterprise データストア、Google 検索。
- エージェント構築ツール: Gemini Enterprise Agent Designer。
- エージェント ホスト: Gemini Enterprise。
- UI: Gemini Enterprise ウェブアプリ。


プロコード カスタム エージェント
このエージェントを使用すると、ユーザーはカスタムツールとルールを使用して、自然言語でデータを検索し、Workspace の操作を行うことができます。次の要素に依存します。
- モデル: Gemini。
- データとアクション: Google Workspace(カレンダー、Gmail、ドライブ、NotebookLM)用の Gemini Enterprise データストア、Google 検索、Google 管理の Vertex AI Search Model Context Protocol(MCP)サーバー、Google Chat メッセージを送信するカスタム ツール関数(Google Chat API 経由)。
- エージェント構築ツール: Agent Development Kit(ADK)。
- エージェント ホスト: Vertex AI Agent Engine。
- UI: Gemini Enterprise ウェブアプリ。


デフォルト エージェントとしての Google Workspace アドオン
このエージェントを使用すると、ユーザーは Workspace アプリの UI のコンテキスト内で、自然言語で Workspace のデータを検索できます。次の要素に依存します。
- モデル: Gemini。
- データ: Google Workspace(カレンダー、Gmail、ドライブ、NotebookLM)用の Gemini Enterprise データストア、Google 検索。
- エージェント ホスト: Gemini Enterprise。
- UI: Chat と Gmail 用の Google Workspace アドオン(カレンダー、ドライブ、ドキュメント、スプレッドシート、スライドにも簡単に拡張可能)。
- Google Workspace アドオン: Apps Script、Gemini Enterprise と Vertex AI の API、コンテキスト(ユーザー メタデータ、選択した Gmail メッセージ)。


学習内容
- データとアクションを可能にする Gemini Enterprise と Google Workspace 間の統合ポイント。
- Gemini Enterprise でホストされるカスタム エージェントを構築するためのノーコード オプションとプロコード オプション。
- ユーザーが Gemini Enterprise ウェブアプリと Google Workspace アプリケーションからエージェントにアクセスする方法。
2. セットアップする
コンセプトを確認する
Gemini Enterprise アプリ
Gemini Enterprise アプリは、検索結果、アクション、エージェントをエンドユーザーに提供します。API のコンテキストでは、「アプリ」という用語と「エンジン」という用語を同じ意味で使用できます。アプリは、データストアのデータを使用して検索結果、回答、アクションを提示するために、データストアに接続されている必要があります。
Gemini Enterprise ウェブアプリ
Gemini Enterprise ウェブアプリは Gemini Enterprise アプリに関連付けられています。これは、従業員が単一のチャット インターフェースを使用して、サイロ化された企業データを検索し、複雑なワークフロー用の専門的な AI エージェントを実行し、エンタープライズ レベルのプライバシーでプロフェッショナル グレードのコンテンツを生成する、一元化された AI ホームベースとして機能します。
リソースを初期化してアクセスする
このセクションでは、お使いのウェブブラウザから次のリソースにアクセスして構成します。
Gemini Enterprise アプリ
新しいタブで Google Cloud コンソールを開き、次の操作を行います。
- プロジェクトを選択します。
- Google Cloud の検索フィールドで Gemini Enterprise を検索して選択し、[+ アプリを作成] をクリックします。Gemini Enterprise のライセンスがない場合は、30 日間の無料トライアル ライセンスを有効にするよう求められます。
- [アプリ名] を
codelabに設定します。 - ID は名前に基づいて生成され、フィールドの下に表示されます。コピーします。
- [マルチリージョン] を
global (Global)に設定します。 - [作成] をクリックします。

- アプリが作成され、[Gemini Enterprise] > [概要] に自動的にリダイレクトされます。
- [フルアクセス権を取得] で [ID を設定] をクリックします。
- 新しい画面で、[Google Identity を使用する] を選択し、[Workforce Identity を確認する] をクリックします。

- 構成が保存され、[Gemini Enterprise] > [概要] に自動的にリダイレクトされます。
- [構成] に移動します。
- [Feature Management] タブで、[Enable agent designer] をオンにして、[Save] をクリックします。

Gemini Enterprise ウェブアプリ
Cloud コンソールから新しいタブで Gemini Enterprise を開き、次の操作を行います。
codelabという名前のアプリをクリックします。- 表示された URL をコピーします。この URL は、次の手順で Gemini Enterprise ウェブアプリに移動するために使用します。

3. ノーコード カスタム エージェント
このエージェントを使用すると、ユーザーは自然言語でデータを検索し、Workspace のアクションを実行できます。次の要素に依存します。
- モデル: Gemini。
- データとアクション: Google Workspace(カレンダー、Gmail、ドライブ、NotebookLM)用の Gemini Enterprise データストア、Google 検索。
- エージェント構築ツール: Gemini Enterprise Agent Designer。
- エージェント ホスト: Gemini Enterprise。
- UI: Gemini Enterprise ウェブアプリ。
コンセプトを確認する
Gemini
Gemini は、Google のマルチモーダル LLM です。人々が、人間の可能性を解き放ち、想像力を高め、好奇心を刺激し、生産性を高めるお手伝いをします。
Gemini Enterprise データストア
Gemini Enterprise データストアは、Google Workspace などのファーストパーティ データソースや、Jira や Salesforce などのサードパーティ アプリケーションから取り込まれたデータを含むエンティティです。サードパーティ アプリケーションのデータを含むデータストアは、データコネクタとも呼ばれます。
Gemini Enterprise エージェント デザイナー
Gemini Enterprise Agent Designer は、Gemini Enterprise でシングルステップとマルチステップのエージェントを作成、管理、起動するためのインタラクティブなノーコード / ローコード プラットフォームです。
ソリューション アーキテクチャを確認する

API を有効にする
Gemini Enterprise Workspace データストアでは、次の API を有効にする必要があります。
- Google Cloud コンソールで、カレンダー、Gmail、People API を有効にします。

- メニュー アイコン ☰ > [API とサービス] > [有効な API とサービス] をクリックし、Google Calendar API、Gmail API、People API がリストに含まれていることを確認します。
OAuth 同意画面を構成する
Gemini Enterprise Workspace カレンダーと Gmail のアクションには、同意画面の構成が必要です。
- Google Cloud コンソールで、メニュー アイコン ☰ > Google 認証プラットフォーム > ブランディング をクリックします。
- [開始] をクリックします。
- [アプリ情報] で、[アプリ名] を
Codelabに設定します。 - [ユーザー サポートメール] で、ユーザーが同意について問い合わせる際に使用するサポートのメールアドレスを選択します。
- [次へ] をクリックします。
- [対象] で [内部] を選択します。
- [次へ] をクリックします。
- [連絡先情報] で、プロジェクトに対する変更の通知を受け取るメールアドレスを入力します。
- [次へ] をクリックします。
- [完了] で、Google API サービスのユーザーデータに関するポリシーを確認し、同意する場合は [Google API サービス: ユーザーデータに関するポリシーに同意します] を選択します。
- [続行]、[作成] の順にクリックします。

- 構成が保存され、[Google Auth Platform] > [概要] に自動的にリダイレクトされます。
- [データアクセス] に移動します。
- [スコープを追加または削除] をクリックします。
- 次のスコープをコピーして、[Manually add scopes] フィールドに貼り付けます。
https://www.googleapis.com/auth/calendar.readonly
https://www.googleapis.com/auth/calendar.events
https://www.googleapis.com/auth/calendar.calendars
https://www.googleapis.com/auth/gmail.send
https://www.googleapis.com/auth/gmail.readonly
- [テーブルに追加]、[更新]、[保存] の順にクリックします。

詳細については、OAuth 同意画面を構成するをご覧ください。
OAuth クライアント認証情報を作成する
Gemini Enterprise 用の新しい OAuth クライアントを作成して、ユーザーを認証します。
- Google Cloud コンソールで、メニュー アイコン ☰ > Google Auth Platform > クライアントをクリックします。
- [+ クライアントを作成] をクリックします。
- [アプリケーションの種類] で [ウェブ アプリケーション] を選択します。
- [名前] を
codelabに設定します。 - [承認済みの JavaScript 生成元] はスキップします。
- [承認済みのリダイレクト URI] セクションで、[URI を追加] をクリックして
https://vertexaisearch.cloud.google.com/oauth-redirectと入力します。 - [作成] をクリックします。
- 新しく作成された OAuth クライアント ID とシークレットがダイアログに表示されます。この情報は安全な場所に保管してください。

データストアを作成する
Cloud コンソールから新しいタブで Gemini Enterprise を開き、次の操作を行います。
codelabという名前のアプリをクリックします。- ナビゲーション メニューで [接続されたデータストア] をクリックします。
- [+ 新しいデータストア] をクリックします。
- [ソース] で「Google カレンダー」を検索し、[選択] をクリックします。
- [アクション] セクションで、前の手順で保存したクライアント ID とクライアント シークレットを入力し、[認証を確認する] をクリックして、OAuth クライアントを認証して承認する手順に沿って操作します。
- [カレンダーの予定を作成] と [カレンダーの予定を更新] のアクションを有効にします。
- [続行] をクリックします。

- [構成] セクションで、[データコネクタ名] を
calendarに設定します。 - [作成] をクリックします。
- [接続されたデータストア] に自動的にリダイレクトされ、新しく追加されたデータストアが表示されます。
Google Gmail データストアを作成します。
- [+ 新しいデータストア] をクリックします。
- [ソース] で [Google Gmail] を検索し、[選択] をクリックします。
- [アクション] セクションで、前の手順で保存したクライアント ID とクライアント シークレットを入力し、[認証を確認する] をクリックします。
- アクション [メールを送信] を有効にします。
- [続行] をクリックします。
- [構成] セクションで、[データコネクタ名] を
gmailに設定します。 - [作成] をクリックします。
- [接続されたデータストア] に自動的にリダイレクトされ、新しく追加されたデータストアが表示されます。
Google ドライブのデータストアを作成します。
- [+ 新しいデータストア] をクリックします。
- [ソース] で「Google ドライブ」を検索し、[選択] をクリックします。
- [データ] セクションで [すべて] を選択し、[続行] をクリックします。
- [構成] セクションで、[データコネクタ名] を
driveに設定します。 - [作成] をクリックします。
- [接続されたデータストア] に自動的にリダイレクトされ、新しく追加されたデータストアが表示されます。
NotebookLM データストアを作成します。
- [+ 新しいデータストア] をクリックします。
- [ソース] で「NotebookLM」を検索し、[選択] をクリックします。
- [構成] セクションで、[データコネクタ名] を
notebooklmに設定します。 - [作成] をクリックします。
- [接続されたデータストア] に自動的にリダイレクトされ、新しく追加されたデータストアが表示されます。
数分後、接続されているすべてのデータストア(NotebookLM を除く)のステータスが [アクティブ] になります。エラーが表示された場合は、データソースをクリックしてエラーの詳細を表示できます。

テストデータストア
先ほどコピーした Gemini Enterprise ウェブアプリの URL を開きます。
- メニュー アイコン ☰ > [チャットを新規作成] をクリックします。
- 新しいチャット メッセージ フィールドのフッターで、[コネクタ] アイコンをクリックし、すべてのコネクタを有効にします。
- コネクタに関連するプロンプトを試せるようになりました。たとえば、チャットで「
Do I have any meetings today?」と入力してenterキーを押します。 - 次に、「
How many emails did I receive today?」と入力してenterキーを押します。 - 最後に、「
Give me the title of the last Drive file I created」と入力してenterキーを押します。

カスタム エージェントを作成する
Gemini Enterprise ウェブアプリで、Agent Designer を使用して新しいエージェントを作成します。
- メニュー アイコン ☰ > [+ 新しいエージェント] をクリックします。
- チャットで「
An agent that always sends pirate-themed emails but use normal English otherwise」と入力し、enterキーを押します。

- Agent Designer は、プロンプトに基づいてエージェントをドラフトし、エディタで開きます。
- [作成] をクリックします。
カスタム エージェントを試す
- Gemini Enterprise ウェブアプリで、新しく作成したエージェントとチャットします。
- メニュー アイコン ☰ > [エージェント] をクリックします。
- [エージェント] でエージェントを選択します。
- 新しいチャット メッセージ フィールドのフッターで、[コネクタ] アイコンをクリックし、[メール] の [アクションを有効にする] をクリックして、手順に沿ってエージェントを承認します。
- チャットで「
Send an email to someone@example.com saying I'll see them at Cloud Next, generate some subject and body yourself」と入力し、enterキーを押します。サンプル メールは、ご自身のメールアドレスに置き換えることができます。 - ✔️ をクリックしてメールを送信します。


4. プロコード カスタム エージェント
このエージェントを使用すると、ユーザーはカスタムツールとルールを使用して、自然言語でデータを検索し、Workspace の操作を行うことができます。次の要素に依存します。
- モデル: Gemini。
- データとアクション: Google Workspace(カレンダー、Gmail、ドライブ、NotebookLM)用の Gemini Enterprise データストア、Google 検索、Google 管理の Vertex AI Search Model Context Protocol(MCP)サーバー、Google Chat メッセージを送信するカスタム ツール関数(Google Chat API 経由)。
- エージェント構築ツール: Agent Development Kit(ADK)。
- エージェント ホスト: Vertex AI Agent Engine。
- UI: Gemini Enterprise ウェブアプリ。
これは Bring Your Own 機能を使用して Gemini Enterprise に統合されるため、デプロイ、登録、構成の手順を行う必要があります。
コンセプトを確認する
Vertex AI
Vertex AI は、AI ソリューション、検索と会話、130 を超える基盤モデル、統合 AI プラットフォームなど、生成 AI を構築して使用するために必要なすべてを提供します。

Agent Development Kit(ADK)
Agent Development Kit(ADK)は、推論、メモリ管理、ツール統合用の事前構築済みモジュールを提供することで、自律型 AI エージェントの作成を簡素化するように設計された、ツールとフレームワークの専用スイートです。
Model Context Protocol(MCP)
Model Context Protocol(MCP)は、ユニバーサルな「プラグ アンド プレイ」インターフェースを通じて、AI アプリケーションとさまざまなデータソースやツール間のシームレスで安全な統合を実現するように設計されたオープン スタンダードです。
関数ツール
関数ツールは、AI モデルがトリガーして特定のアクションを実行したり、外部システムからリアルタイム データを取得したりできる、事前定義された実行可能なルーティンです。これにより、単純なテキスト生成を超えて機能を拡張できます。
ソリューション アーキテクチャを確認する

ソースコードを確認する
agent.py
...
MODEL = "gemini-2.5-flash"
# Gemini Enterprise authentication injects a bearer token into the ToolContext state.
# The key pattern is "GE_AUTH_NAME_<random_digits>".
# We dynamically parse this token to authenticate our MCP and API calls.
GE_AUTH_NAME = "enterprise-ai"
VERTEXAI_SEARCH_TIMEOUT = 15.0
def get_project_id():
"""Fetches the consumer project ID from the environment natively."""
_, project = google.auth.default()
if project:
return project
raise Exception(f"Failed to resolve GCP Project ID from environment.")
def find_serving_config_path():
"""Dynamically finds the default serving config in the engine."""
project_id = get_project_id()
engines = discoveryengine_v1.EngineServiceClient().list_engines(
parent=f"projects/{project_id}/locations/global/collections/default_collection"
)
for engine in engines:
# engine.name natively contains the numeric Project Number
return f"{engine.name}/servingConfigs/default_serving_config"
raise Exception(f"No Discovery Engines found in project {project_id}")
def _get_access_token_from_context(tool_context: ToolContext) -> str:
"""Helper method to dynamically parse the intercepted bearer token from the context state."""
escaped_name = re.escape(GE_AUTH_NAME)
pattern = re.compile(fr"^{escaped_name}_\d+$")
# Handle ADK varying state object types (Raw Dict vs ADK State)
state_dict = tool_context.state.to_dict() if hasattr(tool_context.state, 'to_dict') else tool_context.state
matching_keys = [k for k in state_dict.keys() if pattern.match(k)]
if matching_keys:
return state_dict.get(matching_keys[0])
raise Exception(f"No bearer token found in ToolContext state matching pattern {pattern.pattern}")
def auth_header_provider(tool_context: ToolContext) -> dict[str, str]:
token = _get_access_token_from_context(tool_context)
return {"Authorization": f"Bearer {token}"}
def send_direct_message(email: str, message: str, tool_context: ToolContext) -> dict:
"""Sends a Google Chat Direct Message (DM) to a specific user by email address."""
chat_client = chat_v1.ChatServiceClient(
credentials=Credentials(token=_get_access_token_from_context(tool_context))
)
# 1. Setup the DM space or find existing one
person = chat_v1.User(
name=f"users/{email}",
type_=chat_v1.User.Type.HUMAN
)
membership = chat_v1.Membership(member=person)
space_req = chat_v1.Space(space_type=chat_v1.Space.SpaceType.DIRECT_MESSAGE)
setup_request = chat_v1.SetUpSpaceRequest(
space=space_req,
memberships=[membership]
)
space_response = chat_client.set_up_space(request=setup_request)
space_name = space_response.name
# 2. Send the message
msg = chat_v1.Message(text=message)
message_request = chat_v1.CreateMessageRequest(
parent=space_name,
message=msg
)
message_response = chat_client.create_message(request=message_request)
return {"status": "success", "message_id": message_response.name, "space": space_name}
vertexai_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(
url="https://discoveryengine.googleapis.com/mcp",
timeout=VERTEXAI_SEARCH_TIMEOUT,
sse_read_timeout=VERTEXAI_SEARCH_TIMEOUT
),
tool_filter=['search'],
# The auth_header_provider dynamically injects the bearer token from the ToolContext
# into the MCP call for authentication.
header_provider=auth_header_provider
)
# Answer nicely the following user queries:
# - Please find my meetings for today, I need their titles and links
# - What is the latest Drive file I created?
# - What is the latest Gmail message I received?
# - Please send the following message to someone@example.com: Hello, this is a test message.
root_agent = LlmAgent(
model=MODEL,
name='enterprise_ai',
instruction=f"""
You are a helpful assistant that always uses the Vertex AI MCP search tool to answer the user's message, unless the user asks you to send a message to someone.
If the user asks you to send a message to someone, use the send_direct_message tool to send the message.
You MUST unconditionally use the Vertex AI MCP search tool to find answer, even if you believe you already know the answer or believe the Vertex AI MCP search tool does not contain the data.
The Vertex AI MCP search tool accesses the user's data through datastores including Google Drive, Google Calendar, and Gmail.
Only use the Vertex AI MCP search tool with servingConfig and query parameters, do not use any other parameters.
Always use the servingConfig {find_serving_config_path()} while using the Vertex AI MCP search tool.
""",
tools=[vertexai_mcp, FunctionTool(send_direct_message)]
)
API を有効にする
このソリューションでは、次の追加の API を有効にする必要があります。
- Google Cloud コンソールで、Vertex AI、Cloud Resource Manager、Google Chat の各 API を有効にします。

- メニュー アイコン ☰ > [API とサービス] > [有効な API とサービス] をクリックし、Vertex AI API、Cloud Resource Manager API、Google Chat API がリストに含まれていることを確認します。
OAuth 同意画面を更新する
このソリューションには、追加のデータアクセスが必要です。
- Google Cloud コンソールで、メニュー ☰ > Google Auth プラットフォーム > データアクセスをクリックします。
- [スコープを追加または削除] をクリックします。
- 次のスコープをコピーして、[Manually add scopes] フィールドに貼り付けます。
- [テーブルに追加]、[更新]、[保存] の順にクリックします。
https://www.googleapis.com/auth/cloud-platform
https://www.googleapis.com/auth/chat.messages.create
https://www.googleapis.com/auth/chat.spaces.create
- [テーブルに追加]、[更新]、[保存] の順にクリックします。

OAuth クライアント認証情報を更新する
このソリューションには、追加の承認済みリダイレクト URI が必要です。
- Google Cloud コンソールで、メニュー アイコン ☰ > Google Auth Platform > クライアントをクリックします。
- クライアント名
codelabをクリックします。 - [承認済みのリダイレクト URI] セクションで、[URI を追加] をクリックして
https://vertexaisearch.cloud.google.com/static/oauth/oauth.htmlを入力します。 - [保存] をクリックします。

Vertex AI Search MCP を有効にする
- ターミナルで次のコマンドを実行します。
gcloud beta services mcp enable discoveryengine.googleapis.com \
--project=$(gcloud config get-value project)
Chat 用アプリを構成する
- Google Cloud コンソールで、Google Cloud 検索フィールドに
Google Chat APIを入力し、[Google Chat API]、[管理]、[構成] の順にクリックします。
- [アプリ名] と [説明] を
Gemini Enterpriseに設定します。 - [アバターの URL] を
https://developers.google.com/workspace/add-ons/images/quickstart-app-avatar.pngに設定します。 - [インタラクティブ機能を有効にする] の選択を解除し、表示されたモーダル ダイアログで [無効にする] をクリックします。
- [エラーを Logging に記録する] を選択します。
- [保存] をクリックします。

Vertex AI Agent Engine にエージェントをデプロイする
- この GitHub リポジトリをダウンロードします。
- ターミナルで
solutions/enterprise-ai-agentディレクトリを開き、次のコマンドを実行します。
# 1. Create and activate a new virtual environment python3 -m venv .venv source .venv/bin/activate # 2. Install poetry and project dependencies pip install poetry poetry install # 3. Deploy the agent adk deploy agent_engine \ --project=$(gcloud config get-value project) \ --region=us-central1 \ --display_name="Enterprise AI" \ enterprise_ai

- ログに「Deploying to agent engine...」という行が表示されたら、新しいターミナルを開き、次のコマンドを実行して、Vertex AI Reasoning Engine サービス エージェントに必要な権限を追加します。
# 1. Get the current Project ID
PROJECT_ID=$(gcloud config get-value project)
# 2. Extract the Project Number for that ID
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
# 3. Construct the Service Account name
SERVICE_ACCOUNT="service-${PROJECT_NUMBER}@gcp-sa-aiplatform-re.iam.gserviceaccount.com"
# 4. Apply the IAM policy binding
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT" \
--role="roles/discoveryengine.viewer"
- adk deploy コマンドが完了するまで待ち、コマンド出力の緑色の部分から、新しくデプロイされたエージェントのリソース名をコピーします。

Gemini Enterprise にエージェントを登録する
Cloud コンソールから新しいタブで Gemini Enterprise を開き、次の操作を行います。
codelabという名前のアプリをクリックします。- ナビゲーション メニューで [エージェント] をクリックします。
- [+ エージェントを追加] をクリックします。
- [Agent Engine によるカスタム エージェント] の [追加] をクリックします。[承認] セクションが表示されます。
- [承認を追加] をクリックします。
- [Authorization name] を
enterprise-aiに設定します。ID は名前に基づいて生成され、フィールドの下に表示されます。コピーします。 - [クライアント ID] に、前の手順で作成して更新した OAuth クライアントと同じ値を設定します。
- [クライアント シークレット] を、前の手順で作成して更新した OAuth クライアントと同じ値に設定します。
- [トークン URI] を
https://oauth2.googleapis.com/tokenに設定します。 - 前の手順で作成して更新した OAuth クライアント ID で <CLIENT_ID> を置き換えてから、[認可 URI] を次の値に設定します。
https://accounts.google.com/o/oauth2/v2/auth?client_id=<CLIENT_ID>&redirect_uri=https%3A%2F%2Fvertexaisearch.cloud.google.com%2Fstatic%2Foauth%2Foauth.html&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar.calendars%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar.events%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.send%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fchat.messages.create%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fchat.spaces.create&include_granted_scopes=true&response_type=code&access_type=offline&prompt=consent
- [完了]、[次へ] の順にクリックします。[構成] セクションが表示されます。
- [エージェント名] と [エージェントの説明] を
Enterprise AIに設定します。 - [Agent Engine 推論エンジン] を、前の手順でコピーした推論エンジンのリソース名に設定します。次の形式となります。
projects/<PROJECT_ID>/locations/<LOCATION>/reasoningEngines/<REASONING_ENGINE_ID>
- [作成] をクリックします。新しく追加されたエージェントが [エージェント] に表示されます。
エージェントを試す
- Gemini Enterprise ウェブアプリで、新しく登録したエージェントとチャットします。
- メニュー アイコン ☰ > [エージェント] をクリックします。
- [組織から] でエージェントを選択します。
- チャットで「
Please find my meetings for today, I need their titles and links」と入力し、enterキーを押します。 - [Authorize] をクリックし、認証フローに沿って操作します。

- エージェントは、カレンダーの予定のリストで回答します(ユーザーのアカウントによって異なります)。
- チャットで「
Please send a Chat message to someone@example.com with the following text: Hello!」と入力し、enterキーを押します。 - エージェントが確認メッセージで回答します。


5. デフォルト エージェントとしての Google Workspace アドオン
このエージェントを使用すると、ユーザーは Workspace アプリの UI のコンテキストで、Workspace のデータを自然言語で検索できます。次の要素に依存します。
- モデル: Gemini。
- データ: Google Workspace(カレンダー、Gmail、ドライブ、NotebookLM)用の Gemini Enterprise データストア、Google 検索。
- エージェント ホスト: Gemini Enterprise。
- UI: Chat と Gmail 用の Google Workspace アドオン(カレンダー、ドライブ、ドキュメント、スプレッドシート、スライドにも簡単に拡張可能)。
- Google Workspace アドオン: Apps Script、Gemini Enterprise と Vertex AI の API、コンテキスト(ユーザー メタデータ、選択した Gmail メッセージ)。
Google Workspace アドオンは、StreamAssist API を使用して Gemini Enterprise に接続されます。
コンセプトを確認する
Google Workspace アドオン
Google Workspace アドオンは、1 つ以上の Google Workspace アプリケーション(Gmail、Chat、カレンダー、ドキュメント、ドライブ、Meet、スプレッドシート、スライド)を拡張するカスタマイズされたアプリケーションです。
Apps Script
Apps Script は、Google ドライブを基盤とするクラウドベースの JavaScript プラットフォームで、Google プロダクト全体でタスクの統合と自動化を可能にします。
Google Workspace カード フレームワーク
Google Workspace のカード フレームワークを使用すると、デベロッパーはリッチでインタラクティブなユーザー インターフェースを作成できます。テキスト、画像、ボタンなどのウィジェットを含めることができる、整理された視覚的に魅力的なカードを構築できます。これらのカードは、構造化された情報を提供し、Workspace アプリケーション内で直接クイック アクションを実行できるようにすることで、ユーザー エクスペリエンスを向上させます。
ソリューション アーキテクチャを確認する

ソースコードを確認する
appsscript.json
...
"addOns": {
"common": {
"name": "Enterprise AI",
"logoUrl": "https://developers.google.com/workspace/add-ons/images/quickstart-app-avatar.png"
},
"chat": {},
"gmail": {
"contextualTriggers": [
{
"unconditional": {},
"onTriggerFunction": "onAddonEvent"
}
]
}
},
"oauthScopes": [
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/discoveryengine.assist.readwrite",
"https://www.googleapis.com/auth/gmail.addons.execute",
"https://www.googleapis.com/auth/gmail.addons.current.message.readonly"
]
...
Chat.gs
...
// Service that handles Google Chat operations.
// Handle incoming Google Chat message events, actions will be taken via Google Chat API calls
function onMessage(event) {
if (isInDebugMode()) {
console.log(`MESSAGE event received (Chat): ${JSON.stringify(event)}`);
}
// Extract data from the event.
const chatEvent = event.chat;
setChatConfig(chatEvent.messagePayload.space.name);
// Request AI agent to answer the message
requestAgent(chatEvent.messagePayload.message);
// Respond with an empty response to the Google Chat platform to acknowledge execution
return null;
}
// --- Utility functions ---
// The Chat direct message (DM) space associated with the user
const SPACE_NAME_PROPERTY = "DM_SPACE_NAME"
// Sets the Chat DM space name for subsequent operations.
function setChatConfig(spaceName) {
const userProperties = PropertiesService.getUserProperties();
userProperties.setProperty(SPACE_NAME_PROPERTY, spaceName);
console.log(`Space is set to ${spaceName}`);
}
// Retrieved the Chat DM space name to sent messages to.
function getConfiguredChat() {
const userProperties = PropertiesService.getUserProperties();
return userProperties.getProperty(SPACE_NAME_PROPERTY);
}
// Finds the Chat DM space name between the Chat app and the given user.
function findChatAppDm(userName) {
return Chat.Spaces.findDirectMessage(
{ 'name': userName },
{'Authorization': `Bearer ${getAddonCredentials().getAccessToken()}`}
).name;
}
// Creates a Chat message in the configured space.
function createMessage(message) {
const spaceName = getConfiguredChat();
console.log(`Creating message in space ${spaceName}...`);
return Chat.Spaces.Messages.create(
message,
spaceName,
{},
{'Authorization': `Bearer ${getAddonCredentials().getAccessToken()}`}
).name;
}
Sidebar.gs
...
// Service that handles Gmail operations.
// Triggered when the user opens the Gmail Add-on or selects an email.
function onAddonEvent(event) {
// If this was triggered by a button click, handle it
if (event.parameters && event.parameters.action === 'send') {
return handleSendMessage(event);
}
// Otherwise, just render the default initial sidebar
return createSidebarCard();
}
// Creates the standard Gmail sidebar card consisting of a text input and send button.
// Optionally includes an answer section if a response was generated.
function createSidebarCard(optionalAnswerSection) {
const card = CardService.newCardBuilder();
const actionSection = CardService.newCardSection();
// Create text input for the user's message
const messageInput = CardService.newTextInput()
.setFieldName("message")
.setTitle("Message")
.setMultiline(true);
// Create action for sending the message
const sendAction = CardService.newAction()
.setFunctionName('onAddonEvent')
.setParameters({ 'action': 'send' });
const sendButton = CardService.newTextButton()
.setText("Send message")
.setTextButtonStyle(CardService.TextButtonStyle.FILLED)
.setOnClickAction(sendAction);
actionSection.addWidget(messageInput);
actionSection.addWidget(CardService.newButtonSet().addButton(sendButton));
card.addSection(actionSection);
// Attach the response at the bottom if we have one
if (optionalAnswerSection) {
card.addSection(optionalAnswerSection);
}
return card.build();
}
// Handles clicks from the Send message button.
function handleSendMessage(event) {
const commonEventObject = event.commonEventObject || {};
const formInputs = commonEventObject.formInputs || {};
const messageInput = formInputs.message;
let userMessage = "";
if (messageInput && messageInput.stringInputs && messageInput.stringInputs.value.length > 0) {
userMessage = messageInput.stringInputs.value[0];
}
if (!userMessage || userMessage.trim().length === 0) {
return CardService.newActionResponseBuilder()
.setNotification(CardService.newNotification().setText("Please enter a message."))
.build();
}
let finalQueryText = `USER MESSAGE TO ANSWER: ${userMessage}`;
// If we have an email selected in Gmail, append its content as context
if (event.gmail && event.gmail.messageId) {
try {
GmailApp.setCurrentMessageAccessToken(event.gmail.accessToken);
const message = GmailApp.getMessageById(event.gmail.messageId);
const subject = message.getSubject();
const bodyText = message.getPlainBody() || message.getBody();
finalQueryText += `\n\nEMAIL THE USER HAS OPENED ON SCREEN:\nSubject: ${subject}\nBody:\n---\n${bodyText}\n---`;
} catch (e) {
console.error("Could not fetch Gmail context: " + e);
// Invalidate the token explicitly so the next prompt requests the missing scopes
ScriptApp.invalidateAuth();
CardService.newAuthorizationException()
.setResourceDisplayName("Enterprise AI")
.setAuthorizationUrl(ScriptApp.getAuthorizationUrl())
.throwException();
}
}
try {
const responseText = queryAgent({ text: finalQueryText, forceNewSession: true });
// We leverage the 'showdown' library to parse the LLM's Markdown output into HTML
// We also substitute markdown listings with arrows and adjust newlines for clearer rendering in the sidebar
let displayedText = substituteListingsFromMarkdown(responseText);
displayedText = new showdown.Converter().makeHtml(displayedText).replace(/\n/g, '\n\n');
const textParagraph = CardService.newTextParagraph();
textParagraph.setText(displayedText);
const answerSection = CardService.newCardSection()
.addWidget(textParagraph);
const updatedCard = createSidebarCard(answerSection);
return CardService.newActionResponseBuilder()
.setNavigation(CardService.newNavigation().updateCard(updatedCard))
.build();
} catch (err) {
return CardService.newActionResponseBuilder()
.setNotification(CardService.newNotification().setText("Error fetching response: " + err.message))
.build();
}
}
...
AgentHandler.gs
...
// Service that handles Gemini Enterprise AI Agent operations.
// Submits a query to the AI agent and returns the response string synchronously
function queryAgent(input) {
const isNewSession = input.forceNewSession || !PropertiesService.getUserProperties().getProperty(AGENT_SESSION_NAME);
const sessionName = input.forceNewSession ? createAgentSession() : getOrCreateAgentSession();
let systemPrompt = "SYSTEM PROMPT START Do not respond with tables but use bullet points instead.";
if (input.forceNewSession) {
systemPrompt += " Do not ask the user follow-up questions or converse with them as history is not kept in this interface.";
}
systemPrompt += " SYSTEM PROMPT END\n\n";
const queryText = isNewSession ? systemPrompt + input.text : input.text;
const requestPayload = {
"session": sessionName,
"userMetadata": { "timeZone": Session.getScriptTimeZone() },
"query": { "text": queryText },
"toolsSpec": { "vertexAiSearchSpec": { "dataStoreSpecs": getAgentDataStores().map(ds => { dataStore: ds }) } },
"agentsSpec": { "agentSpecs": [{ "agentId": getAgentId() }] }
};
const responseContentText = UrlFetchApp.fetch(
`https://${getLocation()}-discoveryengine.googleapis.com/v1alpha/${getReasoningEngine()}/assistants/default_assistant:streamAssist?alt=sse`,
{
method: 'post',
headers: { 'Authorization': `Bearer ${ScriptApp.getOAuthToken()}` },
contentType: 'application/json',
payload: JSON.stringify(requestPayload),
muteHttpExceptions: true
}
).getContentText();
if (isInDebugMode()) {
console.log(`Response: ${responseContentText}`);
}
const events = responseContentText.split('\n').map(s => s.replace(/^data:\s*/, '')).filter(s => s.trim().length > 0);
console.log(`Received ${events.length} agent events.`);
let answerText = "";
for (const eventJson of events) {
if (isInDebugMode()) {
console.log("Event: " + eventJson);
}
const event = JSON.parse(eventJson);
// Ignore internal events
if (!event.answer) {
console.log(`Ignored: internal event`);
continue;
}
// Handle text replies
const replies = event.answer.replies || [];
for (const reply of replies) {
const content = reply.groundedContent.content;
if (content) {
if (isInDebugMode()) {
console.log(`Processing content: ${JSON.stringify(content)}`);
}
if (content.thought) {
console.log(`Ignored: thought event`);
continue;
}
answerText += content.text;
}
}
if (event.answer.state === "SUCCEEDED") {
console.log(`Answer text: ${answerText}`);
return answerText;
} else if (event.answer.state !== "IN_PROGRESS") {
throw new Error("Something went wrong, check the Apps Script logs for more info.");
}
}
return answerText;
}
// Gets the list of data stores configured for the agent to include in the request.
function getAgentDataStores() {
const responseContentText = UrlFetchApp.fetch(
`https://${getLocation()}-discoveryengine.googleapis.com/v1/${getReasoningEngine().split('/').slice(0, 6).join('/')}/dataStores`,
{
method: 'get',
// Use the add on service account credentials for data store listing access
headers: { 'Authorization': `Bearer ${getAddonCredentials().getAccessToken()}` },
contentType: 'application/json',
muteHttpExceptions: true
}
).getContentText();
if (isInDebugMode()) {
console.log(`Response: ${responseContentText}`);
}
const dataStores = JSON.parse(responseContentText).dataStores.map(ds => ds.name);
if (isInDebugMode()) {
console.log(`Data stores: ${dataStores}`);
}
return dataStores;
}
...
サービス アカウントを開始する
Google Cloud コンソールで、次の手順を行います。
- メニュー アイコン ☰ > [IAM と管理] > [サービス アカウント] > [+ サービス アカウントを作成] をクリックします。
- [サービス アカウント名] を
ge-add-onに設定します。

- [作成して続行] をクリックします。
- 権限に ディスカバリー エンジン閲覧者ロールを追加します。

- [続行]、[完了] の順にクリックします。[サービス アカウント] ページにリダイレクトし、作成したサービス アカウントが表示されます。

- 新しく作成したサービス アカウントを選択し、[キー] タブを選択します。
- [鍵を追加]、[新しい鍵を作成] の順にクリックします。
- [JSON] を選択し、[作成] をクリックします。

- ダイアログが閉じ、新しく作成された公開鍵/秘密鍵ペアが JSON ファイルとしてローカル環境に自動的にダウンロードされます。
Apps Script プロジェクトを作成して構成する
- 次のボタンをクリックして、Enterprise AI アドオンの Apps Script プロジェクトを開きます。
- [概要] > [コピーを作成] をクリックします。
- Apps Script プロジェクトで、[プロジェクトの設定] > [スクリプトのプロパティを編集] > [スクリプトのプロパティを追加] の順にクリックして、スクリプトのプロパティを追加します。
- REASONING_ENGINE_RESOURCE_NAME を Gemini Enterprise アプリケーション リソース名に設定します。次の形式となります。
# 1. Replace PROJECT_ID with the Google Cloud project ID. # 2. Replace GE_APP_ID with the codelab app ID found in Google Cloud console > Gemini Enterprise > Apps. projects/<PROJECT_ID>/locations/global/collections/default_collection/engines/<GE_APP_ID>
- APP_SERVICE_ACCOUNT_KEY を、前の手順でダウンロードしたサービス アカウント ファイルの JSON キーに設定します。
- [スクリプト プロパティを保存] をクリックします。
Gmail と Chat にデプロイする
Apps Script プロジェクトで、次の手順を行います。
- [デプロイ] > [デプロイをテスト] をクリックし、[インストール] をクリックします。この機能が Gmail で利用できるようになりました。
- [Head Deployment ID] の [Copy] をクリックします。

Google Cloud コンソールで、次の手順を行います。
- Google Cloud の検索フィールドで
Google Chat APIを検索し、[Google Chat API]、[管理]、[構成] の順にクリックします。
- [インタラクティブ機能を有効にする] を選択します。
- [スペースとグループの会話に参加する] のチェックボックスをオフにします。
- [接続設定] で [Apps Script] を選択します。
- [Deployment ID] を、前の手順でコピーした [Head Deployment ID] に設定します。
- [公開設定] で、[Workspace ドメイン内の特定のユーザーとグループにこの Chat 用アプリの利用を許可する] を選択し、メールアドレスを入力します。
- [保存] をクリックします。

アドオンを試す
新しいタブで Google Chat を開き、次の手順を行います。
- Chat 用アプリの Gemini Enterprise とのダイレクト メッセージ スペースを開きます。

- [構成] をクリックして、認証フローを行います。
- 「
What are my meetings for today?」と入力してenterキーを押します。Gemini Enterprise チャットアプリが結果を返します。

新しいタブで Gmail を開き、次の手順を行います。
- 件名を
We need to talkに、本文をAre you available today between 8 and 9 AM?に設定して、自分宛てにメールを送信します。 - 受信したメールを開きます。
- [Enterprise AI] アドオンのサイドバーを開きます。
- [メッセージ] を
Am I?に設定します。 - [メッセージを送信] をクリックします。
- 答えはボタンの後に表示されます。

6. クリーンアップ
Google Cloud プロジェクトを削除する
この Codelab で使用したリソースに対して Google Cloud アカウントで課金されないようにするには、Google Cloud プロジェクトを削除することをおすすめします。
Google Cloud コンソールで、次の手順を行います。
- メニュー アイコン ☰ > [IAM と管理] > [設定] をクリックします。
- [シャットダウン] をクリックします。
- プロジェクト ID を入力します。
- [このままシャットダウン] をクリックします。

7. 完了
おめでとうございます!Gemini Enterprise と Google Workspace を連携させて、従業員向けのソリューションを構築しました。
次のステップ
この Codelab では最も一般的なユースケースのみを紹介しましたが、ソリューションはさまざまな形で拡張して使用できます。たとえば次のような例があります。
- Gemini CLI や Antigravity などの AI を活用したデベロッパー ツールを使用します。
- カスタム MCP、カスタム関数呼び出し、生成 UI などの他のエージェント フレームワークやツールと統合します。
- Vertex AI などの専用プラットフォームでホストされているカスタムを含む他の AI モデルと統合します。
- Dialogflow などの専用プラットフォームでホストされている他のエージェントや、Cloud Marketplace を介してサードパーティがホストしている他のエージェントと統合します。
- Cloud Marketplace でエージェントを公開して、チーム、組織、一般ユーザーを支援します。
その他の情報
YouTube 動画、ドキュメント ウェブサイト、コードサンプル、チュートリアルなど、さまざまなデベロッパー向けリソースがあります。
- Google Cloud Developer Center
- サポート対象のプロダクト | Google Cloud MCP サーバー
- A2UI
- Vertex AI の Model Garden | Google Cloud
- エージェントの概要 | Gemini Enterprise | Google Cloud ドキュメント
- Google Cloud Marketplace と Gemini Enterprise による AI エージェントのスケーリング
- Google Cloud Marketplace で AI エージェントを提供する
- Google Workspace デベロッパーの YouTube チャンネル - デベロッパーの皆様、ようこそ
- Google Workspace デベロッパー ウェブサイト
- すべての Google Workspace アドオン サンプルの GitHub リポジトリ

