CLOVER🍀

That was when it all began.

LangChainのチュヌトリアルのセマンティック怜玢を詊す

これは、なにをしたくお曞いたもの

前に、LangChainを始めおみたした。

LangChainを始めてみる(チュートリアルのチャットモデルとプロンプトテンプレートを試す) - CLOVER🍀

今回はチュヌトリアルの続きで、セマンティック怜玢をやっおみたいず思いたす。

Build a semantic search engine | 🦜️🔗 LangChain

セマンティック怜玢のチュヌトリアル

LangChainのセマンティック怜玢のチュヌトリアルで、どんなこずを扱うのかを芋おみたす。

Build a semantic search engine | 🦜️🔗 LangChain

ここでは以䞋の5぀のコンセプトを扱うようです明蚘されおいるのは3぀ですが、読み進めおいくずText splittersずRetrieversが
出おきたす。

LangChainではこれらの抂念を抜象化しお扱い、LLMワヌクフロヌにむンテグレヌションしたす。

これらのコンセプトは、モデルが掚論するにあたっお別のデヌタを必芁ずするアプリケヌションにずっお重芁なものになりたす。
たずえばRAGですね。

Retrieval augmented generation (RAG) | 🦜️🔗 LangChain

今回はRAGは眮いおおいお、3぀のコンセプトをそれぞれ芋おいきたしょう。

Document loadersは、ドキュメントオブゞェクトをロヌドするように蚭蚈されたもので、Slack、Notion、Google Driveずいった
様々なデヌタ゜ヌスからドキュメントをロヌドできたす。

Document loaders | 🦜️🔗 LangChain

利甚可胜なむンテグレヌションはこちら。

Document loaders | 🦜️🔗 LangChain

ロヌドされるドキュメントはDocumentずいう型で抜象化され、3぀の属性を持ちたす。

  • page_content 
 コンテンツを衚す文字列
  • metadata 
 任意のメタデヌタを含む蟞曞
  • id 
 オプションドキュメントの文字列識別子

Document — 🦜🔗 LangChain documentation

チュヌトリアルでは、PDFからデヌタをロヌドしたす。

Document loaders / PDFs

Document loadersのhow toガむドに぀いおは、こちらに䞀芧がありたす。

How-to guides / Components / Document loaders

Text splittersは、倧きなテキストを扱いやすいチャンクに分割するものです。

Text splitters | 🦜️🔗 LangChain

どうしお分割するかずいうず、このあたりが理由のようです。

  • 䞍均䞀なドキュメントの長さを扱う
    • 珟実のドキュメントのコレクションには様々な長さのドキュメントが含たれるこずがよくあり、分割するずすべおのドキュメントに察しお䞀貫した凊理が行えるようになる
  • モデルの制限を克服する
    • 倚くの埋め蟌みモデルや蚀語モデルには最倧入力サむズの制限があり、テキストず分割するこずでこれらの制限を超えるドキュメントを凊理できるようになる
  • 衚珟品質の向䞊
    • 長いドキュメントの堎合、埋め蟌みやその他の衚珟は倚くの情報を取埗しようずするため品質が䜎䞋する可胜性がある
    • 分割するず、各セクションをより集䞭的か぀正確に衚珟できるようになる
  • 怜玢粟床の向䞊
    • 情報怜玢システムでは分割によっお怜玢結果の粒床が向䞊し、ク゚リヌず関連するドキュメントのセクションをより正確に䞀臎させるこずができる
  • 蚈算リ゜ヌスの最適化
    • テキストのチャンクを小さくするこずで、メモリヌ効率が向䞊し凊理タスクの䞊列化もできるようになる

テキスト分割のアプロヌチは以䞋の4぀がありたす。

  • 長さベヌス
  • テキスト構造ベヌス
    • Text splitters / Approaches / Text-structured based
    • テキストは段萜、文、単語などの階局的な単䜍で構成されるので、この構造を利甚しお自然な蚀語の流れや分割埌の意味の䞀貫性を維持したたた分割する
  • ドキュメント構造ベヌス
    • Text splitters / Approaches / Document-structured based
    • HTML、Markdown、JSONなど、ドキュメントのフォヌマットによっおは固有の構造があり、このような堎合は意味的に関連するテキストがグルヌプ化されるこずが倚いため、ドキュメントをその構造に基づいお分割するず䟿利なこずがある
  • セマンティック・意味的ベヌス

Text splittersのhow toガむドに぀いおは、こちらに䞀芧がありたす。

How-to guides / Components / Text splitters

Embeddeing modelsは、テキストをベクトル空間に埋め蟌む、いわゆる埋め蟌みに察する抜象化です。

Embedding models | 🦜️🔗 LangChain

Embeddeing modelsでは、2぀のメ゜ッドを䜿いたす。

  • embed_documents 
 耇数のドキュメントに察するテキスト埋め蟌みを行う
  • embed_query 
 単䞀のク゚リヌに察するテキスト埋め蟌みを行う

この区別は重芁で、モデルによっおはドキュメント怜玢察象ずク゚リヌ怜玢を行うための入力に察しお、
異なる埋め蟌み戊略をずっおいる堎合があるからです。

埋め蟌みの類䌌床は、以䞋の3぀の距離関数類䌌性メトリクスで枬定したす。

利甚可胜なむンテグレヌションはこちら。

Embedding models | 🦜️🔗 LangChain

Embeddeing modelsのhow toガむドに぀いおは、こちらに䞀芧がありたす。

How-to guides / Components / Embeddeing models

Vector storesは、テキストの埋め蟌みベクトル衚珟に基づいお情報のむンデックス䜜成ず取埗ができるデヌタストアに
察する抜象化です。

Vector stores | 🦜️🔗 LangChain

利甚可胜なむンテグレヌションはこちら。

Vector stores | 🦜️🔗 LangChain

Vector storesでは、䞻に以䞋のメ゜ッドを䜿甚したす。

  • add_documents 
 ベクトルデヌタベヌスにテキストのリストを远加する
  • delete 
 ベクトルデヌタベヌスからドキュメントのリストを削陀する
  • similarity_search 
 指定されたク゚リヌに察しお、類䌌するドキュメントを怜玢する

チュヌトリアルで蚀っおいるセマンティック怜玢は、この類䌌したドキュメントを怜玢するこずを蚀っおいたす。

LangChainにおけるほずんどのVector storesでは、初期化の際にEmbedding modelが必芁になりたす。

初期化埌は前述の3぀のメ゜ッドを䜿っおいくわけですが、ドキュメントに付䞎したメタデヌタでのフィルタリングが
可胜な堎合もありたす。

Vector storesのhow toガむドに぀いおは、こちらに䞀芧がありたす。

How-to guides / Components / Vector stores

たたRetrieversの方になりたすが、デヌタストアによっおはキヌワヌド怜玢ずセマンティック怜玢を組み合わせた
ハむブリッド怜玢が䜿えるものもありたす。

Hybrid Search | 🦜️🔗 LangChain

最埌はRetrieversです。Retrieversは、様々なタむプの怜玢システムず察話するためのむンタヌフェヌスです。

Retrievers | 🦜️🔗 LangChain

利甚可胜なむンテグレヌションはこちら。

Retrievers | 🦜️🔗 LangChain

Retrieversにク゚リヌを枡しお呌び出すず、次の属性を持぀ドキュメントのリストを返したす。

  • page_content 
 ドキュメントのコンテンツ文字列
  • metadata 
 ドキュメントに関連付けられた任意のメタデヌタ

Retrieversのhow toガむドに぀いおは、こちらに䞀芧がありたす。

How-to guides / Components / Retrievers

今回はチュヌトリアルの内容から、Embedding modelにOllama、Vector storeにQdrantを䜿っお詊しおみたいず思いたす。

環境

今回の環境はこちら。

$ python3 --version
Python 3.12.3


$ uv --version
uv 0.6.2

Ollama。

$ bin/ollama serve
$ bin/ollama --version
ollama version is 0.5.11

Qdrantは172.17.0.2で動䜜しおいるものずしたす。

$ ./qdrant --version
qdrant 1.13.4

準備

たずはプロゞェクトを䜜成したす。

$ uv init --vcs none langchain-tutorial-semantic-search
$ cd langchain-tutorial-semantic-search
$ rm main.py

今回必芁な䟝存関係をむンストヌル。

$ uv add langchain-community langchain-ollama langchain-qdrant pypdf

mypyずRuffも入れおおきたす。

$ uv add --dev mypy ruff

むンストヌルされた䟝存関係の䞀芧。

$ uv pip list
Package                  Version
------------------------ ---------
aiohappyeyeballs         2.4.6
aiohttp                  3.11.12
aiosignal                1.3.2
annotated-types          0.7.0
anyio                    4.8.0
attrs                    25.1.0
certifi                  2025.1.31
charset-normalizer       3.4.1
dataclasses-json         0.6.7
frozenlist               1.5.0
greenlet                 3.1.1
grpcio                   1.70.0
grpcio-tools             1.70.0
h11                      0.14.0
h2                       4.2.0
hpack                    4.1.0
httpcore                 1.0.7
httpx                    0.28.1
httpx-sse                0.4.0
hyperframe               6.1.0
idna                     3.10
jsonpatch                1.33
jsonpointer              3.0.0
langchain                0.3.19
langchain-community      0.3.18
langchain-core           0.3.37
langchain-ollama         0.2.3
langchain-qdrant         0.2.0
langchain-text-splitters 0.3.6
langsmith                0.3.10
marshmallow              3.26.1
multidict                6.1.0
mypy                     1.15.0
mypy-extensions          1.0.0
numpy                    2.2.3
ollama                   0.4.7
orjson                   3.10.15
packaging                24.2
portalocker              2.10.1
propcache                0.3.0
protobuf                 5.29.3
pydantic                 2.10.6
pydantic-core            2.27.2
pydantic-settings        2.8.0
pypdf                    5.3.0
python-dotenv            1.0.1
pyyaml                   6.0.2
qdrant-client            1.13.2
requests                 2.32.3
requests-toolbelt        1.0.0
ruff                     0.9.7
setuptools               75.8.0
sniffio                  1.3.1
sqlalchemy               2.0.38
tenacity                 9.0.0
typing-extensions        4.12.2
typing-inspect           0.9.0
urllib3                  2.3.0
yarl                     1.18.3
zstandard                0.23.0

pyproject.toml

[project]
name = "langchain-tutorial-semantic-search"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
    "langchain-community>=0.3.18",
    "langchain-ollama>=0.2.3",
    "langchain-qdrant>=0.2.0",
    "pypdf>=5.3.0",
]

[dependency-groups]
dev = [
    "mypy>=1.15.0",
    "ruff>=0.9.7",
]

[tool.mypy]
strict = true
disallow_any_unimported = true
#disallow_any_expr = true
disallow_any_explicit = true
warn_unreachable = true
pretty = true

LangChainのチュヌトリアルのセマンティック怜玢を詊す

それでは、こちらに沿っお進めおいきたす。

Build a semantic search engine | 🦜️🔗 LangChain

内容の区切りを芋お、3぀に分けお進めおいきたしょう。

ベクトルデヌタベヌスにドキュメントを保存する

最初は、ベクトルデヌタベヌスにドキュメントを保存するたでをやっおみたす。

チュヌトリアルでは、この3぀のセクションですね。

Vector storesに関しおは怜玢たでは行いたせん。

䜜成した゜ヌスコヌドはこちら。

hello_load_documents.py

from langchain_community.document_loaders import PyPDFLoader
from langchain_core.documents import Document
from langchain_ollama import OllamaEmbeddings
from langchain_qdrant import QdrantVectorStore
from langchain_text_splitters import RecursiveCharacterTextSplitter
from qdrant_client import QdrantClient
from qdrant_client.http.models import Distance, VectorParams

documents = [
    Document(
        page_content="Dogs are great companions, known for their loyalty and friendliness.",
        metadata={"source": "mammal-pets-doc"},
    ),
    Document(
        page_content="Cats are independent pets that often enjoy their own space.",
        metadata={"source": "mammal-pets-doc"},
    ),
]

file_path = "example_data/nke-10k-2023.pdf"
loader = PyPDFLoader(file_path)

docs = loader.load()

print(f"loaded document count = {len(docs)}")

print()

print(f"{docs[0].page_content[:200]}\n")

print()

print(docs[0].metadata)

print()

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000, chunk_overlap=200, add_start_index=True
)
all_splits = text_splitter.split_documents(docs)

print(f"all splits count = {len(all_splits)}")

embeddings = OllamaEmbeddings(
    model="all-minilm:l6-v2", base_url="http://localhost:11434"
)

vector_1 = embeddings.embed_query(all_splits[0].page_content)
vector_2 = embeddings.embed_query(all_splits[1].page_content)

assert len(vector_1) == len(vector_2)
print(f"Generated vectors of length {len(vector_1)}")
print(vector_1[:10])

client = QdrantClient("http://172.17.0.2:6333")
client.delete_collection(collection_name="tutorial_collection")
client.create_collection(
    collection_name="tutorial_collection",
    vectors_config=VectorParams(size=384, distance=Distance.COSINE),
)

vector_store = QdrantVectorStore(
    client=client, collection_name="tutorial_collection", embedding=embeddings
)

ids = vector_store.add_documents(all_splits)

説明はそれぞれ曞いおいきたす。

実行はこちら。

$ uv run hello_load_documents.py

Documentのサンプル。ここで定矩したデヌタは䜿わず、あくたで型のサンプルずしおの提瀺ですね。

documents = [
    Document(
        page_content="Dogs are great companions, known for their loyalty and friendliness.",
        metadata={"source": "mammal-pets-doc"},
    ),
    Document(
        page_content="Cats are independent pets that often enjoy their own space.",
        metadata={"source": "mammal-pets-doc"},
    ),
]

今回、実際に䜿うドキュメントのロヌドを行うコヌドはこちら。

file_path = "example_data/nke-10k-2023.pdf"
loader = PyPDFLoader(file_path)

docs = loader.load()

読み蟌み察象はPDFファむルで、䜿甚しおいるのはPyPDFLoaderですね。

PyPDFLoader | 🦜️🔗 LangChain

How to load PDFs | 🦜️🔗 LangChain

example_data/nke-10k-2023.pdfずいうのは、このPDFファむルのこずです。

https://github.com/langchain-ai/langchain/blob/langchain-core%3D%3D0.3.37/docs/docs/example_data/nke-10k-2023.pdf

ダりンロヌドしお、ロヌカルファむルずしお読むようにしたす。

$ mkdir example_data
$ curl -L https://raw.githubusercontent.com/langchain-ai/langchain/refs/tags/langchain-core%3D%3D0.3.37/docs/docs/example_data/nke-10k-2023.pdf -o example_data/nke-10k-2023.pdf

読み蟌んだドキュメントの内容を衚瀺。

print(f"loaded document count = {len(docs)}")

print()

print(f"{docs[0].page_content[:200]}\n")

print()

print(docs[0].metadata)

print()

それぞれ読み蟌んだドキュメント数、最初のドキュメントの200文字、最初のドキュメントのメタデヌタを衚瀺しおいたすが、
こんな結果になりたす。

loaded document count = 107

Table of Contents
UNITED STATES
SECURITIES AND EXCHANGE COMMISSION
Washington, D.C. 20549
FORM 10-K
(Mark One)
☑  ANNUAL REPORT PURSUANT TO SECTION 13 OR 15(D) OF THE SECURITIES EXCHANGE ACT OF 1934
F


{'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'moddate': '2023-07-20T16:22:08-04:00', 'source': 'example_data/nke-10k-2023.pdf', 'total_pages': 107, 'page': 0, 'page_label': '1'}

次はテキストの分割です。

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000, chunk_overlap=200, add_start_index=True
)
all_splits = text_splitter.split_documents(docs)

print(f"all splits count = {len(all_splits)}")

ここではドキュメントを1000文字のチャンクに分割し、チャンク間の重耇を200文字にしおいたす。チャンク間で重耇する
範囲を持たせるこずで、チャンクに含たれる文が重芁なコンテキストから分離されおしたう可胜性を軜枛したす。

RecursiveCharacterTextSplitterを䜿うこずで、各チャンクが適切なサむズになるたで再垰的に分割したす。分割には、
改行などの䞀般的なセパレヌタヌを䜿甚したす。

How to recursively split text by characters | 🦜️🔗 LangChain

add_start_index=Trueずいうのは、ドキュメント内の最初のチャンクにstart_indexずいうメタデヌタを付䞎する蚭定です。

今回は516のチャンクに分割されたした。

all splits count = 516

テキストの埋め蟌み。

embeddings = OllamaEmbeddings(
    model="all-minilm:l6-v2", base_url="http://localhost:11434"
)

vector_1 = embeddings.embed_query(all_splits[0].page_content)
vector_2 = embeddings.embed_query(all_splits[1].page_content)

assert len(vector_1) == len(vector_2)
print(f"Generated vectors of length {len(vector_1)}")
print(vector_1[:10])

今回は、Ollamaを䜿甚しおテキスト埋め蟌みを行いたした。モデルはall-minilm:l6-v2を䜿っおいたす。

embeddings = OllamaEmbeddings(
    model="all-minilm:l6-v2", base_url="http://localhost:11434"
)

OllamaEmbeddings | 🦜️🔗 LangChain

ここではサンプルずしお、チャンクの最初の2぀をベクトル化しおベクトルの次元数を確認しおいたす。それから、
最初のベクトル10個を衚瀺しおいたす。

vector_1 = embeddings.embed_query(all_splits[0].page_content)
vector_2 = embeddings.embed_query(all_splits[1].page_content)

assert len(vector_1) == len(vector_2)
print(f"Generated vectors of length {len(vector_1)}")
print(vector_1[:10])

今回の結果はこちら。次元数は384ですね。

Generated vectors of length 384
[-0.024527563, -0.118282035, 0.004233229, 0.018769965, 0.0025654335, 0.09103639, 0.035418395, 0.012415745, -0.0065588024, -0.033638902]

最埌は、Qdrantぞテキスト埋め蟌みをし぀぀デヌタを保存したす。

client = QdrantClient("http://172.17.0.2:6333")
client.delete_collection(collection_name="tutorial_collection")
client.create_collection(
    collection_name="tutorial_collection",
    vectors_config=VectorParams(size=384, distance=Distance.COSINE),
)

vector_store = QdrantVectorStore(
    client=client, collection_name="tutorial_collection", embedding=embeddings
)

ids = vector_store.add_documents(all_splits)

ここはQdrantのクラむアントを盎接操䜜し、Qdrantのコレクションを䜜成しおいたす。次元数は384、距離メトリクスは
コサむン類䌌床にしたした。

client = QdrantClient("http://172.17.0.2:6333")
client.delete_collection(collection_name="tutorial_collection")
client.create_collection(
    collection_name="tutorial_collection",
    vectors_config=VectorParams(size=384, distance=Distance.COSINE),
)

そしおQdrantのクラむアント、コレクション名、Ollamaを䜿ったEmbedding modelを指定しおQdrantずのVector storeを
䜜成したす。

vector_store = QdrantVectorStore(
    client=client, collection_name="tutorial_collection", embedding=embeddings
)

ids = vector_store.add_documents(all_splits)

最埌にドキュメントを保存しおいたす。

Qdrant | 🦜️🔗 LangChain

この時、ドキュメントを保存する時に同時にテキスト埋め蟌みが行われたす。

なので、この郚分がこのスクリプトで1番重いです。

ids = vector_store.add_documents(all_splits)

http://[Qdrantが動䜜しおいるホスト]:6333/dashboardでQdrantのWeb UIが芋れるようにしおあるので、確認しおおきたす。

良さそうです。

怜玢する

次は、ベクトルデヌタベヌスから怜玢しおみたす。

この郚分ですね。

Build a semantic search engine / Vector stores / Usage

䜜成した゜ヌスコヌドはこちら。

hello_query.py

from langchain_ollama import OllamaEmbeddings
from langchain_qdrant import QdrantVectorStore
from qdrant_client import QdrantClient
import sys

embeddings = OllamaEmbeddings(
    model="all-minilm:l6-v2", base_url="http://localhost:11434"
)

client = QdrantClient("http://172.17.0.2:6333")

vector_store = QdrantVectorStore(
    client=client, collection_name="tutorial_collection", embedding=embeddings
)

query = sys.argv[1]

print(f"query = {query}")

print()

results = vector_store.similarity_search(query)

print(f"result count = {len(results)}")

print(f"first document = {results[0]}")

Vector storeを䜜成するずころたでは、ドキュメントのロヌドの時ず登堎人物は倉わりたせん。

ク゚リヌはコマンドラむン匕数ずしお受け取るようにしたした。

query = sys.argv[1]

怜玢は、similarity_searchで行いたす。この時にク゚リヌもベクトル化されるこずになりたす。

results = vector_store.similarity_search(query)

今回はヒット件数ずドキュメントの最初の1件を衚瀺するようにしたした。

実行結果。

$ uv run hello_query.py 'How many distribution centers does Nike have in the US?'
query = How many distribution centers does Nike have in the US?

result count = 4
first document = page_content='direct to consumer operations sell products through the following number of retail stores in the United States:
U.S. RETAIL STORES NUMBER
NIKE Brand factory stores 213
NIKE Brand in-line stores (including employee-only stores) 74
Converse stores (including factory stores) 82
TOTAL 369
In the United States, NIKE has eight significant distribution centers. Refer to Item 2. Properties for further information.
2023 FORM 10-K 2' metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'moddate': '2023-07-20T16:22:08-04:00', 'source': 'example_data/nke-10k-2023.pdf', 'total_pages': 107, 'page': 4, 'page_label': '5', 'start_index': 3125, '_id': 'b88bb8f3-10c1-4147-9047-4ecdfd335912', '_collection_name': 'tutorial_collection'}


$ uv run hello_query.py 'When was Nike incorporated?'
query = When was Nike incorporated?

result count = 4
first document = page_content='Table of Contents
PART I
ITEM 1. BUSINESS
GENERAL
NIKE, Inc. was incorporated in 1967 under the laws of the State of Oregon. As used in this Annual Report on Form 10-K (this "Annual Report"), the terms "we," "us," "our,"
"NIKE" and the "Company" refer to NIKE, Inc. and its predecessors, subsidiaries and affiliates, collectively, unless the context indicates otherwise.
Our principal business activity is the design, development and worldwide marketing and selling of athletic footwear, apparel, equipment, accessories and services. NIKE is
the largest seller of athletic footwear and apparel in the world. We sell our products through NIKE Direct operations, which are comprised of both NIKE-owned retail stores
and sales through our digital platforms (also referred to as "NIKE Brand Digital"), to retail accounts and to a mix of independent distributors, licensees and sales' metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'moddate': '2023-07-20T16:22:08-04:00', 'source': 'example_data/nke-10k-2023.pdf', 'total_pages': 107, 'page': 3, 'page_label': '4', 'start_index': 0, '_id': 'b19e33b5-8e05-4282-9063-bc308dd64e0d', '_collection_name': 'tutorial_collection'}

チュヌトリアルず同じになりたしたね。

非同期にするにはasimilarity_searchずメ゜ッド名の先頭にaを付けるみたいです。

たた、スコアを埗るにはsimilarity_search_with_scoreメ゜ッドを䜿うようですね。

Retrieverを䜿う

最埌はRetrieverを䜿いたす。ここではちょっず䜿っおみた、ずいう感じですね。

Build a semantic search engine / Retrievers

今回の堎合はVector storeからRetrieverを取埗するのですが、@chainを䜿う方法ずVector storeからas_retrieverメ゜ッドを
䜿っおRetrieverを取埗する方法を䜿いたす。

゜ヌスコヌドはこちら。

hello_retriever.py

from langchain_core.documents import Document
from langchain_core.runnables import chain
from langchain_ollama import OllamaEmbeddings
from langchain_qdrant import QdrantVectorStore
from qdrant_client import QdrantClient

embeddings = OllamaEmbeddings(
    model="all-minilm:l6-v2", base_url="http://localhost:11434"
)

client = QdrantClient("http://172.17.0.2:6333")

vector_store = QdrantVectorStore(
    client=client, collection_name="tutorial_collection", embedding=embeddings
)


@chain
def retriever(query: str) -> list[Document]:
    return vector_store.similarity_search(query, k=1)


results = retriever.batch(
    [
        "How many distribution centers does Nike have in the US?",
        "When was Nike incorporated?",
    ],
)

print(results[0][0])
print()
print(results[1][0])
print()

r = vector_store.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 1},
)

results = r.batch(
    [
        "How many distribution centers does Nike have in the US?",
        "When was Nike incorporated?",
    ],
)

print(results[0][0])
print()
print(results[1][0])
print()

先ほどコマンドラむン匕数から䞎えたク゚リヌを盎接指定しおいたす。

実行結果はこちら。

$ uv run hello_retriever.py
/path/to/langchain-tutorial-semantic-search/.venv/lib/python3.12/site-packages/langchain/__init__.py:30: UserWarning: Importing debug from langchain root module is no longer supported. Please use langchain.globals.set_debug() / langchain.globals.get_debug() instead.
  warnings.warn(
page_content='direct to consumer operations sell products through the following number of retail stores in the United States:
U.S. RETAIL STORES NUMBER
NIKE Brand factory stores 213
NIKE Brand in-line stores (including employee-only stores) 74
Converse stores (including factory stores) 82
TOTAL 369
In the United States, NIKE has eight significant distribution centers. Refer to Item 2. Properties for further information.
2023 FORM 10-K 2' metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'moddate': '2023-07-20T16:22:08-04:00', 'source': 'example_data/nke-10k-2023.pdf', 'total_pages': 107, 'page': 4, 'page_label': '5', 'start_index': 3125, '_id': 'b88bb8f3-10c1-4147-9047-4ecdfd335912', '_collection_name': 'tutorial_collection'}

page_content='Table of Contents
PART I
ITEM 1. BUSINESS
GENERAL
NIKE, Inc. was incorporated in 1967 under the laws of the State of Oregon. As used in this Annual Report on Form 10-K (this "Annual Report"), the terms "we," "us," "our,"
"NIKE" and the "Company" refer to NIKE, Inc. and its predecessors, subsidiaries and affiliates, collectively, unless the context indicates otherwise.
Our principal business activity is the design, development and worldwide marketing and selling of athletic footwear, apparel, equipment, accessories and services. NIKE is
the largest seller of athletic footwear and apparel in the world. We sell our products through NIKE Direct operations, which are comprised of both NIKE-owned retail stores
and sales through our digital platforms (also referred to as "NIKE Brand Digital"), to retail accounts and to a mix of independent distributors, licensees and sales' metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'moddate': '2023-07-20T16:22:08-04:00', 'source': 'example_data/nke-10k-2023.pdf', 'total_pages': 107, 'page': 3, 'page_label': '4', 'start_index': 0, '_id': 'b19e33b5-8e05-4282-9063-bc308dd64e0d', '_collection_name': 'tutorial_collection'}

page_content='direct to consumer operations sell products through the following number of retail stores in the United States:
U.S. RETAIL STORES NUMBER
NIKE Brand factory stores 213
NIKE Brand in-line stores (including employee-only stores) 74
Converse stores (including factory stores) 82
TOTAL 369
In the United States, NIKE has eight significant distribution centers. Refer to Item 2. Properties for further information.
2023 FORM 10-K 2' metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'moddate': '2023-07-20T16:22:08-04:00', 'source': 'example_data/nke-10k-2023.pdf', 'total_pages': 107, 'page': 4, 'page_label': '5', 'start_index': 3125, '_id': 'b88bb8f3-10c1-4147-9047-4ecdfd335912', '_collection_name': 'tutorial_collection'}

page_content='Table of Contents
PART I
ITEM 1. BUSINESS
GENERAL
NIKE, Inc. was incorporated in 1967 under the laws of the State of Oregon. As used in this Annual Report on Form 10-K (this "Annual Report"), the terms "we," "us," "our,"
"NIKE" and the "Company" refer to NIKE, Inc. and its predecessors, subsidiaries and affiliates, collectively, unless the context indicates otherwise.
Our principal business activity is the design, development and worldwide marketing and selling of athletic footwear, apparel, equipment, accessories and services. NIKE is
the largest seller of athletic footwear and apparel in the world. We sell our products through NIKE Direct operations, which are comprised of both NIKE-owned retail stores
and sales through our digital platforms (also referred to as "NIKE Brand Digital"), to retail accounts and to a mix of independent distributors, licensees and sales' metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'moddate': '2023-07-20T16:22:08-04:00', 'source': 'example_data/nke-10k-2023.pdf', 'total_pages': 107, 'page': 3, 'page_label': '4', 'start_index': 0, '_id': 'b19e33b5-8e05-4282-9063-bc308dd64e0d', '_collection_name': 'tutorial_collection'}

今回はこのくらいにしおおきたす。

おわりに

LangChainのチュヌトリアルのセマンティック怜玢を詊しおみたした。

だいぶ基本的な芁玠が出おきた感じがしたすね。

次はRAGをやっおみたしょうか。