♊️ GemiNews 🗞️
🏡
📰 Articles
🏷️ Tags
🧠 Queries
📈 Graphs
☁️ Stats
💁🏻 Assistant
Demo 1: Embeddings + Recommendation
Demo 2: Bella RAGa
Demo 3: NewRetriever
Demo 4: Assistant function calling
Editing article
Title
Summary
Content
<figure><img alt="" src="https://cdn-images-1.medium.com/max/738/1*cwsJqTsvzudgNKgCZqg8ow.png" /><figcaption>Navigate better with deterministic Generative AI & Reverse Geocoding API</figcaption></figure><p>Generative AI models are remarkable at understanding and responding to natural language. But what if you need precise, predictable outputs for critical tasks like address standardization? Traditional generative models can sometimes provide different responses at different times for the same prompts, potentially leading to inconsistencies. That’s where Gemini’s Function Calling capability shines, allowing you to deterministically control elements of the AI’s response.</p><p>In this blog, we’ll illustrate this concept with the address completion and standardization use case. For this we will be building a Java Cloud Function that:</p><ol><li><strong>Takes latitude and longitude coordinates</strong></li><li><strong>Calls the Google Maps Geocoding API to get corresponding addresses</strong></li><li><strong>Uses Gemini 1.o Pro Function Calling feature to deterministically standardize and summarize those addresses in a specific format that we need</strong></li></ol><p>Let’s dive in!</p><h3>Gemini Function Calling</h3><p>Gemini Function Calling stands out in the Generative AI era because it lets you blend the flexibility of generative language models with the precision of traditional programming. Here’s how it works:</p><p><strong>Defining Functions:</strong> You describe functions as if you were explaining them to a coworker. These descriptions include:</p><ol><li>The function’s name (e.g., “getAddress”)</li><li>The parameters it expects (e.g., “latlng” as a string)</li><li>The type of data it returns (e.g., a list of address strings)</li></ol><p><strong>“Tools” for Gemini:</strong> You package function descriptions in the form of API specification into “Tools”. Think of a tool as a specialized toolbox Gemini can use to understand the functionality of the API.</p><p><strong>Gemini as API Orchestrator:</strong> When you send a prompt to Gemini, it can analyze your request and recognize where it can use the tools you’ve provided. Gemini then acts as a smart orchestrator:</p><ol><li>Generates API Parameters: It produces the necessary parameters to call your defined functions.</li><li>Calls External APIs: Gemini doesn’t call the API on your behalf. You call the API based on the parameters and signature that Gemini function calling has generated for you.</li><li>Processes Results: Gemini feeds the results from your API calls back into its generation, letting it incorporate structured information into its final response which you can process in any way you desire for your application.</li></ol><h3>High Level Flow Diagram</h3><p>This diagram represents the flow of data and steps involved in the implementation. Please note that the owner for the respective step is mentioned in the text underneath.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2-HYu2sGPsNwe46UdJuVdA.png" /><figcaption>High level flow diagram of the implementation</figcaption></figure><h3>Industry Use cases and why it matters</h3><p>Below are some of the examples and industry specific use cases for function calling with Gemini.</p><ol><li><strong>Geocoding (Our Use Case):</strong> You’ve seen how to define a “getAddress” function and use it within the context of address standardization.</li><li><strong>Data Validation:</strong> Imagine a function called “validateEmail” that takes a string and checks it against an email validation service. Gemini can help you formulate the parameters string so you can call the email validation API to ensure the quality of generated responses. Remember, Gemini does not make the API call for you.</li><li><strong>Fact-Checking:</strong> Define a “lookupFact” function. Gemini could use this to consult a trusted knowledge base, making its responses more reliable within specific domains.</li></ol><p><strong>Why Function Calling Matters</strong></p><p><strong>Bridging Two Worlds:</strong> LLMs can’t know everything (especially private information, customer details, news that are more recent than its knowledge cut-off date), and by integrating function calling, it’s able to extend its knowledge and capabilities to bridge the gap between open-ended generative AI and the deterministic execution of traditional code.</p><p><strong>Controlled Creativity:</strong> Function Calling injects structured, predictable elements into Gemini’s creative process, ideal for critical use cases or maintaining consistency.</p><p><strong>Building Agent:</strong> Chain together multiple function calls and Gemini processing steps, enabling multi-stage generative AI workflows.</p><h3>Create the Java Cloud Function</h3><p>This is the Gen 2 Cloud Function implementation where we will invoke the Gemini model to orchestrate the input for function Calling, invoke the API and then process the response in another Gemini call and deploy it to a REST endpoint.</p><h3>Setup</h3><ol><li>In the <a href="https://console.cloud.google.com/">Google Cloud Console</a>, on the project selector page, select or create a Google Cloud <a href="https://cloud.google.com/resource-manager/docs/creating-managing-projects">project</a>.</li><li>Make sure that billing is enabled for your Cloud project. Learn how to <a href="https://cloud.google.com/billing/docs/how-to/verify-billing-enabled">check if billing is enabled on a project</a>.</li><li>You will use Cloud Shell, a command-line environment running in Google Cloud that comes preloaded with bq. From the Cloud Console, click Activate Cloud Shell on the top right corner.</li><li>Just for support with building and delivering the app, let’s enable Duet AI. Navigate to <a href="https://console.cloud.google.com/marketplace/product/google/cloudaicompanion.googleapis.com">Duet AI Marketplace</a> to enable the API. You can also run the following command in the Cloud Shell terminal:</li></ol><pre>gcloud services enable cloudaicompanion.googleapis.com –project PROJECT_ID</pre><p>5. Enable necessary APIs for this implementation if you haven’t already.</p><p>Alternative to the gcloud command is through the console using this <a href="https://console.cloud.google.com/apis/enableflow?apiid=bigquery.googleapis.com,bigqueryconnection.googleapis.com,aiplatform.googleapis.com">link</a>.</p><h3>Java Cloud Function</h3><ol><li>Open Cloud Shell Terminal and navigate to the root directory or your default workspace path.</li><li>Click the Cloud Code Sign In icon from the bottom left corner of the status bar and select the active Google Cloud Project that you want to create the Cloud Functions in.</li><li>Click the same icon again and this time select the option to create a new application.</li><li>In the Create New Application pop-up, select Cloud Functions application:</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*n53iiiF7ZuyG9J4U" /><figcaption>Create New Application page 1</figcaption></figure><p>5. Select Java: Hello World option from the next pop-up:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*jRH5u3oXSLqx-a_k" /><figcaption>Create New Application page 2</figcaption></figure><p>6. Provide a name for the project in the project path. In this case, “GeminiFunctionCalling”.</p><p>7. You should see the project structure opened up in a new Cloud Shell Editor view:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*z7PMp8qsGOUik2j1" /><figcaption>Cloud Shell Editor showing the project structure with pom.xml open</figcaption></figure><p>8. Now go ahead and add the necessary dependencies within the <dependencies>… </dependencies> tag in the pom.xml file. You can access the entire <a href="https://github.com/AbiramiSukumaran/GeminiFunctionCalling/blob/main/pom.xml">pom.xml</a> from this project’s github <a href="https://github.com/AbiramiSukumaran/GeminiFunctionCalling">repository</a>.</p><pre><dependency><br> <groupId>com.google.cloud</groupId><br> <artifactId>google-cloud-vertexai</artifactId><br></dependency><br><br><dependency><br> <groupId>com.google.code.gson</groupId><br> <artifactId>gson</artifactId><br> <version>2.10</version><br></dependency></pre><p>9. You can access the entire HelloWorld.java (or whatever you changed it to) class from the github <a href="https://github.com/AbiramiSukumaran/GeminiFunctionCalling/blob/main/src/main/java/cloudcode/helloworld/HelloWorld.java">link</a>. Let’s understand Function Calling by breaking down this class:</p><p><strong>Prompt Input:<br></strong>In this example, this is what the input prompt looks like:</p><pre>“What's the address for the latlong value 40.714224,-73.961452”</pre><p>You can find the below code snippet relevant to the input prompt in the file:</p><pre>String promptText = "What's the address for the latlong value '" + latlngString + "'?"; //40.714224,-73.961452</pre><p><strong>API Specification / Signature Definition:<br></strong>We decided to use the <a href="https://developers.google.com/maps/documentation/geocoding/requests-reverse-geocoding">Reverse Geocoding API</a>. In this example, this is what the API spec looks like:</p><pre>/* Declare the function for the API that we want to invoke (Geo coding API) */<br> FunctionDeclaration functionDeclaration = FunctionDeclaration.newBuilder()<br> .setName("getAddress")<br> .setDescription("Get the address for the given latitude and longitude value.")<br> .setParameters(<br> Schema.newBuilder()<br> .setType(Type.OBJECT)<br> .putProperties("latlng", Schema.newBuilder()<br> .setType(Type.STRING)<br> .setDescription("This must be a string of latitude and longitude coordinates separated by comma")<br> .build())<br> .addRequired("latlng")<br> .build())<br> .build();</pre><p><strong>Gemini to orchestrate the prompt with the API specification:<br></strong>This is the part where we send the prompt input and the API spec to Gemini:</p><pre>// Add the function to a "tool"<br> Tool tool = Tool.newBuilder()<br> .addFunctionDeclarations(functionDeclaration)<br> .build();<br><br><br>// Invoke the Gemini model with the use of the tool to generate the API parameters from the prompt input.<br>GenerativeModel model = GenerativeModel.newBuilder()<br> .setModelName(modelName)<br> .setVertexAi(vertexAI)<br> .setTools(Arrays.asList(tool))<br> .build();<br>GenerateContentResponse response = model.generateContent(promptText);<br>Content responseJSONCnt = response.getCandidates(0).getContent();</pre><p>The response from this is the orchestrated parameters JSON to the API. Output from this step would look like below:</p><pre>role: "model"<br>parts {<br> function_call {<br> name: "getAddress"<br> args {<br> fields {<br> key: "latlng"<br> value {<br> string_value: "40.714224,-73.961452"<br> }<br> }<br> }<br> }<br>}</pre><p>The parameter that needs to be passed to the Reverse Geocoding API is this:</p><p>“latlng=40.714224,-73.961452”</p><p>From the Content object, you can get the Part, call the hasFunctionCall() method to know if it has a function call request that’s returned by the LLM. Call getFunctionCall() to get a FunctionCall object. Use the hasArgs() method to check if there are arguments, and then a getArgs() method to get the actual arguments. It’s a protobuf Struct object. Match the orchestrated result to the format “latlng=VALUE”. Refer to the full code <a href="https://github.com/AbiramiSukumaran/GeminiFunctionCalling/blob/main/src/main/java/cloudcode/helloworld/HelloWorld.java">here</a>.</p><p><strong>Invoke the API:<br></strong>At this point you have everything you need to invoke the API. The part of the code that does it is below:</p><pre>// Create a request<br> String url = API_STRING + "?key=" + API_KEY + params;<br> java.net.http.HttpRequest request = java.net.http.HttpRequest.newBuilder()<br> .uri(URI.create(url))<br> .GET()<br> .build();<br> // Send the request and get the response<br> java.net.http.HttpResponse<String> httpresponse = client.send(request, java.net.http.HttpResponse.BodyHandlers.ofString());<br> // Save the response<br> String jsonResult = httpresponse.body().toString();</pre><p>The string jsonResult holds the stringified response from the reverse Geocoding API. It looks something like this: (This is a formatted version of the output. Please note the result is truncated as well).</p><pre>“...277 Bedford Ave, Brooklyn, NY 11211, USA; 279 Bedford Ave, Brooklyn, NY 11211, USA; 277 Bedford Ave, Brooklyn, NY 11211, USA;...”</pre><p><strong>Process the API response and prepare the prompt:<br></strong>The below code processes the response from the API and prepares the prompt with instructions on how to process the response:</p><pre>// Provide an answer to the model so that it knows what the result<br> // of a "function call" is.<br> String promptString =<br> "You are an AI address standardizer for assisting with standardizing addresses accurately. Your job is to give the accurate address in the standard format as a JSON object containing the fields DOOR_NUMBER, STREET_ADDRESS, AREA, CITY, TOWN, COUNTY, STATE, COUNTRY, ZIPCODE, LANDMARK by leveraging the address string that follows in the end. Remember the response cannot be empty or null. ";<br><br><br>Content content =<br> ContentMaker.fromMultiModalData(<br> PartMaker.fromFunctionResponse(<br> "getAddress",<br> Collections.singletonMap("address", formattedAddress)));<br> String contentString = content.toString();<br> String address = contentString.substring(contentString.indexOf("string_value: \"") + "string_value: \"".length(), contentString.indexOf('"', contentString.indexOf("string_value: \"") + "string_value: \"".length()));<br><br><br> List<SafetySetting> safetySettings = Arrays.asList(<br> SafetySetting.newBuilder()<br> .setCategory(HarmCategory.HARM_CATEGORY_HATE_SPEECH)<br> .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_ONLY_HIGH)<br> .build(),<br> SafetySetting.newBuilder()<br> .setCategory(HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT)<br> .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_ONLY_HIGH)<br> .build()<br> );</pre><p><strong>Invoke Gemini and return the standardized address :<br></strong>The below code passes the processed output from the above step as prompt to Gemini:</p><pre>GenerativeModel modelForFinalResponse = GenerativeModel.newBuilder()<br> .setModelName(modelName)<br> .setVertexAi(vertexAI)<br> .build();<br> GenerateContentResponse finalResponse = modelForFinalResponse.generateContent(promptString + ": " + address, safetySettings);<br> System.out.println("promptString + content: " + promptString + ": " + address);<br> // See what the model replies now<br> System.out.println("Print response: ");<br> System.out.println(finalResponse.toString());<br> String finalAnswer = ResponseHandler.getText(finalResponse);<br> System.out.println(finalAnswer);</pre><p>The finalAnswer variable has the standardized address in JSON format. Sample output below:</p><pre>{"replies":["{ \"DOOR_NUMBER\": null, \"STREET_ADDRESS\": \"277 Bedford Ave\", \"AREA\": \"Brooklyn\", \"CITY\": \"New York\", \"TOWN\": null, \"COUNTY\": null, \"STATE\": \"NY\", \"COUNTRY\": \"USA\", \"ZIPCODE\": \"11211\", \"LANDMARK\": null} null}"]}</pre><p>Now that you have understood how Gemini Function Calling works with the address standardization use case, go ahead and deploy the Cloud Function.</p><p>10. Now that you have understood how Gemini Function Calling works with the address standardization use case, go ahead and deploy the Cloud Function.</p><pre>gcloud functions deploy gemini-fn-calling --gen2 --region=us-central1 --runtime=java11 --source=. --entry-point=cloudcode.helloworld.HelloWorld --trigger-http</pre><p>The result for this deploy command would be a REST URL in the format as below :</p><p><a href="https://us-central1-YOUR_PROJECT_ID.cloudfunctions.net/gemini-fn-calling"><strong>https://us-central1-YOUR_PROJECT_ID.cloudfunctions.net/gemini-fn-calling</strong></a></p><p>11. Test this Cloud Function by running the following command from the terminal:</p><pre>gcloud functions call gemini-fn-calling --region=us-central1 --gen2 --data '{"calls":[["40.714224,-73.961452"]]}'</pre><p>Response for a random sample prompt:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*L2ME8WPaWun8XBIX" /><figcaption>Cloud Shell Terminal response for the Cloud Function call</figcaption></figure><pre> '{"replies":["{ \"DOOR_NUMBER\": \"277\", \"STREET_ADDRESS\": \"Bedford Ave\", \"AREA\":<br> null, \"CITY\": \"Brooklyn\", \"TOWN\": null, \"COUNTY\": \"Kings County\", \"STATE\":<br> \"NY\", \"COUNTRY\": \"USA\", \"ZIPCODE\": \"11211\", \"LANDMARK\": null}}```"]}'</pre><p>The request and response parameters of this Cloud Function are implemented in a way that is compatible with BigQuery’s remote function invocation. It can be directly consumed from BigQuery data in-place. It means that if your data input (lat and long data) lives in BigQuery then you can call the remote function on the data and get the function response which can be stored or processed within BigQuery directly. To learn how to leverage this Cloud Function in performing in-place LLM insights on your database, refer to this <a href="https://medium.com/google-cloud/in-place-llm-insights-bigquery-gemini-for-structured-unstructured-data-analytics-fdfac0421626">blog</a>.</p><h3>Conclusion</h3><p>This project has demonstrated the power of Gemini Function Calling, transforming a generative AI task into a deterministic, reliable process. If you work with generative AI, don’t let its sometimes-unpredictable nature hold you back. Use the power of Gemini 1.0 Pro Function Calling feature and create applications that are as innovative as they are dependable. Start exploring how you can incorporate this feature into your own work! Are there datasets you could validate, information gaps you could fill, or tasks that could be automated with structured calls embedded within your generative AI responses? Here is the link to the <a href="https://github.com/AbiramiSukumaran/GeminiFunctionCalling">repo</a> and for further reading, refer to the documentation for <a href="https://cloud.google.com/vertex-ai">Vertex AI</a>, <a href="https://cloud.google.com/bigquery/docs/remote-functions">BigQuery Remote Functions</a>, and <a href="https://cloud.google.com/functions">Cloud Functions</a> for more in-depth guidance in these areas.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4c86a5ab80a9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/google-cloud/using-gemini-function-calling-in-java-for-deterministic-generative-ai-responses-4c86a5ab80a9">Deterministic Generative AI with Gemini Function Calling in Java</a> was originally published in <a href="https://medium.com/google-cloud">Google Cloud - Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>
Author
Link
Published date
Image url
Feed url
Guid
Hidden blurb
--- !ruby/object:Feedjira::Parser::RSSEntry title: Deterministic Generative AI with Gemini Function Calling in Java url: https://medium.com/google-cloud/using-gemini-function-calling-in-java-for-deterministic-generative-ai-responses-4c86a5ab80a9?source=rss----e52cf94d98af---4 author: Abirami Sukumaran categories: - calling-function - google-cloud-platform - gcp-app-dev - gemini - generative-ai published: 2024-04-03 04:48:45.000000000 Z entry_id: !ruby/object:Feedjira::Parser::GloballyUniqueIdentifier is_perma_link: 'false' guid: https://medium.com/p/4c86a5ab80a9 carlessian_info: news_filer_version: 2 newspaper: Google Cloud - Medium macro_region: Blogs rss_fields: - title - url - author - categories - published - entry_id - content content: '<figure><img alt="" src="https://cdn-images-1.medium.com/max/738/1*cwsJqTsvzudgNKgCZqg8ow.png" /><figcaption>Navigate better with deterministic Generative AI & Reverse Geocoding API</figcaption></figure><p>Generative AI models are remarkable at understanding and responding to natural language. But what if you need precise, predictable outputs for critical tasks like address standardization? Traditional generative models can sometimes provide different responses at different times for the same prompts, potentially leading to inconsistencies. That’s where Gemini’s Function Calling capability shines, allowing you to deterministically control elements of the AI’s response.</p><p>In this blog, we’ll illustrate this concept with the address completion and standardization use case. For this we will be building a Java Cloud Function that:</p><ol><li><strong>Takes latitude and longitude coordinates</strong></li><li><strong>Calls the Google Maps Geocoding API to get corresponding addresses</strong></li><li><strong>Uses Gemini 1.o Pro Function Calling feature to deterministically standardize and summarize those addresses in a specific format that we need</strong></li></ol><p>Let’s dive in!</p><h3>Gemini Function Calling</h3><p>Gemini Function Calling stands out in the Generative AI era because it lets you blend the flexibility of generative language models with the precision of traditional programming. Here’s how it works:</p><p><strong>Defining Functions:</strong> You describe functions as if you were explaining them to a coworker. These descriptions include:</p><ol><li>The function’s name (e.g., “getAddress”)</li><li>The parameters it expects (e.g., “latlng” as a string)</li><li>The type of data it returns (e.g., a list of address strings)</li></ol><p><strong>“Tools” for Gemini:</strong> You package function descriptions in the form of API specification into “Tools”. Think of a tool as a specialized toolbox Gemini can use to understand the functionality of the API.</p><p><strong>Gemini as API Orchestrator:</strong> When you send a prompt to Gemini, it can analyze your request and recognize where it can use the tools you’ve provided. Gemini then acts as a smart orchestrator:</p><ol><li>Generates API Parameters: It produces the necessary parameters to call your defined functions.</li><li>Calls External APIs: Gemini doesn’t call the API on your behalf. You call the API based on the parameters and signature that Gemini function calling has generated for you.</li><li>Processes Results: Gemini feeds the results from your API calls back into its generation, letting it incorporate structured information into its final response which you can process in any way you desire for your application.</li></ol><h3>High Level Flow Diagram</h3><p>This diagram represents the flow of data and steps involved in the implementation. Please note that the owner for the respective step is mentioned in the text underneath.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2-HYu2sGPsNwe46UdJuVdA.png" /><figcaption>High level flow diagram of the implementation</figcaption></figure><h3>Industry Use cases and why it matters</h3><p>Below are some of the examples and industry specific use cases for function calling with Gemini.</p><ol><li><strong>Geocoding (Our Use Case):</strong> You’ve seen how to define a “getAddress” function and use it within the context of address standardization.</li><li><strong>Data Validation:</strong> Imagine a function called “validateEmail” that takes a string and checks it against an email validation service. Gemini can help you formulate the parameters string so you can call the email validation API to ensure the quality of generated responses. Remember, Gemini does not make the API call for you.</li><li><strong>Fact-Checking:</strong> Define a “lookupFact” function. Gemini could use this to consult a trusted knowledge base, making its responses more reliable within specific domains.</li></ol><p><strong>Why Function Calling Matters</strong></p><p><strong>Bridging Two Worlds:</strong> LLMs can’t know everything (especially private information, customer details, news that are more recent than its knowledge cut-off date), and by integrating function calling, it’s able to extend its knowledge and capabilities to bridge the gap between open-ended generative AI and the deterministic execution of traditional code.</p><p><strong>Controlled Creativity:</strong> Function Calling injects structured, predictable elements into Gemini’s creative process, ideal for critical use cases or maintaining consistency.</p><p><strong>Building Agent:</strong> Chain together multiple function calls and Gemini processing steps, enabling multi-stage generative AI workflows.</p><h3>Create the Java Cloud Function</h3><p>This is the Gen 2 Cloud Function implementation where we will invoke the Gemini model to orchestrate the input for function Calling, invoke the API and then process the response in another Gemini call and deploy it to a REST endpoint.</p><h3>Setup</h3><ol><li>In the <a href="https://console.cloud.google.com/">Google Cloud Console</a>, on the project selector page, select or create a Google Cloud <a href="https://cloud.google.com/resource-manager/docs/creating-managing-projects">project</a>.</li><li>Make sure that billing is enabled for your Cloud project. Learn how to <a href="https://cloud.google.com/billing/docs/how-to/verify-billing-enabled">check if billing is enabled on a project</a>.</li><li>You will use Cloud Shell, a command-line environment running in Google Cloud that comes preloaded with bq. From the Cloud Console, click Activate Cloud Shell on the top right corner.</li><li>Just for support with building and delivering the app, let’s enable Duet AI. Navigate to <a href="https://console.cloud.google.com/marketplace/product/google/cloudaicompanion.googleapis.com">Duet AI Marketplace</a> to enable the API. You can also run the following command in the Cloud Shell terminal:</li></ol><pre>gcloud services enable cloudaicompanion.googleapis.com –project PROJECT_ID</pre><p>5. Enable necessary APIs for this implementation if you haven’t already.</p><p>Alternative to the gcloud command is through the console using this <a href="https://console.cloud.google.com/apis/enableflow?apiid=bigquery.googleapis.com,bigqueryconnection.googleapis.com,aiplatform.googleapis.com">link</a>.</p><h3>Java Cloud Function</h3><ol><li>Open Cloud Shell Terminal and navigate to the root directory or your default workspace path.</li><li>Click the Cloud Code Sign In icon from the bottom left corner of the status bar and select the active Google Cloud Project that you want to create the Cloud Functions in.</li><li>Click the same icon again and this time select the option to create a new application.</li><li>In the Create New Application pop-up, select Cloud Functions application:</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*n53iiiF7ZuyG9J4U" /><figcaption>Create New Application page 1</figcaption></figure><p>5. Select Java: Hello World option from the next pop-up:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*jRH5u3oXSLqx-a_k" /><figcaption>Create New Application page 2</figcaption></figure><p>6. Provide a name for the project in the project path. In this case, “GeminiFunctionCalling”.</p><p>7. You should see the project structure opened up in a new Cloud Shell Editor view:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*z7PMp8qsGOUik2j1" /><figcaption>Cloud Shell Editor showing the project structure with pom.xml open</figcaption></figure><p>8. Now go ahead and add the necessary dependencies within the <dependencies>… </dependencies> tag in the pom.xml file. You can access the entire <a href="https://github.com/AbiramiSukumaran/GeminiFunctionCalling/blob/main/pom.xml">pom.xml</a> from this project’s github <a href="https://github.com/AbiramiSukumaran/GeminiFunctionCalling">repository</a>.</p><pre><dependency><br> <groupId>com.google.cloud</groupId><br> <artifactId>google-cloud-vertexai</artifactId><br></dependency><br><br><dependency><br> <groupId>com.google.code.gson</groupId><br> <artifactId>gson</artifactId><br> <version>2.10</version><br></dependency></pre><p>9. You can access the entire HelloWorld.java (or whatever you changed it to) class from the github <a href="https://github.com/AbiramiSukumaran/GeminiFunctionCalling/blob/main/src/main/java/cloudcode/helloworld/HelloWorld.java">link</a>. Let’s understand Function Calling by breaking down this class:</p><p><strong>Prompt Input:<br></strong>In this example, this is what the input prompt looks like:</p><pre>“What's the address for the latlong value 40.714224,-73.961452”</pre><p>You can find the below code snippet relevant to the input prompt in the file:</p><pre>String promptText = "What's the address for the latlong value '" + latlngString + "'?"; //40.714224,-73.961452</pre><p><strong>API Specification / Signature Definition:<br></strong>We decided to use the <a href="https://developers.google.com/maps/documentation/geocoding/requests-reverse-geocoding">Reverse Geocoding API</a>. In this example, this is what the API spec looks like:</p><pre>/* Declare the function for the API that we want to invoke (Geo coding API) */<br> FunctionDeclaration functionDeclaration = FunctionDeclaration.newBuilder()<br> .setName("getAddress")<br> .setDescription("Get the address for the given latitude and longitude value.")<br> .setParameters(<br> Schema.newBuilder()<br> .setType(Type.OBJECT)<br> .putProperties("latlng", Schema.newBuilder()<br> .setType(Type.STRING)<br> .setDescription("This must be a string of latitude and longitude coordinates separated by comma")<br> .build())<br> .addRequired("latlng")<br> .build())<br> .build();</pre><p><strong>Gemini to orchestrate the prompt with the API specification:<br></strong>This is the part where we send the prompt input and the API spec to Gemini:</p><pre>// Add the function to a "tool"<br> Tool tool = Tool.newBuilder()<br> .addFunctionDeclarations(functionDeclaration)<br> .build();<br><br><br>// Invoke the Gemini model with the use of the tool to generate the API parameters from the prompt input.<br>GenerativeModel model = GenerativeModel.newBuilder()<br> .setModelName(modelName)<br> .setVertexAi(vertexAI)<br> .setTools(Arrays.asList(tool))<br> .build();<br>GenerateContentResponse response = model.generateContent(promptText);<br>Content responseJSONCnt = response.getCandidates(0).getContent();</pre><p>The response from this is the orchestrated parameters JSON to the API. Output from this step would look like below:</p><pre>role: "model"<br>parts {<br> function_call {<br> name: "getAddress"<br> args {<br> fields {<br> key: "latlng"<br> value {<br> string_value: "40.714224,-73.961452"<br> }<br> }<br> }<br> }<br>}</pre><p>The parameter that needs to be passed to the Reverse Geocoding API is this:</p><p>“latlng=40.714224,-73.961452”</p><p>From the Content object, you can get the Part, call the hasFunctionCall() method to know if it has a function call request that’s returned by the LLM. Call getFunctionCall() to get a FunctionCall object. Use the hasArgs() method to check if there are arguments, and then a getArgs() method to get the actual arguments. It’s a protobuf Struct object. Match the orchestrated result to the format “latlng=VALUE”. Refer to the full code <a href="https://github.com/AbiramiSukumaran/GeminiFunctionCalling/blob/main/src/main/java/cloudcode/helloworld/HelloWorld.java">here</a>.</p><p><strong>Invoke the API:<br></strong>At this point you have everything you need to invoke the API. The part of the code that does it is below:</p><pre>// Create a request<br> String url = API_STRING + "?key=" + API_KEY + params;<br> java.net.http.HttpRequest request = java.net.http.HttpRequest.newBuilder()<br> .uri(URI.create(url))<br> .GET()<br> .build();<br> // Send the request and get the response<br> java.net.http.HttpResponse<String> httpresponse = client.send(request, java.net.http.HttpResponse.BodyHandlers.ofString());<br> // Save the response<br> String jsonResult = httpresponse.body().toString();</pre><p>The string jsonResult holds the stringified response from the reverse Geocoding API. It looks something like this: (This is a formatted version of the output. Please note the result is truncated as well).</p><pre>“...277 Bedford Ave, Brooklyn, NY 11211, USA; 279 Bedford Ave, Brooklyn, NY 11211, USA; 277 Bedford Ave, Brooklyn, NY 11211, USA;...”</pre><p><strong>Process the API response and prepare the prompt:<br></strong>The below code processes the response from the API and prepares the prompt with instructions on how to process the response:</p><pre>// Provide an answer to the model so that it knows what the result<br> // of a "function call" is.<br> String promptString =<br> "You are an AI address standardizer for assisting with standardizing addresses accurately. Your job is to give the accurate address in the standard format as a JSON object containing the fields DOOR_NUMBER, STREET_ADDRESS, AREA, CITY, TOWN, COUNTY, STATE, COUNTRY, ZIPCODE, LANDMARK by leveraging the address string that follows in the end. Remember the response cannot be empty or null. ";<br><br><br>Content content =<br> ContentMaker.fromMultiModalData(<br> PartMaker.fromFunctionResponse(<br> "getAddress",<br> Collections.singletonMap("address", formattedAddress)));<br> String contentString = content.toString();<br> String address = contentString.substring(contentString.indexOf("string_value: \"") + "string_value: \"".length(), contentString.indexOf('"', contentString.indexOf("string_value: \"") + "string_value: \"".length()));<br><br><br> List<SafetySetting> safetySettings = Arrays.asList(<br> SafetySetting.newBuilder()<br> .setCategory(HarmCategory.HARM_CATEGORY_HATE_SPEECH)<br> .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_ONLY_HIGH)<br> .build(),<br> SafetySetting.newBuilder()<br> .setCategory(HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT)<br> .setThreshold(SafetySetting.HarmBlockThreshold.BLOCK_ONLY_HIGH)<br> .build()<br> );</pre><p><strong>Invoke Gemini and return the standardized address :<br></strong>The below code passes the processed output from the above step as prompt to Gemini:</p><pre>GenerativeModel modelForFinalResponse = GenerativeModel.newBuilder()<br> .setModelName(modelName)<br> .setVertexAi(vertexAI)<br> .build();<br> GenerateContentResponse finalResponse = modelForFinalResponse.generateContent(promptString + ": " + address, safetySettings);<br> System.out.println("promptString + content: " + promptString + ": " + address);<br> // See what the model replies now<br> System.out.println("Print response: ");<br> System.out.println(finalResponse.toString());<br> String finalAnswer = ResponseHandler.getText(finalResponse);<br> System.out.println(finalAnswer);</pre><p>The finalAnswer variable has the standardized address in JSON format. Sample output below:</p><pre>{"replies":["{ \"DOOR_NUMBER\": null, \"STREET_ADDRESS\": \"277 Bedford Ave\", \"AREA\": \"Brooklyn\", \"CITY\": \"New York\", \"TOWN\": null, \"COUNTY\": null, \"STATE\": \"NY\", \"COUNTRY\": \"USA\", \"ZIPCODE\": \"11211\", \"LANDMARK\": null} null}"]}</pre><p>Now that you have understood how Gemini Function Calling works with the address standardization use case, go ahead and deploy the Cloud Function.</p><p>10. Now that you have understood how Gemini Function Calling works with the address standardization use case, go ahead and deploy the Cloud Function.</p><pre>gcloud functions deploy gemini-fn-calling --gen2 --region=us-central1 --runtime=java11 --source=. --entry-point=cloudcode.helloworld.HelloWorld --trigger-http</pre><p>The result for this deploy command would be a REST URL in the format as below :</p><p><a href="https://us-central1-YOUR_PROJECT_ID.cloudfunctions.net/gemini-fn-calling"><strong>https://us-central1-YOUR_PROJECT_ID.cloudfunctions.net/gemini-fn-calling</strong></a></p><p>11. Test this Cloud Function by running the following command from the terminal:</p><pre>gcloud functions call gemini-fn-calling --region=us-central1 --gen2 --data '{"calls":[["40.714224,-73.961452"]]}'</pre><p>Response for a random sample prompt:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*L2ME8WPaWun8XBIX" /><figcaption>Cloud Shell Terminal response for the Cloud Function call</figcaption></figure><pre> '{"replies":["{ \"DOOR_NUMBER\": \"277\", \"STREET_ADDRESS\": \"Bedford Ave\", \"AREA\":<br> null, \"CITY\": \"Brooklyn\", \"TOWN\": null, \"COUNTY\": \"Kings County\", \"STATE\":<br> \"NY\", \"COUNTRY\": \"USA\", \"ZIPCODE\": \"11211\", \"LANDMARK\": null}}```"]}'</pre><p>The request and response parameters of this Cloud Function are implemented in a way that is compatible with BigQuery’s remote function invocation. It can be directly consumed from BigQuery data in-place. It means that if your data input (lat and long data) lives in BigQuery then you can call the remote function on the data and get the function response which can be stored or processed within BigQuery directly. To learn how to leverage this Cloud Function in performing in-place LLM insights on your database, refer to this <a href="https://medium.com/google-cloud/in-place-llm-insights-bigquery-gemini-for-structured-unstructured-data-analytics-fdfac0421626">blog</a>.</p><h3>Conclusion</h3><p>This project has demonstrated the power of Gemini Function Calling, transforming a generative AI task into a deterministic, reliable process. If you work with generative AI, don’t let its sometimes-unpredictable nature hold you back. Use the power of Gemini 1.0 Pro Function Calling feature and create applications that are as innovative as they are dependable. Start exploring how you can incorporate this feature into your own work! Are there datasets you could validate, information gaps you could fill, or tasks that could be automated with structured calls embedded within your generative AI responses? Here is the link to the <a href="https://github.com/AbiramiSukumaran/GeminiFunctionCalling">repo</a> and for further reading, refer to the documentation for <a href="https://cloud.google.com/vertex-ai">Vertex AI</a>, <a href="https://cloud.google.com/bigquery/docs/remote-functions">BigQuery Remote Functions</a>, and <a href="https://cloud.google.com/functions">Cloud Functions</a> for more in-depth guidance in these areas.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4c86a5ab80a9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/google-cloud/using-gemini-function-calling-in-java-for-deterministic-generative-ai-responses-4c86a5ab80a9">Deterministic Generative AI with Gemini Function Calling in Java</a> was originally published in <a href="https://medium.com/google-cloud">Google Cloud - Community</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>'
Language
Active
Ricc internal notes
Imported via /Users/ricc/git/gemini-news-crawler/webapp/db/seeds.d/import-feedjira.rb on 2024-04-03 16:28:21 +0200. Content is EMPTY here. Entried: title,url,author,categories,published,entry_id,content. TODO add Newspaper: filename = /Users/ricc/git/gemini-news-crawler/webapp/db/seeds.d/../../../crawler/out/feedjira/Blogs/Google Cloud - Medium/2024-04-03-Deterministic_Generative_AI_with_Gemini_Function_Calling_in_Java-v2.yaml
Ricc source
Show this article
Back to articles