<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=139163818022217&amp;ev=PageView&amp;noscript=1"> <img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=271598307802760&amp;ev=PageView&amp;noscript=1">

意外と簡単な、LangChainを使用したBoxエージェントの作成

 公開日:2025.04.30  更新日:2026.06.10

この記事では、LangChainのツールインターフェースを使用したBoxエージェントの作成がいかに簡単であるかを紹介します。わずか数行のPythonコードによって、AIモデルでBoxコンテンツの検索、ファイルの読み取り、構造化データの抽出、さらにはBox AIへのドキュメントの要約や分析の依頼を実行できるようにすることが可能です。LangGraphを使用して、順を追って推論できるエージェント内にすべてラップできます。

Model Context Protocol (MCP) を確認し、「これはAIモデルにデータソースを接続するための構造化された手段にすぎない」と思ったことがあるなら、その通りです。ClaudeBoxコンテンツに接続するためのMCPサーバーを作成することと、LangChainツールを使用してエージェントを作成することは、概念的には変わりません。どちらの場合も、AIが会話中に呼び出すことができる形式にAPIコールをラップしています。

比較のために、次のMCPに関する記事をご覧ください。

LangChainにおけるツールの定義

LangChainにおける「ツール」とは、エージェントが呼び出すことのできる関数です。これらの関数は、説明や引数の型などのメタデータでラップされるため、それらをいつ、どのように使用するかを言語モデルで決定できます。

魅力はStructuredTool.from_function()にあり、これを使用すると、通常のPython関数から直接ツールを定義できます。Boxエージェントの実際の例を見てみましょう。

StructuredTool.from_function(
    self.box_search_tool,
    parse_docstring=True,
)

これにより、box_search_toolは、エージェントが呼び出し可能な関数としてラップされます。parse_docstring=Trueフラグでは、LangChainに対して、関数のdocstringから引数の名前と説明を自動的に抽出するよう指示しています。このように、説明可能な新しいツールを定義するのは非常に簡単です。

基になる関数はこのようになっています。

def box_search_tool(
    self,
    query: str,
    file_extensions: List[str] | None = None,
    where_to_look_for_query: List[str] | None = None,
    ancestor_folder_ids: List[str] | None = None,
) -> str:
    """Searches for files in Box using the specified query and filters.

    Args:
        query (str): The search query.
        file_extensions (List[str] | None): A list of file extensions to filter results (e.g., ['.pdf']).
        where_to_look_for_query (List[str] | None): Where to search for the query. Options:
            NAME, DESCRIPTION, FILE_CONTENT, COMMENTS, TAG
        ancestor_folder_ids (List[str] | None): Folder IDs to limit the search scope.
    Returns:
        str: A formatted string containing the search results.
    """

LangChainは、このdocstringを読み取り、エージェントが自然言語で使用できる仕様を作成します。

「名前に「Q2 report」が含まれるファイルをBox内で検索しますが、対象は「Finance」フォルダ内のPDFファイルのみです。」

このツールは、バックグラウンドではbox_search APIを呼び出し、結果の形式をうまく整えます。

search_results = box_search(
    self.client, query, file_extensions, content_types, ancestor_folder_ids
)

# Return id, name, and description for each match
search_results = [
    f"{file.name} (id:{file.id})"
    + (f" {file.description}" if file.description else "")
    for file in search_results
]

出力は、モデルにとって読み取りやすく推論しやすい、単純な文字列です。特別な形式にする必要はありません。

簡単になる理由

開発者がOpenAPI仕様、JSONスキーマ、または特別なラッパーを作成する必要はありません。
関数に適切なdocstringが設定されていれば、すでに利用可能なツールがあるということです。
LangChainが、ユーザー入力 → ツールの引数 → 関数呼び出しの変換を処理します。

このパターンは、ファイルの読み取り、フォルダコンテンツのリスト取得、Box AIの呼び出しなど、Boxの任意の操作に対して繰り返すことができます。エージェント全体が、ラップされたPython関数を並べたものということです。

Boxエージェントのインスタンス化

ツールを定義したら、次に、実際のエージェントを作成します。これは、言語モデルを使用して、どのツールをいつ呼び出すかを推論する部分です。

この例では、LangChaincreate_react_agentヘルパーを使用して、メモリチェックポイントを含むシンプルなReAct (推論と行動) スタイルのエージェントを作成します。このエージェントは、カスタムロジックを記述しなくても、会話して、判断を下し、登録したツールを呼び出すことができます。

以下に、その重要な部分を示します。

memory = MemorySaver()
self.chat = create_react_agent(model, self.tools, checkpointer=memory)
  • modelは、ClaudeGPT-4など、サポートされている任意のBaseChatModelです。
  • self.toolsは、前に登録した関数のリストです。
  • MemorySaverは、メモリ内のメモリチェックポイントを処理します。これは、簡単な実験やステートレスアプリに最適です。

これを実行すると、エージェントの準備が整います。エージェントは以下を把握しています。

  • 利用可能なツール
  • (docstringや関数シグネチャによって) 各ツールを呼び出す方法
  • フォローアップの質問、ツールの呼び出し、直接的な応答を行うタイミング

これだけです。カスタムプランナ、ルーター、またはツールセレクタを記述する必要はありません。LangChainがすべてを処理してくれます。

コンストラクタ全体は次のようになります。

def __init__(self, client: BoxClient, model: BaseChatModel):
    self.client = client
    self.tools = [
        StructuredTool.from_function(self.box_who_am_i, parse_docstring=True),
        StructuredTool.from_function(self.box_search_tool, parse_docstring=True),
        StructuredTool.from_function(self.box_read_tool, parse_docstring=True),
        StructuredTool.from_function(self.box_ask_ai_tool, parse_docstring=True),
        StructuredTool.from_function(self.box_search_folder_by_name, parse_docstring=True),
        StructuredTool.from_function(self.box_ai_extract_data, parse_docstring=True),
        StructuredTool.from_function(self.box_list_folder_content_by_folder_id, parse_docstring=True),
    ]

    memory = MemorySaver()
    self.chat = create_react_agent(model, self.tools, checkpointer=memory)

非常にシンプルである理由
LangChaincreate_react_agent()は、迅速なプロトタイプ作成のために設計されていて、以下の処理を行います。

  • 自然言語からツールへの入力を解析する
  • 適切な引数を指定して適切なツールを呼び出す
  • 中間ステップのメモリチェーンを保持する

ツールリストと言語モデル以外は何も構成する必要はありません。これが、Boxエージェントを短時間で作成するのに最適である理由です。また、一連の機能を公開し、それらの使用方法をLLMに決定させるという点で、MCPサーバーの作成とよく似ていると感じる理由でもあります。

エージェントの呼び出し

Boxエージェントがインスタンス化されたので、そのエージェントと実際の会話を開始できます。以下に例を示します。

def test_agent_tools_box_search(box_client_ccg: BoxClient, chat_config: str):
    client: BoxClient = box_client_ccg
    model = init_chat_model("gpt-4", model_provider="openai")
    box_agent = LangChainBoxAgent(client, model)
    response = box_agent.chat.invoke(
        {"messages": [HumanMessage(content="locate my hab-03-01 file by name")]},
        chat_config,
    )
    messages = response.get("messages", [])
    assert messages != []
    assert any("hab-03-01" in message.content.lower() for message in messages)

バックグラウンドで発生している処理
invoke()を呼び出すと、エージェントは以下の処理を行います。

  • メッセージを分析する
  • 定義したツールのいずれかを使用する必要があるかどうかを判断する
  • メッセージから抽出する引数を使用してツールを呼び出す
  • ツールの出力を使用して推論を続行する
  • 最終的な回答を返す

必要に応じて、複数のツールの呼び出しを連鎖させることもできます。

たとえば、次のように指示したとします。

「「Q2 Budget」フォルダを探して、その中のすべてのPDFのリストを取得してください。」

エージェントは、次の処理を行うでしょう。

  • box_search_folder_by_name(“Q2 Budget”) を呼び出す
  • 結果からフォルダIDを抽出する
  • box_list_folder_content_by_folder_id(folder_id, is_recursive=True) を呼び出す
  • 結果にフィルタをかけてPDFファイルのみを表示する
  • 検索結果の要約を回答する

開発者がロジックを明示的にコーディングしなくても、エージェントがすべて行います。

おまけ: LangGraphの開発ツールを使用してエージェントをデバッグする

LangGraphを使用すると、組み込みのdevコマンドを使用してとても簡単にエージェントをデバッグできます。

0_IEoBVMVGIfCPjBQr

Boxエージェントを初期化したら、次のようにreact_agentを公開します。

from box_ai_agents_toolkit import get_ccg_client
from langchain.chat_models import init_chat_model
from langchain_box_agent.box_agent import LangChainBoxAgent

client = get_ccg_client()
user_info = client.users.get_user_me()
print(f"Connected as: {user_info.name}")

model = init_chat_model("gpt-4", model_provider="openai")
box_agent = LangChainBoxAgent(client, model, use_internal_memory=False)

react_agent = box_agent.react_agent

LangGraphの構成ファイルを以下に示します。

{
  "dependencies": [
    "."
  ],
  "graphs": {
    "agent": "./src/box_agent_langgraph.py:react_agent"
  },
  "env": ".env"
}

次に、ターミナルから次のコマンドを実行します。

langgraph dev --config ./src/langgraph.json

これにより、対話型デバッガーが起動し、そこで、エージェントが実行する各ステップ (ツールへの入力、ツールの出力、モデルの呼び出し、メモリ状態) をすべて視覚的なフローで確認できます。エージェントがなぜそのように動作するのかを理解し、わかりにくいバグを早期に発見するのに非常に役立ちます。

この開発エクスペリエンスは、LangGraphがエージェントにとって強力なオーケストレーションレイヤーになる理由の1つです。

まとめ

LangChainを使用して十分に機能するBoxエージェントを作成するために必要なのはこれだけです。

  • シンプルなPython関数を使用してツールを定義する
  • 定義したツールをLangChainに登録する
  • モデルとメモリを指定してエージェントをインスタンス化する
  • invoke()を呼び出して任意のユーザークエリを処理する

Model Context Protocol (MCP) サーバーを作成したことがある方なら、LangChainが開発者の代わりにオーケストレーションを処理するこのワークフローを身近に感じるでしょう。

Boxの開発者ツールキットを使用すると、一貫性のある安全なAPIを介してAI機能を簡単に公開できます。LangChainは、すべてを結びつけるための推論エンジンを提供します。これらを組み合わせることで、通常のPythonコードを記述するようにAIネイティブアプリを作成できます。


RECENT POST「開発者」の最新記事


開発者

Box、MCPアプリのサポート対象をChatGPT、Microsoft 365 Copilot、Gleanに拡大

開発者

AIエージェントにコンテンツの活用方法を教える: OpenAI Codex向けBox Skillの構築

開発者

Box AIとOpenAI Agents SDKで自律的なドキュメントワークフローを実行

開発者

Box CLI: 開発者とAIエージェントのためのコンテンツCLI