Megosztás a következőn keresztül:


A LangChain használata az Azure Database for PostgreSQL-hez

Az Azure Database for PostgreSQL zökkenőmentesen integrálható a vezető nagy nyelvi modell (LLM) vezénylési csomagokkal, például a LangChainnel. Ez az integráció lehetővé teszi a fejlesztők számára, hogy fejlett AI-képességeket használjanak alkalmazásaikban. A LangChain leegyszerűsíti az LLM-k, a beágyazási modellek és az adatbázisok kezelését és használatát, hogy a generatív AI-alkalmazások könnyebben fejleszthetők legyenek.

Ez a cikk bemutatja, hogyan használhatja az integrált vektoradatbázist az Azure Database for PostgreSQL-ben a dokumentumok gyűjteményekben való tárolására és kezelésére a LangChain használatával. Azt is bemutatja, hogyan hozhat létre indexeket, és hogyan hajthat végre vektorkeresési lekérdezéseket a legközelebbi szomszéd algoritmusok, például a koszinusz távolság, az L2 távolság (euklideszi távolság) és a belső termék használatával a lekérdezésvektorokhoz közeli dokumentumok megkereséséhez.

Vektortámogatás

Az Azure Database for PostgreSQL használatával hatékonyan tárolhat és kérdezhet le több millió vektoros beágyazást a PostgreSQL-ben. A szolgáltatás segít a MI esetek skálázásában a koncepció igazolásától az éles környezetig. A következő előnyöket kínálja:

  • Ismerős SQL-felületet biztosít a vektoros beágyazások és a relációs adatok lekérdezéséhez.
  • pgvector Több mint 100 millió vektor gyorsabb és pontosabb hasonlósági keresésével növeli a DiskANN indexelési algoritmusát.
  • Leegyszerűsíti a műveleteket a relációs metaadatok, a vektorbeágyazások és az idősoros adatok egyetlen adatbázisba való integrálásával.
  • A robusztus PostgreSQL-ökoszisztéma és az Azure-felhőplatform erejét használja nagyvállalati szintű funkciókhoz, beleértve a replikációt és a magas rendelkezésre állást.

Hitelesítés

Az Azure Database for PostgreSQL támogatja a jelszóalapú és a Microsoft Entra (korábbi nevén Azure Active Directory) hitelesítést.

A Microsoft Entra-hitelesítés lehetővé teszi, hogy a Microsoft Entra-azonosítóval hitelesítse magát a PostgreSQL-kiszolgálón. A Microsoft Entra ID nem szükséges külön felhasználóneveket és jelszavakat kezelni az adatbázis felhasználói számára. Ez lehetővé teszi, hogy ugyanazokat a biztonsági mechanizmusokat használja, mint más Azure-szolgáltatások esetében.

Ebben a cikkben bármelyik hitelesítési módszert használhatja.

Beállítás

Az Azure Database for PostgreSQL a nyílt forráskódú LangChain Postgres-támogatással csatlakozik az Azure Database for PostgreSQL-hez. Először töltse le a partnercsomagot:

%pip install -qU langchain_postgres
%pip install -qU langchain-openai
%pip install -qU azure-identity

A pgvector engedélyezése az Azure Database for PostgreSQL-ben

Lásd: A pgvector engedélyezése és használata az Azure Database for PostgreSQL-ben.

Hitelesítő adatok beállítása

Le kell kérnie az Azure Database for PostgreSQL kapcsolati adatait , és környezeti változókként kell hozzáadnia őket.

Állítsa be a USE_ENTRA_AUTH jelzőt, True ha Microsoft Entra-hitelesítést szeretne használni. Ha a Microsoft Entra-hitelesítést használja, csak a gazdagép- és adatbázisneveket kell megadnia. Ha jelszóhitelesítést használ, a felhasználónevet és a jelszót is be kell állítania.

import getpass
import os

USE_ENTRA_AUTH = True

# Supply the connection details for the database
os.environ["DBHOST"] = "<server-name>"
os.environ["DBNAME"] = "<database-name>"
os.environ["SSLMODE"] = "require"

if not USE_ENTRA_AUTH:
    # If you're using a username and password, supply them here
    os.environ["DBUSER"] = "<username>"
    os.environ["DBPASSWORD"] = getpass.getpass("Database Password:")

Azure OpenAI-beágyazások beállítása

os.environ["AZURE_OPENAI_ENDPOINT"] = "<azure-openai-endpoint>"
os.environ["AZURE_OPENAI_API_KEY"] = getpass.getpass("Azure OpenAI API Key:")
AZURE_OPENAI_ENDPOINT = os.environ["AZURE_OPENAI_ENDPOINT"]
AZURE_OPENAI_API_KEY = os.environ["AZURE_OPENAI_API_KEY"]

from langchain_openai import AzureOpenAIEmbeddings

embeddings = AzureOpenAIEmbeddings(
    model="text-embedding-3-small",
    api_key=AZURE_OPENAI_API_KEY,
    azure_endpoint=AZURE_OPENAI_ENDPOINT,
    azure_deployment="text-embedding-3-small",
)

Inicializálás

Microsoft Entra-hitelesítés használata

A következő szakaszok olyan függvényeket tartalmaznak, amelyek a LangChaint a Microsoft Entra-hitelesítés használatára állítják be. A függvény get_token_and_username a azure.identity könyvtárból származó DefaultAzureCredential használatával lekéri az Azure Database for PostgreSQL szolgáltatás tokenjeit. Biztosítja, hogy az SQLAlchemy motor érvényes jogkivonattal rendelkezik, amellyel új kapcsolatokat hozhat létre. A JSON webes jogkivonatot (JWT) is elemzi az adatbázishoz való csatlakozáshoz használt felhasználónév kinyeréséhez.

A create_postgres_engine függvény létrehoz egy SQLAlchemy-motort, amely dinamikusan beállítja a felhasználónevet és a jelszót a jogkivonat-kezelőtől lekért jogkivonat alapján. Ez a motor átadható a LangChain vektortároló connection paraméterének PGVector.

Bejelentkezés az Azure-ba

Az Azure-ba való bejelentkezéshez győződjön meg arról, hogy telepítve van az Azure CLI . Futtassa a következő parancsot a terminálon:

az login

A bejelentkezés után a következő kód lekéri a tokent:

import base64
import json
from functools import lru_cache

from azure.identity import DefaultAzureCredential
from sqlalchemy import create_engine, event
from sqlalchemy.engine.url import URL


@lru_cache(maxsize=1)
def get_credential():
    """Memoized function to create the Azure credential, which caches tokens."""
    return DefaultAzureCredential()


def decode_jwt(token):
    """Decode the JWT payload to extract claims."""
    payload = token.split(".")[1]
    padding = "=" * (4 - len(payload) % 4)
    decoded_payload = base64.urlsafe_b64decode(payload + padding)
    return json.loads(decoded_payload)


def get_token_and_username():
    """Fetches a token and returns the username and token."""
    # Fetch a new token and extract the username
    token = get_credential().get_token(
        "https://ossrdbms-aad.database.windows.net/.default"
    )
    claims = decode_jwt(token.token)
    username = claims.get("upn")
    if not username:
        raise ValueError("Could not extract username from token. Have you logged in?")

    return username, token.token


def create_postgres_engine():
    db_url = URL.create(
        drivername="postgresql+psycopg",
        username="",  # This will be replaced dynamically
        password="",  # This will be replaced dynamically
        host=os.environ["DBHOST"],
        port=os.environ.get("DBPORT", 5432),
        database=os.environ["DBNAME"],
    )

    # Create a SQLAlchemy engine
    engine = create_engine(db_url, echo=True)

    # Listen for the connection event to inject dynamic credentials
    @event.listens_for(engine, "do_connect")
    def provide_dynamic_credentials(dialect, conn_rec, cargs, cparams):
        # Fetch the dynamic username and token
        username, token = get_token_and_username()

        # Override the connection parameters
        cparams["user"] = username
        cparams["password"] = token

    return engine

Jelszóhitelesítés használata

Ha nem a Microsoft Entra-hitelesítést használja, a get_connection_uri biztosít egy kapcsolati URI-t, amely lekéri a felhasználónevet és a jelszót a környezeti változókból.

import urllib.parse


def get_connection_uri():
    # Read URI parameters from the environment
    dbhost = os.environ["DBHOST"]
    dbname = os.environ["DBNAME"]
    dbuser = urllib.parse.quote(os.environ["DBUSER"])
    password = os.environ["DBPASSWORD"]
    sslmode = os.environ["SSLMODE"]

    # Construct the connection URI
    # Use Psycopg 3!
    db_uri = (
        f"postgresql+psycopg://{dbuser}:{password}@{dbhost}/{dbname}?sslmode={sslmode}"
    )
    return db_uri

A vektortároló létrehozása

from langchain_core.documents import Document
from langchain_postgres import PGVector
from langchain_postgres.vectorstores import PGVector

collection_name = "my_docs"

# The connection is either a SQLAlchemy engine or a connection URI
connection = create_postgres_engine() if USE_ENTRA_AUTH else get_connection_uri()

vector_store = PGVector(
    embeddings=embeddings,
    collection_name=collection_name,
    connection=connection,
    use_jsonb=True,
)

A vektortároló kezelése

Elemek hozzáadása a vektortárolóhoz

A dokumentumok azonosító szerinti hozzáadása felülírja az adott azonosítónak megfelelő meglévő dokumentumokat.

docs = [
    Document(
        page_content="there are cats in the pond",
        metadata={"id": 1, "location": "pond", "topic": "animals"},
    ),
    Document(
        page_content="ducks are also found in the pond",
        metadata={"id": 2, "location": "pond", "topic": "animals"},
    ),
    Document(
        page_content="fresh apples are available at the market",
        metadata={"id": 3, "location": "market", "topic": "food"},
    ),
    Document(
        page_content="the market also sells fresh oranges",
        metadata={"id": 4, "location": "market", "topic": "food"},
    ),
    Document(
        page_content="the new art exhibit is fascinating",
        metadata={"id": 5, "location": "museum", "topic": "art"},
    ),
    Document(
        page_content="a sculpture exhibit is also at the museum",
        metadata={"id": 6, "location": "museum", "topic": "art"},
    ),
    Document(
        page_content="a new coffee shop opened on Main Street",
        metadata={"id": 7, "location": "Main Street", "topic": "food"},
    ),
    Document(
        page_content="the book club meets at the library",
        metadata={"id": 8, "location": "library", "topic": "reading"},
    ),
    Document(
        page_content="the library hosts a weekly story time for kids",
        metadata={"id": 9, "location": "library", "topic": "reading"},
    ),
    Document(
        page_content="a cooking class for beginners is offered at the community center",
        metadata={"id": 10, "location": "community center", "topic": "classes"},
    ),
]

vector_store.add_documents(docs, ids=[doc.metadata["id"] for doc in docs])

Elemek frissítése a vektortárolóban

docs = [
    Document(
        page_content="Updated - cooking class for beginners is offered at the community center",
        metadata={"id": 10, "location": "community center", "topic": "classes"},
    )
]
vector_store.add_documents(docs, ids=[doc.metadata["id"] for doc in docs])

Elemek törlése a vektortárolóból

vector_store.delete(ids=["3"])

Lekérdezések a vektortárolóba

Miután létrehozta a vektortárolót, és hozzáadta a vonatkozó dokumentumokat, lekérdezheti a vektortárolót a láncban vagy az ügynökben.

Szűrési támogatás

A vektortároló olyan szűrőket támogat, amelyek a dokumentumok metaadatmezőire alkalmazhatók:

Operátor Jelentés/kategória
$eq Egyenlőség (==)
$ne Egyenlőtlenség (!=)
$lt Kevesebb, mint (<)
$lte Kisebb vagy egyenlő (<=)
$gt Nagyobb, mint (>)
$gte Nagyobb vagy egyenlő (>=)
$in Speciális eset (in)
$nin Speciális eset (nincs benne)
$between Speciálisan kezelve (között)
$like Szöveg (tetszik)
$ilike Szöveg (nincs különbség kis- és nagybetűk között)
$and Logikai (és)
$or Logikai (vagy)

Közvetlen lekérdezés

Az alábbiak szerint végezhet egyszerű hasonlósági keresést:

results = vector_store.similarity_search(
    "kitty", k=10, filter={"id": {"$in": [1, 5, 2, 9]}}
)
for doc in results:
    print(f"* {doc.page_content} [{doc.metadata}]")
    * there are cats in the pond [{'id': 1, 'topic': 'animals', 'location': 'pond'}]
    * ducks are also found in the pond [{'id': 2, 'topic': 'animals', 'location': 'pond'}]
    * the new art exhibit is fascinating [{'id': 5, 'topic': 'art', 'location': 'museum'}]
    * the library hosts a weekly story time for kids [{'id': 9, 'topic': 'reading', 'location': 'library'}]

Ha több mezőt tartalmazó szótárat ad meg, de operátorok nélkül, a felső szint logikai AND szűrőként lesz értelmezve:

vector_store.similarity_search(
    "ducks",
    k=10,
    filter={"id": {"$in": [1, 5, 2, 9]}, "location": {"$in": ["pond", "market"]}},
)
[Document(id='2', metadata={'id': 2, 'topic': 'animals', 'location': 'pond'}, page_content='ducks are also found in the pond'),
 Document(id='1', metadata={'id': 1, 'topic': 'animals', 'location': 'pond'}, page_content='there are cats in the pond')]
vector_store.similarity_search(
    "ducks",
    k=10,
    filter={
        "$and": [
            {"id": {"$in": [1, 5, 2, 9]}},
            {"location": {"$in": ["pond", "market"]}},
        ]
    },
)
[Document(id='2', metadata={'id': 2, 'topic': 'animals', 'location': 'pond'}, page_content='ducks are also found in the pond'),
 Document(id='1', metadata={'id': 1, 'topic': 'animals', 'location': 'pond'}, page_content='there are cats in the pond')]

Ha hasonlósági keresést szeretne végrehajtani, és megkapja a megfelelő pontszámokat, futtassa a következőt:

results = vector_store.similarity_search_with_score(query="cats", k=1)
for doc, score in results:
    print(f"* [SIM={score:3f}] {doc.page_content} [{doc.metadata}]")
* [SIM=0.528338] there are cats in the pond [{'id': 1, 'topic': 'animals', 'location': 'pond'}]

A vektortárolóban PGVector végrehajtható keresések teljes listájáért tekintse meg az API-hivatkozást.

Átalakítás visszakeresővé

A láncok egyszerűbb használata érdekében a vektortárolót egy lekérővé is átalakíthatja:

retriever = vector_store.as_retriever(search_type="mmr", search_kwargs={"k": 1})
retriever.invoke("kitty")
[Document(id='1', metadata={'id': 1, 'topic': 'animals', 'location': 'pond'}, page_content='there are cats in the pond')]

Jelenlegi korlátozások

  • langchain_postgres Csak a Psycopg 3 (psycopg3) használatával működik. Frissítse a kapcsolati sztringeket postgresql+psycopg2://...-ről postgresql+psycopg://langchain:langchain@...-re.
  • A beágyazási tár és a gyűjtemény sémája úgy módosult, hogy megfelelően működjön add_documents a felhasználó által megadott azonosítókkal.
  • Most egy explicit kapcsolati objektumot kell átadnia.
  • Jelenleg nincs olyan mechanizmus , amely támogatja a sémamódosítások egyszerű adatmigrálását. A vektortároló sémamódosításaihoz újra létre kell hoznia a táblákat, és újból hozzá kell adnia a dokumentumokat.