Durch die Unterbrechungsfunktion von Langgraph habe ich gelernt, dass Menschen mitten in der Agentenausführung eingreifen können.
Aber wenn man sich die Beispiele ansieht, ignorieren sie alle einfach die menschliche Interaktion. Was muss ich tun, um tatsächlich eine Bestätigung vom Benutzer zu erhalten? Ich denke, es gibt drei Hauptwege.
Verwendung des Langgraph API-Servers
Sie können den Langgraph-API-Server mit Docker über die Langgraph-CLI ausführen, dann das Diagramm ausführen, den Status ändern und es mit dem Langgraph-SDK neu starten.
Die von langgraph bereitgestellten Artikel müssen in der vorgesehenen Weise verwendet werden. Es gibt viele Einstellungen und es scheint schwierig zu sein, sie in meinen Code zu integrieren
Diagrammverwaltung auf dem Server
Dies ist eine Methode, um nur die notwendigen Teile des oben genannten Langgraph-API-Servers auf meinem benutzerdefinierten Server zu implementieren. Wenn Sie beispielsweise ein Diagramm ausführen, müssen der Client, der das Diagramm ausgeführt hat, und der Diagrammprüfpunkt gespeichert werden. Nach der Bestätigung des Benutzers muss das Diagramm erneut geladen und der Status entsprechend der Antwort des Benutzers geändert werden, um erneut ausgeführt zu werden
Vielleicht gibt es viel zu bedenken.
Steckdosenanschluss
Beim Ausführen des Agenten verbindet er einen Socket und interagiert über den Socket mit dem Benutzer. Dies funktioniert durch einfaches Hinzufügen des Schritts zum Empfangen einer Benutzerbestätigung über eine Socket-Verbindung und eine Socket-Kommunikation im vorhandenen Beispielcode
Stattdessen kann es schwierig sein, Streaming zu implementieren, das wie das Tippen funktioniert.
Implementiert mit Socket-Verbindung
Zuerst wollte ich es so implementieren, dass die Komplexität möglichst nicht zunimmt, also habe ich es mit einer Socket-Verbindung implementiert
Der Server verwendet NestJs und der Client verwendet NextJs.
Server
Erstellen Sie zunächst ein Gateway für die Websocket-Verbindung. Beim Agenten/Start wurde eine Verbindung hergestellt und der Agent wurde sofort ausgeführt.
@WebSocketGateway({ namespace: "/", transport: ["websocket", "polling"], path: "/agent/start", cors: { origin: "*", methods: ["GET", "POST"], credentials: true, }, }) export class AgentGateway implements OnGatewayConnection, OnGatewayDisconnect { @WebSocketServer() server: Server; protected readonly logger = new Logger(this.constructor.name); constructor( private readonly agentFactory: AgentFactory ) {} private pendingConfirmations = new Map<string boolean> void>(); // Handle new connections handleConnection(client: Socket) { console.log(`Client connected: ${client.id}`); // Option 1: Get actionData from query parameters const actionData: { agent: AgentName } = client.handshake.query.actionData ? JSON.parse(client.handshake.query.actionData as string) : null; if (actionData) { this.startAgentProcess(client, actionData); } else { // If no actionData is provided, you can wait for an event client.emit("error", "No action data provided"); client.disconnect(); } } // Handle disconnections handleDisconnect(client: Socket) { console.log(`Client disconnected: ${client.id}`); this.pendingConfirmations.delete(client.id); } // Send confirmation request async sendConfirmationRequest(clientId: string, data: any): Promise<boolean> { return new Promise((resolve) => { this.pendingConfirmations.set(clientId, resolve); this.server.to(clientId).emit("confirmation_request", data); // Optional timeout for response setTimeout(() => { if (this.pendingConfirmations.has(clientId)) { this.pendingConfirmations.delete(clientId); resolve(false); // Default to 'false' if timeout occurs } }, 3000000); // 3000 seconds timeout }); } // Handle client's confirmation response @SubscribeMessage("confirmation_response") handleClientResponse( @MessageBody() data: { confirmed: boolean }, @ConnectedSocket() client: Socket ) { const resolve = this.pendingConfirmations.get(client.id); if (resolve) { resolve(data.confirmed); this.pendingConfirmations.delete(client.id); } } // Start the agent process private async startAgentProcess( client: Socket, actionData: { agent: AgentName } ) { const graph = await this.agentFactory.create({ agentName: actionData.agent, }); const initialInput = { input: "hello world" }; // Thread const graphStateConfig = { configurable: { thread_id: "1" }, streamMode: "values" as const, }; // Run the graph until the first interruption for await (const event of await graph.stream( initialInput, graphStateConfig )) { this.logAndEmit(client, `--- ${event.input} ---`); } // Will log when the graph is interrupted, after step 2. this.logAndEmit(client, "---GRAPH INTERRUPTED---"); const userConfirmed = await this.sendConfirmationRequest(client.id, { message: "Do you want to proceed with this action?", actionData, }); if (userConfirmed) { // If approved, continue the graph execution. We must pass `null` as // the input here, or the graph will for await (const event of await graph.stream(null, graphStateConfig)) { this.logAndEmit(client, `--- ${event.input} ---`); } this.logAndEmit(client, "---ACTION EXECUTED---"); } else { this.logAndEmit(client, "---ACTION CANCELLED---"); } // Optionally disconnect the client client.disconnect(); } private logAndEmit(client: Socket, message: string) { console.log(message); client.emit("message", { message }); } } </boolean></string>
Der Schlüssel ist einfach. Wenn ein Socket verbunden ist, wird sofort ein Agent erstellt und ausgeführt. Wenn er unterbrochen wird, wird eine Bestätigungsanforderungsnachricht an den Client gesendet und gewartet. Sobald die Bestätigung gelöst ist, wird die Grafik fortgesetzt.
Der im obigen Code verwendete Agent ist ein Agent, der die Schritte 1 2 3 unten im Langgraph-Dokument nacheinander ausführt.
const GraphState = Annotation.Root({ input: Annotation<string>, }); const step1 = (state: typeof GraphState.State) => { console.log("---Step 1---"); return state; }; const step2 = (state: typeof GraphState.State) => { console.log("---Step 2---"); return state; }; const step3 = (state: typeof GraphState.State) => { console.log("---Step 3---"); return state; }; const builder = new StateGraph(GraphState) .addNode("step1", step1) .addNode("step2", step2) .addNode("step3", step3) .addEdge(START, "step1") .addEdge("step1", "step2") .addEdge("step2", "step3") .addEdge("step3", END); // Set up memory const graphStateMemory = new MemorySaver(); const graph = builder.compile({ checkpointer: graphStateMemory, interruptBefore: ["step3"], }); return graph; </string>
Kunde
Der Client erstellt einen Hook, um den Agentenstart und seinen Status zu verwalten.
import { useRef, useState } from "react"; import io, { Socket } from "socket.io-client"; export const useAgentSocket = () => { const socketRef = useRef<socket null>(null); const [confirmationRequest, setConfirmationRequest] = useState<any>(null); const [messages, setMessages] = useState<string>([]); const connectAndRun = (actionData: any) => { return new Promise((resolve, reject) => { socketRef.current = io("http://localhost:8000", { path: "/agent/start", transports: ["websocket", "polling"], query: { actionData: JSON.stringify(actionData), }, }); socketRef.current.on("connect", () => { console.log("Connected:", socketRef.current?.id); resolve(void 0); }); socketRef.current.on("connect_error", (error) => { console.error("Connection error:", error); reject(error); }); // Listen for confirmation requests socketRef.current.on("confirmation_request", (data) => { setConfirmationRequest(data); }); // Listen for messages socketRef.current.on("message", (data) => { console.log("Received message:", data); setMessages((prevMessages) => [...prevMessages, data.message]); }); socketRef.current.on("disconnect", () => { console.log("Disconnected from server"); }); }); }; const sendConfirmationResponse = (confirmed: boolean) => { if (socketRef.current) { socketRef.current.emit("confirmation_response", { confirmed }); setConfirmationRequest(null); } }; const disconnectSocket = () => { if (socketRef.current) { socketRef.current.disconnect(); } }; const clearMessages = () => { setMessages([]); }; return { confirmationRequest, sendConfirmationResponse, connectAndRun, disconnectSocket, messages, clearMessages, }; }; </string></any></socket>
Stellt eine Verbindung her und aktualisiert den Bestätigungsanfragestatus, wenn eine Bestätigungsanfrage eintrifft. Schauen Sie sich einfach den Bestätigungsanfragestatus in der UI-Komponente an und öffnen Sie ein Fenster für den Benutzer.
Das obige ist der detaillierte Inhalt vonLanggraph Human In The Loop mit Steckdose. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Detaillierte Erläuterung der Methode für JavaScript -Zeichenfolge und FAQ In diesem Artikel werden zwei Möglichkeiten untersucht, wie String -Zeichen in JavaScript ersetzt werden: Interner JavaScript -Code und interne HTML für Webseiten. Ersetzen Sie die Zeichenfolge im JavaScript -Code Die direkteste Möglichkeit ist die Verwendung der Ersatz () -Methode: str = str.replace ("find", "ersetzen"); Diese Methode ersetzt nur die erste Übereinstimmung. Um alle Übereinstimmungen zu ersetzen, verwenden Sie einen regulären Ausdruck und fügen Sie das globale Flag G hinzu:: STR = Str.Replace (/fi

Dieses Tutorial zeigt Ihnen, wie Sie eine benutzerdefinierte Google -Such -API in Ihr Blog oder Ihre Website integrieren und ein raffinierteres Sucherlebnis bieten als Standard -WordPress -Themen -Suchfunktionen. Es ist überraschend einfach! Sie können die Suche auf y beschränken

Hier sind Sie also bereit, alles über dieses Ding namens Ajax zu lernen. Aber was genau ist das? Der Begriff AJAX bezieht sich auf eine lose Gruppierung von Technologien, mit denen dynamische, interaktive Webinhalte erstellt werden. Der Begriff Ajax, ursprünglich von Jesse J geprägt

Diese Artikelserie wurde Mitte 2017 mit aktuellen Informationen und neuen Beispielen umgeschrieben. In diesem JSON -Beispiel werden wir uns ansehen, wie wir einfache Werte in einer Datei mit JSON -Format speichern können. Mit der Notation des Schlüsselwertpaares können wir jede Art speichern

Nutzen Sie JQuery für mühelose Webseiten -Layouts: 8 Essential Plugins JQuery vereinfacht das Webseitenlayout erheblich. In diesem Artikel werden acht leistungsstarke JQuery -Plugins hervorgehoben, die den Prozess optimieren, insbesondere nützlich für die manuelle Website -Erstellung

Kernpunkte Dies in JavaScript bezieht sich normalerweise auf ein Objekt, das die Methode "besitzt", aber es hängt davon ab, wie die Funktion aufgerufen wird. Wenn es kein aktuelles Objekt gibt, bezieht sich dies auf das globale Objekt. In einem Webbrowser wird es durch Fenster dargestellt. Wenn Sie eine Funktion aufrufen, wird das globale Objekt beibehalten. Sie können den Kontext mithilfe von Methoden wie CALL (), Apply () und Bind () ändern. Diese Methoden rufen die Funktion mit dem angegebenen Wert und den Parametern auf. JavaScript ist eine hervorragende Programmiersprache. Vor ein paar Jahren war dieser Satz

JQuery ist ein großartiges JavaScript -Framework. Wie in jeder Bibliothek ist es jedoch manchmal notwendig, unter die Motorhaube zu gehen, um herauszufinden, was los ist. Vielleicht liegt es daran, dass Sie einen Fehler verfolgen oder nur neugierig darauf sind, wie JQuery eine bestimmte Benutzeroberfläche erreicht

Dieser Beitrag erstellt hilfreiche Cheat -Blätter, Referenzführer, schnelle Rezepte und Code -Snippets für die Entwicklung von Android-, Blackberry und iPhone -App. Kein Entwickler sollte ohne sie sein! Touch Gesten -Referenzhandbuch (PDF) Eine wertvolle Ressource für Desig


Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

mPDF
mPDF ist eine PHP-Bibliothek, die PDF-Dateien aus UTF-8-codiertem HTML generieren kann. Der ursprüngliche Autor, Ian Back, hat mPDF geschrieben, um PDF-Dateien „on the fly“ von seiner Website auszugeben und verschiedene Sprachen zu verarbeiten. Es ist langsamer und erzeugt bei der Verwendung von Unicode-Schriftarten größere Dateien als Originalskripte wie HTML2FPDF, unterstützt aber CSS-Stile usw. und verfügt über viele Verbesserungen. Unterstützt fast alle Sprachen, einschließlich RTL (Arabisch und Hebräisch) und CJK (Chinesisch, Japanisch und Koreanisch). Unterstützt verschachtelte Elemente auf Blockebene (wie P, DIV),

Sicherer Prüfungsbrowser
Safe Exam Browser ist eine sichere Browserumgebung für die sichere Teilnahme an Online-Prüfungen. Diese Software verwandelt jeden Computer in einen sicheren Arbeitsplatz. Es kontrolliert den Zugriff auf alle Dienstprogramme und verhindert, dass Schüler nicht autorisierte Ressourcen nutzen.

MinGW – Minimalistisches GNU für Windows
Dieses Projekt wird derzeit auf osdn.net/projects/mingw migriert. Sie können uns dort weiterhin folgen. MinGW: Eine native Windows-Portierung der GNU Compiler Collection (GCC), frei verteilbare Importbibliotheken und Header-Dateien zum Erstellen nativer Windows-Anwendungen, einschließlich Erweiterungen der MSVC-Laufzeit zur Unterstützung der C99-Funktionalität. Die gesamte MinGW-Software kann auf 64-Bit-Windows-Plattformen ausgeführt werden.

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 Linux neue Version
SublimeText3 Linux neueste Version
