このチュートリアルでは、crewai-mongodb-memory パッケージを使用して、MongoDB Atlas に持続する耐久性がある長期間メモリを CrewAI エージェントに付与します。エージェントはユーザー設定をメモリレコードとして保存し、MongoDB ベクトル検索で意味的に呼び出すため、後のセッションでの新しいクルーは前のセッションからの学習を取り出すことで正しく答えることができます。
MongoDB CRUDAI 統合の詳細については、MongoDBと CRC の統合を参照してください。
前提条件
Atlas の サンプル データ セット からの映画データを含むコレクションを使用します。
Python 3.10 以降。
次のいずれかのMongoDBクラスター タイプ
MongoDBバージョン6.0.11 、7.0.2 、またはそれ以降を実行中Atlas クラスター。 IPアドレスが Atlas プロジェクトのアクセス リストに含まれていることを確認します。
Python と Docker を使用して作成されたローカル Atlas 配置。
atlas-local-lib-py(pip install atlas-local-lib-py) をインストールして、ローカル配置をプログラムで作成および管理します。詳細については、atlas-local-lib-py リポジトリを参照してください。検索とベクトル検索がインストールされた MongoDB Community クラスター。
投票AI APIキー。 APIキーを作成するには、「 投票AIモデルAPIキーの管理 」を参照してください。
エージェントの推論を動作させる㌪大規模言語モデル(LLM)の API キー(Anthropic や OpenAI など)。
MongoDB でエージェント メモリが機能する仕組み
crewai-mongodb-memory バックエンドは CrewAI の StorageBackend プロトコルを実装します。各メモリを MongoDB コレクションのレコードとして保存し、MongoDB ベクトル検索を使用して関連するレコードを意味的に検索します。バックエンドは次のコンポーネントを使用します。
MongoDBStorageBackend: Atlas クラスターに接続し、メモリ レコードを保存し、$vectorSearchクエリを実行してそれらを思い出します。MemoryRecordテキストコンテンツ、/users/alex/preferencesなどの階層的スコープ、任意のカテゴリ、およびベクトル埋め込みを含む単一のメモリを表します。embed_text(): Voyage AIvoyage-4モデルを使用して、保存されたドキュメントとクエリの両方に対して 1024 次元の埋め込みを生成します。
メモリはクルーのインプロセスコンテキストではなく Atlas 内にあるため、同じクラスターとスコープに接続するクルーは、保存されたメモリを呼び出すことができます。
{ "_id": "cff7db8d-aa2e-4d82-8234-e4b8f1ccccb6", "content": "The user always prefers window seats on flights.", "scope": "/users/alex/preferences", "categories": [ "preference" ], "metadata": {}, "importance": 0.5, "created_at": { "$date": "2026-07-14T22:06:59.162Z" }, "last_accessed": { "$date": "2026-07-14T22:06:59.162Z" }, "source": null, "private": false, "embedding": [ 0.03147803992033005, 0.015906454995274544, -0.007409059442579746, 0.028631621971726418, ... ], "scope_ancestors": [ "/users", "/users/alex", "/users/alex/preferences" ] }
エージェントをビルドして実行する
ユーザー設定を保存および呼び出すエージェントを構築および実行するには、次の手順を実行します。
環境を設定します。
ターミナルで次のコマンドを実行して、
crewai-memory-projectという名前の新しいディレクトリを作成し、必要な依存関係をインストールします。mkdir crewai-memory-project cd crewai-memory-project pip install crewai-mongodb-memory crewai "crewai[google-genai]" voyageai python-dotenv プロジェクトで、
.envファイルを作成し、次の行を追加します。ATLAS_URI="<connection-string>" VOYAGE_API_KEY="<voyage-api-key>" ANTHROPIC_API_KEY="<anthropic-api-key>" MODEL="<anthropic-model>" 注意
<connection-string>を Atlas クラスターまたはローカル Atlas 配置の接続文字列に置き換えます。接続stringには、次の形式を使用する必要があります。
mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net 重要:接続文字列にデータベースユーザーの認証情報が含まれていることを確認します。接続文字列の検索方法の詳細については、クライアント ライブラリ経由でクラスターに接続する を参照してください。
接続stringには、次の形式を使用する必要があります。
mongodb://localhost:<port-number>/?directConnection=true 詳細については、「接続文字列 」を参照してください。
エージェントをビルドする。
プロジェクトに main.py という名前のファイルを作成し、次のコードを貼り付けます。
from __future__ import annotations import os import sys import time import warnings from dotenv import load_dotenv load_dotenv() warnings.filterwarnings("ignore") from crewai import Agent, Crew, Task from crewai.tools import tool from crewai_mongodb_memory import MemoryRecord, MongoDBStorageBackend, embed_text from crewai.events import CrewKickoffStartedEvent, CrewKickoffCompletedEvent, AgentExecutionCompletedEvent from crewai.events import BaseEventListener DEMO_DB = "crewai_mem_agent_demo" SCOPE = "/users/alex/preferences" MODEL = os.environ.get("ANTHROPIC_MODEL", "anthropic/claude-3-5-sonnet-latest") EMBEDDING_MODEL = os.environ.get("VOYAGE_MODEL", "voyage-4") # Module-level backend handle so the function tools can reach it. _BACKEND: MongoDBStorageBackend | None = None _SESSION_LABEL = "" # Custom event listener for logging Crew and Agent events. class EventListener(BaseEventListener): def __init__(self): super().__init__() def setup_listeners(self, crewai_event_bus): def on_crew_started(source, event): print(f"Crew '{event.crew_name}' has started execution!") def on_crew_completed(source, event): print(f"Crew '{event.crew_name}' has completed execution!") print(f"Output: {event.output}") def on_agent_execution_completed(source, event): print(f"Agent '{event.agent.role}' completed task") print(f"Output: {event.output}") def banner(title: str) -> None: print(f"\n{'=' * 70}\n{title}\n{'=' * 70}") def embed(text: str, input_type: str) -> list[float]: """Generate embeddings with an explicit Voyage model.""" try: return embed_text(text, input_type=input_type, model=EMBEDDING_MODEL) except TypeError: # Backward compatibility for older crewai-mongodb-memory versions. return embed_text(text, input_type=input_type) def remember_preference(fact: str) -> str: """Store a durable user preference in MongoDB Atlas long-term memory.""" assert _BACKEND is not None rec = MemoryRecord( content=fact, scope=SCOPE, categories=["preference"], embedding=embed(fact, input_type="document"), ) _BACKEND.save([rec]) return f"Stored preference: {fact}" def recall_preferences(query: str) -> str: """Retrieve relevant user preferences from Atlas via $vectorSearch.""" assert _BACKEND is not None qv = embed(query, input_type="query") hits = _BACKEND.search(qv, scope_prefix=SCOPE, limit=3) if not hits: return "No relevant preferences found." for rec, score in hits: print(f" - [{score:.3f}] {rec.content}") return "\n".join(f"- {rec.content} (score={score:.3f})" for rec, score in hits) def build_agent() -> Agent: return Agent( role="Personal Concierge", goal="Help the user with durable long-term memory stored in MongoDB Atlas.", backstory=( """You remember user preferences across sessions. When the user shares a durable preference, call remember_preference. When a request may depend on what you know about them, call recall_preferences first and use the results.""" ), tools=[remember_preference, recall_preferences], llm=MODEL, verbose=True, ) def run_task(description: str, expected_output: str) -> str: """Run a single-task crew (a fresh crew each call is a fresh session).""" agent = build_agent() task = Task(description=description, expected_output=expected_output, agent=agent) crew = Crew(agent, [task]) return str(crew.kickoff()) def main() -> None: global _BACKEND, _SESSION_LABEL uri = os.environ.get("ATLAS_URI") # Fast fail if the required environment variables are not set. if not all([uri, os.environ.get("ANTHROPIC_API_KEY"), os.environ.get("VOYAGE_API_KEY")]): print("This script needs ATLAS_URI, ANTHROPIC_API_KEY, and VOYAGE_API_KEY.") sys.exit(1) print(f"=== CrewAI and MongoDB Atlas long-term memory (model={MODEL}) ===") _BACKEND = MongoDBStorageBackend(uri, database_name=DEMO_DB) _BACKEND.delete(scope_prefix=SCOPE) # clean slate for a repeatable run print("Ensuring Atlas Vector Search index (first build can take ~1 min)...") if not _BACKEND.ensure_vector_index(wait=True): print("Vector index did not become queryable in time.") sys.exit(1) print("Index queryable.") # Initialize the event listener for the agent. listener = EventListener() # Session 1: the agent learns and stores preferences. banner("SESSION 1 - agent stores durable preferences in Atlas") session_1_input = ( """The user says: 'I'm vegetarian, I avoid dairy, and I always prefer window seats on flights.' Store each durable preference.""" ) _SESSION_LABEL = "SESSION 1" print(f" {session_1_input}") out1 = run_task( description=session_1_input, expected_output="A short confirmation of what was stored.", ) print(f"\nAgent (session 1): {out1}") # Atlas indexing is asynchronous, so wait until the facts are searchable. print("\nWaiting for Atlas to index the new memories...") for _ in range(20): if _BACKEND.search(embed("food", input_type="query"), scope_prefix=SCOPE, limit=1): break time.sleep(2) print("Memories searchable.") # Session 2: a brand-new crew with no shared state recalls from Atlas. banner("SESSION 2 - fresh crew answers via recall_preferences") session_2_input = ( """The user is booking a long flight and pre-ordering an in-flight meal. Recommend a seat and a meal that fit their preferences.""" ) _SESSION_LABEL = "SESSION 2" print(f" {session_2_input}") out2 = run_task( description=session_2_input, expected_output="A seat and meal recommendation grounded in recalled preferences.", ) print(f"\nAgent (session 2, brand-new crew): {out2}") banner("Proof: direct $vectorSearch recall over stored preferences") hits = _BACKEND.search( embed("dietary and seating preferences", input_type="query"), scope_prefix=SCOPE, limit=5, ) for rec, score in hits: print(f" - [{score:.3f}] {rec.content}") _BACKEND.delete(scope_prefix=SCOPE) _BACKEND.close() print("\nDone - CrewAI stored and recalled preferences via MongoDB Vector Search.") if __name__ == "__main__": main()
このスクリプトは、次の処理を実行します。
ファイルを実行します。
次のコマンドを実行して、スクリプトを実行します。
python main.py
====================================================================== SESSION 1 - agent stores durable preferences in Atlas ====================================================================== The user says: 'I'm vegetarian, I avoid dairy, and I always prefer window seats on flights.' Store each durable preference. Crew 'crew' has started execution! ╭────────────────────────────── 🤖 Agent Started ──────────────────────────────╮ │ │ │ Agent: Personal Concierge │ │ │ │ Task: The user says: 'I'm vegetarian, I avoid dairy, and I always prefer │ │ window seats on flights.' Store each durable preference. │ │ │ ╰──────────────────────────────────────────────────────────────────────────────╯ Tool remember_preference executed with result: Stored preference: The user is vegetarian.... Tool remember_preference executed with result: Stored preference: The user avoids dairy.... Tool remember_preference executed with result: Stored preference: The user always prefers window seats on flights.... [Finalize] todos_count=0, todos_with_results=0 ╭─────────────────────────── ✅ Agent Final Answer ────────────────────────────╮ │ │ │ Agent: Personal Concierge │ │ │ │ Final Answer: │ │ Stored: │ │ - The user is vegetarian. │ │ - The user avoids dairy. │ │ - The user always prefers window seats on flights. │ │ │ ╰──────────────────────────────────────────────────────────────────────────────╯ Agent 'Personal Concierge' completed task Output: Stored: - The user is vegetarian. - The user avoids dairy. - The user always prefers window seats on flights. Crew 'crew' has completed execution! Output: Stored: - The user is vegetarian. - The user avoids dairy. - The user always prefers window seats on flights. Agent (session 1): Stored: - The user is vegetarian. - The user avoids dairy. - The user always prefers window seats on flights. Waiting for Atlas to index the new memories... Memories searchable. ====================================================================== SESSION 2 - fresh crew answers via recall_preferences ====================================================================== The user is booking a long flight and pre-ordering an in-flight meal. Recommend a seat and a meal that fit their preferences. Crew 'crew' has started execution! ╭────────────────────────────── 🤖 Agent Started ──────────────────────────────╮ │ │ │ Agent: Personal Concierge │ │ │ │ Task: The user is booking a long flight and pre-ordering an in-flight │ │ meal. │ │ Recommend a seat and a meal that fit their preferences. │ │ │ ╰──────────────────────────────────────────────────────────────────────────────╯ - [0.794] The user always prefers window seats on flights. - [0.748] The user is vegetarian. - [0.739] The user avoids dairy. Tool recall_preferences executed with result: - The user always prefers window seats on flights. (score=0.794) - The user is vegetarian. (score=0.748) - The user avoids dairy. (score=0.739)... [Finalize] todos_count=0, todos_with_results=0 ╭─────────────────────────── ✅ Agent Final Answer ────────────────────────────╮ │ │ │ Agent: Personal Concierge │ │ │ │ Final Answer: │ │ I recommend booking a **window seat** for the long flight, since you │ │ prefer window seats. │ │ │ │ For your in-flight meal, choose a **vegetarian dairy-free meal**. If the │ │ airline offers specific meal codes, look for something like **VGML / vegan │ │ meal**, since that will typically meet both preferences: vegetarian and no │ │ dairy. │ │ │ ╰──────────────────────────────────────────────────────────────────────────────╯ Agent 'Personal Concierge' completed task Output: I recommend booking a **window seat** for the long flight, since you prefer window seats. For your in-flight meal, choose a **vegetarian dairy-free meal**. If the airline offers specific meal codes, look for something like **VGML / vegan meal**, since that will typically meet both preferences: vegetarian and no dairy. Crew 'crew' has completed execution! Output: I recommend booking a **window seat** for the long flight, since you prefer window seats. For your in-flight meal, choose a **vegetarian dairy-free meal**. If the airline offers specific meal codes, look for something like **VGML / vegan meal**, since that will typically meet both preferences: vegetarian and no dairy. Agent (session 2, brand-new crew): I recommend booking a **window seat** for the long flight, since you prefer window seats. For your in-flight meal, choose a **vegetarian dairy-free meal**. If the airline offers specific meal codes, look for something like **VGML / vegan meal**, since that will typically meet both preferences: vegetarian and no dairy. ====================================================================== Proof: direct $vectorSearch recall over stored preferences ====================================================================== - [0.770] The user always prefers window seats on flights. - [0.768] The user is vegetarian. - [0.754] The user avoids dairy. Done - CrewAI stored and recalled preferences via MongoDB Vector Search.
注意
LLM の応答とベクトル検索スコアは実行ごとに異なる可能性があるため、出力が異なる可能性があります。