Docs Menu
Docs Home
/ /

LgChuinGo 統合を使い始める

MongoDB ベクトル検索 を LgChuinGo と統合すると、大規模言語モデル(LVM)アプリケーションを構築し、検索拡張生成 (RAG)(RAG)を実装できます。このチュートリアルでは、LgacheinGo とMongoDB ベクトル検索の使用を開始し、データのセマンティック検索を実行し、RAG実装を構築する方法を説明します。具体的には、次のアクションを実行します。

  1. 環境を設定します。

  2. カスタム データをMongoDBに保存します。

  3. データにMongoDB ベクトル検索インデックスを作成します。

  4. 次のベクトル検索クエリを実行します。

    • セマンティック検索。

    • メタデータの事前フィルタリングによるセマンティック検索。

  5. 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 がインストールされています

このチュートリアルを始めるには、まず環境をセットアップする必要があります。次の手順に従って環境を構成してください。

1

ターミナルで次のコマンドを実行して、 langchaingo-mongodbという名前の新しいディレクトリを作成し、プロジェクトを初期化します。

mkdir langchaingo-mongodb
cd langchaingo-mongodb
go mod init langchaingo-mongodb
2

次のコマンドを実行します。

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
3

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>
4

langchaingo-mongodbプロジェクトディレクトリに、main.go という名前のファイルを作成します。チュートリアル全体でこのファイルにコードを追加します。

このセクションでは、カスタム データをMongoDBにロードし、 MongoDB をベクトルデータベース(ベクトルストアとも)としてインスタンス化するための非同期関数を定義します。

1

次のインポートを 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"
)
2

次のコードは、これらのアクションを実行します。

  • 次を指定することで、Atlas をベクトル ストアとして構成します。

    • langchaingo_db.test ドキュメントを格納する Atlas 内のコレクション。

    • vector_index ベクトルストアをクエリするために使用するインデックスとして 。

    • text 未加工のテキスト コンテンツを含むフィールドの名前:

    • embedding 埋め込みを含むフィールド名。

  • カスタム データを準備するには、次の手順を実行します。

    • 各ドキュメントのテキストを定義します。

    • 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
}
3

ファイルを保存し、次のコマンドを実行してデータをMongoDBにロードします。

go run main.go
Connected to MongoDB Atlas.
Successfully added 3 documents to the collection.

Tip

ベクトルストアでベクトル検索クエリを有効にするには、langchaingo_db.testコレクションにMongoDB ベクトル検索インデックスを作成します。

次のインポートを main.goファイルの先頭に追加します。

import (
// Other imports...
"fmt"
"time"
"go.mongodb.org/mongo-driver/v2/bson"
)

main() 関数の外部の main.goファイルで次の関数を定義します。これらの関数はMongoDBコレクションのベクトル検索インデックスを作成および管理します。

  1. SearchIndexExists 関数は、指定された名前の検索インデックスが存在し、クエリ可能かどうかを確認します。

  2. 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対応するコードを表示するには、 タブまたは タブを選択します。

1

セマンティック検索は、クエリと意味的に関連する情報を取得します。次のコードは、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)
2
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 タイプとしてインデックスを作成する必要があります。詳細については、「ベクトル検索のフィールドにインデックスを付ける方法」を参照してください。

1

次の依存関係を main.goファイルに追加します。

import (
// Other imports...
"github.com/tmc/langchaingo/vectorstores"
)
2

次のコードでは、 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)
3
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 に質問に回答するように要求します。

1

次のインポートを main.goファイルの先頭に追加します。

import (
// Other imports...
"strings"
"github.com/tmc/langchaingo/llms/openai"
"github.com/tmc/langchaingo/chains"
"github.com/tmc/langchaingo/prompts"
"github.com/tmc/langchaingo/vectorstores"
)
2

このコードでは、次の処理が行われます。

  • 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)
3

ファイルを保存した後、次のコマンドを実行します。 生成される応答は異なる場合があります。

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 プロジェクトを実行するためのターミナルとコード エディター。

  • マシンにGo がインストールされています

このチュートリアルを始めるには、まず環境をセットアップする必要があります。次の手順に従って環境を構成してください。

1

ターミナルで次のコマンドを実行して、 langchaingo-mongodbという名前の新しいディレクトリを作成し、プロジェクトを初期化します。

mkdir langchaingo-mongodb
cd langchaingo-mongodb
go mod init langchaingo-mongodb
2

次のコマンドを実行します。

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 go.mongodb.org/mongo-driver/v2/mongo
go mod tidy
3

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>
4

langchaingo-mongodbプロジェクトディレクトリに、main.go という名前のファイルを作成します。チュートリアル全体でこのファイルにコードを追加します。

このセクションでは、カスタム データをMongoDBにロードし、 MongoDB をベクトルデータベース(ベクトルストアとも)としてインスタンス化するための非同期関数を定義します。

1

次のインポートを 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"
)
2

次のコードは、これらのアクションを実行します。

  • 次を指定することで、Atlas をベクトル ストアとして構成します。

    • langchaingo_db.test ドキュメントを格納する Atlas 内のコレクション。

    • vector_index ベクトルストアをクエリするために使用するインデックスとして 。

    • text 未加工のテキスト コンテンツを含むフィールドの名前:

    • embedding 埋め込みを含むフィールド名。

  • カスタム データを準備するには、次の手順を実行します。

    • 各ドキュメントのテキストを定義します。

    • 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
}
3

ファイルを保存し、次のコマンドを実行してデータをMongoDBにロードします。

go run main.go
Connected to MongoDB Atlas.
Successfully added 3 documents to the collection.

ベクトルストアでベクトル検索クエリを有効にするには、langchaingo_db.testコレクションにMongoDB ベクトル検索インデックスを作成します。

次のインポートを main.goファイルの先頭に追加します。

import (
// Other imports...
"fmt"
"time"
"go.mongodb.org/mongo-driver/v2/bson"
)

main() 関数の外部の main.goファイルで次の関数を定義します。これらの関数はMongoDBコレクションのベクトル検索インデックスを作成および管理します。

  1. SearchIndexExists 関数は、指定された名前の検索インデックスが存在し、クエリ可能かどうかを確認します。

  2. 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対応するコードを表示するには、 タブまたは タブを選択します。

1

セマンティック検索は、クエリと意味的に関連する情報を取得します。次のコードは、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)
2
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 タイプとしてインデックスを作成する必要があります。詳細については、「ベクトル検索のフィールドにインデックスを付ける方法」を参照してください。

1

次の依存関係を main.goファイルに追加します。

import (
// Other imports...
"github.com/tmc/langchaingo/vectorstores"
)
2

次のコードでは、 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)
3
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 に質問に回答するように要求します。

1

次のインポートを main.goファイルの先頭に追加します。

import (
// Other imports...
"strings"
"github.com/tmc/langchaingo/chains"
"github.com/tmc/langchaingo/prompts"
"github.com/tmc/langchaingo/vectorstores"
)
2

このコードでは、次の処理が行われます。

  • 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)
3

ファイルを保存した後、次のコマンドを実行します。 生成される応答は異なる場合があります。

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は、次の開発者リソースも提供しています。

戻る

LgChuin JavaScript / Typescript

項目一覧