MongoDB ベクトル検索 を LgChuinGo と統合すると、大規模言語モデル(LVM)アプリケーションを構築し、検索拡張生成 (RAG)(RAG)を実装できます。このチュートリアルでは、LgacheinGo とMongoDB ベクトル検索の使用を開始し、データのセマンティック検索を実行し、RAG実装を構築する方法を説明します。具体的には、次のアクションを実行します。
環境を設定します。
カスタム データをMongoDBに保存します。
データにMongoDB ベクトル検索インデックスを作成します。
次のベクトル検索クエリを実行します。
セマンティック検索。
メタデータの事前フィルタリングによるセマンティック検索。
MongoDB ベクトル検索を使用してデータの質問に答え、RAG を実装します。
バックグラウンド
LangChainGo は、LangChain を Go プログラミング言語で実装したものです。これは、コミュニティ主導によるサードパーティ製の LangChain フレームワークのポートです。
LgChuin は、「チェーン」の使用を通じて LVM アプリケーションの作成を簡素化するオープンソースのフレームワークです。 チェーンは 、RAG を含むさまざまなAIユースケースで組み合わせることができる Lgachein 固有のコンポーネントです。
MongoDB ベクトル検索 をLgachein と統合することで、 MongoDB をベクトルデータベースとして使用し、 MongoDB ベクトル検索を使用してセマンティックで類似したドキュメントを検索して RG を実装することができます。RG の詳細については、「 MongoDBを使用した検索拡張生成(RAG) 」を参照してください。
LgChuinGo は、 AIアプリケーション用の LM のオーケストレーションを容易にし、Lgachein の機能をGo のエコシステムに導入します。また、開発者は、 MongoDBなど、ベクトル ストアと互換性のあるデータベースに接続できます。
手順
前提条件
Atlas の サンプル データ セット からの映画データを含むコレクションを使用します。
次のいずれかのMongoDBクラスター タイプ
MongoDB バージョン 6.0.11、7.0.2、またはそれ以降を実行している Atlas クラスター。IP アドレスが Atlas プロジェクトのアクセスリストに含まれていることを確認する。
Atlas CLI を使用して作成されたローカル Atlas 配置。詳細については、「Atlas 配置のローカル配置の作成」を参照してください。
Search とベクトル検索がインストールされたMongoDB Community または Enterprise クラスター。
OpenAI APIキー。APIリクエストに使用できるクレジットを持つ OpenAI アカウントが必要です。OpenAI アカウントの登録の詳細については、OpenAI APIウェブサイト を参照してください。
投票AI APIキー。アカウントとAPIキーを作成するには、Vyage AI のウェブサイト を参照してください。
Go プロジェクトを実行するためのターミナルとコード エディター。
環境を設定する
このチュートリアルを始めるには、まず環境をセットアップする必要があります。次の手順に従って環境を構成してください。
依存関係をインストールします。
次のコマンドを実行します。
go get github.com/joho/godotenv go get github.com/tmc/langchaingo/chains go get github.com/tmc/langchaingo/llms go get github.com/tmc/langchaingo/prompts go get github.com/tmc/langchaingo/vectorstores/mongovector go get github.com/tmc/langchaingo/embeddings/voyageai go get go.mongodb.org/mongo-driver/v2/mongo go mod tidy
環境変数を初期化してください。
langchaingo-mongodbプロジェクトディレクトリに、.envファイルを作成し、次の行を追加します。
OPENAI_API_KEY="<openai-api-key>" VOYAGEAI_API_KEY="<voyage-api-key>" MONGODB_URI="<connection-string>"
プレースホルダー値を、OpenAI APIキー、Voyage AI APIキー、およびMongoDBクラスターの SRV 接続文字列 に置き換えます。接続文字列には、次の形式を使用する必要があります。
mongodb+srv://<username>:<password>@<cluster-name>.mongodb.net/<dbname>
MongoDB をベクトル ストアとして使用
このセクションでは、カスタム データをMongoDBにロードし、 MongoDB をベクトルデータベース(ベクトルストアとも)としてインスタンス化するための非同期関数を定義します。
次の依存関係をインポートします。
次のインポートを main.goファイルの先頭に追加します。
package main import ( "context" "log" "os" "github.com/joho/godotenv" "github.com/tmc/langchaingo/embeddings/voyageai" "github.com/tmc/langchaingo/schema" "github.com/tmc/langchaingo/vectorstores/mongovector" "go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo/options" )
ベクトル ストアの詳細を定義します。
次のコードは、これらのアクションを実行します。
次を指定することで、Atlas をベクトル ストアとして構成します。
カスタム データを準備するには、次の手順を実行します。
各ドキュメントのテキストを定義します。
LangChainGo の
mongovectorパッケージを使用して、テキストの埋め込みを生成します。このパッケージは、ドキュメントの埋め込みを MongoDB に保存し、保存された埋め込みに対する検索を可能にします。テキスト、埋め込み、メタデータを含むドキュメントを構築します。
作成したドキュメントを Atlas に取り込み、ベクトルストアをインスタンス化します。
次のコードをmain.goファイルに貼り付けてください。
// Defines the document structure type Document struct { PageContent string `bson:"text"` Embedding []float32 `bson:"embedding"` Metadata map[string]string `bson:"metadata"` } func main() { const ( voyageAIEmbeddingDim = 1024 similarityAlgorithm = "dotProduct" indexName = "vector_index" databaseName = "langchaingo_db" collectionName = "test" ) if err := godotenv.Load(); err != nil { log.Fatal("No .env file found") } // Loads the MongoDB URI from environment uri := os.Getenv("MONGODB_URI") if uri == "" { log.Fatal("Set your 'MONGODB_URI' environment variable in the .env file") } // Loads the API key from environment voyageApiKey := os.Getenv("VOYAGEAI_API_KEY") if voyageApiKey == "" { log.Fatal("Set your VOYAGEAI_API_KEY environment variable in the .env file") } // Connects to MongoDB cluster client, err := mongo.Connect(options.Client().ApplyURI(uri)) if err != nil { log.Fatalf("Failed to connect to server: %v", err) } defer func() { if err := client.Disconnect(context.Background()); err != nil { log.Fatalf("Error disconnecting the client: %v", err) } }() log.Println("Connected to MongoDB.") // Selects the database and collection coll := client.Database(databaseName).Collection(collectionName) // Creates an embedder client embedder, err := voyageai.NewVoyageAI( voyageai.WithModel("voyage-3-large"), ) if err != nil { log.Fatalf("Failed to create an embedder: %v", err) } // Creates a new MongoDB vector store store := mongovector.New(coll, embedder, mongovector.WithIndex(indexName), mongovector.WithPath("embeddings")) // Checks if the collection is empty, and if empty, adds documents to the MongoDB vector store if isCollectionEmpty(coll) { documents := []schema.Document{ { PageContent: "Proper tuber planting involves site selection, proper timing, and exceptional care. Choose spots with well-drained soil and adequate sun exposure. Tubers are generally planted in spring, but depending on the plant, timing varies. Always plant with the eyes facing upward at a depth two to three times the tuber's height. Ensure 4 inch spacing between small tubers, expand to 12 inches for large ones. Adequate moisture is needed, yet do not overwater. Mulching can help preserve moisture and prevent weed growth.", Metadata: map[string]any{ "author": "A", "type": "post", }, }, { PageContent: "Successful oil painting necessitates patience, proper equipment, and technique. Begin with a carefully prepared, primed canvas. Sketch your composition lightly before applying paint. Use high-quality brushes and oils to create vibrant, long-lasting artworks. Remember to paint 'fat over lean,' meaning each subsequent layer should contain more oil to prevent cracking. Allow each layer to dry before applying another. Clean your brushes often and avoid solvents that might damage them. Finally, always work in a well-ventilated space.", Metadata: map[string]any{ "author": "B", "type": "post", }, }, { PageContent: "For a natural lawn, selection of the right grass type suitable for your climate is crucial. Balanced watering, generally 1 to 1.5 inches per week, is important; overwatering invites disease. Opt for organic fertilizers over synthetic versions to provide necessary nutrients and improve soil structure. Regular lawn aeration helps root growth and prevents soil compaction. Practice natural pest control and consider overseeding to maintain a dense sward, which naturally combats weeds and pest.", Metadata: map[string]any{ "author": "C", "type": "post", }, }, } _, err := store.AddDocuments(context.Background(), documents) if err != nil { log.Fatalf("Error adding documents: %v", err) } log.Printf("Successfully added %d documents to the collection.\n", len(documents)) } else { log.Println("Documents already exist in the collection, skipping document addition.") } } func isCollectionEmpty(coll *mongo.Collection) bool { count, err := coll.EstimatedDocumentCount(context.Background()) if err != nil { log.Fatalf("Failed to count documents in the collection: %v", err) } return count == 0 }
Goプロジェクトを実行します。
ファイルを保存し、次のコマンドを実行してデータをMongoDBにロードします。
go run main.go
Connected to MongoDB Atlas. Successfully added 3 documents to the collection.
Tip
main.goAtlas を使用している場合は、langchaingo_db.test の実行中後、Atlas UIで 名前空間に移動することでベクトル埋め込みを検証できます。
MongoDB ベクトル検索インデックスの作成
ベクトルストアでベクトル検索クエリを有効にするには、langchaingo_db.testコレクションにMongoDB ベクトル検索インデックスを作成します。
次のインポートを main.goファイルの先頭に追加します。
import ( // Other imports... "fmt" "time" "go.mongodb.org/mongo-driver/v2/bson" )
main() 関数の外部の main.goファイルで次の関数を定義します。これらの関数はMongoDBコレクションのベクトル検索インデックスを作成および管理します。
SearchIndexExists関数は、指定された名前の検索インデックスが存在し、クエリ可能かどうかを確認します。CreateVectorSearchIndex関数は、指定されたコレクションにベクトル検索インデックスを作成します。この関数は、インデックスが作成され、クエリ可能になるまでブロックします。
// Checks if the search index exists func SearchIndexExists(ctx context.Context, coll *mongo.Collection, idx string) (bool, error) { log.Println("Checking if search index exists.") view := coll.SearchIndexes() siOpts := options.SearchIndexes().SetName(idx).SetType("vectorSearch") cursor, err := view.List(ctx, siOpts) if err != nil { return false, fmt.Errorf("failed to list search indexes: %w", err) } for cursor.Next(ctx) { index := struct { Name string `bson:"name"` Queryable bool `bson:"queryable"` }{} if err := cursor.Decode(&index); err != nil { return false, fmt.Errorf("failed to decode search index: %w", err) } if index.Name == idx && index.Queryable { return true, nil } } if err := cursor.Err(); err != nil { return false, fmt.Errorf("cursor error: %w", err) } return false, nil } // Creates a vector search index. This function blocks until the index has been // created. func CreateVectorSearchIndex( ctx context.Context, coll *mongo.Collection, idxName string, voyageAIEmbeddingDim int, similarityAlgorithm string, ) (string, error) { type vectorField struct { Type string `bson:"type,omitempty"` Path string `bson:"path,omitempty"` NumDimensions int `bson:"numDimensions,omitempty"` Similarity string `bson:"similarity,omitempty"` } fields := []vectorField{ { Type: "vector", Path: "embeddings", NumDimensions: voyageAIEmbeddingDim, Similarity: similarityAlgorithm, }, { Type: "filter", Path: "metadata.author", }, { Type: "filter", Path: "metadata.type", }, } def := struct { Fields []vectorField `bson:"fields"` }{ Fields: fields, } log.Println("Creating vector search index...") view := coll.SearchIndexes() siOpts := options.SearchIndexes().SetName(idxName).SetType("vectorSearch") searchName, err := view.CreateOne(ctx, mongo.SearchIndexModel{Definition: def, Options: siOpts}) if err != nil { return "", fmt.Errorf("failed to create the search index: %w", err) } // Awaits the creation of the index var doc bson.Raw for doc == nil { cursor, err := view.List(ctx, options.SearchIndexes().SetName(searchName)) if err != nil { return "", fmt.Errorf("failed to list search indexes: %w", err) } if !cursor.Next(ctx) { break } name := cursor.Current.Lookup("name").StringValue() queryable := cursor.Current.Lookup("queryable").Boolean() if name == searchName && queryable { doc = cursor.Current } else { time.Sleep(5 * time.Second) } } return searchName, nil }
main() 関数で前述の関数を呼び出して、ベクトルストアコレクションとインデックスを作成します。次のコードを main() 関数の末尾に追加します。
// SearchIndexExists will return true if the provided index is defined for the // collection. This operation blocks until the search completes. if ok, _ := SearchIndexExists(context.Background(), coll, indexName); !ok { // Creates the vector store collection err = client.Database(databaseName).CreateCollection(context.Background(), collectionName) if err != nil { log.Fatalf("failed to create vector store collection: %v", err) } _, err = CreateVectorSearchIndex(context.Background(), coll, indexName, voyageAIEmbeddingDim, similarityAlgorithm) if err != nil { log.Fatalf("failed to create index: %v", err) } log.Println("Successfully created vector search index.") } else { log.Println("Vector search index already exists.") }
ファイルを保存し、次のコマンドを実行してMongoDB ベクトル検索インデックスを作成します。
go run main.go
Checking if search index exists. Creating vector search index... Successfully created vector search index.
Tip
main.go を実行した後、クラスター内のlangchaingo_db.test コレクションに移動すると、Atlas UI でベクトル検索インデックスを表示できます。
ベクトル検索クエリの実行
このセクションでは、ベクトル化されたデータに対して実行できるさまざまなクエリを示します。インデックスを作成したので、ベクトル検索クエリを実行できます。
Basic Semantic SearchSemantic Search with Filtering対応するコードを表示するには、 タブまたは タブを選択します。
次のコードをメイン関数に追加し、ファイルを保存してください。
セマンティック検索は、クエリと意味的に関連する情報を取得します。次のコードは、SimilaritySearch() メソッドを使用して文字列 "Prevent
weeds" に対するセマンティック検索を実行し、最初のドキュメントのみに結果を限定します。
// Performs basic semantic search docs, err := store.SimilaritySearch(context.Background(), "Prevent weeds", 1) if err != nil { fmt.Println("Error performing search:", err) } fmt.Println("Semantic Search Results:", docs)
以下のコマンドを実行してクエリを実行します。
go run main.go
Semantic Search Results: [{For a natural lawn, selection of the right grass type suitable for your climate is crucial. Balanced watering, generally 1 to 1.5 inches per week, is important; overwatering invites disease. Opt for organic fertilizers over synthetic versions to provide necessary nutrients and improve soil structure. Regular lawn aeration helps root growth and prevents soil compaction. Practice natural pest control and consider overseeding to maintain a dense sward, which naturally combats weeds and pest. map[author:C type:post] 0.69752026}]
コレクション内の別の値とインデックス付きフィールドを比較する MQL 一致式を使用して、データを事前にフィルタリングできます。フィルタリングするメタデータフィールドはすべて、filter タイプとしてインデックスを作成する必要があります。詳細については、「ベクトル検索のフィールドにインデックスを付ける方法」を参照してください。
次のコードをメイン関数に追加し、ファイルを保存してください。
次のコードでは、 SimilaritySearch()メソッドを使用して string "Tulip care"のセマンティック検索を実行します。 次のパラメータを指定します。
1として返すドキュメントの数。0.60のスコアしきい値。
フィルター metadata.type:
post に一致し、スコアしきい値を含むドキュメントが返されます。
// Performs semantic search with metadata filter filter := map[string]interface{}{ "metadata.type": "post", } docs, err := store.SimilaritySearch(context.Background(), "Tulip care", 1, vectorstores.WithScoreThreshold(0.60), vectorstores.WithFilters(filter)) if err != nil { fmt.Println("Error performing search:", err) } fmt.Println("Filter Search Results:", docs)
以下のコマンドを実行してクエリを実行します。
go run main.go
Filter Search Results: [{Proper tuber planting involves site selection, proper timing, and exceptional care. Choose spots with well-drained soil and adequate sun exposure. Tubers are generally planted in spring, but depending on the plant, timing varies. Always plant with the eyes facing upward at a depth two to three times the tuber's height. Ensure 4 inch spacing between small tubers, expand to 12 inches for large ones. Adequate moisture is needed, yet do not overwater. Mulching can help preserve moisture and prevent weed growth. map[author:A type:post] 0.64432365}]
データに関する質問に答えます
このセクションでは、 MongoDB ベクトル検索と LgChuinGo を使用した RAG の実装を示します。MongoDB ベクトル検索を使用してセマンティックに類似したドキュメントを検索したので、次のコード例を使用して、 MongoDB ベクトル検索によって返されたドキュメントに対して LM に質問に回答するように要求します。
メイン関数の末尾に次のコードを追加し、ファイルを保存します。
このコードでは、次の処理が行われます。
MongoDB ベクトル検索 を、セマンティクスで類似したドキュメントを検索するための検索バーとしてインスタンス化します。
検索されたドキュメントをクエリのコンテキストとして使用するように LM に指示するための LgChuinGo プロンプト テンプレートを定義します。 LgChuinGo はこれらのドキュメントを
{{.context}}入力変数に、クエリを{{.question}}変数に入力します。指定されたプロンプト テンプレートに基づいて、OpenAI のチャット モデルを使用してコンテキストを考慮した応答を生成するチェーンを構築します。
初心者向けの絵画に関するサンプルクエリをチェーンに送信し、プロンプトとレトリーバーを使用して関連するコンテキストを収集します。
LLM の応答と、コンテキストとして使用されたドキュメントを返して表示します。
// Implements RAG to answer questions on your data optionsVector := []vectorstores.Option{ vectorstores.WithScoreThreshold(0.60), } retriever := vectorstores.ToRetriever(&store, 1, optionsVector...) // Loads OpenAI API key from environment openaiApiKey := os.Getenv("OPENAI_API_KEY") if openaiApiKey == "" { log.Fatal("Set your OPENAI_API_KEY environment variable in the .env file") } // Creates an OpenAI LLM client llm, err := openai.New(openai.WithToken(openaiApiKey), openai.WithModel("gpt-4o"), openai.WithEmbeddingModel("voyage-3-large")) if err != nil { log.Fatalf("Failed to create an LLM client: %v", err) } prompt := prompts.NewPromptTemplate( `Answer the question based on the following context: {{.context}} Question: {{.question}}`, []string{"context", "question"}, ) llmChain := chains.NewLLMChain(llm, prompt) ctx := context.Background() const question = "How do I get started painting?" documents, err := retriever.GetRelevantDocuments(ctx, question) if err != nil { log.Fatalf("Failed to retrieve documents: %v", err) } var contextBuilder strings.Builder for i, document := range documents { contextBuilder.WriteString(fmt.Sprintf("Document %d: %s\n", i+1, document.PageContent)) } contextStr := contextBuilder.String() inputs := map[string]interface{}{ "context": contextStr, "question": question, } out, err := chains.Call(ctx, llmChain, inputs) if err != nil { log.Fatalf("Failed to run LLM chain: %v", err) } log.Println("Source documents:") for i, doc := range documents { log.Printf("Document %d: %s\n", i+1, doc.PageContent) } responseText, ok := out["text"].(string) if !ok { log.Println("Unexpected response type") return } log.Println("Question:", question) log.Println("Generated Answer:", responseText)
次のコマンドを実行して、ファイルを実行します。
ファイルを保存した後、次のコマンドを実行します。 生成される応答は異なる場合があります。
go run main.go
Source documents: Document 1: "Successful oil painting necessitates patience, proper equipment, and technique. Begin with a carefully prepared, primed canvas. Sketch your composition lightly before applying paint. Use high-quality brushes and oils to create vibrant, long-lasting artworks. Remember to paint 'fat over lean,' meaning each subsequent layer should contain more oil to prevent cracking. Allow each layer to dry before applying another. Clean your brushes often and avoid solvents that might damage them. Finally, always work in a well-ventilated space." Question: How do I get started painting? Generated Answer: To get started painting, you should begin with a carefully prepared, primed canvas. Sketch your composition lightly before applying paint. Use high-quality brushes and oils to create vibrant, long-lasting artworks. Remember to paint 'fat over lean,' meaning each subsequent layer should contain more oil to prevent cracking. Allow each layer to dry before applying another. Clean your brushes often and avoid solvents that might damage them. Finally, always work in a well-ventilated space.
前提条件
Atlas の サンプル データ セット からの映画データを含むコレクションを使用します。
次のいずれかのMongoDBクラスター タイプ
MongoDB バージョン 6.0.11、7.0.2、またはそれ以降を実行している Atlas クラスター。IP アドレスが Atlas プロジェクトのアクセスリストに含まれていることを確認する。
Atlas CLI を使用して作成されたローカル Atlas 配置。詳細については、「Atlas 配置のローカル配置の作成」を参照してください。
Search とベクトル検索がインストールされたMongoDB Community または Enterprise クラスター。
OpenAI APIキー。APIリクエストに使用できるクレジットを持つ OpenAI アカウントが必要です。OpenAI アカウントの登録の詳細については、OpenAI APIウェブサイト を参照してください。
Go プロジェクトを実行するためのターミナルとコード エディター。
環境を設定する
このチュートリアルを始めるには、まず環境をセットアップする必要があります。次の手順に従って環境を構成してください。
環境変数を初期化してください。
langchaingo-mongodbプロジェクトディレクトリに、.envファイルを作成し、次の行を追加します。
OPENAI_API_KEY="<api-key>" MONGODB_URI="<connection-string>"
プレースホルダー値を OpenAI APIキーとMongoDBクラスターの SRV 接続文字列 に置き換えます。接続文字列には、次の形式を使用する必要があります。
mongodb+srv://<username>:<password>@<cluster-name>.mongodb.net/<dbname>
MongoDB をベクトル ストアとして使用
このセクションでは、カスタム データをMongoDBにロードし、 MongoDB をベクトルデータベース(ベクトルストアとも)としてインスタンス化するための非同期関数を定義します。
次の依存関係をインポートします。
次のインポートを main.goファイルの先頭に追加します。
package main import ( "context" "log" "os" "github.com/joho/godotenv" "github.com/tmc/langchaingo/embeddings" "github.com/tmc/langchaingo/llms/openai" "github.com/tmc/langchaingo/schema" "github.com/tmc/langchaingo/vectorstores/mongovector" "go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo/options" )
ベクトル ストアの詳細を定義します。
次のコードは、これらのアクションを実行します。
次を指定することで、Atlas をベクトル ストアとして構成します。
カスタム データを準備するには、次の手順を実行します。
各ドキュメントのテキストを定義します。
LangChainGo の
mongovectorパッケージを使用して、テキストの埋め込みを生成します。このパッケージは、ドキュメントの埋め込みを MongoDB に保存し、保存された埋め込みに対する検索を可能にします。テキスト、埋め込み、メタデータを含むドキュメントを構築します。
作成したドキュメントを Atlas に取り込み、ベクトルストアをインスタンス化します。
次のコードをmain.goファイルに貼り付けてください。
// Defines the document structure type Document struct { PageContent string `bson:"text"` Embedding []float32 `bson:"embedding"` Metadata map[string]string `bson:"metadata"` } func main() { const ( openAIEmbeddingModel = "text-embedding-3-small" openAIEmbeddingDim = 1536 similarityAlgorithm = "dotProduct" indexName = "vector_index" databaseName = "langchaingo_db" collectionName = "test" ) if err := godotenv.Load(); err != nil { log.Fatal("No .env file found") } // Loads the MongoDB URI from environment uri := os.Getenv("MONGODB_URI") if uri == "" { log.Fatal("Set your 'MONGODB_URI' environment variable in the .env file") } // Loads the API key from environment apiKey := os.Getenv("OPENAI_API_KEY") if apiKey == "" { log.Fatal("Set your OPENAI_API_KEY environment variable in the .env file") } // Connects to MongoDB client, err := mongo.Connect(options.Client().ApplyURI(uri)) if err != nil { log.Fatalf("Failed to connect to server: %v", err) } defer func() { if err := client.Disconnect(context.Background()); err != nil { log.Fatalf("Error disconnecting the client: %v", err) } }() log.Println("Connected to MongoDB.") // Selects the database and collection coll := client.Database(databaseName).Collection(collectionName) // Creates an OpenAI LLM embedder client llm, err := openai.New(openai.WithEmbeddingModel(openAIEmbeddingModel)) if err != nil { log.Fatalf("Failed to create an embedder client: %v", err) } // Creates an embedder from the embedder client embedder, err := embeddings.NewEmbedder(llm) if err != nil { log.Fatalf("Failed to create an embedder: %v", err) } // Creates a new MongoDB vector store store := mongovector.New(coll, embedder, mongovector.WithIndex(indexName), mongovector.WithPath("embeddings")) // Checks if the collection is empty, and if empty, adds documents to the MongoDB database vector store if isCollectionEmpty(coll) { documents := []schema.Document{ { PageContent: "Proper tuber planting involves site selection, proper timing, and exceptional care. Choose spots with well-drained soil and adequate sun exposure. Tubers are generally planted in spring, but depending on the plant, timing varies. Always plant with the eyes facing upward at a depth two to three times the tuber's height. Ensure 4 inch spacing between small tubers, expand to 12 inches for large ones. Adequate moisture is needed, yet do not overwater. Mulching can help preserve moisture and prevent weed growth.", Metadata: map[string]any{ "author": "A", "type": "post", }, }, { PageContent: "Successful oil painting necessitates patience, proper equipment, and technique. Begin with a carefully prepared, primed canvas. Sketch your composition lightly before applying paint. Use high-quality brushes and oils to create vibrant, long-lasting artworks. Remember to paint 'fat over lean,' meaning each subsequent layer should contain more oil to prevent cracking. Allow each layer to dry before applying another. Clean your brushes often and avoid solvents that might damage them. Finally, always work in a well-ventilated space.", Metadata: map[string]any{ "author": "B", "type": "post", }, }, { PageContent: "For a natural lawn, selection of the right grass type suitable for your climate is crucial. Balanced watering, generally 1 to 1.5 inches per week, is important; overwatering invites disease. Opt for organic fertilizers over synthetic versions to provide necessary nutrients and improve soil structure. Regular lawn aeration helps root growth and prevents soil compaction. Practice natural pest control and consider overseeding to maintain a dense sward, which naturally combats weeds and pest.", Metadata: map[string]any{ "author": "C", "type": "post", }, }, } _, err := store.AddDocuments(context.Background(), documents) if err != nil { log.Fatalf("Error adding documents: %v", err) } log.Printf("Successfully added %d documents to the collection.\n", len(documents)) } else { log.Println("Documents already exist in the collection, skipping document addition.") } } func isCollectionEmpty(coll *mongo.Collection) bool { count, err := coll.EstimatedDocumentCount(context.Background()) if err != nil { log.Fatalf("Failed to count documents in the collection: %v", err) } return count == 0 }
Goプロジェクトを実行します。
ファイルを保存し、次のコマンドを実行してデータをMongoDBにロードします。
go run main.go
Connected to MongoDB Atlas. Successfully added 3 documents to the collection.
Tip
main.goAtlas を使用している場合は、langchaingo_db.test の実行中後、Atlas UIで 名前空間に移動することでベクトル埋め込みを検証できます。
MongoDB ベクトル検索インデックスの作成
ベクトルストアでベクトル検索クエリを有効にするには、langchaingo_db.testコレクションにMongoDB ベクトル検索インデックスを作成します。
次のインポートを main.goファイルの先頭に追加します。
import ( // Other imports... "fmt" "time" "go.mongodb.org/mongo-driver/v2/bson" )
main() 関数の外部の main.goファイルで次の関数を定義します。これらの関数はMongoDBコレクションのベクトル検索インデックスを作成および管理します。
SearchIndexExists関数は、指定された名前の検索インデックスが存在し、クエリ可能かどうかを確認します。CreateVectorSearchIndex関数は、指定されたコレクションにベクトル検索インデックスを作成します。この関数は、インデックスが作成され、クエリ可能になるまでブロックします。
// Checks if the search index exists func SearchIndexExists(ctx context.Context, coll *mongo.Collection, idx string) (bool, error) { log.Println("Checking if search index exists.") view := coll.SearchIndexes() siOpts := options.SearchIndexes().SetName(idx).SetType("vectorSearch") cursor, err := view.List(ctx, siOpts) if err != nil { return false, fmt.Errorf("failed to list search indexes: %w", err) } for cursor.Next(ctx) { index := struct { Name string `bson:"name"` Queryable bool `bson:"queryable"` }{} if err := cursor.Decode(&index); err != nil { return false, fmt.Errorf("failed to decode search index: %w", err) } if index.Name == idx && index.Queryable { return true, nil } } if err := cursor.Err(); err != nil { return false, fmt.Errorf("cursor error: %w", err) } return false, nil } // Creates a vector search index. This function blocks until the index has been // created. func CreateVectorSearchIndex( ctx context.Context, coll *mongo.Collection, idxName string, openAIEmbeddingDim int, similarityAlgorithm string, ) (string, error) { type vectorField struct { Type string `bson:"type,omitempty"` Path string `bson:"path,omitempty"` NumDimensions int `bson:"numDimensions,omitempty"` Similarity string `bson:"similarity,omitempty"` } fields := []vectorField{ { Type: "vector", Path: "embeddings", NumDimensions: openAIEmbeddingDim, Similarity: similarityAlgorithm, }, { Type: "filter", Path: "metadata.author", }, { Type: "filter", Path: "metadata.type", }, } def := struct { Fields []vectorField `bson:"fields"` }{ Fields: fields, } log.Println("Creating vector search index...") view := coll.SearchIndexes() siOpts := options.SearchIndexes().SetName(idxName).SetType("vectorSearch") searchName, err := view.CreateOne(ctx, mongo.SearchIndexModel{Definition: def, Options: siOpts}) if err != nil { return "", fmt.Errorf("failed to create the search index: %w", err) } // Awaits the creation of the index var doc bson.Raw for doc == nil { cursor, err := view.List(ctx, options.SearchIndexes().SetName(searchName)) if err != nil { return "", fmt.Errorf("failed to list search indexes: %w", err) } if !cursor.Next(ctx) { break } name := cursor.Current.Lookup("name").StringValue() queryable := cursor.Current.Lookup("queryable").Boolean() if name == searchName && queryable { doc = cursor.Current } else { time.Sleep(5 * time.Second) } } return searchName, nil }
main() 関数で前述の関数を呼び出して、ベクトルストアコレクションとインデックスを作成します。次のコードを main() 関数の末尾に追加します。
// SearchIndexExists will return true if the provided index is defined for the // collection. This operation blocks until the search completes. if ok, _ := SearchIndexExists(context.Background(), coll, indexName); !ok { // Creates the vector store collection err = client.Database(databaseName).CreateCollection(context.Background(), collectionName) if err != nil { log.Fatalf("failed to create vector store collection: %v", err) } _, err = CreateVectorSearchIndex(context.Background(), coll, indexName, openAIEmbeddingDim, similarityAlgorithm) if err != nil { log.Fatalf("failed to create index: %v", err) } log.Println("Successfully created vector search index.") } else { log.Println("Vector search index already exists.") }
ファイルを保存し、次のコマンドを実行してMongoDB ベクトル検索インデックスを作成します。
go run main.go
Checking if search index exists. Creating vector search index... Successfully created vector search index.
Tip
main.go を実行した後、クラスター内のlangchaingo_db.test コレクションに移動すると、Atlas UI でベクトル検索インデックスを表示できます。
ベクトル検索クエリの実行
このセクションでは、ベクトル化されたデータに対して実行できるさまざまなクエリを示します。インデックスを作成したので、ベクトル検索クエリを実行できます。
Basic Semantic SearchSemantic Search with Filtering対応するコードを表示するには、 タブまたは タブを選択します。
次のコードをメイン関数に追加し、ファイルを保存してください。
セマンティック検索は、クエリと意味的に関連する情報を取得します。次のコードは、SimilaritySearch() メソッドを使用して文字列 "Prevent
weeds" に対するセマンティック検索を実行し、最初のドキュメントのみに結果を限定します。
// Performs basic semantic search docs, err := store.SimilaritySearch(context.Background(), "Prevent weeds", 1) if err != nil { fmt.Println("Error performing search:", err) } fmt.Println("Semantic Search Results:", docs)
以下のコマンドを実行してクエリを実行します。
go run main.go
Semantic Search Results: [{For a natural lawn, selection of the right grass type suitable for your climate is crucial. Balanced watering, generally 1 to 1.5 inches per week, is important; overwatering invites disease. Opt for organic fertilizers over synthetic versions to provide necessary nutrients and improve soil structure. Regular lawn aeration helps root growth and prevents soil compaction. Practice natural pest control and consider overseeding to maintain a dense sward, which naturally combats weeds and pest. map[author:C type:post] 0.69752026}]
コレクション内の別の値とインデックス付きフィールドを比較する MQL 一致式を使用して、データを事前にフィルタリングできます。フィルタリングするメタデータフィールドはすべて、filter タイプとしてインデックスを作成する必要があります。詳細については、「ベクトル検索のフィールドにインデックスを付ける方法」を参照してください。
次のコードをメイン関数に追加し、ファイルを保存してください。
次のコードでは、 SimilaritySearch()メソッドを使用して string "Tulip care"のセマンティック検索を実行します。 次のパラメータを指定します。
1として返すドキュメントの数。0.60のスコアしきい値。
フィルター metadata.type:
post に一致し、スコアしきい値を含むドキュメントが返されます。
// Performs semantic search with metadata filter filter := map[string]interface{}{ "metadata.type": "post", } docs, err := store.SimilaritySearch(context.Background(), "Tulip care", 1, vectorstores.WithScoreThreshold(0.60), vectorstores.WithFilters(filter)) if err != nil { fmt.Println("Error performing search:", err) } fmt.Println("Filter Search Results:", docs)
以下のコマンドを実行してクエリを実行します。
go run main.go
Filter Search Results: [{Proper tuber planting involves site selection, proper timing, and exceptional care. Choose spots with well-drained soil and adequate sun exposure. Tubers are generally planted in spring, but depending on the plant, timing varies. Always plant with the eyes facing upward at a depth two to three times the tuber's height. Ensure 4 inch spacing between small tubers, expand to 12 inches for large ones. Adequate moisture is needed, yet do not overwater. Mulching can help preserve moisture and prevent weed growth. map[author:A type:post] 0.64432365}]
データに関する質問に答えます
このセクションでは、 MongoDB ベクトル検索と LgChuinGo を使用した RAG の実装を示します。MongoDB ベクトル検索を使用してセマンティックに類似したドキュメントを検索したので、次のコード例を使用して、 MongoDB ベクトル検索によって返されたドキュメントに対して LM に質問に回答するように要求します。
メイン関数の末尾に次のコードを追加し、ファイルを保存します。
このコードでは、次の処理が行われます。
MongoDB ベクトル検索 を、セマンティクスで類似したドキュメントを検索するための検索バーとしてインスタンス化します。
検索されたドキュメントをクエリのコンテキストとして使用するように LM に指示するための LgChuinGo プロンプト テンプレートを定義します。 LgChuinGo はこれらのドキュメントを
{{.context}}入力変数に、クエリを{{.question}}変数に入力します。指定されたプロンプト テンプレートに基づいて、OpenAI のチャット モデルを使用してコンテキストを考慮した応答を生成するチェーンを構築します。
初心者向けの絵画に関するサンプルクエリをチェーンに送信し、プロンプトとレトリーバーを使用して関連するコンテキストを収集します。
LLM の応答と、コンテキストとして使用されたドキュメントを返して表示します。
// Implements RAG to answer questions on your data optionsVector := []vectorstores.Option{ vectorstores.WithScoreThreshold(0.60), } retriever := vectorstores.ToRetriever(&store, 1, optionsVector...) prompt := prompts.NewPromptTemplate( `Answer the question based on the following context: {{.context}} Question: {{.question}}`, []string{"context", "question"}, ) llmChain := chains.NewLLMChain(llm, prompt) ctx := context.Background() const question = "How do I get started painting?" documents, err := retriever.GetRelevantDocuments(ctx, question) if err != nil { log.Fatalf("Failed to retrieve documents: %v", err) } var contextBuilder strings.Builder for i, document := range documents { contextBuilder.WriteString(fmt.Sprintf("Document %d: %s\n", i+1, document.PageContent)) } contextStr := contextBuilder.String() inputs := map[string]interface{}{ "context": contextStr, "question": question, } out, err := chains.Call(ctx, llmChain, inputs) if err != nil { log.Fatalf("Failed to run LLM chain: %v", err) } log.Println("Source documents:") for i, doc := range documents { log.Printf("Document %d: %s\n", i+1, doc.PageContent) } responseText, ok := out["text"].(string) if !ok { log.Println("Unexpected response type") return } log.Println("Question:", question) log.Println("Generated Answer:", responseText)
次のコマンドを実行して、ファイルを実行します。
ファイルを保存した後、次のコマンドを実行します。 生成される応答は異なる場合があります。
go run main.go
Source documents: Document 1: "Successful oil painting necessitates patience, proper equipment, and technique. Begin with a carefully prepared, primed canvas. Sketch your composition lightly before applying paint. Use high-quality brushes and oils to create vibrant, long-lasting artworks. Remember to paint 'fat over lean,' meaning each subsequent layer should contain more oil to prevent cracking. Allow each layer to dry before applying another. Clean your brushes often and avoid solvents that might damage them. Finally, always work in a well-ventilated space." Question: How do I get started painting? Generated Answer: To get started painting, you should begin with a carefully prepared, primed canvas. Sketch your composition lightly before applying paint. Use high-quality brushes and oils to create vibrant, long-lasting artworks. Remember to paint 'fat over lean,' meaning each subsequent layer should contain more oil to prevent cracking. Allow each layer to dry before applying another. Clean your brushes often and avoid solvents that might damage them. Finally, always work in a well-ventilated space.
このチュートリアルを完了すると、 MongoDB ベクトル検索と LgChuinGo が正常に統合され、RAGアプリケーションが構築されます。これで次の操作を実行しました。
アプリケーションをサポートするために必要な環境を開始し、構成した
カスタム データをMongoDBに保存し、 MongoDB をベクトルストアとしてインスタンス化しました
データにMongoDB ベクトル検索インデックスを構築し、セマンティック検索機能を有効化
ベクトル埋め込みを使用して、意味的に関連するデータを取得しました
メタデータ フィルターを組み込むことで、検索結果を強化しました
MongoDB ベクトル検索を使用して RG ワークフローを実装し、データに基づいて質問に意味のある回答を提供しました
次のステップ
MongoDB ベクトル検索を使い始める方法の詳細については、MongoDB ベクトル検索クイック スタート を参照し、ドロップダウン メニューから Go を選択します。
ベクトル埋め込みの詳細を見るには、「ベクトル埋め込みの作成方法」を表示し、ドロップダウン メニューから Go を選択します。
LgChuinGo と Hookingface を統合する方法については、 MongoDBで使用される検索拡張生成(RAG) を参照してください。
APIキーやクレジットを必要とせずに RG を実装する方法については、「 MongoDB ベクトル検索を使用してローカル RAG 実装を構築する 」を参照してください。
MongoDBは、次の開発者リソースも提供しています。
Tip
LangChainGo、OpenAI、MongoDB の統合について詳しくは、「OpenAI の埋め込みを使って MongoDB Atlas をベクトル ストアとして利用する方法」を参照してください。