Tetap teratur dengan koleksi
Simpan dan kategorikan konten berdasarkan preferensi Anda.
Agen bawaan yang Anda buat di langkah terakhir tidak dapat memberikan data dinamis seperti saldo akun karena semuanya di-hardcode ke dalam agen.
Pada langkah tutorial ini,
Anda akan membuat
webhook
yang dapat memberikan data dinamis ke agen.
Fungsi Cloud Run
digunakan untuk menghosting webhook dalam tutorial ini karena kesederhanaannya,
tetapi ada banyak cara lain untuk menghosting layanan webhook.
Contoh ini juga menggunakan bahasa pemrograman Go, tetapi Anda dapat menggunakan bahasa apa pun yang didukung oleh fungsi Cloud Run.
Membuat Fungsi
Fungsi Cloud Run dapat dibuat dengan konsol Google Cloud (kunjungi dokumentasi, buka konsol).
Untuk membuat fungsi untuk tutorial ini:
Agen Dialogflow dan fungsi Anda harus berada dalam project yang sama.
Ini adalah cara termudah bagi Dialogflow untuk memiliki
akses aman ke fungsi Anda.
Sebelum membuat fungsi,
pilih project Anda dari Google Cloud konsol.
Klik Create Function, lalu tetapkan kolom berikut:
Environment: generasi ke-1
Nama fungsi: tutorial-banking-webhook
Region: Jika Anda menentukan region untuk agen, gunakan region yang sama.
HTTP Trigger type: HTTP
URL: Klik tombol salin di sini dan simpan nilainya.
Anda akan memerlukan URL ini saat mengonfigurasi webhook.
Autentikasi: Wajibkan autentikasi
Wajibkan HTTPS: dicentang
Klik Simpan.
Klik Berikutnya (Anda tidak memerlukan runtime, build, koneksi, atau setelan keamanan khusus).
Tetapkan kolom berikut:
Runtime: Pilih runtime Go terbaru.
Kode sumber: Editor Inline
Titik entri: HandleWebhookRequest
Ganti kode dengan kode berikut:
packageestwhimport("context""encoding/json""fmt""log""net/http""os""strings""cloud.google.com/go/spanner""google.golang.org/grpc/codes")//clientisaSpannerclient,createdonlyoncetoavoidcreation//foreveryrequest.//See:https://cloud.google.com/functions/docs/concepts/go-runtime#one-time_initializationvarclient*spanner.Clientfuncinit(){//Ifusingadatabase,theseenvironmentvariableswillbeset.pid:=os.Getenv("PROJECT_ID")iid:=os.Getenv("SPANNER_INSTANCE_ID")did:=os.Getenv("SPANNER_DATABASE_ID")ifpid!="" && iid!="" && did!=""{db:=fmt.Sprintf("projects/%s/instances/%s/databases/%s",pid,iid,did)log.Printf("Creating Spanner client for %s",db)varerrerror//Usethebackgroundcontextwhencreatingtheclient,//butusetherequestcontextforcallstotheclient.//See:https://cloud.google.com/functions/docs/concepts/go-runtime#contextcontextclient,err=spanner.NewClient(context.Background(),db)iferr!=nil{log.Fatalf("spanner.NewClient: %v",err)}}}typequeryResultstruct{Actionstring`json:"action"`Parametersmap[string]interface{}`json:"parameters"`}typetextstruct{Text[]string`json:"text"`}typemessagestruct{Texttext`json:"text"`}//webhookRequestisusedtounmarshalaWebhookRequestJSONobject.Notethat//notallmembersneedtobedefined--justthosethatyouneedtoprocess.//Asanalternative,youcouldusethetypesprovidedby//theDialogflowprotocolbuffers://https://godoc.org/google.golang.org/genproto/googleapis/cloud/dialogflow/v2#WebhookRequesttypewebhookRequeststruct{Sessionstring`json:"session"`ResponseIDstring`json:"responseId"`QueryResultqueryResult`json:"queryResult"`}//webhookResponseisusedtomarshalaWebhookResponseJSONobject.Notethat//notallmembersneedtobedefined--justthosethatyouneedtoprocess.//Asanalternative,youcouldusethetypesprovidedby//theDialogflowprotocolbuffers://https://godoc.org/google.golang.org/genproto/googleapis/cloud/dialogflow/v2#WebhookResponsetypewebhookResponsestruct{FulfillmentMessages[]message`json:"fulfillmentMessages"`}//accountBalanceCheckhandlesthesimilarnamedactionfuncaccountBalanceCheck(ctxcontext.Context,requestwebhookRequest)(webhookResponse,error){account:=request.QueryResult.Parameters["account"].(string)account=strings.ToLower(account)vartablestringifaccount=="savings account"{table="Savings"}else{table="Checking"}s:="Your balance is $0"ifclient!=nil{//ASpannerclientexists,soaccessthedatabase.//See:https://pkg.go.dev/cloud.google.com/go/spanner#ReadOnlyTransaction.ReadRowrow,err:=client.Single().ReadRow(ctx,table,spanner.Key{1},//TheaccountID[]string{"Balance"})iferr!=nil{ifspanner.ErrCode(err)==codes.NotFound{log.Printf("Account %d not found",1)}else{returnwebhookResponse{},err}}else{//Arowwasreturned,socheckthevaluevarbalanceint64err:=row.Column(0, &balance)iferr!=nil{returnwebhookResponse{},err}s=fmt.Sprintf("Your balance is $%.2f",float64(balance)/100.0)}}response:=webhookResponse{FulfillmentMessages:[]message{{Text:text{Text:[]string{s},},},},}returnresponse,nil}//Defineatypeforhandlerfunctions.typehandlerFnfunc(ctxcontext.Context,requestwebhookRequest)(webhookResponse,error)//Createamapfromactiontohandlerfunction.varhandlersmap[string]handlerFn=map[string]handlerFn{"account.balance.check":accountBalanceCheck,}//handleErrorhandlesinternalerrors.funchandleError(whttp.ResponseWriter,errerror){log.Printf("ERROR: %v",err)http.Error(w,fmt.Sprintf("ERROR: %v",err),http.StatusInternalServerError)}//HandleWebhookRequesthandlesWebhookRequestandsendstheWebhookResponse.funcHandleWebhookRequest(whttp.ResponseWriter,r*http.Request){varrequestwebhookRequestvarresponsewebhookResponsevarerrerror//ReadinputJSONiferr=json.NewDecoder(r.Body).Decode(&request);err!=nil{handleError(w,err)return}log.Printf("Request: %+v",request)//Gettheactionfromtherequest,andcallthecorresponding//functionthathandlesthataction.action:=request.QueryResult.Actioniffn,ok:=handlers[action];ok{response,err=fn(r.Context(),request)}else{err=fmt.Errorf("Unknown action: %s",action)}iferr!=nil{handleError(w,err)return}log.Printf("Response: %+v",response)//Sendresponseiferr=json.NewEncoder(w).Encode(&response);err!=nil{handleError(w,err)return}}
Klik Deploy.
Tunggu hingga indikator status menunjukkan bahwa fungsi telah berhasil di-deploy.
Sambil menunggu, periksa kode yang baru saja Anda deploy.
Mengonfigurasi webhook untuk agen
Setelah webhook ada sebagai layanan,
Anda perlu mengaitkan webhook ini dengan agen Anda.
Hal ini dilakukan melalui fulfillment.
Untuk mengaktifkan dan mengelola fulfillment bagi agen Anda:
Berikan URL yang Anda salin dari atas.
Biarkan kolom lain kosong.
Klik Simpan di bagian bawah halaman.
Setelah fulfillment diaktifkan untuk agen,
Anda perlu mengaktifkan fulfillment untuk intent:
Pilih Intent di menu sidebar kiri.
Pilih intent account.balance.check.
Scroll ke bawah ke bagian Fulfillment.
Aktifkan Enable webhook call for this intent.
Klik Simpan.
Mencoba agen
Agen Anda kini siap untuk dicoba.
Klik tombol Test Agent untuk membuka simulator.
Coba lakukan percakapan berikut dengan agen:
Giliran percakapan
Anda
Agen
1
Halo
Halo, terima kasih telah memilih ACME Bank.
2
Saya ingin mengetahui saldo akun saya
Untuk akun mana Anda ingin mengetahui saldo: tabungan atau giro?
3
Giro
Berikut saldo terbaru Anda: $0,00
Pada giliran percakapan #3,
Anda memberikan "giro" sebagai jenis akun.
Intent account.balance.check memiliki parameter yang disebut account.
Parameter ini ditetapkan ke "checking" (memeriksa) dalam percakapan ini.
Intent juga memiliki nilai tindakan "account.balance.check".
Layanan webhook dipanggil,
dan parameter serta nilai tindakan diteruskan.
Jika memeriksa kode webhook di atas, Anda akan melihat bahwa tindakan ini memicu fungsi bernama serupa untuk dipanggil.
Fungsi ini menentukan saldo akun.
Fungsi ini memeriksa apakah variabel lingkungan tertentu ditetapkan
dengan informasi untuk terhubung ke database.
Jika variabel lingkungan ini tidak ditetapkan, fungsi akan menggunakan saldo akun yang di-hardcode.
Pada langkah berikutnya,
Anda akan mengubah lingkungan untuk fungsi tersebut
agar mengambil data dari database.
Pemecahan masalah
Kode webhook menyertakan pernyataan logging.
Jika Anda mengalami masalah, coba lihat log untuk fungsi Anda.
Informasi selengkapnya
Untuk informasi selengkapnya tentang langkah-langkah di atas, lihat:
[[["Mudah dipahami","easyToUnderstand","thumb-up"],["Memecahkan masalah saya","solvedMyProblem","thumb-up"],["Lainnya","otherUp","thumb-up"]],[["Sulit dipahami","hardToUnderstand","thumb-down"],["Informasi atau kode contoh salah","incorrectInformationOrSampleCode","thumb-down"],["Informasi/contoh yang saya butuhkan tidak ada","missingTheInformationSamplesINeed","thumb-down"],["Masalah terjemahan","translationIssue","thumb-down"],["Lainnya","otherDown","thumb-down"]],["Terakhir diperbarui pada 2025-09-04 UTC."],[[["\u003cp\u003eThis tutorial guides you through creating a webhook using Cloud Run functions to provide dynamic data, such as account balances, to a Dialogflow agent, enhancing its capabilities beyond hardcoded responses.\u003c/p\u003e\n"],["\u003cp\u003eThe webhook, hosted via Cloud Run functions, interacts with the Dialogflow agent through fulfillment, and this interaction is triggered by specific intents, in this example, the 'account.balance.check' intent.\u003c/p\u003e\n"],["\u003cp\u003eThe example uses the Go programming language to develop the webhook code, which can be viewed and edited inline within the Google Cloud console, and handles requests and responses between Dialogflow and a potential database.\u003c/p\u003e\n"],["\u003cp\u003eTo set up the webhook, you must first create a Cloud Run function within the same Google Cloud project as your Dialogflow agent, ensuring secure access, then configure fulfillment within Dialogflow, associating it with the created function's URL.\u003c/p\u003e\n"],["\u003cp\u003eAfter enabling the webhook for specific intents and configuring fulfillment, you can test the enhanced Dialogflow agent using the simulator, where the agent can now retrieve and display dynamic account balance information.\u003c/p\u003e\n"]]],[],null,["# Create a webhook service\n\nThe prebuilt agent you created in the last step\ncannot provide dynamic data like account balances,\nbecause everything is hardcoded into the agent.\nIn this step of the tutorial,\nyou will create a\n[webhook](/dialogflow/es/docs/fulfillment-overview)\nthat can provide dynamic data to the agent.\n[Cloud Run functions](/functions/docs)\nare used to host the webhook in this tutorial due to their simplicity,\nbut there are many other ways that you could host a webhook service.\nThe example also uses the Go programming language,\nbut you can use any\n[language supported by Cloud Run functions](/functions/docs/concepts/exec).\n\nCreate the Function\n-------------------\n\nCloud Run functions can be created with the Google Cloud console ([visit documentation](https://support.google.com/cloud/answer/3465889?ref_topic=3340599), [open console](https://console.cloud.google.com/)).\nTo create a function for this tutorial:\n\n1. It is important that your Dialogflow agent and the function\n are both in the same project.\n This is the easiest way for Dialogflow to have\n [secure access to your function](/dialogflow/es/docs/fulfillment-webhook#gcf).\n Before creating the function,\n select your project from the Google Cloud console.\n\n [Go to project selector](https://console.cloud.google.com/projectselector2/home/dashboard)\n2. Open the Cloud Run functions overview page.\n\n [Go to Cloud Run functions overview](https://console.cloud.google.com/functions/list)\n3. Click **Create Function**, and set the following fields:\n\n - **Environment**: 1st gen\n - **Function name**: tutorial-banking-webhook\n - **Region**: If you specified a region for your agent, use the same region.\n - **HTTP Trigger type**: HTTP\n - **URL**: Click the copy button here and save the value. You will need this URL when configuring the webhook.\n - **Authentication**: Require authentication\n - **Require HTTPS**: checked\n4. Click **Save**.\n\n5. Click **Next** (You do not need special runtime, build,\n connections, or security settings).\n\n6. Set the following fields:\n\n - **Runtime**: Select the latest Go runtime.\n - **Source code**: Inline Editor\n - **Entry point**: HandleWebhookRequest\n7. Replace the code with the following:\n\n ```python\n package estwh\n\n import (\n \t\"context\"\n \t\"encoding/json\"\n \t\"fmt\"\n \t\"log\"\n \t\"net/http\"\n \t\"os\"\n \t\"strings\"\n\n \t\"cloud.google.com/go/spanner\"\n \"google.golang.org/grpc/codes\"\n )\n\n // client is a Spanner client, created only once to avoid creation\n // for every request.\n // See: https://cloud.google.com/functions/docs/concepts/go-runtime#one-time_initialization\n var client *spanner.Client\n\n func init() {\n \t// If using a database, these environment variables will be set.\n \tpid := os.Getenv(\"PROJECT_ID\")\n \tiid := os.Getenv(\"SPANNER_INSTANCE_ID\")\n \tdid := os.Getenv(\"SPANNER_DATABASE_ID\")\n \tif pid != \"\" && iid != \"\" && did != \"\" {\n \t\tdb := fmt.Sprintf(\"projects/%s/instances/%s/databases/%s\",\n \t\t\tpid, iid, did)\n \t\tlog.Printf(\"Creating Spanner client for %s\", db)\n \t\tvar err error\n \t\t// Use the background context when creating the client,\n \t\t// but use the request context for calls to the client.\n \t\t// See: https://cloud.google.com/functions/docs/concepts/go-runtime#contextcontext\n \t\tclient, err = spanner.NewClient(context.Background(), db)\n \t\tif err != nil {\n \t\t\tlog.Fatalf(\"spanner.NewClient: %v\", err)\n \t\t}\n \t}\n }\n\n type queryResult struct {\n \tAction string `json:\"action\"`\n \tParameters map[string]interface{} `json:\"parameters\"`\n }\n\n type text struct {\n \tText []string `json:\"text\"`\n }\n\n type message struct {\n \tText text `json:\"text\"`\n }\n\n // webhookRequest is used to unmarshal a WebhookRequest JSON object. Note that\n // not all members need to be defined--just those that you need to process.\n // As an alternative, you could use the types provided by\n // the Dialogflow protocol buffers:\n // https://godoc.org/google.golang.org/genproto/googleapis/cloud/dialogflow/v2#WebhookRequest\n type webhookRequest struct {\n \tSession string `json:\"session\"`\n \tResponseID string `json:\"responseId\"`\n \tQueryResult queryResult `json:\"queryResult\"`\n }\n\n // webhookResponse is used to marshal a WebhookResponse JSON object. Note that\n // not all members need to be defined--just those that you need to process.\n // As an alternative, you could use the types provided by\n // the Dialogflow protocol buffers:\n // https://godoc.org/google.golang.org/genproto/googleapis/cloud/dialogflow/v2#WebhookResponse\n type webhookResponse struct {\n \tFulfillmentMessages []message `json:\"fulfillmentMessages\"`\n }\n\n // accountBalanceCheck handles the similar named action\n func accountBalanceCheck(ctx context.Context, request webhookRequest) (\n \twebhookResponse, error) {\n \taccount := request.QueryResult.Parameters[\"account\"].(string)\n \taccount = strings.ToLower(account)\n \tvar table string\n \tif account == \"savings account\" {\n \t\ttable = \"Savings\"\n \t} else {\n \t\ttable = \"Checking\"\n \t}\n \ts := \"Your balance is $0\"\n \tif client != nil {\n \t\t// A Spanner client exists, so access the database.\n \t\t// See: https://pkg.go.dev/cloud.google.com/go/spanner#ReadOnlyTransaction.ReadRow\n \t\trow, err := client.Single().ReadRow(ctx,\n \t\t\ttable,\n \t\t\tspanner.Key{1}, // The account ID\n \t\t\t[]string{\"Balance\"})\n \t\tif err != nil {\n \t\t\tif spanner.ErrCode(err) == codes.NotFound {\n \t\t\t\tlog.Printf(\"Account %d not found\", 1)\n \t\t\t} else {\n \t\t\t\treturn webhookResponse{}, err\n \t\t\t}\n \t\t} else {\n \t\t\t// A row was returned, so check the value\n \t\t\tvar balance int64\n \t\t\terr := row.Column(0, &balance)\n \t\t\tif err != nil {\n \t\t\t\treturn webhookResponse{}, err\n \t\t\t}\n \t\t\ts = fmt.Sprintf(\"Your balance is $%.2f\", float64(balance)/100.0)\n \t\t}\n \t}\n \tresponse := webhookResponse{\n \t\tFulfillmentMessages: []message{\n \t\t\t{\n \t\t\t\tText: text{\n \t\t\t\t\tText: []string{s},\n \t\t\t\t},\n \t\t\t},\n \t\t},\n \t}\n \treturn response, nil\n }\n\n // Define a type for handler functions.\n type handlerFn func(ctx context.Context, request webhookRequest) (\n \twebhookResponse, error)\n\n // Create a map from action to handler function.\n var handlers map[string]handlerFn = map[string]handlerFn{\n \t\"account.balance.check\": accountBalanceCheck,\n }\n\n // handleError handles internal errors.\n func handleError(w http.ResponseWriter, err error) {\n \tlog.Printf(\"ERROR: %v\", err)\n \thttp.Error(w,\n \t\tfmt.Sprintf(\"ERROR: %v\", err),\n \t\thttp.StatusInternalServerError)\n }\n\n // HandleWebhookRequest handles WebhookRequest and sends the WebhookResponse.\n func HandleWebhookRequest(w http.ResponseWriter, r *http.Request) {\n \tvar request webhookRequest\n \tvar response webhookResponse\n \tvar err error\n\n \t// Read input JSON\n \tif err = json.NewDecoder(r.Body).Decode(&request); err != nil {\n \t\thandleError(w, err)\n \t\treturn\n \t}\n \tlog.Printf(\"Request: %+v\", request)\n\n \t// Get the action from the request, and call the corresponding\n \t// function that handles that action.\n \taction := request.QueryResult.Action\n \tif fn, ok := handlers[action]; ok {\n \t\tresponse, err = fn(r.Context(), request)\n \t} else {\n \t\terr = fmt.Errorf(\"Unknown action: %s\", action)\n \t}\n \tif err != nil {\n \t\thandleError(w, err)\n \t\treturn\n \t}\n \tlog.Printf(\"Response: %+v\", response)\n\n \t// Send response\n \tif err = json.NewEncoder(w).Encode(&response); err != nil {\n \t\thandleError(w, err)\n \t\treturn\n \t}\n }\n ```\n\n \u003cbr /\u003e\n\n8. Click **Deploy**.\n\n9. Wait until the status indicator shows that the function\n has successfully deployed.\n While waiting, examine the code you just deployed.\n\nConfigure the webhook for your agent\n------------------------------------\n\nNow that the webhook exists as a service,\nyou need to associate this webhook with your agent.\nThis is done via fulfillment.\nTo enable and manage fulfillment for your agent:\n\n1. Go to the [Dialogflow ES console](https://dialogflow.cloud.google.com).\n2. Select the pre-built agent you just created.\n3. Select **Fulfillment** in the left sidebar menu.\n4. Toggle the **Webhook** field to **Enabled**.\n5. Provide the URL that you copied from above. Leave all other fields blank.\n6. Click **Save** at the bottom of the page.\n\nNow that fulfillment is enabled for the agent,\nyou need to enable fulfillment for an intent:\n\n1. Select **Intents** in the left sidebar menu.\n2. Select the **account.balance.check** intent.\n3. Scroll down to the **Fulfillment** section.\n4. Toggle **Enable webhook call for this intent** to on.\n5. Click **Save**.\n\nTry the agent\n-------------\n\nYour agent is now ready to try.\nClick the **Test Agent** button to open the simulator.\nAttempt to have the following conversation with the agent:\n\nAt conversational turn #3,\nyou supplied \"checking\" as the account type.\nThe **account.balance.check** intent has a parameter called **account**.\nThis parameter is set to \"checking\" in this conversation.\nThe intent also has an action value of \"account.balance.check\".\nThe webhook service is called,\nand it is passed the parameter and action values.\n\nIf you examine the webhook code above,\nyou see that this action triggers a similar named function to be called.\nThe function determines the account balance.\nThe function checks whether specific environment variables are set\nwith information for connecting to the database.\nIf these environment variables are not set,\nthe function uses a hardcoded account balance.\nIn upcoming steps,\nyou will alter the environment for the function\nso that it retrieves data from a database.\n\nTroubleshooting\n---------------\n\nThe webhook code includes logging statements.\nIf you are having issues, try viewing the logs for your function.\n\nMore information\n----------------\n\nFor more information about the steps above, see:\n\n- [Cloud Run functions Go quickstart](/functions/docs/console-quickstart-1st-gen)"]]