AIエージェントの場合: ドキュメントインデックスはhttps://www.mongodb.com/ja-jp/docs/llms.txt で利用可能です。任意のURLパスに .md を追加することで、すべてのページのマークダウン バージョンが利用できます。
Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
MongoDB Branding Shape
Click here >
Docs Menu

MongoDB を使用して AI エージェントをビルドする

MongoDB は、 AIエージェントを構築するためのいくつかの機能を提供します。ベクトルデータベースとドキュメントデータベースの両方として、 MongoDB はエージェント的 RG のさまざまな検索方法、また、短期間および長期のエージェントメモリのために同じデータベースにエージェントインタラクションを保存します。

はじめる

生成系 AI の文脈において、AI エージェントとは、通常、AI モデルを組み合わせて、LLM などを用いながら、あらかじめ定義されたツール群を使ってタスクを自律的または半自律的に実行できるシステムを指します。

AI エージェントはツールを使用してコンテキストを収集し、外部システムとやり取りし、アクションを実行できます。エージェントは独自の実行フロー(プランニング)を定義し、前のインタラクションを記憶して応答(メモリ)を通知できます。したがって、AI エージェントは、推論、計画、意思決定を必要とする複雑なタスクに最適です。

MongoDBを使用した単一エージェント アーキテクチャを示す図

AI エージェントには通常、以下のコンポーネントの組み合わせが含まれます。

認識

エージェントへの入力。テキスト入力は AI エージェントの最も一般的な知覚メカニズムですが、入力は音声、画像、またはマルチモーダル データであることもあります。

プランニング

エージェントが次に何をすべきかをどのように判断するか。このコンポーネントには通常、LLM やプロンプトが含まれ、フィードバック ループやさまざまなプロンプト エンジニアリング技術技術を用いて構成されます。たとえば、連鎖的思考や reAct などを活用し、LLM が複雑なタスクを論理的に処理できるように支援します。

AI エージェントは、意思決定者としての単一の LLM、複数のプロンプトを備えた LLM、連携して動作する複数の LLM、またはこれらのアプローチの任意の組み合わせで構成できます。

ツール

エージェントがタスクのコンテキストを収集する方法。ツールを使用することで、エージェントは外部システムとやり取りし、ベクトル検索、ウェブ検索、他のサービスからの API 呼び出しなどのアクションを実行できます。

メモリ

エージェントのやり取りを保存するシステムです。これにより、エージェントは過去の経験から学び、応答に役立てることができます。メモリは短期(現在のセッション用)または長期(セッション間で保持される)にすることができます。

注意

AI エージェントは設計パターン、機能、複雑さが異なります。他のエージェント アーキテクチャ(マルチエージェント システムを含む)について詳しくは、「エージェンティックデザインパターン」を参照してください。

MongoDB は、 AIエージェントを構築するための次のコンポーネントをサポートしています。

  • ツール: MongoDB の検索機能を活用して、エージェントが関連情報を検索し、エージェント型 RAG を実装するためのツールとして使用します。

  • メモリ: エージェントのインタラクションを短期および長期のメモリの両方の MongoDB コレクションに保存します。

AI エージェントのコンテキストでは、ツールとは、エージェントがプログラムで定義し、呼び出すことができるものを指します。ツールは、テキストの生成だけでなく、外部システムとのやり取り、情報の検索、アクションの実行など、エージェントの機能を拡張します。ツールは通常、以下を含む特定のインターフェースで定義されます。

  • エージェントがツールを使用するタイミングを理解するのに役立つ名前と説明。

  • 必須パラメーターとその期待される形式。

  • 呼び出された際に実際の操作を実行する関数です。

エージェントは推論機能を使用して、ユーザーの入力と現在のタスクに基づいて、どのツールを使用するか、いつ使用するか、どのパラメーターを提供するかを決定します。

標準のMongoDBクエリに加えて、 MongoDB はエージェントのツールとして実装できるいくつかの検索機能を提供します。

ツールは、手動で、またはツールの作成と呼び出しのための組み込みの抽象化を提供する フレームワーク を使用して定義できます。

ツールは、エージェントが特定のタスクを実行するために呼び出すことができる関数として定義されています。例として、次の構文は、ベクトル検索クエリを実行するツールを定義する方法を示します。

async function vectorSearchTool(query) {
const pipeline = [
{
$vectorSearch: {
// Vector search query pipeline...
}
}
];
const results = await collection.aggregate(pipeline).toArray();
return results;
}
def vector_search_tool(query: str) -> str:
pipeline = [
{
"$vectorSearch": {
# Vector search query pipeline...
}
}
]
results = collection.aggregate(pipeline)
array_of_results = []
for doc in results:
array_of_results.append(doc)
return array_of_results

ツール呼び出しは、エージェントがツールを実行するために使用するものです。エージェント内でツール呼び出しを処理する方法を定義することも、フレームワークを使用してこれを処理することもできます。これらは通常、ツール名とツールに渡すその他の引数を含むJSONオブジェクトとして定義されるため、エージェントは適切なパラメーターを使用してツールを呼び出すことができます。例、次の構文は、エージェントがベクトル検索ツールを呼び出す方法を示しています。

{
"tool": "vector_search_tool",
"args": { "query": "What is MongoDB?" },
"id": "call_H5TttXb423JfoulF1qVfPN3m"
}

MongoDB をベクトルデータベースとして使用することで、 エージェント Atlas のサンプル データ セット を作成するための検索ツールを作成できます。これは、 AIエージェントを通じて検索および生成プロセスを動的に統合することができる RG の高度な形式です。

MongoDBを使用したエージェント的 RG アーキテクチャの図

このアプローチにより、より複雑なワークフローとユーザー インタラクションが可能になります。例、セマンティック検索にはMongoDB ベクトル検索を使用し、全文検索にはMongoDB Search を使用するなど、タスクに基づいて最適な取得ツールを決定するようにAIエージェントを構成できます。また、エージェントの取得機能をさらにカスタマイズするために、さまざまなコレクションに対してさまざまな取得ツールを定義することもできます。

エージェントのメモリに以前のやり取りに関する情報を保存することで、エージェントは過去の経験から学ぶことができ、より関連性の高いパーソナライズされた応答を提供できるようになります。これは、文脈を必要とするタスク、例えば会話エージェントにとって特に重要です。こうしたエージェントは、首尾一貫して文脈に適した応答を提供するために、会話の前のターンを記憶しておく必要があります。エージェントメモリには、主に 2 つのタイプがあります。

  • 短期メモリ:最近のやり取りやアクティブなタスクコンテキストなど、現在のセッションの情報を保存します。

  • 長期メモリ:セッション間で情報を保持し、過去の会話や時間の経過に伴うパーソナライズされた設定などを含みます。

MongoDB はドキュメントデータベースでもあるため、 インタラクションをMongoDBコレクションに保存することでエージェントのメモリを実装できます。その後、エージェントは必要に応じてこのコレクションをクエリまたはアップデートできます。MongoDBでエージェントメモリを実装するにはいくつかの方法があります。

  • 短期メモリの場合、インタラクションを保存する際に特定のセッションを識別するためのsession_idフィールドを含め、その後、同じ ID を持つインタラクションをクエリしてエージェントにコンテキストとして渡すことができます。

  • 長期メモリの場合、LLM を使用して複数のインタラクションを処理し、ユーザーの好みや重要なコンテキストなどの関連情報を抽出し、その情報をエージェントが必要に応じてクエリできる別のコレクションに保存することができます。

  • チャット履歴をより効率的かつ複雑に取得できる堅牢なメモリ管理システムを構築するには、 MongoDB Search またはMongoDB ベクトル検索を活用して、セッション全体の重要なインタラクションを保存、インデックス、クエリを実行します。

短期メモリを保存するコレクション内のドキュメントは次のように表示される可能性があります。

{
"session_id": "123",
"user_id": "jane_doe",
"interactions":
[
{
"role": "user",
"content": "What is MongoDB?",
"timestamp": "2025-01-01T12:00:00Z"
},
{
"role": "assistant",
"content": "MongoDB is the world's leading modern database.",
"timestamp": "2025-01-01T12:00:05Z"
}
]
}

長期メモリを保存するコレクション内のドキュメントは次のように表示される可能性があります。

{
"user_id": "jane_doe",
"last_updated": "2025-05-22T09:15:00Z",
"preferences": {
"conversation_tone": "casual",
"custom_instructions": [
"I prefer concise answers."
],
},
"facts": [
{
"interests": ["AI", "MongoDB"],
}
]
}

次のフレームワークも、 MongoDBのエージェントメモリの直接抽象化を提供します。

フレームワーク
主な機能

LgChuin

  • MongoDBChatMessageHistory: チャットメッセージ履歴コンポーネント

  • MongoDBAtlasSemanticCache:セマンティックキャッシュコンポーネント

詳しくは、チュートリアルを参照してください。

LangGraph

  • MongoDBSaver: 永続化に使用できる短期間メモリ チェックポイント

  • MongoDBStore: MongoDBにメモリを保存するための長期ドキュメントストア( Python統合でのみ利用可能)

詳しくは、 LongGraphLgGraph.js を参照してください。

次のチュートリアルでは、エージェントフレームワークなしで、 MongoDBを使用してエージェント用 RAG とメモリ用にAIエージェントを構築する方法を説明します。


➤ このチュートリアルの言語を設定するには、 言語を選択 ドロップダウン メニューを使用します。


このチュートリアルの実行可能なバージョンをPythonノートとして操作します。

Atlas の サンプル データ セット からの映画データを含むコレクションを使用します。

  • 次のいずれかのMongoDBクラスター タイプ

    • MongoDBバージョン6.0.11を実行しているAtlas クラスター7.0.2、またはそれ以降。IPアドレスが Atlas プロジェクトのアクセス リストに含まれていることを確認します。

    • Atlas CLI を使用して作成されたローカル Atlas 配置。詳細については、「Atlas 配置のローカル配置の作成」を参照してください。

    • Search とベクトル検索がインストールされたMongoDB Community または Enterprise クラスター。

  • Voyage AI API キー。

  • OpenAI API キー。

注意

このチュートリアルでは、Voyage AI と OpenAI のモデルを使用していますが、コードを変更して、任意のモデルを使用できます。

この AI エージェントを使用して、カスタムデータソースに関する質問に回答し、計算を実行できます。また、前のやり取りを記憶して、応答に反映させることもできます。次のコンポーネントを使用します。

  • 認識:テキスト入力。

  • 計画:タスクを推論するための LLM とさまざまなプロンプト。

  • ツール:ベクトル検索ツールと計算ツール。

  • メモリ:インタラクションを MongoDB コレクションに保存。

1
  1. プロジェクトを初期化し、依存関係をインストールします。

    新しいプロジェクトディレクトリを作成し、必要な依存関係をインストールします。

    mkdir mongodb-ai-agent
    cd mongodb-ai-agent
    npm init -y
    npm install --quiet dotenv mongodb voyageai openai langchain @langchain/community @langchain/core mathjs pdf-parse@1

    注意

    プロジェクトでは、次の構造を使用します。

    mongodb-ai-agent
    ├── .env
    ├── config.js
    ├── ingest-data.js
    ├── tools.js
    ├── memory.js
    ├── planning.js
    └── index.js
  2. 環境を構成します。

    プロジェクトに .env という名前の環境ファイルを作成します。このファイルには、エージェント、 MongoDB接続文字列、 MongoDBデータベースとコレクションの名前のAPIキーが含まれます。

    次のコードをコピーして、.env に貼り付けますファイル.

    プレースホルダー値をMongoDB接続文字列と、Vyage AIおよび OpenAI APIキーで置き換えます。

    MONGODB_URI="<mongodb-connection-string>"
    VOYAGE_API_KEY="<voyage-api-key>"
    OPENAI_API_KEY= "<openai-api-key>"

    注意

    <connection-string> を Atlas クラスターまたはローカル Atlas 配置の接続文字列に置き換えます。

    接続stringには、次の形式を使用する必要があります。

    mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net

    クライアント ライブラリを使用したクラスターへの接続」を参照してください。

    接続stringには、次の形式を使用する必要があります。

    mongodb://localhost:<port-number>/?directConnection=true

    詳細については、「接続文字列 」を参照してください。

2

プロジェクトに config.js という名前のファイルを作成します。このファイルは、環境変数を読み取り、アプリケーションをMongoDBデータベースや OpenAI などのサービスに接続します。

次のコードをコピーして、 config.jsファイルに貼り付けます。

import dotenv from 'dotenv';
import { MongoClient } from 'mongodb';
import OpenAI from "openai";
// Load environment variables from .env file
dotenv.config();
// MongoDB cluster configuration
export const MONGODB_URI = process.env.MONGODB_URI;
export const mongoClient = new MongoClient(MONGODB_URI);
export const agentDb = mongoClient.db("ai_agent_db");
export const vectorCollection = agentDb.collection("embeddings");
export const memoryCollection = agentDb.collection("chat_history");
// Model Configuration
export const OPENAI_MODEL = "gpt-4o";
export const VOYAGE_MODEL = "voyage-3-large";
export const VOYAGE_API_KEY = process.env.VOYAGE_API_KEY;
// Initialize OpenAI Client
export const openAIClient = new OpenAI({ apiKey: process.env.OPENAI_API_KEY,});
3

プロジェクトに ingest-data.js という名前のファイルを作成します。このスクリプトは、 埋め込みモデルを使用して、最近のMongoDB の収益レポートを含むサンプルPDF をMongoDBのコレクションに取り込みます。voyage-3-largeこのコードには、データがまだ存在しない場合にベクトル検索インデックスを作成する関数も含まれています。

詳細については、「取り込み」をご覧ください。

次のコードをコピーして、 ingest-data.jsファイルに貼り付けます。

import { PDFLoader } from "@langchain/community/document_loaders/fs/pdf";
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
import { vectorCollection } from "./config.js";
import { VOYAGE_API_KEY, VOYAGE_MODEL } from "./config.js";
import { VoyageAIClient } from "voyageai";
import { MONGODB_URI } from "./config.js";
import * as fs from 'fs';
import fetch from 'node-fetch';
console.log("Connecting to MongoDB:", MONGODB_URI);
const EMBEDDING_DIMENSIONS = 1024;
// Use Voyage AI Client SDK to get embeddings
export async function getEmbedding(data, input_type) {
if (!VOYAGE_API_KEY) {
throw new Error("VOYAGE_API_KEY is not set in environment variables.");
}
try {
const client = new VoyageAIClient({ apiKey: VOYAGE_API_KEY });
const response = await client.embed({
input: [data],
model: VOYAGE_MODEL,
input_type: input_type // "document" or "query"
});
if (response.data && response.data.length > 0) {
return response.data[0].embedding;
}
throw new Error("No embedding data found from Voyage AI response.");
}
catch (error) {
console.error("Error generating Voyage AI embedding:", error);
return null;
}
}
// Ingest data from a PDF, generate embeddings, and store in MongoDB
export async function ingestData() {
try {
// download PDF
const rawData = await fetch("https://investors.mongodb.com/node/13176/pdf");
const pdfBuffer = await rawData.arrayBuffer();
fs.writeFileSync("investor-report.pdf", Buffer.from(pdfBuffer));
// load and split PDF
const loader = new PDFLoader("investor-report.pdf");
const data = await loader.load();
const textSplitter = new RecursiveCharacterTextSplitter({
chunkSize: 400,
chunkOverlap: 20,
});
const docs = await textSplitter.splitDocuments(data);
console.log(`Chunked PDF into ${docs.length} documents.`);
// generate embeddings and insert
const insertDocuments = await Promise.all(docs.map(async doc => ({
document: doc,
embedding: await getEmbedding(doc.pageContent, "document"),
})));
const result = await vectorCollection.insertMany(insertDocuments, { ordered: false });
console.log("Inserted documents:", result.insertedCount);
} catch (err) {
console.error("Ingestion error:", err);
}
}
// Create a vector search index
export async function createVectorIndex() {
try {
// check if the index already exists
const existingIndexes = await vectorCollection.listSearchIndexes().toArray();
if (existingIndexes.some(index => index.name === "vector_index")) {
console.log("Vector index already exists. Skipping creation.");
return;
}
// define your Vector Search index
const index = {
name: "vector_index",
type: "vectorSearch",
definition: {
"fields": [
{
"type": "vector",
"path": "embedding",
"numDimensions": EMBEDDING_DIMENSIONS,
"similarity": "cosine",
}
]
}
}
// run the helper method to ensure the index is created
const result = await vectorCollection.createSearchIndex(index);
console.log(`New index named ${result} is building.`);
// wait for the index to be ready to query
console.log("Polling to check if the index is ready. This may take up to a minute.")
let isQueryable = false;
while (!isQueryable) {
const cursor = vectorCollection.listSearchIndexes();
for await (const index of cursor) {
if (index.name === result) {
if (index.queryable) {
console.log(`${result} is ready for querying.`);
isQueryable = true;
} else {
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
}
}
} catch (err) {
console.error("Error creating vector index:", err);
throw err;
}
}
4

プロジェクトに tools.js という名前のファイルを作成します。このファイルは、エージェントが質問に答えるために使用できるツールを定義します。この例では、次のツールを定義します。

  • vectorSearchToolベクトル検索クエリを実行して、コレクションから関連するドキュメントを取得します。

  • calculatorTool: 基本的な数学操作に mathjs ライブラリを使用します。

次のコードをコピーして、 Tools.jsファイルに貼り付けます。

import { getEmbedding } from './ingest-data.js';
import { vectorCollection } from './config.js';
import { evaluate } from 'mathjs';
// Vector search tool
export async function vectorSearchTool(userInput) {
const queryEmbedding = await getEmbedding(userInput, "query");
const pipeline = [
{
$vectorSearch: {
index: "vector_index",
queryVector: queryEmbedding,
path: "embedding",
exact: true,
limit: 5
}
},
{
$project: {
_id: 0,
"document.pageContent": 1
}
}
];
const cursor = vectorCollection.aggregate(pipeline);
const results = await cursor.toArray();
return results;
}
// Simple calculator tool
export function calculatorTool(userInput) {
try {
const result = evaluate(userInput);
return String(result);
} catch (e) {
return `Error: ${e.message}`;
}
}
5

プロジェクトに memory.js という名前のファイルを作成します。このファイルは、エージェントが対話を保存するために使用するシステムを定義します。この例では、次の関数を定義して短期メモリを実装します。

  • storeChatMessage:インタラクションに関する情報を MongoDB コレクションに保存します。

  • retrieveSessionHistorysession_idフィールドを使用して特定のセッションのすべてのインタラクションを取得するには。

次のコードをコピーして、 memory.jsファイルに貼り付けます。

import { memoryCollection } from './config.js';
/**
* Store a chat message in the memory collection.
* @param {string} sessionId - unique identifier for the chat session
* @param {string} role - role of the sender (user or system)
* @param {string} content - content of the message
*/
export async function storeChatMessage(sessionId, role, content) {
const message = {
session_id: sessionId,
role,
content,
timestamp: new Date(), // use JS date for timestamp
};
await memoryCollection.insertOne(message);
}
/**
* Retrieve the chat history for a session.
* @param {string} sessionId - unique identifier for the chat session
* @returns {Promise<Array<{role: string, content: string}>>}
*/
export async function retrieveSessionHistory(sessionId) {
const cursor = memoryCollection
.find({ session_id: sessionId })
.sort({ timestamp: 1 });
const messages = [];
await cursor.forEach(msg => {
messages.push({ role: msg.role, content: msg.content });
});
return messages;
}
6

プロジェクトに planning.js という名前のファイルを作成します。このファイルには、エージェントの実行フローを決定するためのさまざまなプロンプトと LLM 呼び出しが含まれます。この例では、次の関数を定義します。

  • openAIChatCompletion: 応答を生成するために OpenAI APIを呼び出すヘルパー関数。

  • toolSelector:LLMがタスクに適したツールを選択する方法を決定します。

  • generateAnswer: ツールを使用し、LLM を呼び出し、結果をプロセシングすることで、エージェントの実行フローを調整します。

  • getLLMResponse: LLM 応答生成用のヘルパー関数。

次のコードをコピーして、 plan.jsファイルに貼り付けます。

import { vectorSearchTool, calculatorTool } from './tools.js';
import { storeChatMessage, retrieveSessionHistory } from './memory.js';
import { openAIClient, OPENAI_MODEL } from './config.js';
// OpenAI chat completion helper
export async function openAIChatCompletion(messages) {
try {
const completion = await openAIClient.chat.completions.create({
model: OPENAI_MODEL,
messages,
max_tokens: 1024,
});
return completion.choices[0].message.content;
} catch (error) {
console.error("Error in openAIChatCompletion:", error);
throw error;
}
}
// Tool selector function to determine which tool to use based on user input and session history
export async function toolSelector(userInput, sessionHistory = []) {
const systemPrompt = `
Select the appropriate tool from the options below. Consider the full context of the conversation before deciding.
Tools available:
- vector_search_tool: Retrieve specific context about recent MongoDB earnings and announcements
- calculator_tool: For mathematical operations
- none: For general questions without additional context
Process for making your decision:
1. Analyze if the current question relates to or follows up on a previous vector search query
2. For follow-up questions, incorporate context from previous exchanges to create a comprehensive search query
3. Only use calculator_tool for explicit mathematical operations
4. Default to none only when certain the other tools won't help
When continuing a conversation:
- Identify the specific topic being discussed
- Include relevant details from previous exchanges
- Formulate a query that stands alone but preserves conversation context
Return a JSON object only: {"tool": "selected_tool", "input": "your_query"}
`.trim();
const messages = [
{ role: "system", content: systemPrompt },
...sessionHistory,
{ role: "user", content: userInput }
];
try {
const response = await openAIChatCompletion(messages);
let toolCall;
try {
toolCall = JSON.parse(response);
} catch {
try {
toolCall = eval(`(${response})`);
} catch {
return { tool: "none", input: userInput };
}
}
return {
tool: toolCall.tool || "none",
input: toolCall.input || userInput
};
} catch (err) {
console.error("Error in toolSelector:", err);
return { tool: "none", input: userInput };
}
}
// Function to get LLM response based on messages and system message content
async function getLlmResponse(messages, systemMessageContent) {
const systemMessage = { role: "system", content: systemMessageContent };
let fullMessages;
if (messages.some(msg => msg.role === "system")) {
fullMessages = [...messages, systemMessage];
} else {
fullMessages = [systemMessage, ...messages];
}
const response = await openAIChatCompletion(fullMessages);
return response;
}
// Function to generate response based on user input
export async function generateResponse(sessionId, userInput) {
await storeChatMessage(sessionId, "user", userInput);
const sessionHistory = await retrieveSessionHistory(sessionId);
const llmInput = [...sessionHistory, { role: "user", content: userInput }];
const { tool, input: toolInput } = await toolSelector(userInput, sessionHistory);
console.log("Tool selected:", tool);
let response;
if (tool === "vector_search_tool") {
const contextResults = await vectorSearchTool(toolInput);
const context = contextResults.map(doc => doc.document?.pageContent || JSON.stringify(doc)).join('\n---\n');
const systemMessageContent = `
Answer the user's question based on the retrieved context and conversation history.
1. First, understand what specific information the user is requesting
2. Then, locate the most relevant details in the context provided
3. Finally, provide a clear, accurate response that directly addresses the question
If the current question builds on previous exchanges, maintain continuity in your answer.
Only state facts clearly supported by the provided context. If information is not available, say 'I DON'T KNOW'.
Context:
${context}
`.trim();
response = await getLlmResponse(llmInput, systemMessageContent);
} else if (tool === "calculator_tool") {
response = calculatorTool(toolInput);
} else {
const systemMessageContent = "You are a helpful assistant. Respond to the user's prompt as best as you can based on the conversation history.";
response = await getLlmResponse(llmInput, systemMessageContent);
}
await storeChatMessage(sessionId, "system", response);
return response;
}
7

最後に、プロジェクトに「index.js」という名前のファイルを作成します。このファイルはエージェントを実行し、エージェントと交流できるようにします。

次のコードをコピーして、インデックスの.jsファイルに貼り付けます。

import readline from 'readline';
import { mongoClient } from './config.js';
import { ingestData, createVectorIndex } from './ingest-data.js';
import { generateResponse } from './planning.js';
// Prompt for user input
async function prompt(question) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
return new Promise(resolve => rl.question(question, answer => {
rl.close();
resolve(answer);
}));
}
async function main() {
try {
await mongoClient.connect();
const runIngest = await prompt("Ingest sample data? (y/n): ");
if (runIngest.trim().toLowerCase() === 'y') {
await ingestData();
console.log("\nAttempting to create/verify Vector Search Index...");
await createVectorIndex();
} else {
await createVectorIndex(); // ensure index exists even if not ingesting data
}
const sessionId = await prompt("Enter a session ID: ");
while (true) {
const userQuery = await prompt("\nEnter your query (or type 'quit' to exit): ");
if (userQuery.trim().toLowerCase() === 'quit') break;
if (!userQuery.trim()) {
console.log("Query cannot be empty. Please try again.");
continue;
}
const answer = await generateResponse(sessionId, userQuery);
console.log("\nAnswer:");
console.log(answer);
}
} finally {
await mongoClient.close();
}
}
main();

プロジェクトを保存し、次のコマンドを実行します。エージェントを実行する際には以下に従います。

  • まだ行っていない場合は、エージェントにサンプルデータを取り込むように指示します。

  • セッションIDを入力して、新しいセッションを開始するか、既存のセッションを続行してください。

  • 質問をしてください。エージェントは、ツール、以前の対話、計画フェーズで定義されたプロンプトに基づいて応答を生成します。

サンプルインタラクションについては、出力例を参照してください。

node index.js
Ingest sample data? (y/n): y
Chunked PDF into 100 documents.
Inserted documents: 100
Attempting to create/verify Vector Search Index...
New index named vector_index is building.
Polling to check if the index is ready. This may take up to a minute.
vector_index is ready for querying.
Enter a session ID: 123
Enter your query (or type 'quit' to exit): What was MongoDB's latest acquisition?
Tool selected: vector_search_tool
Answer:
MongoDB recently acquired Voyage AI, a pioneer in embedding and reranking models that power next-generation AI applications.
Enter your query (or type 'quit' to exit): What do they do?
Tool selected: vector_search_tool
Answer: Voyage AI is a company that specializes in
state-of-the-art embedding and reranking models designed to
power next-generation AI applications. These technologies help
organizations build more advanced and trustworthy AI
capabilities.
Enter your query (or type 'quit' to exit): What is 123+456?
Tool selected: calculator_tool
Answer:
579

Tip

Atlas を使用している場合は、ai_agent_db.embeddings 名前空間に移動することで、埋め込みとインタラクションを検証できます。Atlas UI で。

8

基本的な AI エージェントが完成したので、次の方法で開発を続けることができます:

  • ベクトル検索ツールのパフォーマンスを向上させ、RAG パイプラインを微調整します

  • ハイブリッドまたは全文検索ツールなど、エージェントにツールを追加します。

  • より高度なプロンプトと呼び出す LLM を使用して計画フェーズを洗練させます。

  • MongoDB SearchMongoDB ベクトル検索を使用して、セッション間の重要なインタラクションを保存および検索することで、長期メモリおよびより高度なメモリ システムを実装します。

1
  1. プロジェクトを初期化し、依存関係をインストールします。

    新しいプロジェクトディレクトリを作成し、必要な依存関係をインストールします。

    mkdir mongodb-ai-agent
    cd mongodb-ai-agent
    pip install --quiet --upgrade pymongo voyageai openai langchain langchain-mongodb
    langchain-community python-dotenv

    注意

    プロジェクトでは、次の構造を使用します。

    mongodb-ai-agent
    ├── .env
    ├── config.py
    ├── ingest_data.py
    ├── tools.py
    ├── memory.py
    ├── planning.py
    ├── main.py
  2. 環境を構成します。

    プロジェクトに .env という名前の環境ファイルを作成します。このファイルには、エージェント、 MongoDB接続文字列、 MongoDBデータベースとコレクションの名前のAPIキーが含まれます。

    次のコードをコピーして、.env に貼り付けますファイル.

    プレースホルダー値をMongoDB接続文字列と、Vyage AIおよび OpenAI APIキーで置き換えます。

    MONGODB_URI="<mongodb-connection-string>"
    VOYAGE_API_KEY="<voyage-api-key>"
    OPENAI_API_KEY= "<openai-api-key>"

    注意

    <connection-string> を Atlas クラスターまたはローカル Atlas 配置の接続文字列に置き換えます。

    接続stringには、次の形式を使用する必要があります。

    mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net

    クライアント ライブラリを使用したクラスターへの接続」を参照してください。

    接続stringには、次の形式を使用する必要があります。

    mongodb://localhost:<port-number>/?directConnection=true

    詳細については、「接続文字列 」を参照してください。

2

プロジェクトに config.py という名前のファイルを作成します。このファイルは、環境変数を読み取り、アプリケーションをMongoDBデータベースや OpenAI などのサービスに接続します。

以下のコードをコピーして、config.py ファイルに貼り付けます。

from pymongo import MongoClient
from openai import OpenAI
import voyageai
from dotenv import load_dotenv
import os
# Load environment variables from .env file
load_dotenv()
# Environment variables (private)
MONGODB_URI = os.getenv("MONGODB_URI")
VOYAGE_API_KEY = os.getenv("VOYAGE_API_KEY")
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
# MongoDB cluster configuration
mongo_client = MongoClient(MONGODB_URI)
agent_db = mongo_client["ai_agent_db"]
vector_collection = agent_db["embeddings"]
memory_collection = agent_db["chat_history"]
# Model configuration
voyage_client = voyageai.Client(api_key=VOYAGE_API_KEY)
openai_client = OpenAI(api_key=OPENAI_API_KEY)
VOYAGE_MODEL = "voyage-3-large"
OPENAI_MODEL = "gpt-4o"
3

プロジェクトに ingest_data.py という名前のファイルを作成します。このスクリプトは、 埋め込みモデルを使用して、最近のMongoDB の収益レポートを含むサンプルPDF をMongoDBのコレクションに取り込みます。voyage-3-largeこのコードには、データがまだ存在しない場合にベクトル検索インデックスを作成する関数も含まれています。

詳細については、「取り込み」をご覧ください。

次のコードをコピーして、 ingest_data.pyファイルに貼り付けます。

from config import vector_collection, voyage_client, VOYAGE_MODEL
from pymongo.operations import SearchIndexModel
from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
import time
# Define a function to generate embeddings
def get_embedding(data, input_type = "document"):
embeddings = voyage_client.embed(
data, model = VOYAGE_MODEL, input_type = input_type
).embeddings
return embeddings[0]
# --- Ingest embeddings into MongoDB ---
def ingest_data():
# Chunk PDF data
loader = PyPDFLoader("https://investors.mongodb.com/node/13176/pdf")
data = loader.load()
text_splitter = RecursiveCharacterTextSplitter(chunk_size=400, chunk_overlap=20)
documents = text_splitter.split_documents(data)
print(f"Successfully split PDF into {len(documents)} chunks.")
# Ingest chunked documents into collection
print("Generating embeddings and ingesting documents...")
docs_to_insert = []
for i, doc in enumerate(documents):
embedding = get_embedding(doc.page_content)
if embedding:
docs_to_insert.append({
"text": doc.page_content,
"embedding": embedding
})
if docs_to_insert:
result = vector_collection.insert_many(docs_to_insert)
print(f"Inserted {len(result.inserted_ids)} documents into the collection.")
else:
print("No documents were inserted. Check embedding generation process.")
# --- Create the vector search index ---
index_name = "vector_index"
search_index_model = SearchIndexModel(
definition = {
"fields": [
{
"type": "vector",
"numDimensions": 1024,
"path": "embedding",
"similarity": "cosine"
}
]
},
name=index_name,
type="vectorSearch"
)
try:
vector_collection.create_search_index(model=search_index_model)
print(f"Search index '{index_name}' creation initiated.")
except Exception as e:
print(f"Error creating search index: {e}")
return
# Wait for initial sync to complete
print("Polling to check if the index is ready. This may take up to a minute.")
predicate=None
if predicate is None:
predicate = lambda index: index.get("queryable") is True
while True:
indices = list(vector_collection.list_search_indexes(index_name))
if len(indices) and predicate(indices[0]):
break
time.sleep(5)
print(index_name + " is ready for querying.")
4

プロジェクトに tools.py という名前のファイルを作成します。このファイルは、エージェントが質問に答えるために使用できるツールを定義します。この例では、次のツールを定義します。

  • vector_search_toolベクトル検索クエリを実行して、コレクションから関連するドキュメントを取得します。

  • calculator_tool:基本的な数学操作に eval() 関数を使用します。

以下のコードをコピーして、tools.py ファイルに貼り付けます。

from config import vector_collection
from ingest_data import get_embedding
# Define a vector search tool
def vector_search_tool(user_input: str) -> str:
query_embedding = get_embedding(user_input)
pipeline = [
{
"$vectorSearch": {
"index": "vector_index",
"queryVector": query_embedding,
"path": "embedding",
"exact": True,
"limit": 5
}
}, {
"$project": {
"_id": 0,
"text": 1
}
}
]
results = vector_collection.aggregate(pipeline)
array_of_results = []
for doc in results:
array_of_results.append(doc)
return array_of_results
# Define a simple calculator tool
def calculator_tool(user_input: str) -> str:
try:
result = eval(user_input)
return str(result)
except Exception as e:
return f"Error: {str(e)}"
5

プロジェクトに memory.py という名前のファイルを作成します。このファイルは、エージェントが対話を保存するために使用するシステムを定義します。この例では、次の関数を定義して短期メモリを実装します。

  • store_chat_message:インタラクションに関する情報を MongoDB コレクションに保存します。

  • retrieve_session_historysession_idフィールドを使用して特定のセッションのすべてのインタラクションを取得するには。

以下のコードをコピーして、memory.py ファイルに貼り付けます。

from config import memory_collection
from datetime import datetime
from typing import List
def store_chat_message(session_id: str, role: str, content: str) -> None:
message = {
"session_id": session_id, # Unique identifier for the chat session
"role": role, # Role of the sender (user or system)
"content": content, # Content of the message
"timestamp": datetime.now(), # Timestamp of when the message was sent
}
memory_collection.insert_one(message)
def retrieve_session_history(session_id: str) -> List:
# Query the collection for messages with a specific "session_id" in ascending order
cursor = memory_collection.find({"session_id": session_id}).sort("timestamp", 1)
# Iterate through the cursor and return a JSON object with the message role and content
if cursor:
messages = [{"role": msg["role"], "content": msg["content"]} for msg in cursor]
else:
messages = []
return messages
6

プロジェクトに planning.py という名前のファイルを作成します。このファイルには、エージェントの実行フローを決定するためのさまざまなプロンプトと LLM 呼び出しが含まれます。この例では、次の関数を定義します。

  • tool_selector:LLMがタスクに適したツールを選択する方法を決定します。

  • generate_answer: ツールを使用し、LLM を呼び出し、結果をプロセシングすることで、エージェントの実行フローを調整します。

  • get_llm_response: LLM 応答生成用のヘルパー関数。

以下のコードをコピーして、planning.py ファイルに貼り付けます。

from config import openai_client, OPENAI_MODEL
from tools import vector_search_tool, calculator_tool
from memory import store_chat_message, retrieve_session_history
# Define a tool selector function that decides which tool to use based on user input and message history
def tool_selector(user_input, session_history=None):
messages = [
{
"role": "system",
"content": (
"Select the appropriate tool from the options below. Consider the full context of the conversation before deciding.\n\n"
"Tools available:\n"
"- vector_search_tool: Retrieve specific context about recent MongoDB earnings and announcements\n"
"- calculator_tool: For mathematical operations\n"
"- none: For general questions without additional context\n"
"Process for making your decision:\n"
"1. Analyze if the current question relates to or follows up on a previous vector search query\n"
"2. For follow-up questions, incorporate context from previous exchanges to create a comprehensive search query\n"
"3. Only use calculator_tool for explicit mathematical operations\n"
"4. Default to none only when certain the other tools won't help\n\n"
"When continuing a conversation:\n"
"- Identify the specific topic being discussed\n"
"- Include relevant details from previous exchanges\n"
"- Formulate a query that stands alone but preserves conversation context\n\n"
"Return a JSON object only: {\"tool\": \"selected_tool\", \"input\": \"your_query\"}"
)
}
]
if session_history:
messages.extend(session_history)
messages.append({"role": "user", "content": user_input})
response = openai_client.chat.completions.create(
model=OPENAI_MODEL,
messages=messages
).choices[0].message.content
try:
tool_call = eval(response)
return tool_call.get("tool"), tool_call.get("input")
except:
return "none", user_input
# Define the agent workflow
def generate_response(session_id: str, user_input: str) -> str:
# Store the user input in the chat history collection
store_chat_message(session_id, "user", user_input)
# Initialize a list of inputs to pass to the LLM
llm_input = []
# Retrieve the session history for the current session and add it to the LLM input
session_history = retrieve_session_history(session_id)
llm_input.extend(session_history)
# Append the user message in the correct format
user_message = {
"role": "user",
"content": user_input
}
llm_input.append(user_message)
# Call the tool_selector function to determine which tool to use
tool, tool_input = tool_selector(user_input, session_history)
print("Tool selected: ", tool)
# Process based on selected tool
if tool == "vector_search_tool":
context = vector_search_tool(tool_input)
# Construct the system prompt using the retrieved context and append it to the LLM input
system_message_content = (
f"Answer the user's question based on the retrieved context and conversation history.\n"
f"1. First, understand what specific information the user is requesting\n"
f"2. Then, locate the most relevant details in the context provided\n"
f"3. Finally, provide a clear, accurate response that directly addresses the question\n\n"
f"If the current question builds on previous exchanges, maintain continuity in your answer.\n"
f"Only state facts clearly supported by the provided context. If information is not available, say 'I DON'T KNOW'.\n\n"
f"Context:\n{context}"
)
response = get_llm_response(llm_input, system_message_content)
elif tool == "calculator_tool":
# Perform the calculation using the calculator tool
response = calculator_tool(tool_input)
else:
system_message_content = "You are a helpful assistant. Respond to the user's prompt as best as you can based on the conversation history."
response = get_llm_response(llm_input, system_message_content)
# Store the system response in the chat history collection
store_chat_message(session_id, "system", response)
return response
# Helper function to get the LLM response
def get_llm_response(messages, system_message_content):
# Add the system message to the messages list
system_message = {
"role": "system",
"content": system_message_content,
}
# If the system message should go at the end (for context-based queries)
if any(msg.get("role") == "system" for msg in messages):
messages.append(system_message)
else:
# For general queries, put system message at beginning
messages = [system_message] + messages
# Get response from LLM
response = openai_client.chat.completions.create(
model=OPENAI_MODEL,
messages=messages
).choices[0].message.content
return response
7

最後に、プロジェクトに「main.py」という名前のファイルを作成します。このファイルはエージェントを実行し、エージェントと交流できるようにします。

次のコードをコピーして、main.pyファイルに貼り付けます。

from config import mongo_client
from ingest_data import ingest_data
from planning import generate_response
if __name__ == "__main__":
try:
run_ingest = input("Ingest sample data? (y/n): ")
if run_ingest.lower() == 'y':
ingest_data()
session_id = input("Enter a session ID: ")
while True:
user_query = input("\nEnter your query (or type 'quit' to exit): ")
if user_query.lower() == 'quit':
break
if not user_query.strip():
print("Query cannot be empty. Please try again.")
continue
answer = generate_response(session_id, user_query)
print("\nAnswer:")
print(answer)
finally:
mongo_client.close()

プロジェクトを保存し、次のコマンドを実行します。エージェントを実行する際には以下に従います。

  • まだ行っていない場合は、エージェントにサンプルデータを取り込むように指示します。

  • セッションIDを入力して、新しいセッションを開始するか、既存のセッションを続行してください。

  • 質問をしてください。エージェントは、ツール、以前の対話、計画フェーズで定義されたプロンプトに基づいて応答を生成します。

サンプルインタラクションについては、出力例を参照してください。

python main.py
Ingest sample data? (y/n): y
Successfully split PDF into 104 chunks.
Generating embeddings and ingesting documents...
Inserted 104 documents into the collection.
Search index 'vector_index' creation initiated.
Polling to check if the index is ready. This may take up to a minute.
vector_index is ready for querying.
Enter a session ID: 123
Enter your query (or type 'quit' to exit): What was MongoDB's latest acquisition?
Tool selected: vector_search_tool
Answer:
MongoDB's latest acquisition was Voyage AI.
Enter your query (or type 'quit' to exit): What do they do?
Tool selected: vector_search_tool
Answer:
Voyage AI is a company that specializes in state-of-the-art embedding and reranking models designed to power next-generation AI applications. These technologies help organizations build more advanced and trustworthy AI capabilities.
Enter your query (or type 'quit' to exit): What is 123+456?
Tool selected: calculator_tool
Answer:
579

Tip

Atlas を使用している場合は、ai_agent_db.embeddings 名前空間に移動することで、埋め込みとインタラクションを検証できます。Atlas UI で。

8

基本的な AI エージェントが完成したので、次の方法で開発を続けることができます:

  • ベクトル検索ツールのパフォーマンスを向上させ、RAG パイプラインを微調整します

  • ハイブリッドまたは全文検索ツールなど、エージェントにツールを追加します。

  • より高度なプロンプトと呼び出す LLM を使用して計画フェーズを洗練させます。

  • MongoDB SearchMongoDB ベクトル検索を使用して、セッション間の重要なインタラクションを保存および検索することで、長期メモリおよびより高度なメモリ システムを実装します。

MongoDB を使用して AI エージェントを構築する詳細なチュートリアルについては、次の表を参照してください。