Delen via


LangChain gebruiken met Azure Database for PostgreSQL

Azure Database for PostgreSQL kan naadloos worden geïntegreerd met toonaangevende indelingspakketten voor grote taalmodellen (LLM), zoals LangChain. Met deze integratie kunnen ontwikkelaars geavanceerde AI-mogelijkheden in hun toepassingen gebruiken. LangChain kan het beheer en het gebruik van LLM's, het insluiten van modellen en databases stroomlijnen, zodat generatieve AI-toepassingen gemakkelijker kunnen worden ontwikkeld.

In dit artikel leest u hoe u de geïntegreerde vectordatabase in Azure Database for PostgreSQL gebruikt voor het opslaan en beheren van documenten in verzamelingen met LangChain. U ziet ook hoe u indexen maakt en vectorzoekquery's uitvoert met behulp van algoritmen voor dichtstbijzijnde buren, zoals cosinusafstand, L2-afstand (Euclidische afstand) en binnenste product om documenten dicht bij de queryvectoren te vinden.

Vectorondersteuning

U kunt Azure Database for PostgreSQL gebruiken om miljoenen vector-insluitingen efficiënt op te slaan en op te vragen in PostgreSQL. De service kan u helpen bij het schalen van uw AI-gebruiksvoorbeelden van proof-of-concept tot productie. Het biedt deze voordelen:

  • Biedt een vertrouwde SQL-interface voor het uitvoeren van query's op vector-insluitingen en relationele gegevens.
  • pgvector Verbeteren met een snellere en nauwkeurigere gelijkeniszoekopdracht over meer dan 100 miljoen vectoren met behulp van het DiskANN-indexeringsalgoritme.
  • Vereenvoudigt bewerkingen door relationele metagegevens, vector-insluitingen en tijdreeksgegevens te integreren in één database.
  • Maakt gebruik van de kracht van het robuuste PostgreSQL-ecosysteem en het Azure-cloudplatform voor hoogwaardige functies, waaronder replicatie en hoge beschikbaarheid.

Authenticatie

Azure Database for PostgreSQL ondersteunt verificatie op basis van wachtwoorden en Microsoft Entra (voorheen Azure Active Directory).

Met Microsoft Entra-verificatie kunt u Microsoft Entra ID gebruiken om te verifiëren bij uw PostgreSQL-server. Microsoft Entra ID elimineert de noodzaak om afzonderlijke gebruikersnamen en wachtwoorden voor uw databasegebruikers te beheren. Hiermee kunt u dezelfde beveiligingsmechanismen gebruiken die u voor andere Azure-services gebruikt.

In dit artikel kunt u beide verificatiemethoden gebruiken.

Configuratie

Azure Database for PostgreSQL maakt gebruik van de opensource-ondersteuning voor LangChain Postgres om verbinding te maken met Azure Database for PostgreSQL. Download eerst het partnerpakket:

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

Pgvector inschakelen in Azure Database for PostgreSQL

Zie Pgvector inschakelen en gebruiken in Azure Database for PostgreSQL.

Inloggegevens instellen

U moet uw Azure Database for PostgreSQL-verbindingsgegevens ophalen en toevoegen als omgevingsvariabelen.

Stel de USE_ENTRA_AUTH vlag in op True als u Microsoft Entra-verificatie wilt gebruiken. Als u Microsoft Entra-verificatie gebruikt, moet u de enige host- en databasenamen opgeven. Als u wachtwoordverificatie gebruikt, moet u ook de gebruikersnaam en het wachtwoord instellen.

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-insluitingen instellen

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",
)

Initialisatie

Microsoft Entra-verificatie gebruiken

De volgende secties bevatten functies waarmee LangChain wordt ingesteld voor het gebruik van Microsoft Entra-verificatie. De functie get_token_and_username haalt tokens op voor de Azure Database for PostgreSQL-service door DefaultAzureCredential te gebruiken uit de azure.identity-bibliotheek. Het zorgt ervoor dat de SQLAlchemy-engine een geldig token heeft waarmee nieuwe verbindingen kunnen worden gemaakt. Het parseert ook het token, een JSON-webtoken (JWT), om de gebruikersnaam te extraheren die wordt gebruikt om verbinding te maken met de database.

De create_postgres_engine functie maakt een SQLAlchemy-engine waarmee de gebruikersnaam en het wachtwoord dynamisch worden ingesteld op basis van het token dat is opgehaald uit de tokenbeheer. Deze engine kan worden doorgegeven aan de connection-parameter van de PGVector LangChain-vectoropslag.

Aanmelden bij Azure

Als u zich wilt aanmelden bij Azure, moet u ervoor zorgen dat de Azure CLI is geïnstalleerd. Voer de volgende opdracht uit in uw terminal:

az login

Nadat u zich hebt aangemeld, wordt met de volgende code het token opgehaald:

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

Wachtwoordverificatie gebruiken

Als u geen Microsoft Entra-verificatie gebruikt, get_connection_uri biedt u een verbindings-URI waarmee de gebruikersnaam en het wachtwoord worden opgehaald uit omgevingsvariabelen:

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

Het vectorarchief maken

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,
)

Beheer van de vectoropslag

Items toevoegen aan het vectorarchief

Als u documenten per id toevoegt, worden alle bestaande documenten overschreven die overeenkomen met die id.

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])

Items in het vectorarchief bijwerken

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])

Items verwijderen uit het vectorarchief

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

Queries naar de vectorwinkel

Nadat u uw vectorwinkel hebt gemaakt en de relevante documenten hebt toegevoegd, kunt u een query uitvoeren op de vectorwinkel in uw chain of agent.

Ondersteuning voor filteren

Het vectorarchief ondersteunt een set filters die kunnen worden toegepast op de metagegevensvelden van de documenten:

Operateur Betekenis/categorie
$eq Gelijkheid (==)
$ne Ongelijkheid (!=)
$lt Kleiner dan (<)
$lte Kleiner dan of gelijk aan (<=)
$gt Groter dan (>)
$gte Groter dan of gelijk aan (>=)
$in Speciaal behandeld (in)
$nin Speciale casus (niet in)
$between Speciaal geval behandeld (tussen)
$like Tekst (zoals)
$ilike Tekst (hoofdletterongevoelig)
$and Logisch (en)
$or Logisch (of)

Directe query

U kunt als volgt een eenvoudige overeenkomstenzoekopdracht uitvoeren:

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'}]

Als u een woordenlijst met meerdere velden opgeeft, maar geen operatoren, wordt het hoogste niveau geïnterpreteerd als een logisch AND filter:

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')]

Als u een overeenkomstenzoekopdracht wilt uitvoeren en de bijbehorende scores wilt ontvangen, kunt u het volgende uitvoeren:

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'}]

Raadpleeg de API-verwijzing voor een volledige lijst met zoekopdrachten die u kunt uitvoeren in een PGVector vectorarchief.

Transformatie naar een retriever

U kunt het vectorarchief ook omzetten in een retriever voor eenvoudiger gebruik in uw ketens:

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')]

Huidige beperkingen

  • langchain_postgres werkt alleen met Psycopg 3 (psycopg3). Werk uw verbindingsreeksen bij van postgresql+psycopg2://... naar postgresql+psycopg://langchain:langchain@....
  • Het schema van het insluitarchief en de verzameling is gewijzigd om correct te werken met door de gebruiker opgegeven ID's add_documents.
  • U moet nu een expliciet verbindingsobject doorgeven.
  • Op dit moment is er geen mechanisme dat ondersteuning biedt voor eenvoudige gegevensmigratie bij schemawijzigingen. Voor alle schemawijzigingen in het vectorarchief moet u de tabellen opnieuw maken en de documenten opnieuw toevoegen.