メインコンテンツへスキップ
RFPに回答するには、散在するドキュメントやSlackのスレッド、社内の暗黙知をくまなく調べ、正しい答えを見つけ出さなければならないことがよくあります。営業担当者は、社内のどこかに既に存在する回答を書き直すだけで何時間も無駄にしてしまうことがあります。さらに悪いことに、推測に頼って不正確な情報を取り込んでしまうことさえあります。 このチュートリアルでは、Boxを活用したセルフサービスのRFP回答集を構築します。
  1. 営業チームが、承認済みの提案書やRFPへの回答を厳選します。
  2. アプリケーションがHubs APIを使用してSales Hubをセットアップし、そのコンテンツにインデックスを作成して、HubポータルをCRMに埋め込みます。
  3. 営業担当者はBox AIを使用して自然言語でHubにクエリを実行し、権限が管理された承認済みコンテンツに基づく正確な回答を得ることができます。

構築する内容

このチュートリアルの最後には、次の機能を備えた実用的な統合ソリューションが完成します。
  • Box Hubs APIを使用して、Sales Hubをプログラムからプロビジョニングする。
  • 承認済みRFPコンテンツを含む厳選されたフォルダをHubに追加する。
  • HubのAIチャットインターフェースをCRMに埋め込む。
  • Box AIを使用してHubに対してクエリを実行し、承認済みのコンテンツに基づいて営業に関する質問に回答する。

前提条件

始める前に、以下が揃っていることを確認してください。
  • で、Box Hubsが有効になっていること。c2>Box Hubsの構成</c2>を参照してください。
  • Boxアプリケーションで、クライアント資格情報許可認証が構成され、[ユーザーアクセストークンを生成する] が有効になっていること。
  • Python 3.11以上。
  • アプリで以下のスコープが有効になっていること。
    • Boxに格納されているすべてのファイルとフォルダの読み取り
    • Boxに格納されているすべてのファイルとフォルダへの書き込み
    • AIを管理する
  • BoxユーザーID (管理コンソールの [ユーザー] で確認できます)。

手順

このソリューションでは、以下に示す3つのBox Platform機能を組み合わせます。
コンポーネント目的API
Hub厳選されたコンテンツにインデックスを作成し、検索可能で権限が継承されたポータルに集約するPOST /2.0/hubs
Hubの項目フォルダやファイルをHubに追加するPOST /2.0/hubs/:id/manage_items
Box AIHubコンテンツに基づいて、自然言語の質問に回答するPOST /2.0/ai/ask
Box Hubsは、基になるソースファイルの権限を継承します。営業担当者には、Box内で既にアクセス権限を持つコンテンツから派生した回答のみが表示されます。別途、アクセス制御レイヤーを用意する必要はありません。
1

BoxでのRFPコンテンツの整理

統合を構築する前に、承認済みの営業コンテンツを整理しておきます。フォルダ構造が整理されていると、Box AIの回答品質とコンテンツガバナンスの両方が改善されます。Box内に以下のようなフォルダ構造を作成するか、ご自身のBoxアカウントにこの共有フォルダをコピーします。このフォルダには、以下に示す各サブフォルダ用のサンプルファイルが含まれています。
Sales Content/
├── RFP Responses/
│   ├── 2025-Q1-Acme-RFP-Response.pdf
│   ├── 2024-Q4-Enterprise-Security-RFP.docx
│   └── 2024-Q3-Healthcare-Compliance-RFP.pdf
├── Proposals/
│   ├── Enterprise-Platform-Proposal-Template.docx
│   └── Mid-Market-Proposal-Template.docx
├── Competitive Intelligence/
│   ├── Competitor-Comparison-Matrix.xlsx
│   └── Win-Loss-Analysis-Q1-2025.pdf
└── Pricing/
    ├── Enterprise-Pricing-Guide.pdf
    └── Volume-Discount-Schedule.xlsx
最上位のSales Contentフォルダおよび各サブフォルダのフォルダIDをメモしておいてください。これらは、Hubに項目を追加する際に使用します。
認証済みユーザーがこのコンテンツにアクセスできることを確認してください。このチュートリアルではuser_idを用いたCCGを使用しているため、クライアントはその特定のユーザーとして動作します。このユーザーは、Hubに追加する予定のすべてのフォルダに対して、少なくともビューアーの権限を持っている必要があります。サービスアカウント (user_idではなくenterprise_id) を使用している場合は、そのサービスアカウントのメールアドレスを、フォルダのコラボレータとして招待する必要があります。サービスアカウントのメールアドレスを確認するには、開発者コンソールに移動し、アプリを開いて、[アプリの詳細] の下のサービスアカウントIDを表示します (AutomationUser_xxxxx_xxxxxx@boxdevedition.comのような形式になっています)。
コンテンツは厳選し、最新の状態に保ってください。Box AIの回答の質は、情報源の質に直接左右されます。古くなった提案書は削除し、廃止された価格表はアーカイブしてください。
2

開発環境のセットアップ

  1. ターミナルを開き、新しいプロジェクトディレクトリを作成します。
mkdir sales-rfp-hub && cd sales-rfp-hub
  1. Pythonの仮想環境を作成してアクティブ化します。
python3 -m venv .venv
source .venv/bin/activate
アクティブ化すると、ターミナルのプロンプトの先頭に(.venv)と表示されます。これにより、仮想環境内で作業していることがわかります。
新しいターミナルウィンドウやタブを開くたびに、プロジェクトディレクトリからsource .venv/bin/activateを実行して、仮想環境を再アクティブ化する必要があります。コマンドの実行中にModuleNotFoundErrorが表示される場合、通常、venvがアクティブ化されていないことを意味します。
  1. 必要なパッケージをインストールします。
pip install box-sdk-gen python-dotenv
  1. 資格情報を保存するための.envファイルを作成し、以下の内容を追加します。プレースホルダの値を、Box開発者コンソールで確認した実際の資格情報で置き換えます。
BOX_CLIENT_ID=your_client_id
BOX_CLIENT_SECRET=your_client_secret
BOX_USER_ID=your_box_user_id
SALES_CONTENT_FOLDER_ID=your_sales_content_folder_id
.envファイルはバージョン管理システムにコミットさせないでください。.env.gitignoreに追加します。
環境変数の理解: .envファイルには機密情報 (実際の資格情報) が保存されています。Pythonコードは、os.getenv("VARIABLE_NAME")を使用してこれらの名前を参照することで、その値を読み取ります。たとえばos.getenv("BOX_CLIENT_ID")を実行すると、.envファイル内のBOX_CLIENT_ID=の隣に保存されている値を検索します。以下の手順でコードをコピーする際は、引用符で囲まれた変数名をそのまま正確に保持してください。実際の資格情報に置き換えないでください。
3

Boxクライアントの認証

プロジェクトディレクトリにbox_client.pyという名前の新しいファイルを作成します。そのファイルを開き、以下のコードを貼り付けます。
import os
from box_sdk_gen import (
    BoxClient,
    BoxCCGAuth,
    CCGConfig,
)

def get_box_client() -> BoxClient:
    config = CCGConfig(
        client_id=os.getenv("BOX_CLIENT_ID"),
        client_secret=os.getenv("BOX_CLIENT_SECRET"),
        user_id=os.getenv("BOX_USER_ID"),
    )
    auth = BoxCCGAuth(config=config)
    return BoxClient(auth=auth)
このチュートリアルでは (enterprise_idではなく) user_idを使用して、特定のBoxユーザーとして認証を受けます。これにより、クライアントはそのユーザーが持つ権限を使用して動作し、そのユーザーが招待されているコンテンツにアクセスできるようになります。ユーザーIDは、管理コンソールの [ユーザー] で確認するか、Boxウェブアプリで自分のアバターをクリックしてURLを確認してください。
エンドユーザーが関与しないサーバー間の自動化には、クライアント資格情報許可をお勧めします。アプリの構成で、[ユーザーアクセストークンを生成] が有効になっていることを確認します。その他の認証オプションについては、 を参照してください。
4

Sales Hubのプロビジョニング

create_hub.pyという名前のファイルを作成します。このスクリプトにより、新しいHubが作成され、その中に営業コンテンツのフォルダが配置されます。
import os
from dotenv import load_dotenv
from box_sdk_gen import (
    BoxClient,
    FolderReferenceV2025R0,
    HubItemOperationV2025R0,
    HubItemOperationV2025R0ActionField,
)

from box_client import get_box_client

load_dotenv()

def create_sales_hub(client: BoxClient) -> str:
    hub = client.hubs.create_hub_v2025_r0(
        "Sales RFP Answer Bank",
        description=(
            "Curated library of approved proposals, RFP responses, "
            "competitive intelligence, and pricing materials for the sales team."
        ),
    )

    print(f"Created hub: {hub.title} (ID: {hub.id})")
    return hub.id

def add_content_to_hub(
    client: BoxClient, hub_id: str, folder_id: str
):
    client.hub_items.manage_hub_items_v2025_r0(
        hub_id,
        operations=[
            HubItemOperationV2025R0(
                action=HubItemOperationV2025R0ActionField.ADD,
                item=FolderReferenceV2025R0(id=folder_id),
            )
        ],
    )
    print(f"Added folder {folder_id} to hub {hub_id}")

def main():
    client = get_box_client()

    hub_id = create_sales_hub(client)

    sales_folder_id = os.getenv("SALES_CONTENT_FOLDER_ID")
    add_content_to_hub(client, hub_id, sales_folder_id)

    print(f"\nSales Hub ready. Hub ID: {hub_id}")
    print("Share this hub with your sales team or embed it in your CRM.")

if __name__ == "__main__":
    main()
スクリプトを実行します:
python create_hub.py
Hubが作成され、コンテンツが追加されたことを確認するメッセージが表示されます。メッセージに表示されたHub IDを記録しておきます。これは後の手順で必要になります。
最上位フォルダを追加すると、そのフォルダ内のすべてのファイル (サブフォルダ内のファイルも含む) に自動的にインデックスが作成されます。Box内のそれらのフォルダに新しいファイルが追加されると、Hubのコンテンツも自動的に更新されます。
5

Hubへのアクセス管理

コラボレーションを追加することで、Sales Hubにアクセスできるユーザーを管理します。これにより、適切なユーザーのみがコンテンツにクエリを実行できることを確認できます。manage_access.pyという名前のファイルを作成します。
from dotenv import load_dotenv
from box_sdk_gen import (
    BoxClient,
    CreateHubCollaborationV2025R0Hub,
    CreateHubCollaborationV2025R0AccessibleBy,
)

from box_client import get_box_client

load_dotenv()

def add_hub_collaborator(
    client: BoxClient,
    hub_id: str,
    user_email: str,
    role: str = "viewer",
):
    collaboration = client.hub_collaborations.create_hub_collaboration_v2025_r0(
        CreateHubCollaborationV2025R0Hub(id=hub_id),
        CreateHubCollaborationV2025R0AccessibleBy(
            type="user", login=user_email
        ),
        role,
    )
    print(f"Added {user_email} as {role} to hub {hub_id}")
    return collaboration

def main():
    client = get_box_client()

    hub_id = "YOUR_HUB_ID"  # Replace with the hub ID from Step 4

    sales_reps = [
        "rep1@example.com",
        "rep2@example.com",
    ]

    for email in sales_reps:
        add_hub_collaborator(client, hub_id, email, role="viewer")

if __name__ == "__main__":
    main()
コンテンツの照会のみを行う営業担当者にはviewerの役割を使用し、ライブラリの内容を厳選する営業マネージャーにはeditorを使用します。利用可能なすべての役割の詳細については、を参照してください。
6

Box AIを使用したHubへのクエリ実行

この統合の最大の強みは、営業担当者が厳選されたコンテンツに対して自然言語で質問できる点にあります。query_hub.pyという名前のファイルを作成します。
from dotenv import load_dotenv
from box_sdk_gen import (
    BoxClient,
    CreateAiAskMode,
    AiItemAsk,
)

from box_client import get_box_client

load_dotenv()

def ask_sales_question(
    client: BoxClient, hub_id: str, question: str
) -> str:
    response = client.ai.create_ai_ask(
        mode=CreateAiAskMode.SINGLE_ITEM_QA,
        prompt=question,
        items=[
            AiItemAsk(
                type="hubs",
                id=hub_id,
            )
        ],
    )

    return response.answer

def main():
    client = get_box_client()

    hub_id = "YOUR_HUB_ID"  # Replace with the hub ID from Step 4

    questions = [
        "What is our standard SLA for enterprise support?",
        "How do we handle data residency requirements for EU customers?",
        "What security certifications do we hold?",
        "What discount tiers are available for 500+ seat deals?",
    ]

    for question in questions:
        print(f"\nQ: {question}")
        answer = ask_sales_question(client, hub_id, question)
        print(f"A: {answer}")

if __name__ == "__main__":
    main()
以下を実行します。
python query_hub.py
Box AIは、インデックスが作成されたHubコンテンツを検索し、承認済みの資料に基づいて回答を返します。HubはBoxの権限を引き継いでいるため、AIはクエリを実行したユーザーがアクセス権限を持つドキュメントのみを参照します。この時点でプロジェクトディレクトリには、以下のファイルが含まれていることになります。
sales-rfp-hub/
├── .env
├── .venv/
├── box_client.py
├── create_hub.py
├── manage_access.py
└── query_hub.py
7

統合のテスト

本番環境に移行する前に、各コンポーネントが正しく動作することを確認してください。
コマンドを実行する前に、sales-rfp-hubディレクトリを開いていること、また、仮想環境がアクティブ化されていることを確認します。
cd ~/sales-rfp-hub
source .venv/bin/activate
1. 認証を確認します。資格情報が有効であることを簡単に確認します。
python -c "from box_client import get_box_client; client = get_box_client(); user = client.users.get_user_me(); print(f'Authenticated as: {user.name} ({user.login})')"
Boxのユーザー名とメールアドレスが表示されます。invalid_clientと表示されている場合は、.envの資格情報を確認してください。2. Hubを作成し、コンテンツを追加します。
python create_hub.py
次のように表示されます。
Created hub: Sales RFP Answer Bank (ID: 12345678)
Added folder 987654321 to hub 12345678

Sales Hub ready. Hub ID: 12345678
出力からHub IDをコピーします。query_hub.pymanage_access.pyを開き、YOUR_HUB_IDをこの値に置き換えます。
Hubを作成してコンテンツを追加したら、クエリを実行する前に、Boxがファイルにインデックスを作成するまで数分待ちます。インデックス作成が完了する前に、新規作成したHubにクエリを実行しても、結果が空になったり、不完全になったりすることがあります。
3. Hubにクエリを実行します。
python query_hub.py
質問に続き、営業コンテンツから抽出された回答が表示されます。回答が空であったり、汎用的な内容であったりする場合は、以下の点を確認してください。
  • Hub IDが正しいこと。
  • コンテンツフォルダに、サブフォルダだけでなくドキュメントも含まれていること。
  • インデックス作成が完了するまで十分な時間が経過していること。
4. Boxで確認します。Boxウェブアプリを開き、左側のサイドバーから [Hubs] に移動します。「営業用RFP回答集」Hubが表示され、コンテンツフォルダのリストが表示されます。
8

最新状態のHubの維持

この手順では、Hubを最新の状態に保つうえで参考となるパターンを紹介します。今すぐこれを実行する必要はありません。営業コンテンツに変更が生じた際に、アプリケーションコードに組み込んでください。
内容の古い回答集は、回答がまったくない場合よりも厄介です。営業コンテンツが変更されたときにHubの項目を更新することで、コンテンツの鮮度を自動的に維持できます。
from box_sdk_gen import (
    BoxClient,
    FolderReferenceV2025R0,
    HubItemOperationV2025R0,
    HubItemOperationV2025R0ActionField,
)

def refresh_hub_content(
    client: BoxClient, hub_id: str, new_folder_id: str
):
    """Add a new content folder to the hub."""
    client.hub_items.manage_hub_items_v2025_r0(
        hub_id,
        operations=[
            HubItemOperationV2025R0(
                action=HubItemOperationV2025R0ActionField.ADD,
                item=FolderReferenceV2025R0(id=new_folder_id),
            )
        ],
    )
    print(f"Added folder {new_folder_id} to hub {hub_id}")

def remove_outdated_content(
    client: BoxClient, hub_id: str, old_folder_id: str
):
    """Remove a folder from the hub."""
    client.hub_items.manage_hub_items_v2025_r0(
        hub_id,
        operations=[
            HubItemOperationV2025R0(
                action=HubItemOperationV2025R0ActionField.REMOVE,
                item=FolderReferenceV2025R0(id=old_folder_id),
            )
        ],
    )
    print(f"Removed folder {old_folder_id} from hub {hub_id}")
これと併せて、四半期ごとにコンテンツのレビュープロセスを実施します。営業部門がHubのコンテンツを確認し、古い資料をアーカイブし、承認済みの新しいコンテンツを追加します。Hubのインデックスは自動的に再作成されます。

トラブルシューティング

仮想環境がアクティブ化されていません。pythonコマンドを実行する前に、プロジェクトディレクトリからsource .venv/bin/activateを実行してください。新しく開いたターミナルタブは、すべて個別にアクティブ化する必要があります。
以下のように、.envファイルを確認します。
  • BOX_CLIENT_IDおよびBOX_CLIENT_SECRETが、開発者コンソール > [Platformアプリ] > [アプリ] > [構成] の値と一致していることを確認します。
  • BOX_USER_IDが有効なBoxユーザーID (数字で構成され、管理コンソールの [ユーザー] で確認可能) であることを確認します。
  • 開発者コンソールでアプリが承認されていることを確認します。
  • アプリの種類がクライアント資格情報許可であり、[ユーザーアクセストークンを生成] が有効になっていることを確認します。
認証されたユーザーに、必要なスコープまたは権限がありません。
  • アプリで、[すべてのファイルとフォルダの読み取り] スコープと [すべてのファイルとフォルダへの書き込み] スコープが有効になっていることを確認します。
  • [AIを管理する] スコープが有効になっていることを確認します (Box AIクエリを利用するには必須)。
  • サービスアカウントを使用してる場合は、そのアカウントがコンテンツフォルダにコラボレータとして招待されていることを確認します。
フォルダIDが正しくないか、認証されたユーザーにそのフォルダへのアクセス権限がありません。以下の点を確認してください。
  • .envファイル内のフォルダIDが、BoxのURLと一致している (https://app.box.com/folder/123456789であれば、フォルダIDは123456789となります)。
  • BOX_USER_IDで指定されたユーザーは、そのフォルダに対してビューアー以上の権限を持っている。
これは通常、Hubコンテンツでインデックス作成が完了していないか、そのコンテンツが質問に適合していないことを意味します。
  • コンテンツを追加してから、クエリを実行するまで数分待ちます。インデックス作成はすぐには完了しません。
  • Boxウェブアプリで [Hubs] を確認し、Hub内に空のフォルダではなく、ファイルが含まれていることを確認します。
  • ドキュメントにテキストが含まれていることを確認します (OCR処理されていないスキャン画像のPDFでは検索できません)。
  • そのHubに存在することがわかっているコンテンツに直接関連する質問をしてみます。
Hubは正常に作成されているようなのに、現在のユーザーがコラボレータとしてアクセスできない場合は、manage_access.pyを実行して自身を追加するか、Hubの所有者を確認してください。または、Box管理者に確認し、企業でBox Hubsが有効になっていることを確認してください。

CRMへのHubの埋め込み

HubのAIチャットインターフェースをCRM (Salesforce、HubSpot、または社内のカスタムツールなど) に直接埋め込むことで、営業担当者はHubのコンテンツを活用した専用のチャットボット機能を利用できるようになります。Boxでは、HubのAIチャットについて、チャットボタンとチャットウィジェットという2つの埋め込みモードをサポートしています。 埋め込みパラメータとオプションの詳細なリストについては、を参照してください。
埋め込みHubにアクセスするユーザーは、既存のBoxセッションを通じて認証を行います。既にBoxにサインインしている場合 (SSOを導入している企業では一般的なケースです)、追加のログインプロンプトが表示されることなく、チャットがシームレスに読み込まれます。ユーザーは、Hubに対するビューアー以上の権限が必要です。

本番環境へのスケーリング

地域、業種、または製品ラインごとに別々の営業チームがある場合は、それぞれに専用のHubをプロビジョニングできます。まず、create_hub.pycreate_sales_hubを更新し、ハードコートされた値ではなくオプションのtitleパラメータを受け入れるようにします。次に、各チームに対してループ処理を行います。
teams = {
    "EMEA": "EMEA_FOLDER_ID",
    "APAC": "APAC_FOLDER_ID",
    "Americas": "AMERICAS_FOLDER_ID",
}

for team, folder_id in teams.items():
    hub_id = create_sales_hub(client, title=f"Sales RFP Bank — {team}")
    add_content_to_hub(client, hub_id, folder_id)
POST /2.0/ai/askエンドポイントは、以前のQ&Aのやり取りを格納したdialogue_historyパラメータを受け付けます。やり取りのリストを管理し、リクエストごとにそれを渡すことにより、担当者はコンテキストを失うことなく、「データ保管場所について詳しく説明してもらえますか?」といったフォローアップの質問を行うことができます。query_hub.pyに以下を追加するか、同じimportとクライアント設定を含む新しいスクリプトを作成します。
from datetime import datetime, timezone
from box_sdk_gen import AiDialogueHistory

history = []

while True:
    question = input("Q: ")
    response = client.ai.create_ai_ask(
        mode=CreateAiAskMode.SINGLE_ITEM_QA,
        prompt=question,
        items=[AiItemAsk(type="hubs", id=hub_id)],
        dialogue_history=history,
    )
    print(f"A: {response.answer}")
    history.append(
        AiDialogueHistory(
            prompt=question,
            answer=response.answer,
            created_at=datetime.now(timezone.utc).isoformat(),
        )
    )
を使用して、Hubへのクエリ頻度や、最も頻繁にアクセスされるコンテンツを監視します。このデータは、営業部門がコンテンツの選定に優先順位を付けたり、回答集のROIを測定したりするのに役立ちます。
Hubとを組み合わせて、古くなった営業資料を自動的にアーカイブまたは削除します。を使用して、コンテンツにレビューの日付や所有者をタグ付けします。

次の手順

請求書の取り込み自動化

Box AI Extractとメタデータを活用して、買掛金処理を自動化します。

Box Hubs APIリファレンス

高度なHub管理については、詳細なHubs APIガイドを参照してください。