OpenAI Agents SDKを使用してビルドするエージェントのバッキング データベースとして MongoDB を使用できます。Agents SDKは、一連のプリミティブからエージェントアプリケーションを構築するためのPythonフレームワークです。
エージェントは、指示とツールが設定された大規模言語モデル(LLM)です。
ハンドオフ。あるエージェントがタスクを別のエージェントに委任することを可能にするもの。
ガードレール。エージェントの入力と出力を検証します。
セッション。エージェントの実行全体で会話履歴を保存します。
SDK は 2 つのデザイン原則に従っています。実際のアプリケーションをビルドするのに十分な機能が含まれていますが、短時間で学ぶのに十分なほど少ないプリミティブです。そのデフォルト設定でも良い結果が得られます。また、エージェントの実行する各ステップをカスタマイズできます。
Agents SDK で MongoDB を使用する理由とは?
エージェント SDK は、MongoDB に会話履歴を持続化するセッション実装である MongoDBSession を提供します。MongoDB にその履歴を保存することで、エージェントは以下の利点を得られます。
水平スケーラブルなマルチプロセスセッションストレージ。セッション状態は単一プロセスのメモリではなく、クラスター内に保存されます。そのため、同じクラスターに接続するワーカー、コンテナ、またはサーバーレス関数は会話を続行できます。各メッセージには単調増加の
seqカウンターが含まれており、これによって複数の同時書き込みでのメッセージの順序が維持されます。1 つのデータベースで会話データとアプリケーションデータを取り扱います。アプリケーションで既に MongoDB を使用している場合、エージェントは同じ接続と同じドライバーを介して操作データを読み取り、セッション履歴を書き込みます。このため、メモリサービスの配置することとセキュリティのための別個のサービスは不要です。
エージェントの状態向けの柔軟なドキュメント。document model は、会話のターン、ツールの呼び出し、構造化された出力を、それらが進化するにつれてまとめて保存します。これにより、スキーマ移行を行わずにレコードする内容を拡張することができます。
クエリ可能なエージェント履歴。セッション履歴は通常のコレクションに保存されます。そのため、エージェントの動作を監査したり、分析をビルドするために、クエリ、集計、インデックスを行うことができます。
A path to retrieval. Because your agents already connect to MongoDB, you can add MongoDB Vector Search to the same cluster to give them semantic retrieval over your data. To learn more, see Agentic RAG.
Tutorial
このチュートリアルでは、マルチエージェントの旅行アシスタントをビルドする。トリアージ エージェントは、2 人の専門エージェントをツールとして呼び出し、質問に答えます。そして、両方の専門エージェントは、会話セッションを保存する同じクラスターから参照データを読み取ります。
前提条件
Atlas の サンプル データ セット からの映画データを含むコレクションを使用します。
Python 3.10 以降。
次のいずれかのMongoDBクラスター タイプ
MongoDB バージョン 6.0.11 を実行している Atlas クラスター、7.0.2以降。IP アドレスが Atlas プロジェクトのアクセスリストに含まれていることを確認します。
Python と Docker を使用して作成されたローカル Atlas 配置。
atlas-local-lib-py(pip install atlas-local-lib-py) をインストールして、ローカル配置をプログラムで作成および管理します。詳細については、atlas-local-lib-py リポジトリを参照してください。A MongoDB Community cluster with Search and Vector Search installed.
OpenAI APIキー。APIリクエストに使用できるクレジットを持つ OpenAI アカウントが必要です。OpenAI アカウントの登録の詳細については、OpenAI APIウェブサイト を参照してください。
環境を設定する
環境変数を設定します。
アプリケーションは Atlas 接続文字列を ATLAS_URI から読み取ります。また、エージェント SDK は OPENAI_API_KEY からキーを読み取ります。
export ATLAS_URI="<connection-string>" export OPENAI_API_KEY="<api-key>"
<connection-string> プレースホルダー値をクラスターの SRV 接続文字列 に置き換えます。
接続stringには、次の形式を使用する必要があります。
mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net
エージェントをビルドする
アプリケーションファイルを作成します。
multi_agent_app.py というファイルを作成し、次のコードを貼り付けます。インライン コメントには、アプリケーションの各パートがどのように MongoDB を使用しているかが説明されています。
"""Multi-agent travel assistant backed by MongoDB Atlas. A triage agent answers travel questions by calling two specialist agents as tools. Both specialists read reference data from the same Atlas cluster that stores the conversation session, so every agent in the application shares one database. """ import asyncio import os from agents import Agent, Runner, function_tool from agents.extensions.memory import MongoDBSession from pymongo import AsyncMongoClient # The script reads your credentials from the environment so that you # don't commit them to source control. REQUIRED_ENV_VARS = ("ATLAS_URI", "OPENAI_API_KEY") DATABASE_NAME = "travel_assistant" # One client serves both the agent tools and the session store. Because # you create the client yourself, your application owns its lifecycle. # main() assigns both of these after it validates the environment. client: AsyncMongoClient | None = None database = None async def lookup_destination(city: str) -> str: """Look up travel guidance for a destination city.""" # Sub-agent tools query the shared database directly, so the agents # answer from your data instead of from model training data. document = await database.destinations.find_one({"city": city}) if document is None: return f"No destination guide found for {city}." return ( f"{document['city']}: best months are {document['best_months']}. " f"{document['summary']}" ) async def lookup_policy(topic: str) -> str: """Look up the company travel policy for a topic.""" document = await database.policies.find_one({"topic": topic}) if document is None: return f"No policy found for {topic}." return f"{document['topic']}: {document['rule']}" # Each specialist is a full agent with its own instructions and tools. destination_agent = Agent( name="Destination expert", instructions=( "You advise travelers on destinations. Always call " "lookup_destination and answer only from what it returns." ), tools=[lookup_destination], ) policy_agent = Agent( name="Policy expert", instructions=( "You answer questions about the company travel policy. Always " "call lookup_policy and answer only from what it returns." ), tools=[lookup_policy], ) # The as_tool() pattern turns each specialist into a tool that the # triage agent can call. Unlike a handoff, control returns to the # triage agent after each call, so it can combine both answers in one # reply. triage_agent = Agent( name="Travel assistant", instructions=( "You are a travel assistant. Use the destination and policy " "tools to gather facts before you answer, and call both when " "the question needs both. Remember details the traveler shared " "earlier in the conversation." ), tools=[ destination_agent.as_tool( tool_name="ask_destination_expert", tool_description="Get travel guidance about a city.", ), policy_agent.as_tool( tool_name="ask_policy_expert", tool_description="Get the company travel policy for a topic.", ), ], ) async def seed_reference_data() -> None: """Load the sample data that the specialist agents read.""" await database.destinations.delete_many({}) await database.policies.delete_many({}) await database.destinations.insert_many( [ { "city": "Lisbon", "best_months": "March through May", "summary": "Mild spring weather and low hotel rates.", }, { "city": "Reykjavik", "best_months": "June through August", "summary": "Long daylight hours and open highland roads.", }, ] ) await database.policies.insert_many( [ {"topic": "flights", "rule": "Book economy for flights under six hours."}, {"topic": "hotels", "rule": "Nightly rates must stay under 250 USD."}, ] ) async def main() -> None: global client, database # Fail fast with a clear message instead of surfacing a connection # error or an authentication error later in the run. missing = [name for name in REQUIRED_ENV_VARS if not os.environ.get(name)] if missing: raise SystemExit( "Set these environment variables before you run this script: " + ", ".join(missing) ) client = AsyncMongoClient(os.environ["ATLAS_URI"]) database = client[DATABASE_NAME] await seed_reference_data() # The session stores conversation history in Atlas. Pass the # existing client so the session and the agent tools share one # connection pool. session = MongoDBSession( session_id="traveler-123", client=client, database=DATABASE_NAME, ) # Confirm connectivity before the first run. await session.ping() # The Runner loads prior turns from the session and writes the new # turn back, so the second question resolves "there" without you # passing the history yourself. first = await Runner.run( triage_agent, "I'm planning a trip to Lisbon. When should I go?", session=session, ) print(first.final_output) second = await Runner.run( triage_agent, "What's our hotel budget for that trip?", session=session, ) print(second.final_output) # session.close() is a no-op when you supply the client, so close # the client yourself. await client.close() if __name__ == "__main__": asyncio.run(main())
アプリケーションで MongoDB を使用する方法
アプリケーションは 1 つの AsyncMongoClient を作成し、それをエージェントとセッション間で共有します。
専門エージェントは、ツール機能から
destinationsとpoliciesのコレクションをクエリします。そのため、ユーザーのデータから答えます。MongoDBSession各会話のターンを、同じデータベース内のagent_sessionsコレクションとagent_messagesコレクションに書き込みます。両方のコレクション名は設定可能です。また、セッションは初回使用時に必要なインデックスを作成します。
アプリケーションがクライアント自体を構築するため、クライアントのライフサイクルはアプリケーションに属し、session.close() は何も行いません。セッションにクライアントを所有させるには、MongoDBSession.from_uri() を使用して作成します。
次のステップ
Agents SDK を使用した複数のエージェントの連携について学ぶには、OpenAI ドキュメントの以下のページを参照してください。
複数のエージェントのオーケストレーション。コードによるオーケストレーションとLLMによるオーケストレーションのトレードオフについて解説します。
ハンドオフ は、会話をツールとして呼び出すのではなく、別のエージェントに委任するために使用します。
ガードレール(エージェントの入力と出力を検証するため)
セッションで、
MongoDBSessionの全リファレンスをご覧ください。