この記事について
この記事では、Dialogflow CX を使用してデータストア参照型検索エージェントを作成するための調査内容や、その他の関連する調査結果をまとめています。
dialogflowCXの回答で使える変数について
- Dialogflow CX の「Agent Says」などで使用できるシステム変数を活用することで、ユーザーとのやり取りをより動的にすることができます。これらの変数は、データストアからの検索結果やユーザーの入力、セッション情報、ナレッジベースの詳細情報、日時関連など、様々な情報を参照する際に役立ちます。
システム変数の一覧
- ① データストアの検索結果
- 検索結果のテキスト内容:
$request.knowledge.answers[0]
→ データストアから取得した検索結果の内容が格納されている。 - 関連ファイルのリンク情報:
$request.knowledge.sources[0]
→ 検索結果に関連するファイルのリンク情報が入っている。
- 検索結果のテキスト内容:
- ② ユーザー入力関連
- ユーザーの発話内容:
$request.query
→ ユーザーが送信したメッセージの全文。 - 特定のパラメータ値:
$session.params.<パラメータ名>
→ フロー内で設定されたパラメータの値を取得できる。
- ユーザーの発話内容:
- ③ セッション情報
- セッションID:
$session.id
→ 現在の会話セッションの一意な識別子。 - ユーザー情dia報:
$session.params.userId
→ ユーザーIDなど、セッション内で保持されている情報。
- セッションID:
- ④ ナレッジベースの詳細情報
- タイトル情報:
$sys.func.GET_FIELD($sys.func.GET($request.knowledge.sources[0], 0), "title")
→ 検索結果のドキュメントのタイトルを取得。 - ドキュメントのURL:
$sys.func.GET_FIELD($sys.func.GET($request.knowledge.sources[0], 0), "uri")
→ ナレッジベースのドキュメントのリンクを取得。
- タイトル情報:
- ⑤ 日時関連
- 現在の日付:
$sys.date
→YYYY-MM-DD
形式で現在の日付を取得。 - 現在の時刻:
$sys.time
→HH:mm:ss
形式で現在の時刻を取得。
- 現在の日付:
参照記事
Dialogflow CX Webhook を使用して AI でテキスト生成をして回答を行うコード
- このコードは、Google Cloud Functions を利用して HTTP リクエストを受け取り、Vertex AI の Generative Model(Gemini)を使用してテキストを生成し、その結果を返す Webhook のコードです。良ければ参考にしてください。
webhook設定


requirements.txt
functions-framework==3.*
requests
google-cloud-aiplatform
vertexai
furl
google-cloud-storage
main.py
import functions_framework
import requests
import vertexai
import json
from vertexai.generative_models import GenerationConfig, GenerativeModel, Part
from furl import furl
from google.cloud import storage
from urllib.parse import urlparse
from pathlib import Path
def interview(project_id: str,location: str,model: str,text: str) -> str:
# Initialize Vertex AI
vertexai.init(project=project_id, location=location)
# Load the model
model = GenerativeModel(model_name=model)
# Generation Config
config = GenerationConfig(
max_output_tokens=2048, temperature=0.4, top_p=1, top_k=32
)
# Generate text
response = model.generate_content(
text, generation_config=config
)
return response.text
@functions_framework.http
def webhook(request):
response = request.get_json()
text = response["text"]
model = "gemini-1.5-flash-001"
output_text = interview("project_id","us-central1",model,text)
response["fulfillmentResponse"] = {
"messages": [
{
"text": {
"text": [
output_text
],
"allowPlaybackInterruption": False
}
}
]
}
print(json.dumps({"severity": "INFO", "message": response}))
return response
dialogflowCXのwebhookでリッチコンテンツを使ってみた。
リッチコンテンツとは
Dialogflow CX では、ボタン・画像・カードなどのインタラクティブな要素を含む応答フォーマットを使用でき、設定することで、利便性が向上します。
- やりたいこと
- URLをボタン式にして出力したい
- 試したこと
- webhookのresponse部分を下記のように設定して動作を確認する
- 結果
- 無事ボタン式で動作した
webhook設定


参照記事
リッチコンテンツを適用したwebhookのresponse設定部分
response["fulfillmentResponse"] = {
"messages": [ # Dialogflow CX のレスポンスメッセージ
{
"payload": { # メッセージのペイロード(リッチコンテンツを含む)
"richContent": [ # Dialogflow CX のリッチコンテンツ(複数の UI 要素をリストで管理)
[
{
"type": "info", # 情報カード(タイトル+説明文)
"title": "参照テキスト", # タイトル部分
"subtitle": "hello_test", # サブタイトル(追加説明)
},
{
"type": "button", # ボタン要素(クリック可能)
"icon": { # ボタンに表示するアイコン設定
"type": "chevron_right", # 矢印アイコン
"color": "#FF9800" # オレンジ色のアイコン
},
"text": "参照リンク", # ボタンに表示するテキスト
"link": "https://example.com" # ボタンをクリックしたときのリンク先
},
{
"type": "divider" # 区切り線(コンテンツの分割用)
}
]
]
}
}
]
}
データストアにアップロードしたGCSのファイルが文字化けする場合の対処法
- データストアにアップロードしたGCSのファイルをリンクから表示する際、文字化けが発生することがあります。これは、ファイル自体のエンコード設定の問題か、ブラウザのエンコード設定の問題が原因である可能性があります。このような問題を防ぐために、ファイルをGCSにアップロードする際にエンコード設定を適切に定義するコードをご紹介します。
- 使用ライブラリのインストール
pip install google-cloud-storage
- Google Cloudの認証について
storage.Client()
を使うには、Google Cloudの認証情報が必要です。認証にはサービスアカウントキーを使用します。手順としては以下の通りです。- Google Cloud Consoleでサービスアカウントを作成し、JSONキーをダウンロードします。
- 環境変数
GOOGLE_APPLICATION_CREDENTIALS
にダウンロードしたサービスアカウントキーのパスを設定します。
GCSへのアップコード
bucket_name = "" #アップ先バケット名
file_name = "" #アップ先ファイルディレクトリ
text = ""
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)
blob = bucket.blob(file_name)
blob.upload_from_string(text, content_type='text/plain; charset=UTF-8', timeout=300)
GCSからファイル取得コード
bucket_name = "" #アップ先バケット名
file_name = "" #アップ先ファイルディレクトリ
storage_client = storage.Client()
bucket = storage_client.get_bucket(bucket_name)
blob = storage.Blob(file_name, bucket)
content = blob.download_as_string().decode('utf-8')
Dialogflow CXのデータストア参照対話型エージェントのプロンプトで、データの文の区切りを認識させることはできるのか?
- やりたいこと
- データストアに .txt ファイルをアップロードし、Dialogflow CX のデータストア参照型対話エージェントで一文のみを参照して回答させたいが、実際には周囲の文章も含めて取得され、回答されてしまう。これを一文だけ参照して回答させることが可能かを、
Agent Settings > Gen AI > Datastore > カスタムプロンプト
のプロンプトで設定してみて確認したい。
- データストアに .txt ファイルをアップロードし、Dialogflow CX のデータストア参照型対話エージェントで一文のみを参照して回答させたいが、実際には周囲の文章も含めて取得され、回答されてしまう。これを一文だけ参照して回答させることが可能かを、
- 結果
- 下記のような指示文をプロンプトに追加してみたが、一文ごとに区切られることはなく、回答率が下がるだけだった。
ソースからユーザーのクエリに最も関連性の高い「一文」のみを抽出し、それ以外の文を含めずに回答してください。
文が長い場合でも、一つの完全な文のみを返してください。
回答に関係のない文を含めないでください。ソースから最も関連性の高い「一文」のみを抜き出して回答してください。
他の文や周囲の文脈を含めず、厳密に一文のみを抽出してください。ソース内で最も関連性の高い一文のみを抜き出して回答してください。他の文や前後の文脈を加えず、厳密に一文だけを提示してください。また、[。]は文の区切りを意味します
- ファイルの文章を「。」ではなく改行で区切るようにしたところ、一文だけを参照するようになった。しかし、参照部分が二つ以上の文に分かれている場合、参照されなくなってしまった。
- 下記のような指示文をプロンプトに追加してみたが、一文ごとに区切られることはなく、回答率が下がるだけだった。
Dialogflow CX のデータストアを参照する対話型エージェントが出力した、GCS のファイルの URL リンクで、テキストフラグメントが時々反映されない問題の原因
- Dialogflow CX で対話型エージェントがデータストアの検索結果として参照ファイルのリンク情報を出力した際に、通常はされるべきテキストフラグメントが反映されない場合の原因と解決策について紹介します。
テキストフラグメントの仕組みについて
#:~:text=キーワード
の形式で URL の末尾につけると、
ページ内の指定したキーワードの部分へ直接スクロール し、該当テキストがハイライトされます。
Chrome や Edge などの一部のブラウザで対応しています。
ほとんどのテキストフラグメントが反映されない原因と解決策
- 原因
- 空白や改行の違いにより、テイストフラグメントの文とGCS内のファイルの文が一致せず、ハイライトされない問題が発生する事がある
- テキストフラグメントには文字数制限があり、その制限を超えるとハイライトされなくなる。
- 解決策
- ファイルに改行や空白を含めない
- Webhookを使用して文字数を調整したり、テキストフラグメントの文とGCS内のテキストフラグメントの文の類似部分を取得し、それを基にテキストフラグメントの文を置き換えてDialogflow CXに結果を返すようにするなど
dialogflowCXの対話型エージェントに紐づけるデータストアにBigQueryのデータは入れられるのか?
- やりたいこと
- Dialogflow CX の対話型エージェントに紐づけるデータストアとして、BigQuery(BQ)のデータをアップロードできるか確認したい。
- 試したこと
- Dialogflow CX の対話型エージェントに接続可能な以下の 3 つのデータストア形式に、BQ のデータをアップロードできるか検証した。
- 非構造化ドキュメント(PDF、HTML、TXT など) → アップロード不可
- リンクされた非構造化ドキュメント(JSONL とメタデータ) → アップロード不可
- チャットアプリケーション用のよくある質問の構造化データ(CSV) → アップロード不可
- また、エージェントに紐づける前に、BQ の以下の 5 種類のデータストアを作成し、それぞれに JSON や CSV を格納して検証したが、対話型エージェントとの接続はできなかった。
- Structured – BigQuery table with your own schema
Structured with metadata – BigQuery table with metadata
メディア – 構造化メディアデータが格納された BigQuery テーブル
Unstructured – BigQuery table with metadata
Healthcare – BigQuery table with structured healthcare data
- Structured – BigQuery table with your own schema
- Dialogflow CX の対話型エージェントに接続可能な以下の 3 つのデータストア形式に、BQ のデータをアップロードできるか検証した。
エージェントに紐づいているデータストアは削除できるのか?
- やりたいこと
- エージェントに紐づいているデータストアを削除できるのかを検証する
- 試したこと
- 設定や記事を詳しく確認
- データストアを削除するコードを使ってみる
- 結果
- 設定には該当する項目が見当たらなかった。
- 発見した記事には、以下のように記載されていた。
「アプリに接続されているデータストアは削除できません。データストアがアプリに接続されている場合は、そのアプリを削除する必要があります。」 - データストアを削除するコードを実行したところ、データストアがアプリに紐付いているため削除できないというエラーが発生した。
データストアのファイルを削除する際に使用したサンプルコードが掲載されている記事。
2.5MB以上のファイルを、Dialogflow CXで利用可能なすべてのデータストアに登録し、それぞれのデータストアで受け入れ可能かを検証した結果、どのファイル形式が2.5MB以上のサイズでも登録可能であるかを確認する。
- やりたいこと
- 2.5MB以上のTXT、JSON、HTML、PDF、CSV形式のファイルを、Dialogflow CXに紐づけられるすべての形式のデータストアに登録し検証した結果、どのファイル形式がどのデータストアで2.5MB以上のサイズでも通るのかを確認しました。
- 検証方法
- dialogflowCXと紐づけられていない状態のデータストアにファイルを追加して検証。
- データを登録した後、Dialogflow CXと紐づけられることを確認。
- 既にDialogflow CXと紐づけられたデータストアにファイルを追加して検証。
- dialogflowCXと紐づけられていない状態のデータストアにファイルを追加して検証。
検証結果
dialogflow CXに紐づけられていない状態のデータストア
非構造化ドキュメント(PDF、HTML、TXT など)
結果: PDFのみ2.5MB以上が通った
リンクされた非構造化ドキュメント(JSONL とメタデータ)
結果: PDFのみ2.5MBが通った
チャット アプリケーション用のよくある質問の構造化データ(CSV)
結果: CSVのみ項目ごとに分割されファイル化されたが通った
ファイルをアップロードした後、すべてのデータストアが Dialogflow CX と紐づけられた。
既にDialogflow CXと紐づけられたデータストア
非構造化ドキュメント(PDF、HTML、TXT など)
結果: PDFのみ2.5MB以上のファイルが通った
リンクされた非構造化ドキュメント(JSONL とメタデータ)
結果: PDFもその他も通らなかった
チャット アプリケーション用のよくある質問の構造化データ(CSV)
結果: CSVのみ項目ごとに分割されファイル化されたが通った
全体的な結果まとめ
- PDFとCSVはそれぞれの方法で2.5MB以上でも読み込めることが確認できた。
- エージェントに紐づけられていない状態では、リンクされた非構造化ドキュメントでもPDFが通った。
しかし、エージェントに紐づけられた状態で作成した場合、リンクされた非構造化ドキュメントではPDFも通らなくなる傾向があった。
PDFをテキスト化するおすすめのAPI「Document AI」
- PDFをテキスト化できるAPIを探していたところ、「Document AI」を見つけました。試した結果、高精度でテキストを取得できたので、共有しておきます。
参考記事


GCS へフォルダ構造を維持したままアップロードおよびダウンロードを行うコード。
os.walk()
を使い、GCSにフォルダ構造を維持したまま アップロードするコードとダウンロードするPythonコードを共有しておきます。
GCSへのアップロードコード
from google.cloud import storage
import os
def upload_folder_with_structure(bucket_name, local_folder, destination_folder=""):
"""フォルダ自体を含めてGCSにアップロード"""
client = storage.Client()
bucket = client.bucket(bucket_name)
# アップロードするフォルダの名前を取得
folder_name = os.path.basename(os.path.normpath(local_folder))
for root, _, files in os.walk(local_folder):
for file_name in files:
local_path = os.path.join(root, file_name)
# `local_folder` を基準にした相対パスを取得し、その前にフォルダ名を追加
relative_path = os.path.relpath(local_path, local_folder)
gcs_path = os.path.join(destination_folder, folder_name, relative_path).replace("\\", "/") # Windows対策
blob = bucket.blob(gcs_path)
blob.upload_from_filename(local_path)
print(f"Uploaded {local_path} to gs://{bucket_name}/{gcs_path}")
# 使用例
bucket_name = "your-bucket-name"
local_folder = "path/to/local/folder"
gcs_folder = "your-gcs-folder" # 空文字ならGCSのルートにアップロード
upload_folder_with_structure(bucket_name, local_folder, gcs_folder)
GCSからのダウンロードコード
from google.cloud import storage
import os
def download_folder_from_gcs(bucket_name, gcs_folder, local_folder):
"""GCSのフォルダをローカルにフォルダ構造を維持したままダウンロード"""
client = storage.Client()
bucket = client.bucket(bucket_name)
# GCSのフォルダ内のオブジェクト一覧を取得
blobs = bucket.list_blobs(prefix=gcs_folder)
for blob in blobs:
# GCS上のパスをローカルのパスに変換
relative_path = os.path.relpath(blob.name, gcs_folder).lstrip("/")
local_path = os.path.join(local_folder, relative_path)
# フォルダ構造を作成
os.makedirs(os.path.dirname(local_path), exist_ok=True)
# ファイルをダウンロード
blob.download_to_filename(local_path)
print(f"Downloaded gs://{bucket_name}/{blob.name} to {local_path}")
# 使用例
bucket_name = "your-bucket-name"
gcs_folder = "your-gcs-folder/local-folder" # ダウンロードしたいGCSフォルダ
local_folder = "path/to/local/destination" # 保存先のローカルフォルダ
download_folder_from_gcs(bucket_name, gcs_folder, local_folder)
os.walk()参照記事

まとめ
Dialogflow CX で使えるシステム変数について
- データストアの検索結果を取得する
$request.knowledge.answers[0]
や、
ユーザー入力やセッション情報を取得する$request.query
$session.params.<パラメータ名>
などのシステム変数について紹介した
Dialogflow CX Webhook を使用して AI でテキスト生成をして回答を行うコード
- Dialogflow CX の webhook機能を使ってGoogle Cloud Functions で HTTP リクエストを処理し、Gemini でテキスト生成を行うサンプルコードを紹介した
Dialogflow CX の Webhook でリッチコンテンツを使ってみた
- Dialogflow CX のリッチコンテンツ(ボタン・カード・画像など)についてや、
- リッチコンテンツを適用した Google Cloud Functions の response 部分のサンプルを紹介した。
Dialogflow CX のデータストアにアップロードした GCS のファイルが文字化けする場合の対処法
- GCSにアップロードしたファイルが文字化けするほとんどの原因は、エンコード設定の不一致で。アップロード時とダウンロード時にフォーマットを明示的に指定することで回避可能。サンプルコードも記載しています。
Dialogflow CX のデータストア参照対話型エージェントのプロンプトで、データの文の区切りを認識させることはできるのか?
- Dialogflow CX のデータストア参照型対話エージェントで、一文のみを参照して回答させる設定を試みたが、周囲の文も含まれてしまう問題が発生。
- プロンプトで「一文のみを抽出する」指示を追加 → 効果なし、回答率低下
- 「。」ではなく改行で区切る → 一文のみ参照されるが、参照部分が複数文に分かれると取得されない
Dialogflow CX のデータストアを参照する対話型エージェントが出力した GCS のファイルの URL リンクで、テキストフラグメントが時々反映されない問題の原因
- 大半の原因は、空白や改行の違いによりテキストフラグメントがGCS内のテキストと一致しないことや、文字数制限を超えてハイライトが無効になることだった。
- その対策として、ファイル内の改行や空白を最小限に抑えるほか、Webhookを使用して文字数を調整し、GCS内の類似テキストを基にフラグメントを最適化する方法がある。
Dialogflow CX の対話型エージェントに紐づけるデータストアに BigQuery のデータは入れられるのか?
- 検証した範囲内でアップロードはできなかった
エージェントに紐づいているデータストアを削除する方法
- 検証した範囲内では紐づいているエージェントがある場合、削除は不可、
先にエージェントを削除する必要があった。
2.5MB 以上のファイルを Dialogflow CX で利用可能なすべてのデータストアに登録し、それぞれのデータストアで受け入れ可能かを検証した結果、どのファイル形式が 2.5MB
以上のサイズでも登録可能であるかを確認する
- PDFとCSVは登録可能(CSVは分割される)リンクされた非構造化ドキュメント(JSONLなど)は2.5MB以上が通らない。エージェントと未紐づけのデータストアではPDFが通過するが、紐づけ後は通らなくなる傾向あり
PDF をテキスト化するおすすめの API「Document AI」
- PDFをテキスト化するうえでおすすめのAPIを紹介しました。
GCS へフォルダ構造を維持したままアップロードおよびダウンロードを行うコード
- GCS へフォルダ構造を維持したままアップロードおよびダウンロードを行うサンプルコードを紹介しました。