In diesem Leitfaden finden Sie Anleitungen und Best Practices für Entwickler, die mit der RPC-Methode FoodOrderingService.BidiProcessOrder Funktionen für die Essensbestellung erstellen.
Diese bidirektionale Streaming-API in Echtzeit ist das Herzstück des KI-Agents für die Essensbestellung und ermöglicht die dynamische, dialogbasierte Bestellannahme in verschiedenen Anwendungen wie mobilen Apps, Sprachassistenten, Drive-thrus und Kiosken.
Übersicht über BidiProcessOrder
Mit der Methode BidiProcessOrder wird ein dauerhafter, bidirektionaler Kommunikationskanal zwischen Ihrer Clientanwendung und dem KI-Agenten für die Essensbestellung eingerichtet. Im Gegensatz zu standardmäßigen unären RPCs für Anfragen und Antworten ermöglicht dieser Streaming-Ansatz Folgendes:
- Interaktion mit geringer Latenz: Kontinuierlicher Austausch von Informationen ohne den Overhead wiederholter HTTP-Anfragen.
- Multimodale Eingabe:Verarbeitung von Audio-Streams (für Sprachbestellungen), Texteingaben und clientseitigen Ereignissen.
- Echtzeitantworten:Der Agent kann während des Gesprächs Audio, Text, Bestellaktualisierungen und andere Signale zurücksenden.
BidiProcessOrder kann nicht über REST aufgerufen werden. Integrationen müssen ein verbindungsorientiertes Protokoll verwenden:
- gRPC (empfohlen): Bietet ein robustes und effizientes Framework für bidirektionales Streaming.
- WebSocket:Geeignet für Clients oder Umgebungen, in denen gRPC aufgrund von Programmiersprachen- oder Netzwerkbeschränkungen nicht infrage kommt.
Ausführliche Typdefinitionen finden Sie in der BidiProcessOrder API Reference. Bei WebSocket-Integrationen werden JSON-Darstellungen dieser Typen verwendet, wie im WebSocket-Abschnitt beschrieben.
Vorbereitung
Vor der Integration in BidiProcessOrder:
API aktivieren:Achten Sie darauf, dass die Food Ordering AI Agent API in Ihrem Google Cloud-Projekt aktiviert ist.
bash gcloud services enable foodorderingaiagent.googleapis.com --project=PROJECT_IDAuthentifizierung:Wählen Sie eine Authentifizierungsmethode aus und richten Sie alle erforderlichen Dienstkonten und IAM-Rollen ein, wie unter Authentifizierung beschrieben.
Menü-Ingestion:Ein gültiges Menü muss aufgenommen und mit einem
Storeverknüpft werden. Weitere Informationen finden Sie unter Menüdaten einbinden.
Authentifizierung
Um eine sichere Verbindung zum BidiProcessOrder-RPC herzustellen, muss sich Ihre Anwendung mit einem Google Cloud Dienstkonto authentifizieren.
1. Dienstkonto konfigurieren
- Dienstkonto erstellen:Erstellen Sie in Ihrem Google Cloud Projekt ein Dienstkonto, das Ihre Anwendung zur Authentifizierung bei der Food Ordering AI Agent API verwendet. Weitere Informationen finden Sie unter Dienstkonten erstellen und verwalten.
IAM-Rollen zuweisen:Weisen Sie diesem Dienstkonto die erforderlichen IAM-Rollen zu. Die primäre Rolle, die zum Aufrufen von
BidiProcessOrdererforderlich ist:- Food Ordering Agent User (
roles/foodorderingaiagent.agentUser): Ermöglicht dem Dienstkonto, eine Verbindung zum Bestellservice herzustellen und Sitzungen zu verarbeiten.
Sie können diese Rolle über die Google Cloud -Konsole oder
gcloudzuweisen:bash gcloud projects add-iam-policy-binding PROJECT_ID \ --member="serviceAccount:SERVICE_ACCOUNT_EMAIL" \ --role="roles/foodorderingaiagent.agentUser"- Food Ordering Agent User (
2. Authentifizierungsablauf für Anwendungen
Der genaue Authentifizierungsablauf hängt von der Architektur Ihrer Anwendung ab, insbesondere davon, ob die Clientanwendung (z.B. mobile App, Kiosksoftware) direkt oder über Ihr eigenes Backend eine Verbindung herstellt.
Häufiges Szenario: Authentifizieren einer kundenorientierten Clientanwendung
Das ist ein typisches Muster für mobile Apps oder Webanwendungen:
- Client-to-YourAuth::Die Client-App für Endnutzer (mobil, Web) wird mit dem vorhandenen Nutzerauthentifizierungssystem authentifiziert (z. B. Firebase Authentication oder Ihr eigener OAuth-Server).
- Token Exchange:Nachdem die Client-App den Nutzer authentifiziert hat, fordert sie ein kurzlebiges Token von einem sicheren Backend-Dienst an, den Sie kontrollieren (z.B. ein „API Token Service“).
Generierung von Zugriffstokens:Ihr Backend-Dienst generiert mit den Anmeldedaten des Google Cloud Dienstkonto-Principals, der in Schritt 1 konfiguriert wurde, ein standardmäßiges OAuth 2.0-Zugriffstoken für den Bereich
https://www.googleapis.com/auth/cloud-platform. Dazu können Sie die Google Cloud -Clientbibliotheken für die Authentifizierung verwenden.- Sicherheit:Dienstkontoschlüssel oder Anmeldedaten, die zum Generieren dieser Tokens verwendet werden, müssen sicher in Ihrem Backend gespeichert und verwaltet werden. Geben Sie private Schlüssel von Dienstkonten niemals direkt in Clientanwendungen für Endnutzer frei. Weitere Informationen finden Sie unter Best Practices für die Verwaltung von Dienstkontoschlüsseln.
Token an Client:Ihr Back-End-Dienst gibt das generierte Google-Zugriffstoken an die Client-App zurück.
API-Aufruf:Die Client-App verwendet dieses Google-Zugriffstoken, um ihre gRPC- oder WebSocket-Verbindung zum
BidiProcessOrder-RPC zu authentifizieren.
3. Token verwenden
- gRPC:Die Google gRPC-Clientbibliotheken verarbeiten in der Regel die Aktualisierung von Tokens und die Einbeziehung in die Aufrufmetadaten, wenn Anmeldedaten für Dienstkonten bereitgestellt werden.
- WebSocket (nicht im Browser): Fügen Sie das Token in den
Authorization: Bearer TOKEN-Header ein. - WebSocket (Browser): Wie im Abschnitt zu WebSocket beschrieben, können für direkte Browser-WebSocket-Verbindungen keine Autorisierungsheader verwendet werden. Ein serverseitiger Streamingproxy ist erforderlich, um die Verbindung Ihrer Clients zu Google Cloudzu authentifizieren.
Verbindung zur API herstellen
Sie können einen Stream mit gRPC-Clientbibliotheken oder einer WebSocket-Verbindung einrichten.
gRPC
Die Verwendung von gRPC ist der empfohlene Ansatz. Sie verwenden die Clientbibliotheken für die Sprache Ihrer Wahl (z.B. Node.js), die auf der BidiProcessOrder API-Referenz basieren.
Die grundlegenden Schritte sind:
- Erstellen Sie einen gRPC-Channel zum Food Ordering AI Agent API-Endpunkt (z.B.
foodorderingaiagent.googleapis.com). - Client-Stub für
FoodOrderingServiceabrufen - Rufen Sie die Methode
BidiProcessOrderauf, die ein Stream-Objekt zum Senden von Anfragen und Empfangen von Antworten zurückgibt. - Implementieren Sie die Geschäftslogik entsprechend Ihrem Anwendungsfall, wobei gleichzeitig Folgendes gilt:
- Sendet Audio-, Text- und Ereigniseingaben vom Endnutzer.
- Verarbeitet Nachrichten vom Agenten, einschließlich Audio, Text und Ereignisse.
Node.js
const {FoodOrderingServiceClient} = require('@google-cloud/foodorderingaiagent');
const client = new FoodOrderingServiceClient();
// The stream is initialized immediately. You can now write commands and attach listeners.
const stream = client.bidiProcessOrder();
WebSocket
Bei WebSocket-Verbindungen lautet der URL-Pfad:
wss://foodorderingaiagent.googleapis.com/ws/google.cloud.foodorderingaiagent.v1beta.FoodOrderingService/BidiProcessOrder/locations/LOCATION
LOCATION: z.B.us
Erforderliche Header:
Authorization:Bearer TOKEN– Dabei istTOKENein OAuth 2.0-Zugriffstoken, das für Ihr Dienstkonto abgerufen wurde.
Nachrichtenformat:
- Client zu Server:Nachrichten, die an die API gesendet werden (z.B.
Config,AudioInput,TextInput,EventInput), müssen JSON-Darstellungen desBidiProcessOrderRequest-Protokolls sein, die alswebsocket.TextMessagegesendet werden. - Server zu Client:Von der API empfangene Nachrichten (
BidiProcessOrderResponse) werden alswebsocket.BinaryMessagegesendet. Der Inhalt dieser binären Nachrichten ist jedoch eine JSON-Nutzlast. - Binärdaten:Binärdaten in den JSON-Nutzlasten (z.B.
customerAudioinAudioInput,agentAudioinAgentAudio) müssen base64-codiert sein.
Node.js-WebSocket-Beispiel
Hier sehen Sie ein Beispiel dafür, wie Sie mit der ws-Bibliothek in Node.js eine Verbindung zur API herstellen und mit ihr interagieren:
const WebSocket = require('ws');
// Replace with your actual values
const location = 'LOCATION';
const projectId = 'PROJECT_ID';
const sessionId = 'SESSION_ID';
const brandId = 'BRAND_ID';
const storeId = 'STORE_ID';
const token = 'OAUTH_TOKEN';
const wsUrl = `wss://foodorderingaiagent.googleapis.com/ws/google.cloud.foodorderingaiagent.v1beta.FoodOrderingService/BidiProcessOrder/locations/${location}`;
const ws = new WebSocket(wsUrl, {
headers: {
'Authorization': `Bearer ${token}`
}
});
ws.on('open', () => {
console.log('Connected to WebSocket');
// 1. Send the required initial Config message
const configRequest = {
config: {
session: `projects/${projectId}/locations/${location}/sessions/${sessionId}`,
store: `projects/${projectId}/locations/${location}/brands/${brandId}/stores/${storeId}`
}
};
// Client-to-server messages are sent as TextMessage
ws.send(JSON.stringify(configRequest));
console.log('Sent Config message');
});
ws.on('message', (data, isBinary) => {
// The documentation specifies that server-to-client messages
// are sent as BinaryMessage containing a JSON payload.
if (isBinary) {
try {
const response = JSON.parse(data.toString('utf8'));
console.log('Received response:', response);
if (response.agentText) {
console.log(`Agent: ${response.agentText.text}`);
}
if (response.agentAudio) {
const audioBytes = Buffer.from(response.agentAudio.agentAudio, 'base64');
console.log(`Received ${audioBytes.length} bytes of agent audio.`);
// Play or process the audio bytes here
}
if (response.endSession) {
console.log('Session ended by agent.');
ws.close();
}
} catch (e) {
console.error('Failed to parse JSON response:', e);
}
}
});
ws.on('close', () => {
console.log('Connection closed');
});
Sitzungslebenszyklus
Mit jedem Aufruf von BidiProcessOrder wird eine Sitzung gestartet. Die Sitzung bleibt aktiv, solange der Stream geöffnet ist.
1. Initiierung (Konfigurationsnachricht)
- Nachdem die Verbindung hergestellt wurde, muss die erste Nachricht, die vom Client gesendet wird, ein
BidiProcessOrderRequestmit der NachrichtConfigsein. - Pflichtfelder in
Config:session: Eine eindeutige, vom Client generierte Sitzungskennung. Format:projects/PROJECT/locations/LOCATION/sessions/SESSION_ID.store: Der Ressourcenname derStore. Format:projects/PROJECT/locations/LOCATION/brands/BRAND/stores/STORE.- Der Agent verwendet
store, um das entsprechende Menü und die entsprechende Konfiguration zu laden.
- Der Agent verwendet
Node.js
// Send the first message containing Config
stream.write({
config: {
session: client.sessionPath(projectId, location, sessionId),
store: client.storePath(projectId, location, brandId, storeId),
}
});
2. Eingaben senden
- Nach dem ersten
Configkann der Client einen Stream vonBidiProcessOrderRequest-Nachrichten mit einer der folgenden Eingaben senden:AudioInput: Rohaudiodaten (in der Regel 16-Bit-PCM mit 16.000 Hz, keine Header). Wird für Sprachinteraktionen verwendet.TextInput: SMS vom Nutzer.EventInput: Signale für Ereignisse wieDriveOffEvent(für Drive-thru-Anwendungsfälle, wenn das Fahrzeug abfährt),CrewInterjectionEvent(für jede Situation, in der ein Mensch die Rolle der Bestellannahme während der Unterhaltung übernimmt) oderOrderStateUpdateEvent(wenn die Bestellung clientseitig geändert wird, z.B. über eine Touch-Oberfläche).
Node.js
// Stream user inputs over the active connection
stream.write({textInput: {text: 'Hi, I\'d like to order a cheeseburger.'}});
3. Antworten erhalten
- Gleichzeitig sendet der Agent einen Stream von
BidiProcessOrderResponse-Nachrichten zurück. Ihr Client muss in der Lage sein, verschiedene Antworttypen im Feldoneof responsezu verarbeiten:AgentAudio: Synthetisierte Audio-Bytes, die für Sprachinteraktionen für den Nutzer wiedergegeben werden.AgentText: Textversion der Antwort des Agenten.SpeechRecognition: Transkript der erkannten Sprache des Nutzers.UpdatedOrderState: Enthält den vollständigen aktuellen Status desOrderdes Kunden, wenn er vom Kundenservicemitarbeiter aktualisiert wird. Verwenden Sie diesen, um die Auftragsdarstellung Ihrer Anwendung zu aktualisieren. Dies sollte in der Regel zu einer Aktualisierung der Benutzeroberfläche oder eines Systems für die Aufzeichnung von Informationen zum Bestellstatus führen, z. B. eines Kassensystems.InterruptionSignal: Gibt an, dass der Nutzer die Sprachausgabe des Agents unterbrochen hat. Der Client sollte die Wiedergabe aller ausgehendenAgentAudiosofort beenden.AgentEvent: Besondere Ereignisse, z. B.RestartOrder>, die eine Clientaktion erfordern.SuggestedOptions: Bietet kontextbezogene Optionen, die ein Nutzer als Nächstes auswählen könnte. Diese sind nützlich für die Anzeige auf einem Bildschirm.EndSession: Gibt an, dass die Sitzung vom Kundenservicemitarbeiter beendet wurde (z.B. Bestellung abgeschlossen, Nutzer fährt weg oder Kundenservicemitarbeiter eskaliert).
Node.js
// Attach event listeners to handle responses sequentially
stream.on('data', (response) => {
if (response.agentAudio) {
console.log(`Received ${response.agentAudio.agentAudio.length} bytes of agent audio.`);
} else if (response.agentText) {
console.log(`Agent: ${response.agentText.text}`);
} else if (response.speechRecognition) {
console.log(`Recognized User Speech: ${response.speechRecognition.transcript}`);
} else if (response.updatedOrderState) {
console.log('Order updated.');
} else if (response.interruptionSignal) {
console.log('User interrupted the agent. Stop playing audio!');
} else if (response.endSession) {
console.log(`Session ended. Type: ${response.endSession.type}, Reason: ${response.endSession.reason}`);
stream.end();
}
});
stream.on('error', (err) => {
console.error('Stream error:', err);
});
4. Stream schließen
- Der Stream kann vom Client oder vom Server geschlossen werden. Normalerweise signalisiert der Server das Ende einer Unterhaltung mit einer
EndSession-Nachricht. Der Client sollte den Stream schließen, wenn diese Nachricht empfangen wird.
Bestimmte Nachrichtentypen verarbeiten
In den folgenden Abschnitten wird beschrieben, wie Sie mit bestimmten Antworttypen umgehen, die Ihr Client beim Aufrufen von BidiProcessOrder erhält.
AudioInput
- Audio in Chunks streamen, sobald es verfügbar ist.
- Format: 16-Bit-Linear-PCM, 16.000 Hz Abtastrate.
- Audio-Chunks enthalten nicht die Audio-Header, die normalerweise einer WAV-Datei vorangestellt werden.
- Geben Sie für Drive-thru-Szenarien mit aktivierter Echounterdrückung (
enable_echo_cancellationinConfig) sowohlcustomer_audioals auchcrew_audioan.
UpdatedOrderState
- Diese Nachricht enthält den vollständigen Status der Bestellung bei jedem Senden.
Ersetzen Sie alle lokalen Caches der Bestellung durch den Inhalt der empfangenen
Order-Nachricht. - Verwenden Sie die
custom_integration_attributesin denOrder-Elementen und ‑Modifizierern, um dieOrder-Inhalte entsprechenden Entitäten im System Ihrer Anwendung zuzuordnen.
InterruptionSignal
- Halte nach dem Empfang sofort die Wiedergabe von
AgentAudioan und lösche alle zwischengespeicherten Agent-Audiodaten. So wird ein natürlicher Konversationsablauf gewährleistet, wenn der Nutzer die Sprachausgabe des Agents unterbricht.
EndSession
- Prüfen Sie
EndType(z.B.DRIVE_OFF,AGENT_ESCALATION). - Ihre Anwendung sollte die Verbindung ordnungsgemäß schließen und den Nutzer entsprechend weiterleiten (z.B. im Fall von
AGENT_ESCALATIONeinen menschlichen Supervisor benachrichtigen oder zu einem Bestellbestätigungsstatus wechseln).
Best Practices
- Nachrichten asynchron verarbeiten:Minimieren Sie die Latenz, indem Sie Threads oder nicht blockierende E/A verwenden, um Anfragen gleichzeitig zu senden und eingehende Antworten zu verarbeiten.
- Logik für die erneute Verbindung:Implementieren Sie eine robuste Logik für die erneute Verbindung im Falle von Netzwerkproblemen. Denken Sie daran, die ursprüngliche
Config-Nachricht mit derselben Sitzungs-ID zu senden, um die Fortsetzung zu versuchen. - Fehlerbehandlung:Überwachen Sie den Stream auf Fehler. gRPC- und WebSocket-Bibliotheken bieten Mechanismen zum Erkennen von Stream-Schließungen oder Transportfehlern. Protokollieren Sie diese Ereignisse und gehen Sie sorgfältig damit um.
- Audio-Buffering:Audio-Puffer sorgfältig verwalten und bei Bedarf implementieren, um eine reibungslose Wiedergabe von
AgentAudiound eine rechtzeitige Bereitstellung vonAudioInputzu gewährleisten. Wägen Sie bei der Entscheidung für ein Pufferschema sorgfältig den Kompromiss zwischen Latenz und Wiedergabequalität ab. - Verwaltung von Sitzungs-IDs:Achten Sie darauf, dass Sitzungs-IDs für jede einzelne Bestellung/Unterhaltung eindeutig sind.
- Ressourcenverwaltung:Schließen Sie Streams und geben Sie Ressourcen frei, wenn die Sitzung abgeschlossen ist oder nicht behebbarer Fehler auftreten.
- Timeouts:Der Stream selbst kann zwar lange bestehen (standardmäßig bis zu 15 Minuten), aber bei Bedarf sollten Sie Timeouts auf Anwendungsebene für bestimmte Status in Betracht ziehen.
Beispiel für einen Integrationsablauf (konzeptionell)
- Eine Bestellung wird von einer Client-App (z.B. einer mobilen App) initiiert.
- Stellen Sie eine gRPC-/WebSocket-Verbindung zu
BidiProcessOrderher. - Senden Sie
BidiProcessOrderRequestmitConfig(Sitzungs-ID, Händler-ID). - Empfangen Sie die erste
AgentAudio(z.B. eine Willkommensnachricht) und spielen Sie sie ab. - Nutzer spricht: Audio aufnehmen und in
AudioInput-Nachrichten streamen. - Sie erhalten
SpeechRecognition(Transkript anzeigen),AgentAudio(Antwort abspielen) und möglicherweiseUpdatedOrderState(Warenkorb in der Benutzeroberfläche aktualisieren). - Wenn der Nutzer den Vorgang unterbricht, empfange
InterruptionSignalund beende die Wiedergabe. - Der Austausch von Audio- oder Texteingaben und Antworten des KI-Agenten wird fortgesetzt.
- Nutzer bestätigt Bestellung: Der Kundenservicemitarbeiter sendet das endgültige
UpdatedOrderState. - Der Kundenservicemitarbeiter sendet
EndSession: Der Kunde schließt den Stream und die Bestellung im Kassensystem mit den Daten aus dem letztenUpdatedOrderStateab.
Vollständiges Beispiel
In der Anleitung oben werden die Streamingkonzepte Schritt für Schritt erläutert. Hier sehen Sie, wie ein vollständiger End-to-End-Integrationsablauf aussieht.
Node.js
Bevor Sie dieses Beispiel anwenden, folgen Sie der Node.js-Einrichtungsanleitung in der Kurzanleitung zur Verwendung von Clientbibliotheken für den KI-Agenten für die Essensbestellung.
Richten Sie zur Authentifizierung beim KI-Agent für die Essensbestellung Standardanmeldedaten für Anwendungen ein. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.
const {FoodOrderingServiceClient} = require('@google-cloud/foodorderingaiagent');
async function bidiProcessOrderSample(projectId, location, brand, store, sessionId) {
const client = new FoodOrderingServiceClient();
// Create the resource names
const sessionPath = client.sessionPath(projectId, location, sessionId);
const storePath = client.storePath(projectId, location, brand, store);
// Initialize the stream using gRPC. See the WebSocket section for the equivalent WebSocket implementation.
const stream = client.bidiProcessOrder();
// Attach event listeners to handle responses sequentially
stream.on('data', (response) => {
if (response.agentAudio) {
console.log(`Received ${response.agentAudio.agentAudio.length} bytes of agent audio.`);
} else if (response.agentText) {
console.log(`Agent: ${response.agentText.text}`);
} else if (response.speechRecognition) {
console.log(`Recognized User Speech: ${response.speechRecognition.transcript}`);
} else if (response.updatedOrderState) {
console.log('Order updated.');
} else if (response.interruptionSignal) {
console.log('User interrupted the agent. Stop playing audio!');
} else if (response.endSession) {
console.log(`Session ended. Type: ${response.endSession.type}, Reason: ${response.endSession.reason}`);
stream.end();
}
});
stream.on('error', (err) => {
console.error('Stream error:', err);
});
// 1. Send the first message containing Config
stream.write({
config: {
session: sessionPath,
store: storePath,
}
});
// 2. Stream user inputs over the active connection
stream.write({textInput: {text: 'Hi, I\'d like to order a cheeseburger.'}});
}