Foundry memória használata a LangChainnel és LangGraph-tal

Használja a langchain-azure-ai jelölőt és a Foundry Memory-t hosszú távú memória hozzáadásához az alkalmazásokhoz. Ebben a cikkben létrehoz egy memóriaalapú láncot, tárolja a felhasználói beállításokat, visszahívja őket egy új munkamenetben, és közvetlen memória-lekérdezéseket futtat.

Ez a minta a LangChain és a LangGraph alkalmazások esetében is működik. Az alapvető ötlet a rövid távú csevegési előzmények megőrzése a futtatókörnyezetben, és az Foundry Memory használata hosszú távú tárolóként felhasználói szintű környezetként.

Az Foundry Memory a hosszú távú memóriára összpontosít. Rövid távú, lépésről-lépésre állapot megtartása a LangChain vagy LangGraph futási környezeti állapotában.

Előfeltételek

  • Egy Azure előfizetés. Hozzon létre egyet ingyen.
  • Egy Foundry-projekt.
  • Üzembe helyezett Microsoft Foundry-csevegési modell memórialekéréshez.
    • Ez az oktatóanyag a "gpt-4.1"-t használja.
  • Üzembe helyezett csevegőmodell és beágyazási modell a memóriatárolóhoz.
    • Ez az oktatóanyag a text-embedding-3-large-t használja.
  • Python 3.10-et vagy újabb verziót.
  • Azure CLI be van jelentkezve (az login), hogy DefaultAzureCredential hitelesíthesse magát Azure AI Developer szerepkörrel.

A környezet konfigurálása

Telepítse az oktatóanyaghoz szükséges csomagokat. A LangChain és a LangGraph integrációjához a langchain-azure-ai, a memóriatárolók kezeléséhez a azure-ai-projects, és a hitelesítéshez a azure-identity használható.

pip install -U "langchain-azure-ai" azure-ai-projects

Állítsa be az oktatóanyagban használt környezeti változókat:

export AZURE_AI_PROJECT_ENDPOINT="https://<resource>.services.ai.azure.com/api/projects/<project>"

A memóriamodell ismertetése

Az Foundry Memória két hosszú távú memóriatípust tárol és kér le:

  • Felhasználói profil memóriája: stabil felhasználói adatok és preferenciák, például előnyben részesített név vagy táplálkozási korlátozások.
  • Csevegőösszegző memória: a korábbi vitafórumok összefoglalói.

A memória a "hatókör" gondolatát használja az információk particionálására, hogy azok folyamatosan tárolhatók és lekérhetők legyenek. A hatókörök olyanok, mint azonosítók vagy kulcsok az információk rendszerezéséhez.

  • A hosszú távú memória stabil identitásaként használhatja a felhasználói azonosítókat . Tartsa ugyanazt a munkamenetek során az adott felhasználó számára.
  • A munkamenet-azonosítókat rövid távú beszélgetési identitásként használhatja. Módosítsa csevegés közben.
  • Az erőforrás-azonosítókat több felhasználó hosszú távú memóriájának stabil azonosítójaként használhatja.

Ez az elkülönítés lehetővé teszi, hogy az alkalmazás a nem kapcsolódó beszélgetések összekeverése nélkül jegyezze fel a munkamenetek felhasználói beállításait.

A memóriatároló létrehozása

Az első lépések előtt létre kell hoznia egy memóriatárolót. Ehhez a művelethez használja a Microsoft Foundry-projektek SDK-azure-ai-projects.

import os

from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
	MemoryStoreDefaultDefinition,
	MemoryStoreDefaultOptions,
)
from azure.core.exceptions import ResourceNotFoundError
from azure.identity import DefaultAzureCredential

endpoint = os.environ["AZURE_AI_PROJECT_ENDPOINT"]
credential = DefaultAzureCredential()
client = AIProjectClient(endpoint=endpoint, credential=credential)

store_name = "lc-integration-test-store"
try:
    store = client.beta.memory_stores.get(store_name)
    print(f"✓ Memory store '{store_name}' already exists")
except ResourceNotFoundError:
    print(f"Creating memory store '{store_name}'...")
    definition = MemoryStoreDefaultDefinition(
        chat_model="gpt-4.1", 						# Change for your LLM model
        embedding_model="text-embedding-3-large",	# Change for your emebddings model
        options=MemoryStoreDefaultOptions(
            user_profile_enabled=True,
            chat_summary_enabled=True,
        ),
    )
    store = client.beta.memory_stores.create(
        name=store_name,
        description="Long-term memory store",
        definition=definition,
    )
    print(f"✓ Memory store '{store_name}' created successfully")
✓ Memory store 'lc-integration-test-store' created successfully

A kódrészlet leírása: Csatlakozik az Foundry-projekthez, lekéri vagy létrehozza a memóriatárolót, és lehetővé teszi a felhasználói profilt, valamint a csevegések összegzését.

Memória használata a LangGraphban és a LangChainben

Az Foundry Memory két objektum bevezetésével integrálható a LangGraphban és a LangChainben:

  • Az osztály langchain_azure_ai.chat_message_history.AzureAIMemoryChatMessageHistory létrehoz egy memóriaalapú csevegési előzményt.
  • Az osztály langchain_azure_ai.retrievers.AzureAIMemoryRetriever lehetővé teszi az emlékek lekérését a csevegőüzenetek előzményeiből.

Általában a következő gyakorlati lekérési stratégiákat használhatja velük:

  • A válaszok személyre szabásához kérje le a felhasználói profil memóriáját a beszélgetés korai szakaszában.
  • Kérje le a csevegés összefoglaló memóriáját az aktuális fordulat alapján a releváns korábbi környezet helyreállításához.

Példa: Munkamenet-tudatos memóriaréteg hozzáadása

Ebben a példában egyetlen futtathatót hozunk létre a LangChainben, amely lekéri a releváns hosszú távú memóriát, beszúrja a parancssorba, és rövid távú csevegési előzményekkel és hosszú távú memóriával együtt hajtja végre a modellt.

Nézzük meg, hogyan valósíthatja meg:

A csevegőüzenetek előzményeinek létrehozása

Ez a példa egy stabil user_id memóriatartományt használ. Használja a session_id-t az egyes munkameneteken belüli beszélgetési környezethez.

from langchain_azure_ai.chat_history import AzureAIMemoryChatMessageHistory
from langchain_azure_ai.retrievers import AzureAIMemoryRetriever
from langchain_core.chat_history import InMemoryChatMessageHistory

_session_histories: dict[tuple[str, str], AzureAIMemoryChatMessageHistory] = {}

def get_session_history(user_id: str, session_id: str) -> AzureAIMemoryChatMessageHistory:
    """Get or create a session history for a user and session.
    
    Args:
        user_id: Stable user identifier (used as scope in Foundry Memory)
        session_id: Ephemeral session identifier
        
    Returns:
        AzureAIMemoryChatMessageHistory instance
    """
    cache_key = (user_id, session_id)
    if cache_key not in _session_histories:
        _session_histories[cache_key] = AzureAIMemoryChatMessageHistory(
            project_endpoint=endpoint,
            credential=credential,
            store_name=store_name,
            scope=user_id,
            base_history=InMemoryChatMessageHistory(),
            update_delay=0,  # TEST MODE: process updates immediately (default ~300s)
        )
    return _session_histories[cache_key]


def get_foundry_retriever(user_id: str, session_id: str) -> AzureAIMemoryRetriever:
    """Get a retriever tied to the cached session history.
    
    This preserves incremental search state across turns.
    
    Args:
        user_id: Stable user identifier
        session_id: Ephemeral session identifier
        
    Returns:
        AzureAIMemoryRetriever instance
    """
    return get_session_history(user_id, session_id).get_retriever(k=5)

A kódrészlet leírása: Páronként (user_id, session_id) létrehoz egy memóriaalapú előzményt és lekérőt, és gyorsítótárazza őket, így a lekérési állapot több fordulóban is megmarad ugyanabban a munkamenetben. Ebben az útmutatóban azonnal láthatóvá teszi a update_delay=0 memóriafrissítéseket. Termelési környezetben használja az alapértelmezett késleltetést, hacsak nincs kifejezetten szüksége azonnali kinyerésre. session_histories használatával elkerülhető, hogy folyamatosan újra létre kell hoznia az objektumokat.

A futtatható összeállítása memória lekéréssel

Hozzunk létre egy futtathatót a hurok implementálásához:

from typing import Any
import os

from langchain.chat_models import init_chat_model
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import ConfigurableFieldSpec, RunnablePassthrough
from langchain_core.runnables.history import RunnableWithMessageHistory

llm = init_chat_model("azure_ai:gpt-4.1", temperature=0.7)

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "You are helpful and concise. Use prior memories when relevant."),
        MessagesPlaceholder("history"),
        ("system", "Memories:\n{memories}"),
        ("human", "{question}"),
    ]
)


def chain_for_session(user_id: str, session_id: str) -> RunnableWithMessageHistory:
    """Create a chain with message history for a specific user and session.
    
    Args:
        user_id: Stable user identifier
        session_id: Ephemeral session identifier
        
    Returns:
        Runnable chain with message history
    """
    retriever = get_foundry_retriever(user_id, session_id)

    def format_memories(x: dict[str, Any]) -> str:
        """Retrieve and format memories as text."""
        docs = retriever.invoke(x["question"])
        return (
            "\n".join([doc.page_content for doc in docs])
            if docs
            else "No relevant memories found."
        )

    # Use RunnablePassthrough.assign to add memories to the input dict
    # RunnableWithMessageHistory will inject history automatically
    chain = RunnablePassthrough.assign(memories=format_memories) | prompt | llm

    chain_with_history = RunnableWithMessageHistory(
        chain,
        get_session_history=get_session_history,
        input_messages_key="question",
        history_messages_key="history",
        history_factory_config=[
            ConfigurableFieldSpec(
                id="user_id",
                annotation=str,
                name="User ID",
                description="Unique identifier for the user.",
                default="",
                is_shared=True,
            ),
            ConfigurableFieldSpec(
                id="session_id",
                annotation=str,
                name="Session ID",
                description="Unique identifier for the session.",
                default="",
                is_shared=True,
            ),
        ],
    )
    return chain_with_history

Mit csinál ez a kódrészlet: Létrehoz egy futtathatót, amely beilleszti a beolvasott memóriákat a promptba, majd RunnableWithMessageHistory segítségével becsomagolja, hogy a csevegési előzmények és a hosszú távú memória együttműködjön.

Ez a minta determinisztikussá teszi az utasítást: minden egyes fordulat explicit módon tartalmazza a beolvasott memóriát a Memories szakaszban.

Munkameneteken átívelő gyakorlati forgatókönyv futtatása

Ez a forgatókönyv a hosszú távú memória teljes értékét mutatja be:

  1. Az A munkamenetben a felhasználó megosztja a beállításokat.
  2. A B munkamenetben az alkalmazás automatikusan visszahívja ezeket a beállításokat.
import time

user_id = "user_001"
session_id = "session_2026_02_10_001"
chain = chain_for_session(user_id, session_id)

# 4) Session A: seed preferences (long-term memory extraction happens async)
print(
	"\n=== Turn 1 (Session A): Introduce a preference "
	"(will be extracted into long-term memory) ==="
)
r1 = chain.invoke(
	{"question": "Hi! Call me JT. I prefer dark roast coffee and budget trips."},
	config={"configurable": {"user_id": user_id, "session_id": session_id}},
)
print("ASSISTANT:", r1.content)

print("\n=== Turn 2 (Session A): Add another preference ===")
r2 = chain.invoke(
	{
		"question": "Also, I usually drink green tea in the afternoon "
		"and I like staying in hostels."
	},
	config={"configurable": {"user_id": user_id, "session_id": session_id}},
)
print("ASSISTANT:", r2.content)

# Because we set update_delay=0, extraction should happen immediately for demo.
# If you use the default delay, you may need to wait before querying from new session.
time.sleep(60)

# 5) Cross-session test: same user_id, new session_id
session_id_b = "session_2026_02_10_002"
chain_b = chain_for_session(user_id, session_id_b)

print("\n=== Turn 3 (Session B): New session should recall coffee preference ===")
r4 = chain_b.invoke(
	{"question": "Remind me of my coffee preference and travel style."},
	config={"configurable": {"user_id": user_id, "session_id": session_id_b}},
)
print("ASSISTANT:", r4.content)

print("\n=== Turn 4 (Session B): Retrieve another preference ===")
r5 = chain_b.invoke(
	{
		"question": "What do I usually drink in the afternoon, "
		"and where do I like to stay?"
	},
	config={"configurable": {"user_id": user_id, "session_id": session_id_b}},
)
print("ASSISTANT:", r5.content)
=== Turn 1 (Session A) ===
ASSISTANT: Nice to meet you, JT. I noted that you prefer dark roast coffee and budget trips.

=== Turn 2 (Session A) ===
ASSISTANT: Got it. I also noted that you usually drink green tea in the afternoon and prefer hostels.

=== Turn 3 (Session B) ===
ASSISTANT: Your coffee preference is dark roast, and your travel style is budget trips.

=== Turn 4 (Session B) ===
ASSISTANT: You usually drink green tea in the afternoon, and you like staying in hostels.

A kódrészlet leírása: Az A munkamenet felhasználói beállításainak magolása, a B munkamenet indítása ugyanazzal a felhasználóval, és azt mutatja, hogy az alkalmazás vissza tudja hívni a munkamenetek korábbi beállításait.

Példa: Memória közvetlen lekérdezése nem csevegéses használati esetekhez

Használjon alkalmi leolvasót, ha közvetlen memóriaolvasást szeretne a beszélgetési folyamaton kívül, például személyre szabási köztes szoftverben vagy profilvizsgálati eszközökben.

adhoc = AzureAIMemoryRetriever(
	project_endpoint=endpoint,
	credential=credential,
	store_name=store_name,
	scope=user_id,
	k=5,
)
print("\n=== Turn 5 (Ad-hoc): Direct retriever query without session history ===")
adhoc_docs = adhoc.invoke("What are my drinking preferences?")
for i, doc in enumerate(adhoc_docs, start=1):
	print(f"MEMORY {i}:", doc.page_content)
MEMORY 1: Prefers dark roast coffee.
MEMORY 2: Prefers budget trips.
MEMORY 3: Usually drinks green tea in the afternoon.
MEMORY 4: Likes staying in hostels.

A kódrészlet leírása: Az aktuális hatókör közvetlen memóriakeresését futtatja. Minden emlék lekérésre kerül (korlátozva k), de relevancia szerint van rendezve.

Ezt a mintát akkor használja, ha közvetlen memóriaolvasásra van szüksége olyan funkciókhoz, mint a profilkártyák, a személyre szabási köztes szoftver vagy a munkafolyamat-útválasztás.

Példa: Memória használata grafikonokon

A LangGraph ugyanazt a fogalmi mintát használja:

  • Tartsd stabilan a user_id-t a hosszú távú memória érdekében.
  • Rövid távú szálkörnyezethez használja thread_id (vagy azzal egyenértékű).
  • A modellcsomópont meghívása előtt kérje le a memóriát.

Ha már rendelkezik egy StateGraph, illessze be az adatlekérést a modellcsomópontjába, és csatolja a memóriaszöveget a modell bemenetéhez. Egy másik tipikus stratégia az előmodell-horog használata.

from langgraph.graph import MessagesState


def call_model_with_foundry_memory(state: MessagesState, config: dict):
	user_id = config["configurable"]["user_id"]
	session_id = config["configurable"]["thread_id"]
	query = state["messages"][-1].content

	retriever = get_foundry_retriever(user_id, session_id)
	docs = retriever.invoke(query)
	memory_text = "\n".join(d.page_content for d in docs) if docs else ""

	response = llm.invoke(
		[
			{"role": "system", "content": "Use prior memories when relevant."},
			{"role": "system", "content": f"Memories:\n{memory_text}"},
			*state["messages"],
		]
	)
	return {"messages": [response]}

Mit csinál ez a kódrészlet: Megjelenít egy LangGraph csomópont mintázatot, amely lekéri a Foundry memóriát a jelenlegi lépéshez, és beilleszti azt a modell bemenetébe.

A LangGraph memóriafogalmainak szélesebb körű ismertetése:

Az előzetes verzió korlátainak és a működési útmutatónak a megismerése

Az éles környezetbe való áttérés előtt ellenőrizze az alábbi korlátozásokat:

  • A memória előzetes verzióban van, és a viselkedés változhat.
  • A memóriához kompatibilis csevegési és beágyazási üzembe helyezésekre van szükség.
  • A kvóták tárolónként és hatókörönként érvényesek, beleértve a keresési és frissítési kérelmek arányát is.

Tervezze meg a memóriamérgezés vagy a gyorsinjektálási kísérletek védelmi vezérlőit is. Ellenőrizze a nem megbízható bemeneteket, mielőtt befolyásolják a tárolt memóriát.

Erőforrások törlése

A minták futtatása után törölje a hatókört, hogy a tesztadatok ne szivárogjanak be a jövőbeli futtatásokba.

result = client.memory_stores.delete_scope(name=store_name, scope=user_id)
print(
	f"Deleted {getattr(result, 'deleted_count', 'all')} memories "
	f"for scope '{user_id}'."
)
Deleted 4 memories for scope 'user_001'.