Azure SQL은 관계형 데이터베이스 내에서 직접 벡터 임베딩의 생성, 저장 및 쿼리를 간소화하는 전용 Vector data type을 제공합니다. 이를 통해 별도의 벡터 데이터베이스와 관련 통합이 필요 없어지며, 솔루션의 보안을 강화하면서 전체적인 복잡성을 줄일 수 있습니다.
Azure SQL은 확장성, 보안성 및 고가용성을 결합한 강력한 서비스로, 현대적인 데이터베이스 솔루션의 모든 이점을 제공합니다. 정교한 쿼리 최적화 도구와 엔터프라이즈 기능을 활용하여 기존 SQL 쿼리와 함께 벡터 유사도 검색을 수행하여 데이터 분석 및 의사 결정을 향상시킵니다. Azure SQL Database를 사용한 지능형 애플리케이션에 대해 자세히 알아보세요 이 노트북은 통합된 SQL vector database를 활용하여 문서를 저장하고 Cosine(코사인 거리), L2(유클리드 거리), IP(내적)를 사용하여 쿼리 벡터에 가까운 문서를 찾는 벡터 검색 쿼리를 수행하는 방법을 보여줍니다

Setup

langchain-sqlserver python 패키지를 설치합니다. 코드는 다음 통합 패키지에 있습니다:langchain-sqlserver.
!pip install langchain-sqlserver==0.1.1

Credentials

이 노트북을 실행하는 데 필요한 자격 증명은 없으며, langchain-sqlserver 패키지를 다운로드했는지 확인하기만 하면 됩니다 모델 호출에 대한 최고 수준의 자동 추적을 원하시면 아래 주석을 해제하여 LangSmith API 키를 설정할 수도 있습니다:
os.environ["LANGSMITH_API_KEY"] = getpass.getpass("Enter your LangSmith API key: ")
os.environ["LANGSMITH_TRACING"] = "true"

Initialization

from langchain_sqlserver import SQLServer_VectorStore
Azure 포털의 데이터베이스 설정에서 Azure SQL DB 연결 문자열을 찾으세요 자세한 정보: Connect to Azure SQL DB - Python
import os

import pyodbc

# Define your SQLServer Connection String
_CONNECTION_STRING = (
    "Driver={ODBC Driver 18 for SQL Server};"
    "Server=<YOUR_DBSERVER>.database.windows.net,1433;"
    "Database=test;"
    "TrustServerCertificate=yes;"
    "Connection Timeout=60;"
    "LongAsMax=yes;"
)

# Connection string can vary:
# "mssql+pyodbc://<username>:<password><servername>/<dbname>?driver=ODBC+Driver+18+for+SQL+Server" -> With Username and Password specified
# "mssql+pyodbc://<servername>/<dbname>?driver=ODBC+Driver+18+for+SQL+Server&Trusted_connection=yes" -> Uses Trusted connection
# "mssql+pyodbc://<servername>/<dbname>?driver=ODBC+Driver+18+for+SQL+Server" -> Uses EntraID connection
# "mssql+pyodbc://<servername>/<dbname>?driver=ODBC+Driver+18+for+SQL+Server&Trusted_connection=no" -> Uses EntraID connection
이 예제에서는 Azure OpenAI를 사용하여 임베딩을 생성하지만, LangChain에서 제공하는 다른 임베딩을 사용할 수도 있습니다. 가이드에 따라 Azure Portal에서 Azure OpenAI 인스턴스 버전을 배포할 수 있습니다. 인스턴스가 실행되면 인스턴스 이름과 키가 있는지 확인하세요. 키는 Azure Portal의 인스턴스 “Keys and Endpoint” 섹션에서 찾을 수 있습니다.
!pip install langchain-openai
# Import the necessary Libraries
from langchain_openai import AzureChatOpenAI, AzureOpenAIEmbeddings

# Set your AzureOpenAI details
azure_endpoint = "https://<YOUR_ENDPOINT>.openai.azure.com/"
azure_deployment_name_embedding = "text-embedding-3-small"
azure_deployment_name_chatcompletion = "chatcompletion"
azure_api_version = "2023-05-15"
azure_api_key = "YOUR_KEY"


# Use AzureChatOpenAI for chat completions
llm = AzureChatOpenAI(
    azure_endpoint=azure_endpoint,
    azure_deployment=azure_deployment_name_chatcompletion,
    openai_api_version=azure_api_version,
    openai_api_key=azure_api_key,
)

# Use AzureOpenAIEmbeddings for embeddings
embeddings = AzureOpenAIEmbeddings(
    azure_endpoint=azure_endpoint,
    azure_deployment=azure_deployment_name_embedding,
    openai_api_version=azure_api_version,
    openai_api_key=azure_api_key,
)

Manage vector store

from langchain_community.vectorstores.utils import DistanceStrategy
from langchain_sqlserver import SQLServer_VectorStore

# Initialize the vector store
vector_store = SQLServer_VectorStore(
    connection_string=_CONNECTION_STRING,
    distance_strategy=DistanceStrategy.COSINE,  # optional, if not provided, defaults to COSINE
    embedding_function=embeddings,  # you can use different embeddings provided in LangChain
    embedding_length=1536,
    table_name="langchain_test_table",  # using table with a custom name
)

Add items to vector store

## we will use some artificial data for this example
query = [
    "I have bought several of the Vitality canned dog food products and have found them all to be of good quality. The product looks more like a stew than a processed meat and it smells better. My Labrador is finicky and she appreciates this product better than  most.",
    "The candy is just red , No flavor . Just  plan and chewy .  I would never buy them again",
    "Arrived in 6 days and were so stale i could not eat any of the 6 bags!!",
    "Got these on sale for roughly 25 cents per cup, which is half the price of my local grocery stores, plus they rarely stock the spicy flavors. These things are a GREAT snack for my office where time is constantly crunched and sometimes you can't escape for a real meal. This is one of my favorite flavors of Instant Lunch and will be back to buy every time it goes on sale.",
    "If you are looking for a less messy version of licorice for the children, then be sure to try these!  They're soft, easy to chew, and they don't get your hands all sticky and gross in the car, in the summer, at the beach, etc. We love all the flavos and sometimes mix these in with the chocolate to have a very nice snack! Great item, great price too, highly recommend!",
    "We had trouble finding this locally - delivery was fast, no more hunting up and down the flour aisle at our local grocery stores.",
    "Too much of a good thing? We worked this kibble in over time, slowly shifting the percentage of Felidae to national junk-food brand until the bowl was all natural. By this time, the cats couldn't keep it in or down. What a mess. We've moved on.",
    "Hey, the description says 360 grams - that is roughly 13 ounces at under $4.00 per can. No way - that is the approximate price for a 100 gram can.",
    "The taste of these white cheddar flat breads is like a regular cracker - which is not bad, except that I bought them because I wanted a cheese taste.<br /><br />What was a HUGE disappointment? How misleading the packaging of the box is. The photo on the box (I bought these in store) makes it look like it is full of long flatbreads (expanding the length and width of the box). Wrong! The plastic tray that holds the crackers is about 2"
    " smaller all around - leaving you with about 15 or so small flatbreads.<br /><br />What is also bad about this is that the company states they use biodegradable and eco-friendly packaging. FAIL! They used a HUGE box for a ridiculously small amount of crackers. Not ecofriendly at all.<br /><br />Would I buy these again? No - I feel ripped off. The other crackers (like Sesame Tarragon) give you a little<br />more bang for your buck and have more flavor.",
    "I have used this product in smoothies for my son and he loves it. Additionally, I use this oil in the shower as a skin conditioner and it has made my skin look great. Some of the stretch marks on my belly has disappeared quickly. Highly recommend!!!",
    "Been taking Coconut Oil for YEARS.  This is the best on the retail market.  I wish it was in glass, but this is the one.",
]

query_metadata = [
    {"id": 1, "summary": "Good Quality Dog Food"},
    {"id": 8, "summary": "Nasty No flavor"},
    {"id": 4, "summary": "stale product"},
    {"id": 11, "summary": "Great value and convenient ramen"},
    {"id": 5, "summary": "Great for the kids!"},
    {"id": 2, "summary": "yum falafel"},
    {"id": 9, "summary": "Nearly killed the cats"},
    {"id": 6, "summary": "Price cannot be correct"},
    {"id": 3, "summary": "Taste is neutral, quantity is DECEITFUL!"},
    {"id": 7, "summary": "This stuff is great"},
    {"id": 10, "summary": "The reviews don't lie"},
]
vector_store.add_texts(texts=query, metadatas=query_metadata)
[1, 8, 4, 11, 5, 2, 9, 6, 3, 7, 10]

Query vector store

벡터 저장소가 생성되고 관련 문서가 추가되면 체인이나 에이전트를 실행하는 동안 쿼리하고 싶을 것입니다. 간단한 유사도 검색은 다음과 같이 수행할 수 있습니다:
# Perform a similarity search between the embedding of the query and the embeddings of the documents
simsearch_result = vector_store.similarity_search("Good reviews", k=3)
print(simsearch_result)
[Document(metadata={'id': 1, 'summary': 'Good Quality Dog Food'}, page_content='I have bought several of the Vitality canned dog food products and have found them all to be of good quality. The product looks more like a stew than a processed meat and it smells better. My Labrador is finicky and she appreciates this product better than  most.'), Document(metadata={'id': 7, 'summary': 'This stuff is great'}, page_content='I have used this product in smoothies for my son and he loves it. Additionally, I use this oil in the shower as a skin conditioner and it has made my skin look great. Some of the stretch marks on my belly has disappeared quickly. Highly recommend!!!'), Document(metadata={'id': 5, 'summary': 'Great for the kids!'}, page_content="If you are looking for a less messy version of licorice for the children, then be sure to try these!  They're soft, easy to chew, and they don't get your hands all sticky and gross in the car, in the summer, at the beach, etc. We love all the flavos and sometimes mix these in with the chocolate to have a very nice snack! Great item, great price too, highly recommend!")]

Filtering Support

벡터 저장소는 문서의 메타데이터 필드에 적용할 수 있는 필터 세트를 지원합니다. 이 기능을 통해 개발자와 데이터 분석가는 쿼리를 세밀하게 조정하여 검색 결과가 필요에 정확하게 부합하도록 할 수 있습니다. 특정 메타데이터 속성을 기반으로 필터를 적용함으로써 사용자는 검색 범위를 제한하여 가장 관련성 높은 데이터 하위 집합에만 집중할 수 있습니다.
# hybrid search -> filter for cases where id not equal to 1.
hybrid_simsearch_result = vector_store.similarity_search(
    "Good reviews", k=3, filter={"id": {"$ne": 1}}
)
print(hybrid_simsearch_result)
[Document(metadata={'id': 7, 'summary': 'This stuff is great'}, page_content='I have used this product in smoothies for my son and he loves it. Additionally, I use this oil in the shower as a skin conditioner and it has made my skin look great. Some of the stretch marks on my belly has disappeared quickly. Highly recommend!!!'), Document(metadata={'id': 5, 'summary': 'Great for the kids!'}, page_content="If you are looking for a less messy version of licorice for the children, then be sure to try these!  They're soft, easy to chew, and they don't get your hands all sticky and gross in the car, in the summer, at the beach, etc. We love all the flavos and sometimes mix these in with the chocolate to have a very nice snack! Great item, great price too, highly recommend!"), Document(metadata={'id': 3, 'summary': 'Taste is neutral, quantity is DECEITFUL!'}, page_content='The taste of these white cheddar flat breads is like a regular cracker - which is not bad, except that I bought them because I wanted a cheese taste.<br /><br />What was a HUGE disappointment? How misleading the packaging of the box is. The photo on the box (I bought these in store) makes it look like it is full of long flatbreads (expanding the length and width of the box). Wrong! The plastic tray that holds the crackers is about 2 smaller all around - leaving you with about 15 or so small flatbreads.<br /><br />What is also bad about this is that the company states they use biodegradable and eco-friendly packaging. FAIL! They used a HUGE box for a ridiculously small amount of crackers. Not ecofriendly at all.<br /><br />Would I buy these again? No - I feel ripped off. The other crackers (like Sesame Tarragon) give you a little<br />more bang for your buck and have more flavor.')]

Similarity Search with Score

유사도 검색을 실행하고 해당 점수를 받으려면 다음을 실행할 수 있습니다:
simsearch_with_score_result = vector_store.similarity_search_with_score(
    "Not a very good product", k=12
)
print(simsearch_with_score_result)
[(Document(metadata={'id': 3, 'summary': 'Taste is neutral, quantity is DECEITFUL!'}, page_content='The taste of these white cheddar flat breads is like a regular cracker - which is not bad, except that I bought them because I wanted a cheese taste.<br /><br />What was a HUGE disappointment? How misleading the packaging of the box is. The photo on the box (I bought these in store) makes it look like it is full of long flatbreads (expanding the length and width of the box). Wrong! The plastic tray that holds the crackers is about 2 smaller all around - leaving you with about 15 or so small flatbreads.<br /><br />What is also bad about this is that the company states they use biodegradable and eco-friendly packaging. FAIL! They used a HUGE box for a ridiculously small amount of crackers. Not ecofriendly at all.<br /><br />Would I buy these again? No - I feel ripped off. The other crackers (like Sesame Tarragon) give you a little<br />more bang for your buck and have more flavor.'), 0.651870006770711), (Document(metadata={'id': 8, 'summary': 'Nasty No flavor'}, page_content='The candy is just red , No flavor . Just  plan and chewy .  I would never buy them again'), 0.6908952973052638), (Document(metadata={'id': 4, 'summary': 'stale product'}, page_content='Arrived in 6 days and were so stale i could not eat any of the 6 bags!!'), 0.7360955776468822), (Document(metadata={'id': 1, 'summary': 'Good Quality Dog Food'}, page_content='I have bought several of the Vitality canned dog food products and have found them all to be of good quality. The product looks more like a stew than a processed meat and it smells better. My Labrador is finicky and she appreciates this product better than  most.'), 0.7408823529514486), (Document(metadata={'id': 9, 'summary': 'Nearly killed the cats'}, page_content="Too much of a good thing? We worked this kibble in over time, slowly shifting the percentage of Felidae to national junk-food brand until the bowl was all natural. By this time, the cats couldn't keep it in or down. What a mess. We've moved on."), 0.782995248991772), (Document(metadata={'id': 7, 'summary': 'This stuff is great'}, page_content='I have used this product in smoothies for my son and he loves it. Additionally, I use this oil in the shower as a skin conditioner and it has made my skin look great. Some of the stretch marks on my belly has disappeared quickly. Highly recommend!!!'), 0.7912681479906212), (Document(metadata={'id': 2, 'summary': 'yum falafel'}, page_content='We had trouble finding this locally - delivery was fast, no more hunting up and down the flour aisle at our local grocery stores.'), 0.809213468778896), (Document(metadata={'id': 10, 'summary': "The reviews don't lie"}, page_content='Been taking Coconut Oil for YEARS.  This is the best on the retail market.  I wish it was in glass, but this is the one.'), 0.8281482301097155), (Document(metadata={'id': 5, 'summary': 'Great for the kids!'}, page_content="If you are looking for a less messy version of licorice for the children, then be sure to try these!  They're soft, easy to chew, and they don't get your hands all sticky and gross in the car, in the summer, at the beach, etc. We love all the flavos and sometimes mix these in with the chocolate to have a very nice snack! Great item, great price too, highly recommend!"), 0.8283754326400574), (Document(metadata={'id': 6, 'summary': 'Price cannot be correct'}, page_content='Hey, the description says 360 grams - that is roughly 13 ounces at under $4.00 per can. No way - that is the approximate price for a 100 gram can.'), 0.8323967822635847), (Document(metadata={'id': 11, 'summary': 'Great value and convenient ramen'}, page_content="Got these on sale for roughly 25 cents per cup, which is half the price of my local grocery stores, plus they rarely stock the spicy flavors. These things are a GREAT snack for my office where time is constantly crunched and sometimes you can't escape for a real meal. This is one of my favorite flavors of Instant Lunch and will be back to buy every time it goes on sale."), 0.8387189489406939)]
Azure SQL 벡터 저장소에서 실행할 수 있는 다양한 검색의 전체 목록은 API reference를 참조하세요.

Similarity Search when you already have embeddings you want to search on

# if you already have embeddings you want to search on
simsearch_by_vector = vector_store.similarity_search_by_vector(
    [-0.0033353185281157494, -0.017689190804958344, -0.01590404286980629, ...]
)
print(simsearch_by_vector)
[Document(metadata={'id': 8, 'summary': 'Nasty No flavor'}, page_content='The candy is just red , No flavor . Just  plan and chewy .  I would never buy them again'), Document(metadata={'id': 4, 'summary': 'stale product'}, page_content='Arrived in 6 days and were so stale i could not eat any of the 6 bags!!'), Document(metadata={'id': 3, 'summary': 'Taste is neutral, quantity is DECEITFUL!'}, page_content='The taste of these white cheddar flat breads is like a regular cracker - which is not bad, except that I bought them because I wanted a cheese taste.<br /><br />What was a HUGE disappointment? How misleading the packaging of the box is. The photo on the box (I bought these in store) makes it look like it is full of long flatbreads (expanding the length and width of the box). Wrong! The plastic tray that holds the crackers is about 2 smaller all around - leaving you with about 15 or so small flatbreads.<br /><br />What is also bad about this is that the company states they use biodegradable and eco-friendly packaging. FAIL! They used a HUGE box for a ridiculously small amount of crackers. Not ecofriendly at all.<br /><br />Would I buy these again? No - I feel ripped off. The other crackers (like Sesame Tarragon) give you a little<br />more bang for your buck and have more flavor.'), Document(metadata={'id': 6, 'summary': 'Price cannot be correct'}, page_content='Hey, the description says 360 grams - that is roughly 13 ounces at under $4.00 per can. No way - that is the approximate price for a 100 gram can.')]
# Similarity Search with Score if you already have embeddings you want to search on
simsearch_by_vector_with_score = vector_store.similarity_search_by_vector_with_score(
    [-0.0033353185281157494, -0.017689190804958344, -0.01590404286980629, ...]
)
print(simsearch_by_vector_with_score)
[(Document(metadata={'id': 8, 'summary': 'Nasty No flavor'}, page_content='The candy is just red , No flavor . Just  plan and chewy .  I would never buy them again'), 0.9648153551769503), (Document(metadata={'id': 4, 'summary': 'stale product'}, page_content='Arrived in 6 days and were so stale i could not eat any of the 6 bags!!'), 0.9655108580341948), (Document(metadata={'id': 3, 'summary': 'Taste is neutral, quantity is DECEITFUL!'}, page_content='The taste of these white cheddar flat breads is like a regular cracker - which is not bad, except that I bought them because I wanted a cheese taste.<br /><br />What was a HUGE disappointment? How misleading the packaging of the box is. The photo on the box (I bought these in store) makes it look like it is full of long flatbreads (expanding the length and width of the box). Wrong! The plastic tray that holds the crackers is about 2 smaller all around - leaving you with about 15 or so small flatbreads.<br /><br />What is also bad about this is that the company states they use biodegradable and eco-friendly packaging. FAIL! They used a HUGE box for a ridiculously small amount of crackers. Not ecofriendly at all.<br /><br />Would I buy these again? No - I feel ripped off. The other crackers (like Sesame Tarragon) give you a little<br />more bang for your buck and have more flavor.'), 0.9840511208615808), (Document(metadata={'id': 6, 'summary': 'Price cannot be correct'}, page_content='Hey, the description says 360 grams - that is roughly 13 ounces at under $4.00 per can. No way - that is the approximate price for a 100 gram can.'), 0.9915737524649991)]

Delete items from vector store

Delete Row by ID

# delete row by id
vector_store.delete(["3", "7"])
True

Drop Vector Store

# drop vectorstore
vector_store.drop()

Load a Document from Azure Blob Storage

다음은 Azure Blob Storage 컨테이너에서 파일을 로드하여 문서를 청크로 분할한 후 SQL Vector 저장소에 로드하는 예제입니다. Azure Blog Storage는 클라우드를 위한 Microsoft의 객체 스토리지 솔루션입니다. Blob Storage는 대량의 비구조화 데이터를 저장하는 데 최적화되어 있습니다.
pip install azure-storage-blob
from langchain.document_loaders import AzureBlobStorageFileLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_core.documents import Document

# Define your connection string and blob details
conn_str = "DefaultEndpointsProtocol=https;AccountName=<YourBlobName>;AccountKey=<YourAccountKey>==;EndpointSuffix=core.windows.net"
container_name = "<YourContainerName"
blob_name = "01 Harry Potter and the Sorcerers Stone.txt"

# Create an instance of AzureBlobStorageFileLoader
loader = AzureBlobStorageFileLoader(
    conn_str=conn_str, container=container_name, blob_name=blob_name
)

# Load the document from Azure Blob Storage
documents = loader.load()

# Split the document into smaller chunks if necessary
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
split_documents = text_splitter.split_documents(documents)

# Print the number of split documents
print(f"Number of split documents: {len(split_documents)}")
Number of split documents: 528
API Reference:AzureBlobStorageContainerLoader
# # Initialize the vector store & insert the documents in AzureSQLDB with their embeddings
vector_store = SQLServer_VectorStore(
    connection_string=_CONNECTION_STRING,
    distance_strategy=DistanceStrategy.COSINE,
    embedding_function=embeddings,
    embedding_length=1536,
    table_name="harrypotter",
)  # Replace with your actual vector store initialization

# Add split documents to the vector store individually
for i, doc in enumerate(split_documents):
    vector_store.add_documents(documents=[doc], ids=[f"doc_{i}"])

print("Documents added to the vector store successfully!")
Documents added to the vector store successfully!

Query directly

from typing import List, Tuple

# Perform similarity search
query = "Why did the Dursleys not want Harry in their house?"
docs_with_score: List[Tuple[Document, float]] = (
    vector_store.similarity_search_with_score(query)
)

for doc, score in docs_with_score:
    print("-" * 60)
    print("Score: ", score)
    print(doc.page_content)
    print("-" * 60)
------------------------------------------------------------
Score:  0.3626232679001803
The Dursleys had everything they wanted, but they also had a secret, and their greatest fear was that somebody would discover it. They didn’t think they could bear it if anyone found out about the Potters. Mrs. Potter was Mrs. Dursley’s sister, but they hadn’t met for several years; in fact, Mrs. Dursley pretended she didn’t have a sister, because her sister and her good-for-nothing husband were as unDursleyish as it was possible to be. The Dursleys shuddered to think what the neighbors would say if the Potters arrived in the street. The Dursleys knew that the Potters had a small son, too, but they had never even seen him. This boy was another good reason for keeping the Potters away; they didn’t want Dudley mixing with a child like that.
------------------------------------------------------------
------------------------------------------------------------
Score:  0.44752797298657554
The Dursleys’ house had four bedrooms: one for Uncle Vernon and Aunt Petunia, one for visitors (usually Uncle Vernon’s sister, Marge), one where Dudley slept, and one where Dudley kept all the toys and things that wouldn’t fit into his first bedroom. It only took Harry one trip upstairs to move everything he owned from the cupboard to this room. He sat down on the bed and stared around him. Nearly everything in here was broken. The month-old video camera was lying on top of a small, working tank Dudley had once driven over the next door neighbor’s dog; in the corner was Dudley’s first-ever television set, which he’d put his foot through when his favorite program had been canceled; there was a large birdcage, which had once held a parrot that Dudley had swapped at school for a real air rifle, which was up on a shelf with the end all bent because Dudley had sat on it. Other shelves were full of books. They were the only things in the room that looked as though they’d never been touched.
------------------------------------------------------------
------------------------------------------------------------
Score:  0.4652486419877385
M r. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much. They were the last people you’d expect to be involved in anything strange or mysterious, because they just didn’t hold with such nonsense.

Mr. Dursley was the director of a firm called Grunnings, which made drills. He was a big, beefy man with hardly any neck, although he did have a very large mustache. Mrs. Dursley was thin and blonde and had nearly twice the usual amount of neck, which came in very useful as she spent so much of her time craning over garden fences, spying on the neighbors. The Dursleys had a small son called Dudley and in their opinion there was no finer boy anywhere.
------------------------------------------------------------
------------------------------------------------------------
Score:  0.4739086301927252
Hagrid was watching him sadly.

“Took yeh from the ruined house myself, on Dumbledore’s orders. Brought yeh ter this lot….”

“Load of old tosh,” said Uncle Vernon. Harry jumped; he had almost forgotten that the Dursleys were there. Uncle Vernon certainly seemed to have got back his courage. He was glaring at Hagrid and his fists were clenched.

“Now, you listen here, boy,” he snarled, “I accept there’s something strange about you, probably nothing a good beating wouldn’t have cured — and as for all this about your parents, well, they were weirdoes, no denying it, and the world’s better off without them in my opinion — asked for all they got, getting mixed up with these wizarding types — just what I expected, always knew they’d come to a sticky end —”

But at that moment, Hagrid leapt from the sofa and drew a battered pink umbrella from inside his coat. Pointing this at Uncle Vernon like a sword, he said, “I’m warning you, Dursley — I’m warning you — one more word….”
------------------------------------------------------------

Usage for retrieval-augmented generation

Use Case 1: 스토리 북 기반 Q&A 시스템

Q&A 기능을 통해 사용자는 스토리, 캐릭터 및 이벤트에 대한 구체적인 질문을 하고 간결하고 맥락이 풍부한 답변을 얻을 수 있습니다. 이는 책에 대한 이해를 향상시킬 뿐만 아니라 마법의 세계의 일부가 된 것처럼 느끼게 합니다.

Query by turning into retriever

LangChain Vector 저장소는 사용자의 쿼리를 기반으로 상위 10개의 관련 문서를 찾기 위한 효율적인 유사도 검색을 가능하게 하여 정교한 Q&A 시스템 구축을 간소화합니다. retrievervector_store에서 생성되며, create_stuff_documents_chain 함수를 사용하여 질문-답변 체인이 구축됩니다. ChatPromptTemplate 클래스를 사용하여 프롬프트 템플릿을 작성하여 구조화되고 맥락이 풍부한 응답을 보장합니다. Q&A 애플리케이션에서는 답변을 생성하는 데 사용된 출처를 사용자에게 보여주는 것이 중요한 경우가 많습니다. LangChain의 내장 create_retrieval_chain은 검색된 소스 문서를 “context” 키 아래의 출력으로 전파합니다: LangChain RAG 튜토리얼 및 위에서 언급한 용어에 대해 여기에서 자세히 알아보세요
from typing import List, Tuple

import pandas as pd
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate


# Define the function to perform the RAG chain invocation
def get_answer_and_sources(user_query: str):
    # Perform similarity search with scores
    docs_with_score: List[Tuple[Document, float]] = (
        vector_store.similarity_search_with_score(
            user_query,
            k=10,
        )
    )

    # Extract the context from the top results
    context = "\n".join([doc.page_content for doc, score in docs_with_score])

    # Define the system prompt
    system_prompt = (
        "You are an assistant for question-answering tasks based on the story in the book. "
        "Use the following pieces of retrieved context to answer the question. "
        "If you don't know the answer, say that you don't know, but also suggest that the user can use the fan fiction function to generate fun stories. "
        "Use 5 sentences maximum and keep the answer concise by also providing some background context of 1-2 sentences."
        "\n\n"
        "{context}"
    )

    # Create the prompt template
    prompt = ChatPromptTemplate.from_messages(
        [
            ("system", system_prompt),
            ("human", "{input}"),
        ]
    )

    # Create the retriever and chains
    retriever = vector_store.as_retriever()
    question_answer_chain = create_stuff_documents_chain(llm, prompt)
    rag_chain = create_retrieval_chain(retriever, question_answer_chain)

    # Define the input
    input_data = {"input": user_query}

    # Invoke the RAG chain
    response = rag_chain.invoke(input_data)

    # Print the answer
    print("Answer:", response["answer"])

    # Prepare the data for the table
    data = {
        "Doc ID": [
            doc.metadata.get("source", "N/A").split("/")[-1]
            for doc in response["context"]
        ],
        "Content": [
            doc.page_content[:50] + "..."
            if len(doc.page_content) > 100
            else doc.page_content
            for doc in response["context"]
        ],
    }

    # Create a DataFrame
    df = pd.DataFrame(data)

    # Print the table
    print("\nSources:")
    print(df.to_markdown(index=False))
# Define the user query
user_query = "How did Harry feel when he first learnt that he was a Wizard?"

# Call the function to get the answer and sources
get_answer_and_sources(user_query)
Answer: When Harry first learned that he was a wizard, he felt quite sure there had been a horrible mistake. He struggled to believe it because he had spent his life being bullied and mistreated by the Dursleys. If he was really a wizard, he wondered why he hadn't been able to use magic to defend himself. This disbelief and surprise were evident when he gasped, “I’m a what?”

Sources:
| Doc ID                                      | Content                                               |
|:--------------------------------------------|:------------------------------------------------------|
| 01 Harry Potter and the Sorcerers Stone.txt | Harry was wondering what a wizard did once he’d fi... |
| 01 Harry Potter and the Sorcerers Stone.txt | Harry realized his mouth was open and closed it qu... |
| 01 Harry Potter and the Sorcerers Stone.txt | “Most of us reckon he’s still out there somewhere ... |
| 01 Harry Potter and the Sorcerers Stone.txt | “Ah, go boil yer heads, both of yeh,” said Hagrid.... |
# Define the user query
user_query = "Did Harry have a pet? What was it"

# Call the function to get the answer and sources
get_answer_and_sources(user_query)
Yes, Harry had a pet owl named Hedwig. He decided to call her Hedwig after finding the name in a book titled *A History of Magic*.

Sources:
| Doc ID                                      | Content                                               |
|:--------------------------------------------|:------------------------------------------------------|
| 01 Harry Potter and the Sorcerers Stone.txt | Harry sank down next to the bowl of peas. “What di... |
| 01 Harry Potter and the Sorcerers Stone.txt | Harry kept to his room, with his new owl for compa... |
| 01 Harry Potter and the Sorcerers Stone.txt | As the snake slid swiftly past him, Harry could ha... |
| 01 Harry Potter and the Sorcerers Stone.txt | Ron reached inside his jacket and pulled out a fat... |

API reference

SQLServer Vectorstore 기능 및 구성에 대한 자세한 문서는 API reference를 참조하세요: https://python.langchain.com/api_reference/sqlserver/index.html
Connect these docs programmatically to Claude, VSCode, and more via MCP for real-time answers.
I