Persistenter Zustandsspeicher für in Microsoft Foundry gehostete Agents (Vorschau)

Der dauerhafte Zustandsspeicher für Microsoft foundry hosted agents stellt servergestützten Schlüsselwertspeicher für JSON-Daten bereit, die beibehalten werden müssen, wenn ein Agentcontainer abstürzt, neu gestartet oder nach einem Leerlauf entfernt wird. Verwenden Sie sie zum Speichern von Framework-Prüfpunkten, anwendungsverwalteten Unterhaltungsverlauf, Zwischenartefakten und Benutzereinstellungen.

Ihr Agent schreibt und aktualisiert Zustandsspeicherelemente explizit. Im Gegensatz zu Sitzungen und Unterhaltungen füllt die Plattform den Speicher nicht automatisch auf. Der Speicher unterstützt die Isolation pro Benutzer, Tags, optimistische Parallelität und konfigurierbare Ablaufzeit.

In diesem Artikel wird erläutert, wie Sie Daten partitionieren, Anruferidentität verwalten, Speicher und Elemente erstellen und darauf zugreifen und innerhalb von Dienstgrenzwerten arbeiten. Während der Vorschau ist der Zustandsspeicher nur für gehostete Agenten verfügbar.

Important

Elemente, die in diesem Artikel als Vorschau gekennzeichnet sind, befinden sich derzeit in der Vorschau. Diese Vorschau wird ohne Service Level Agreement (SLA) bereitgestellt, und Microsoft empfiehlt sie nicht für Produktionsworkloads. Manche Features werden möglicherweise nicht unterstützt oder sind nur eingeschränkt verwendbar. Weitere Informationen finden Sie unter Zusätzliche Nutzungsbedingungen für Microsoft Azure-Vorschauversionen.

Was im Zustandsspeicher beibehalten werden sollte

Die Rechenkapazität eines gehosteten Agenten ist flüchtig. Wenn der Container neu gestartet wird oder die Plattform sie nach einem Leerlauf ausräumt, verliert ihr Agent alles, was er außerhalb einer Sitzung auf einen lokalen Datenträger schreibt. Der Statusspeicher enthält den Zustand, der den Container überleben muss.

Typische Inhalte sind:

  • Framework-Prüfpunkte, sodass ein „Bring-your-own-Agent“-Framework wie LangGraph oder Microsoft Agent Framework seinen eigenen Graphen oder Workflowstatus fortsetzen kann.
  • Konversationsverlauf, den Ihr Agent selbst verwaltet – also der Fall des Invocations-Protokolls, bei dem die Plattform den Konversationsverlauf nicht für Sie speichert.
  • Generierte Artefakte und Zwischenergebnisse, die in einem späteren Schritt benötigt werden.
  • Profile, Einstellungen und andere dauerhaft gespeicherte Anwendungsdaten pro Benutzer.

Der Statusspeicher ist nicht die einzige Option. Eine Datenbank, ein BLOB-Speicher oder ein anderer anwendungseigener Speicher funktioniert auf die gleiche Weise. Der Zustandsspeicher entfernt die Notwendigkeit, diesen Speicher selbst bereitzustellen und zu sichern, und es wendet das Identitätsmodell des Agents automatisch an.

Halten Sie Die Werte klein genug, um bei Bedarf abzurufen. Ein Element ist auf 1 MB begrenzt, sodass große Binärdateien in blob-Speicher gehören, wobei der Speicher einen Verweis darauf enthält.

Tip

Langlaufende Agents können Fortschrittsmarkierungen und Sammelprüfpunkte in separaten Elementen im selben Zustandsspeicher beibehalten. Ein Wiederherstellungsschema finden Sie unter Zustand für lang laufende Agents verwalten.

Stores

Ein FoundryStateStore Client ist an einen Speichernamen Ihrer Wahl gebunden. Dieser Name dient sowohl als Identität des Speichers als auch als dessen äußerste Partition. Ein Speicher enthält schlüsselierte JSON-Elemente, die Sie lesen, schreiben, löschen und auflisten können.

  • Der Store-Name ist die Identität: Sie können einen Store-Namen nach der Erstellung nicht mehr ändern. Wählen Sie daher vorab ein stabiles Benennungsschema aus.
  • Get-or-create ist der Vorgang auf Speicherebene: Ein einzelner Get-or-Create-Aufruf ruft den Speicher ab oder erstellt ihn, wenn er nicht vorhanden ist. Erstellungsoptionen gelten nur für die erste Erstellung, sodass der Dienst sie ignoriert, wenn der Speicher bereits vorhanden ist. Ein Elementschreibvorgang erstellt keinen fehlenden Speicher.
  • Elementlebensdauer: Ein Leerlauffenster auf Speicherebene entfernt Elemente. Der Standardwert ist 30 Tage, und Sie können einen Speicher so konfigurieren, dass Elemente nie ablaufen. Schreibvorgänge erneuern das Fenster, Lesevorgänge hingegen nicht. Sie legen diese Option beim Erstellen fest.

Partitionieren von Daten

Der Speicher bietet Ihnen zwei unabhängige Methoden zum Partitionieren von Daten, und die meisten Agents benötigen nur eine davon.

  • Nach Speichername: Jeder Speichername ist eine eigene Partition. Namen können / enthalten, sodass Sie es als Hierarchietrennzeichen verwenden können, wie in checkpoints/thread-abc oder workflow-state/run-42. Wählen Sie diese Partition aus, wenn der Code, der ein Element liest, immer über den Partitionsbezeichner verfügt, um den Namen neu zu erstellen.
  • Nach Endbenutzer: Ein Speicher, der mit Benutzerisolation erstellt wurde, partitioniert seine Elemente nach Endbenutzer, sodass ein einzelner Speichername sicher für die Benutzer eines mandantenfähigen Agenten freigegeben werden kann. Wählen Sie diese Partition aus, wenn derselbe Speichername mehreren Benutzern dient. Sie legen diese Option beim Erstellen fest, und der Store ermittelt den Benutzer aus der Anfrage statt aus den von Ihrem Code übergebenen Werten. Ausführliche Informationen finden Sie unter Anruferidentität.

Bevorzugen Sie die schmalste Partition, die Ihr Lookup-Pfad rekonstruieren kann. Ein Speichername, der einen Bezeichner codiert, ist nur dann nützlich, wenn jeder Aufrufer, der das Element liest, noch über diesen Bezeichner verfügt. Wenn eine Abfrage nur einen Elementschlüssel enthält, wie es bei einem Prüfpunktlader des Frameworks typischerweise der Fall ist, halten Sie den Speichernamen einfach und überlassen Sie die Partitionierung stattdessen der Benutzerisolierung.

Die beiden Achsen lassen sich kombinieren, sollten jedoch konzeptionell getrennt bleiben: Der Name eines Speichers sollte nur einen Bereich ohne Benutzerbezug enthalten, etwa eine Thread-, Ausführungs- oder Workflow-Kennung.

Important

Codieren Sie keine Endbenutzer-ID in einen Speichernamen. Store-Namen erscheinen in operativen Oberflächen wie Protokollen und Fehlermeldungen, und ein Name, den Ihr eigener Code erzeugt, ist keine verifizierte Identität. Verwenden Sie die Benutzerisolation für die benutzerspezifische Partitionierung, sodass die Plattform die Grenze anhand des Aufrufers durchsetzt, den sie festgelegt hat, anstatt anhand eines Werts, den Ihr Agent bereitstellt.

Anrufer-Identität

Der Statusspeicher wendet das Identitätsmodell des gehosteten Agents an. Unter container protocol 2.0.0 enthält jede Anfrage, die die Plattform an Ihren Agenten weiterleitet, einen x-agent-foundry-call-idHeader, der den Aufrufer identifiziert, und der Store ermittelt daraus den agierenden Endnutzer. Die Foundry-SDKs leiten den Header bei Store-Anrufen für Sie weiter, sodass die meisten Agents sie nie direkt verarbeiten.

Zwei Konsequenzen sind wichtig, wenn Sie mit ihr entwerfen:

  • Die Benutzerisolierung wird von der Aufruf-ID abgeleitet: In einem benutzerisolierten Speicher stammt die Partition von dem Aufrufer, den die Plattform identifiziert hat, und nicht von etwas, das Ihr Agent übermittelt. Ein gehosteter Agent stellt keinen eigenen Endbenutzerbezeichner zur Verfügung. Wenn Ihre Laufzeit ihre eigenen HTTP-Anforderungen ausgibt, anstatt einen SDK-Client zu verwenden, leiten Sie den Header unverändert weiter, und behandeln Sie den Wert als undurchsichtig.
  • Lokale Ausführungen unterstützen keine Benutzerisolation: Die Plattform stellt die Anruf-ID nicht außerhalb der Plattform bereit. Weder das Python noch .NET SDK können die Benutzerisolation erzwingen, wenn Sie den Container lokal ausführen. Testen Sie Benutzerisolationsgrenzen mit einem bereitgestellten gehosteten Agent.

Aufruf-ID in zurückgestellte Arbeit übernehmen

Elementoperationen werden im Namen eines Aufrufers ausgeführt, Speicheroperationen hingegen nicht.

Betrieb Geltungsbereich Handelnder Benutzer
create_item, set_item, get_item, delete_item, , list_keys Die Elemente im gebundenen Speicher Aufgelöst von der Aufruf-ID, wenn der Speicher Benutzerisolierung verwendet
Abrufen oder Erstellen für den Speicher Der Store selbst Nicht aufgelöst; der Vorgang ist auf den Speicher beschränkt

Standardmäßig verwendet ein Elementvorgang die Aufruf-ID der Anfrage, innerhalb der er ausgeführt wird. Das ist genau das Richtige für Arbeit, die während dieser Anfrage abgeschlossen wird.

Arbeit, die die Anforderung überdauert, hat keine Umgebungsaufruf-ID zu erben, z. B. Hintergrundverarbeitung oder ein Schritt, der in einer späteren Prozesslebensdauer fortgesetzt wird. Jede Elementoperation akzeptiert in diesem Fall eine explizite Aufruf-ID. Bitte erfassen, solange Sie noch Zugriff darauf haben. Führen Sie es parallel zur Arbeit aus, und geben Sie es bei jedem Elementvorgang zurück, damit diese Vorgänge weiterhin für den ursprünglichen Aufrufer ausgeführt werden.

Die Anruf-ID identifiziert den Aufrufer der aktuellen Anforderung und partitioniert nur die Elemente innerhalb eines vom Benutzer isolierten Speichers. Sie unterteilt nichts anderes, was in Ihrem Container gespeichert ist. Für Dateien, Datenbankzeilen oder Caches, die Ihr eigener Code besitzt, schlüsseln Sie diese durch die Sitzungs-ID und die Benutzer-ID, wie in Multiplex-Benutzern in einer freigegebenen Sitzung beschrieben.

Items

Ein Element ist ein Schlüssel und ein JSON-Wert mit optionalen Zeichenfolgentags.

  • Werte sind Ihre Anwendungs-JSON: Der Speicher interpretiert keinen Elementwert. Serialisieren Sie Ihr Framework oder Ihre Domänenmodelle explizit.
  • Tags dienen zum Filtern: Tags sind einfache Zeichenfolgenbeschriftungen, die mit AND übereinstimmen, wenn Sie Schlüssel auflisten. Höherstufen Sie nur die Felder, nach denen Sie filtern müssen.
  • Die Auflistung gibt nur Schlüssel zurück: Eine Seite mit Schlüsseln ist billig, auch wenn die Werte groß sind, sodass das Auflisten und Abrufen separate Schritte sind.
  • Optimistische Parallelität: Jedes Element trägt ein ETag. Verwenden Sie eine If-Match Vorbedingung für Lese-Ändern-Schreibvorgänge bei änderbaren Elementen, z. B. Zählern, bei denen ein verlorenes Update den Zustand beschädigen würde. Eine nicht erfüllte Vorbedingung gibt das aktuelle ETag zurück.
  • Nur-Anfüge-Prüfpunkte benötigen keine Voraussetzungen: Wenn bei jedem Speichern ein neuer Schlüssel geschrieben wird, gibt es keinen Schreibkonflikt, sodass der Prüfpunktpfad If-Match nie benötigt.

Store und Elemente erstellen

Das folgende Beispiel ruft einen benutzerisolierten Speicher ab oder erstellt ihn, schreibt ein Element, liest es wieder aus und listet Schlüssel nach Tag auf. Get-or-create ist der einzige Aufruf auf Store-Ebene, den ein Agent benötigt: Es ruft den Store ab oder erstellt ihn mit den von Ihnen übergebenen Optionen, falls der Store nicht vorhanden ist.

from azure.ai.agentserver.core.storage import FoundryStateStore

# Fetch the store, or create it on first use
store = await FoundryStateStore.get_or_create(
    "checkpoints/thread-abc",
    user_isolation=True,
)

# Write an item; the value is your own application JSON
await store.set_item(
    "step-1",
    {"done": False, "attempt": 1},
    tags={"kind": "checkpoint"},
)

# Read it back
item = await store.get_item("step-1")
if item is not None:
    print(item.key, item.value["done"], item.etag)

# List keys by tag, then fetch only the values you need
page = await store.list_keys(tags={"kind": "checkpoint"}, limit=50, order="asc")
for key in page.keys:
    print(key.key, key.etag)

Wenn Sie keinen Endpunkt übergeben, ermittelt der Client den Projekt-Endpunkt aus der Umgebung, den die Plattform für einen gehosteten Agent festlegt.

Dienstbegrenzungen

Der Dienst erzwingt diese Grenzwerte. Wenn Sie einen Grenzwert verletzen, gibt der Dienst das ungültige Feld in der Fehlermeldung zurück 400 Bad Request und benennt es.

Feld Begrenzung
Geschäftsname 1-128 Zeichen, die innerhalb des Projekts und des Agenten eindeutig sind.
Elementschlüssel 1–128 Zeichen, innerhalb des Speichers eindeutig.
Elementwert Bis zu 1 MB serialisiertes JSON.
Shop- oder Artikel-Tags Bis zu 16 Einträge. Ein Schlüssel ist 1 bis 64 Zeichen, und ein Wert beträgt bis zu 256 Zeichen.
Description Bis zu 1.024 Zeichen.
Tasten pro Listenseite 1–100, mit einem Standardwert von 20.