Dieser Leitfaden enthält Anleitungen und Best Practices für Entwickler, die mit der RPC-Methode FoodOrderingService.BidiProcessOrder Lösungen für die Essensbestellung erstellen.
Diese bidirektionale Streaming-API in Echtzeit ist das Herzstück des Food Ordering KI-Agenten und ermöglicht die dynamische, dialogorientierte Bestellannahme in verschiedenen Anwendungen wie mobilen Apps, Sprachassistenten, Drive-ins und Kiosken.
Übersicht über BidiProcessOrder
Die Methode BidiProcessOrder stellt einen dauerhaften bidirektionalen Kommunikationskanal zwischen Ihrer Clientanwendung und dem KI-Agenten für die Essensbestellung her. Im Gegensatz zu standardmäßigen unären RPCs für Anfragen und Antworten bietet dieser Streaming-Ansatz folgende Vorteile:
- Interaktion mit geringer Latenz: Kontinuierlicher Informationsaustausch ohne den Aufwand wiederholter HTTP-Anfragen.
- Multimodale Eingabe: Verarbeitung von Audiostreams (für die Sprachbestellung), Texteingaben und clientseitigen Ereignissen.
- Antworten in Echtzeit: Der Agent kann während der Unterhaltung Audio, Text, Bestellaktualisierungen und andere Signale zurücksenden.
BidiProcessOrder kann nicht mit REST aufgerufen werden. Für Integrationen muss ein verbindungsorientiertes Protokoll verwendet werden:
- gRPC (empfohlen): Bietet ein robustes und effizientes Framework für bidirektionales Streaming.
- WebSocket: Geeignet für Clients oder Umgebungen, in denen gRPC aufgrund von Einschränkungen bei der Programmiersprache oder dem Netzwerk nicht geeignet ist.
Ausführliche Typdefinitionen finden Sie in der BidiProcessOrder API Referenz. WebSocket-Integrationen verwenden JSON-Darstellungen dieser Typen, wie im Abschnitt zu WebSocket beschrieben.
Vorbereitung
Bevor Sie BidiProcessOrder einbinden:
API aktivieren: Prüfen Sie, ob die Food Ordering AI Agent API in Ihrem Google Cloud Projekt aktiviert ist.
bash gcloud services enable foodorderingaiagent.googleapis.com --project=PROJECT_IDAuthentifizierung: Legen Sie Ihren Authentifizierungsansatz fest und richten Sie alle erforderlichen Dienstkonten und IAM-Rollen ein, wie unter Authentifizierung beschrieben.
Menüaufnahme: 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 zur 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 Dienst konto, mit dem sich Ihre Anwendung bei der Food Ordering AI Agent API authentifiziert. 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, 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 Console oder
gcloud:bash gcloud projects add-iam-policy-binding PROJECT_ID \ --member="serviceAccount:SERVICE_ACCOUNT_EMAIL" \ --role="roles/foodorderingaiagent.agentUser"zuweisen- Food Ordering Agent User (
2. Authentifizierungsablauf für Anwendungen
Der genaue Authentifizierungsablauf hängt von Ihrer Anwendungsarchitektur ab, insbesondere davon, ob die Clientanwendung (z.B. mobile App, Kiosksoftware) eine direkte Verbindung herstellt oder über Ihr eigenes Back-End.
Häufiges Szenario: Authentifizierung einer für Nutzer bestimmten Clientanwendung
Dies ist ein typisches Muster für mobile Apps oder Webanwendungen:
- Client-to-YourAuth: Die Endnutzer-Clientanwendung (mobil, Web) authentifiziert sich mit Ihrem vorhandenen Nutzerauthentifizierungssystem (z. B. Firebase Authentication oder Ihr eigener OAuth-Server).
- Tokenaustausch: Nachdem die Clientanwendung den Nutzer authentifiziert hat, fordert sie ein kurzlebiges Token von einem sicheren Backend-Dienst an, den Sie kontrollieren (z.B. ein „API-Token-Dienst“).
Zugriffstoken generieren: Ihr Backend-Dienst generiert mit den Anmeldedaten des in Schritt 1 konfigurierten Dienstkontos ein standardmäßiges OAuth 2.0-Zugriffstoken für den
https://www.googleapis.com/auth/cloud-platformZugriffsbereich. Google Cloud Dies kann mit den Google Cloud Authentifizierungs-Client bibliotheken erfolgen.- Sicherheit: Dienstkontoschlüssel oder Anmeldedaten, die zum Generieren dieser Tokens verwendet werden, müssen sicher in Ihrem Back-End gespeichert und verwaltet werden. Geben Sie private Schlüssel von Dienstkonten niemals direkt für Endnutzer-Clientanwendungen frei. Weitere Informationen finden Sie unter Best Practices für die Verwaltung von Dienstkontoschlüsseln.
Token an Client: Ihr Backend-Dienst gibt das generierte Google-Zugriffstoken an die Clientanwendung zurück.
API-Aufruf: Die Clientanwendung verwendet dieses Google-Zugriffstoken, um ihre gRPC- oder WebSocket-Verbindung zur
BidiProcessOrder-RPC zu authentifizieren.
3. Token verwenden
- gRPC: Die Google gRPC-Clientbibliotheken verarbeiten in der Regel die Tokenaktualisierung und -einbindung in die Aufrufmetadaten, wenn Anmeldedaten für Dienstkonten angegeben werden.
- WebSocket (nicht im Browser): Fügen Sie das Token in den
Authorization: Bearer TOKENHeader ein. - WebSocket (Browser): Wie im Abschnitt zu WebSocket erwähnt, können bei direkten WebSocket-Verbindungen im Browser keine Autorisierungsheader verwendet werden. Ein serverseitiger Streaming-Proxy ist erforderlich, um die Verbindung Ihres Clients zu authentifizieren Google Cloud.
Verbindung zur API herstellen
Sie können einen Stream mit gRPC-Clientbibliotheken oder einer WebSocket-Verbindung einrichten.
gRPC
Die Verwendung von gRPC wird empfohlen. Sie verwenden die Clientbibliotheken für Ihre bevorzugte Sprache (z.B. Node.js), die auf der API-Referenz zu BidiProcessOrder basieren.
Die grundlegenden Schritte sind:
- Erstellen Sie einen gRPC-Kanal zum API-Endpunkt des Food Ordering AI Agent (z.B.
foodorderingaiagent.googleapis.com). - Rufen Sie einen Client-Stub für
FoodOrderingServiceab. - 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 geschieht:
- Audio-, Text- und Ereigniseingaben vom Endnutzer werden gesendet.
- Nachrichten vom Agenten werden verarbeitet, einschließlich Audio, Text und Ereignissen.
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
Für 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- WobeiTOKENein OAuth 2.0-Zugriffstoken ist, 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-Protos sein und alswebsocket.TextMessagegesendet werden. - Server zu Client: Nachrichten, die von der API empfangen werden (
BidiProcessOrderResponse), werden alswebsocket.BinaryMessagegesendet. Der Inhalt dieser Binärnachrichten 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 für die Verbindung und Interaktion mit der API über WebSockets in Node.js mit der ws-Bibliothek:
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');
});
Lebenszyklus der Sitzung
Jeder Aufruf von BidiProcessOrder initiiert eine Sitzung. Die Sitzung bleibt aktiv, solange der Stream geöffnet ist.
1. Initiierung (Konfigurationsnachricht)
- Nach dem Herstellen der Verbindung muss die erste Nachricht , die vom Client gesendet wird
, eine
BidiProcessOrderRequestmit derConfigNachricht sein. - Erforderliche Felder in
Config:session: Eine eindeutige vom Client generierte Sitzungs-ID. Format:projects/PROJECT/locations/LOCATION/sessions/SESSION_ID.store: Der Ressourcenname desStore. 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
mode(optional fürBidiProcessOrder): StandardmäßigHYBRID(Sprache und Text). Wenn Sie anstelle vonBidiProcessOrderdie unäre REST- oder gRPCProcessOrderAPI verwenden, mussmodeexplizit aufTEXTgesetzt werden.
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 der ersten
Configkann der Client einen Stream vonBidiProcessOrderRequest-Nachrichten senden, die eine der folgenden Eingaben enthalten:AudioInput: Rohaudiodaten (in der Regel 16-Bit-Linear-PCM mit 16.000 Hz, keine Header). Wird für Sprachinteraktionen verwendet.TextInput: Textnachrichten vom Nutzer.EventInput: Signale für Ereignisse wieDriveOffEvent(für Drive-in-Anwendungsfälle, wenn das Fahrzeug abfährt),CrewInterjectionEvent(für jede Situation, in der ein Mensch während der Unterhaltung die Rolle der Bestellannahme übernimmt) oderOrderStateUpdateEvent(wenn die Bestellung auf der Clientseite 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 empfangen
- 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 Audiobytes, die für den Nutzer wiedergegeben werden sollen. Wird für Sprachinteraktionen verwendet.AgentText: Textversion der Antwort des Agenten.SpeechRecognition: Transkript der erkannten Sprache des Nutzers.UpdatedOrderState: Enthält den vollständigen aktuellen Status derOrderdes Kunden, wenn sie vom Agenten aktualisiert wird. Verwenden Sie diese Option, um die Bestellrepräsentation Ihrer Anwendung zu aktualisieren. Dies sollte in der Regel zu einer Aktualisierung einer Benutzeroberfläche oder eines Aufzeichnungssystems für Bestellstatusinformationen führen, z. B. eines Kassensystems.InterruptionSignal: Gibt an, dass der Nutzer die Rede des Agenten unterbrochen hat. Der Client sollte die Wiedergabe von ausgehendemAgentAudiosofort beenden.AgentEvent: Besondere Ereignisse wieRestartOrder, die eine Clientaktion erfordern.SuggestedOptions: Bietet kontextbezogene Optionen, die ein Nutzer als Nächstes auswählen könnte. Nützlich für die Anzeige auf einem Bildschirm.EndSession: Gibt an, dass die Sitzung vom Agenten beendet wurde (z.B. Bestellung abgeschlossen, Nutzer abgefahren oder Eskalation an einen menschlichen Agenten).
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. In der Regel 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 bestimmte Antworttypen verarbeiten, die Ihr Client beim Aufrufen von BidiProcessOrder erhält.
AudioInput
- Streamen Sie Audio in Blöcken, sobald es verfügbar ist.
- Format: 16-Bit-Linear-PCM, Abtastrate 16.000 Hz.
- Audioblöcke enthalten nicht die Audioheader, die normalerweise einer WAV-Datei vorangestellt sind.
- Geben Sie für Drive-in-Szenarien mit aktivierter Echounterdrückung (
enable_echo_cancellationinConfig) sowohlcustomer_audioals auchcrew_audioan.
UpdatedOrderState
- Diese Nachricht enthält jedes Mal den vollständigen Status der Bestellung, wenn sie gesendet wird.
Ersetzen Sie alle lokalen Caches der Bestellung durch den Inhalt der empfangenen
Order-Nachricht. - Verwenden Sie die
custom_integration_attributesin denOrder-Elementen und -Modifikatoren, um denOrder-Inhalt entsprechenden Entitäten im Aufzeichnungssystem Ihrer Anwendung zuzuordnen.
InterruptionSignal
- Beenden Sie nach dem Empfang sofort die Wiedergabe von
AgentAudiound löschen Sie alle gepufferten Agent-Audiodaten. So wird ein natürlicher Konversationsablauf gewährleistet, wenn der Nutzer die Rede des Agenten 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. einen menschlichen Supervisor im Fall von
AGENT_ESCALATIONbenachrichtigen oder zu einem Bestellbestätigungsstatus übergehen).
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 Wiederherstellung der Verbindung: Implementieren Sie eine robuste Logik für die Wiederherstellung der Verbindung bei Netzwerkproblemen. Senden Sie dazu die erste
Config-Nachricht mit derselben Sitzungs-ID, um die Wiederaufnahme zu versuchen. - Fehlerbehandlung: Überwachen Sie den Stream auf Fehler. gRPC- und WebSocket-Bibliotheken bieten Mechanismen zum Erkennen von Stream-Schließungen oder Übertragungsfehlern. Protokollieren Sie diese Ereignisse und behandeln Sie sie ordnungsgemäß.
- Audio-Buffering: Verwalten Sie Audio-Puffer sorgfältig und implementieren Sie bei Bedarf Buffering, um eine reibungslose Wiedergabe von
AgentAudiound eine rechtzeitige Übermittlung vonAudioInputzu gewährleisten. Berücksichtigen Sie bei der Entscheidung für Ihr Buffering-Schema sorgfältig den Kompromiss zwischen Latenz und Wiedergabequalität. - Sitzungs-ID-Verwaltung: 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 wenn nicht behebbare Fehler auftreten.
- Zeitüberschreitungen: Der Stream selbst kann zwar lange bestehen (standardmäßig bis zu 15 Minuten), aber Sie können bei Bedarf Zeitüberschreitungen auf Anwendungsebene für bestimmte Status festlegen.
Beispiel für einen Integrationsablauf (konzeptionell)
- Die Clientanwendung (z.B. mobile App) initiiert eine Bestellung.
- Stellen Sie eine gRPC-/WebSocket-Verbindung zu
BidiProcessOrderher. - Senden Sie
BidiProcessOrderRequestmitConfig(Sitzungs-ID, Store-ID). - Empfangen Sie die erste
AgentAudio(z.B. Willkommensnachricht) und geben Sie sie wieder. - Nutzer spricht: Audio aufnehmen und in
AudioInput-Nachrichten streamen. - Empfangen Sie
SpeechRecognition(Transkript anzeigen),AgentAudio(Antwort wiedergeben) und möglicherweiseUpdatedOrderState(Warenkorb auf der Benutzeroberfläche aktualisieren). - Wenn der Nutzer unterbricht, empfangen Sie
InterruptionSignalund beenden Sie die Wiedergabe. - Setzen Sie den Austausch von Audio- oder Texteingaben und Agent-Antworten fort.
- Nutzer bestätigt Bestellung: Agent sendet endgültiges
UpdatedOrderState. - Agent sendet
EndSession: Client schließt den Stream und schließt die Bestellung im Kassensystem mit Daten aus dem letztenUpdatedOrderStateab.
Vollständiges Beispiel
In der obigen Anleitung werden die Streaming-Konzepte 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 Food Ordering AI Agent-Kurzanleitung zur Verwendung von Clientbibliotheken.
Richten Sie zur Authentifizierung bei Food Ordering AI Agent 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.'}});
}