From 7062dbc9663823c2571bff60e6852387695d2e9b Mon Sep 17 00:00:00 2001 From: Kristopher Overholt Date: Thu, 17 Oct 2024 11:17:16 -0500 Subject: [PATCH] feat: Add an intro to LangGraph + Gemini notebook with tools and workflow (#1273) # Description This PR adds a sample notebook that uses LangGraph and Gemini to automate the process of retrieving real-time and historical exchange rates from a currency API, verifying the accuracy of the data, and generating a report summarizing the findings. --------- Co-authored-by: Owl Bot Co-authored-by: Holt Skinner <13262395+holtskinner@users.noreply.github.com> Co-authored-by: Holt Skinner --- .github/CODEOWNERS | 2 +- .github/actions/spelling/allow.txt | 1 + .../intro_langgraph_gemini.ipynb | 774 ++++++++++++++++++ 3 files changed, 776 insertions(+), 1 deletion(-) create mode 100644 gemini/orchestration/intro_langgraph_gemini.ipynb diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1ad39d9748..95dc268aab 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -26,7 +26,7 @@ /generative-ai/language @polong-lin @GoogleCloudPlatform/generative-ai-devrel /generative-ai/language/getting-started @polong-lin @iamthuya @GoogleCloudPlatform/generative-ai-devrel /generative-ai/language/grounding @koverholt @holtskinner @GoogleCloudPlatform/generative-ai-devrel -/generative-ai/language/orchestration/langchain @kweinmeister @RajeshThallam @GoogleCloudPlatform/generative-ai-devrel +/generative-ai/language/orchestration @koverholt @kweinmeister @RajeshThallam @GoogleCloudPlatform/generative-ai-devrel /generative-ai/language/prompts @polong-lin @GoogleCloudPlatform/generative-ai-devrel /generative-ai/language/prompts/prompt_optimizer @nhootan @inardini @GoogleCloudPlatform/generative-ai-devrel /generative-ai/language/sample-apps @rominirani @GoogleCloudPlatform/generative-ai-devrel diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index b086aa3be0..b2c59c2979 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -125,6 +125,7 @@ ICML INFOPLIST IVF Isner +JPY Jang Jedi Joji diff --git a/gemini/orchestration/intro_langgraph_gemini.ipynb b/gemini/orchestration/intro_langgraph_gemini.ipynb new file mode 100644 index 0000000000..1bea27fc85 --- /dev/null +++ b/gemini/orchestration/intro_langgraph_gemini.ipynb @@ -0,0 +1,774 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "ur8xi4C7S06n" + }, + "outputs": [], + "source": [ + "# Copyright 2024 Google LLC\n", + "#\n", + "# Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JAPoU8Sm5E6e" + }, + "source": [ + "# From API to Report: Building a Currency Analysis Agent with LangGraph and Gemini\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " \"Google
Open in Colab\n", + "
\n", + "
\n", + " \n", + " \"Google
Open in Colab Enterprise\n", + "
\n", + "
\n", + " \n", + " \"Vertex
Open in Vertex AI Workbench\n", + "
\n", + "
\n", + " \n", + " \"GitHub
View on GitHub\n", + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "84f0f73a0f76" + }, + "source": [ + "| | |\n", + "|-|-|\n", + "| Author(s) | [Kristopher Overholt](https://github.com/koverholt/) |" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "tvgnzT1CKxrO" + }, + "source": [ + "## Overview\n", + "\n", + "This notebook demonstrates how to build an AI-powered currency analysis agent using [LangGraph](https://langchain-ai.github.io/langgraph/), an orchestration framework for language models, and the [Gemini API in Vertex AI](https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models). This example showcases the potential of combining LangGraph's workflow capabilities with Gemini's language understanding and generation skills to streamline and automate complex financial analysis tasks. To learn more about the motivation and benefits of using LangGraph to build AI agents, refer to the [Why LangGraph?](https://langchain-ai.github.io/langgraph/concepts/high_level/) documentation.\n", + "\n", + "The agent automates the process of retrieving real-time and historical exchange rates from a currency API, verifying the accuracy of the data, and generating a report summarizing the findings. By defining a structured workflow with distinct nodes for API interaction, data validation, and report generation, the agent efficiently handles each stage of the currency analysis process:\n", + "\n", + "\n", + "\n", + "In this notebook tutorial, you'll learn how to:\n", + "\n", + "- Design and implement a multi-stage LangGraph workflow for interacting with external APIs and processing data\n", + "- Integrate the Gemini API to enable natural language understanding and report generation\n", + "- Use LangChain tools to access and query external data sources\n", + "- Validate data accuracy using Gemini's reasoning capabilities\n", + "- Generate clear and informative reports from the analyzed data" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "61RBz8LLbxCR" + }, + "source": [ + "## Get started" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "No17Cw5hgx12" + }, + "source": [ + "### Install Vertex AI SDK and other required packages\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "id": "tFy3H3aPgx12" + }, + "outputs": [], + "source": [ + "%pip install -q -U \\\n", + " langgraph \\\n", + " langchain-google-vertexai \\\n", + " requests" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "R5Xep4W9lq-Z" + }, + "source": [ + "### Restart runtime\n", + "\n", + "To use the newly installed packages in this Jupyter runtime, you must restart the runtime. You can do this by running the cell below, which restarts the current kernel.\n", + "\n", + "The restart might take a minute or longer. After it's restarted, continue to the next step." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "id": "XRvKdaPDTznN" + }, + "outputs": [], + "source": [ + "import IPython\n", + "\n", + "app = IPython.Application.instance()\n", + "app.kernel.do_shutdown(True)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SbmM4z7FOBpM" + }, + "source": [ + "
\n", + "⚠️ The kernel is going to restart. Wait until it's finished before continuing to the next step. ⚠️\n", + "
\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dmWOrTJ3gx13" + }, + "source": [ + "### Authenticate your notebook environment (Colab only)\n", + "\n", + "If you're running this notebook on Google Colab, run the cell below to authenticate your environment." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "id": "NyKGtVQjgx13" + }, + "outputs": [], + "source": [ + "import sys\n", + "\n", + "if \"google.colab\" in sys.modules:\n", + " from google.colab import auth\n", + "\n", + " auth.authenticate_user()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DF4l8DTdWgPY" + }, + "source": [ + "### Set Google Cloud project information and initialize Vertex AI SDK\n", + "\n", + "To get started using Vertex AI, you must have an existing Google Cloud project and [enable the Vertex AI API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com).\n", + "\n", + "Learn more about [setting up a project and a development environment](https://cloud.google.com/vertex-ai/docs/start/cloud-environment)." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "id": "Nqwi-5ufWp_B" + }, + "outputs": [], + "source": [ + "import os\n", + "\n", + "import vertexai\n", + "\n", + "PROJECT_ID = \"[your-project-id]\" # @param {type:\"string\", isTemplate: true}\n", + "if PROJECT_ID == \"[your-project-id]\":\n", + " PROJECT_ID = str(os.environ.get(\"GOOGLE_CLOUD_PROJECT\"))\n", + "\n", + "LOCATION = os.environ.get(\"GOOGLE_CLOUD_REGION\", \"us-central1\")\n", + "\n", + "vertexai.init(project=PROJECT_ID, location=LOCATION)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "EdvJRUWRNGHE" + }, + "source": [ + "## Building and running the currency analysis agent" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5303c05f7aa6" + }, + "source": [ + "### Import libraries\n", + "\n", + "This section imports the necessary libraries for LangGraph, LangChain, Vertex AI, and other utilities needed for your agent's functionality.\n", + "\n", + "This includes tools for interacting with the Gemini API, defining custom tools, managing agent state, and displaying results." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "id": "6fc324893334" + }, + "outputs": [], + "source": [ + "# Standard libraries\n", + "import logging\n", + "from typing import Annotated, TypedDict\n", + "\n", + "# IPython display utilities\n", + "from IPython.display import Image, Markdown, display\n", + "\n", + "# LangChain core components\n", + "from langchain_core.messages import HumanMessage, SystemMessage\n", + "from langchain_core.tools import tool\n", + "\n", + "# Vertex AI and Gemini integration\n", + "from langchain_google_vertexai import ChatVertexAI\n", + "\n", + "# LangGraph components\n", + "from langgraph.checkpoint.memory import MemorySaver\n", + "from langgraph.graph import END, START, StateGraph\n", + "from langgraph.graph.message import add_messages\n", + "from langgraph.prebuilt import ToolNode\n", + "import requests" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "e43229f3ad4f" + }, + "source": [ + "### Initialize agent state and agent memory\n", + "\n", + "Here, you initialize your agent's [memory](https://langchain-ai.github.io/langgraph/how-tos/memory/manage-conversation-history/) to store information during the workflow.\n", + "\n", + "You also define the schema for your [agent's state](https://langchain-ai.github.io/langgraph/how-tos/state-model/), which includes the task description and conversation history." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "cf93d5f0ce00" + }, + "outputs": [], + "source": [ + "# Define the agent's state\n", + "\n", + "\n", + "class AgentState(TypedDict):\n", + " task: str\n", + " messages: Annotated[list, add_messages]\n", + "\n", + "\n", + "# Initialize agent memory\n", + "memory = MemorySaver()\n", + "\n", + "# Set logging level to ERROR to filter warnings\n", + "logger = logging.getLogger()\n", + "logger.setLevel(logging.ERROR)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "27b61a7e7ef6" + }, + "source": [ + "### Initialize Gemini model\n", + "\n", + "Initialize the Gemini model from Vertex AI, specifying the model version and temperature settings.\n", + "\n", + "This sets up the core language model that will power your agent's actions." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "id": "ca1c01bb3175" + }, + "outputs": [], + "source": [ + "model = ChatVertexAI(model=\"gemini-1.5-pro-002\", temperature=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "a91e085ac90e" + }, + "source": [ + "### Define tools\n", + "\n", + "This section defines a custom tool that will be used by your agent to retrieve currency exchange rates from an external API. The tool fetches exchange rates for a specified currency pair and date.\n", + "\n", + "Your LangGraph application will use this [tool node to call functions](https://langchain-ai.github.io/langgraph/how-tos/tool-calling/) and obtain information from the outside world." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "id": "4b5cff5eeb89" + }, + "outputs": [], + "source": [ + "@tool\n", + "def get_exchange_rate(\n", + " currency_from: str = \"USD\",\n", + " currency_to: str = \"EUR\",\n", + " currency_date: str = \"latest\",\n", + "):\n", + " \"\"\"Retrieves the exchange rate between two currencies on a specified date.\n", + "\n", + " Args:\n", + " currency_from (str, optional): The base currency. Defaults to \"USD\".\n", + " currency_to (str, optional): The target currency. Defaults to \"EUR\".\n", + " currency_date (str, optional): The date for the exchange rate (YYYY-MM-DD).\n", + " Use \"latest\" for the most recent rate. Defaults to \"latest\".\n", + " \"\"\"\n", + " response = requests.get(\n", + " f\"https://api.frankfurter.app/{currency_date}\",\n", + " params={\"from\": currency_from, \"to\": currency_to},\n", + " )\n", + " return response.json()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6cf6b70b7bb6" + }, + "source": [ + "### Define prompts and functions for each node\n", + "\n", + "Here, you define the prompts and functions that will be used for each node in the LangGraph workflow. These prompts guide the Gemini model in performing specific actions, such as retrieving exchange rates, verifying their accuracy, and generating a report.\n", + "\n", + "By separating out our agent's functionality into distinct nodes, you can choose exactly which actions that node should perform and how much to defer to the LLM vs. application code in a given node. Notice how each node uses information from the global state, then updates the global state variables in the `return` statement." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "id": "c94afec80030" + }, + "outputs": [], + "source": [ + "#######################################\n", + "# Agent Node: Look up the exchange rate\n", + "#######################################\n", + "\n", + "\n", + "def agent_node(state: AgentState):\n", + " messages = state[\"messages\"]\n", + " model_with_tools = model.bind_tools(tools)\n", + " response = model_with_tools.invoke(messages)\n", + " return {\"messages\": [response]}\n", + "\n", + "\n", + "#########################################\n", + "# Tool Node: Define based on API function\n", + "#########################################\n", + "\n", + "tools = [get_exchange_rate]\n", + "tool_node = ToolNode(tools)\n", + "\n", + "\n", + "# Determine if additional tool calls are needed\n", + "def should_continue(state: AgentState):\n", + " messages = state[\"messages\"]\n", + " last_message = messages[-1]\n", + " if last_message.tool_calls:\n", + " return \"tools\"\n", + " return \"review\"\n", + "\n", + "\n", + "#########################################\n", + "# Review Node: Analyze and review results\n", + "#########################################\n", + "\n", + "REVIEW_PROMPT = \"\"\"You are a financial expert. Analyze the converted\n", + "rates and verify the correctness of the figures.\n", + "This is the conversation history so far:\n", + "{messages}\"\"\"\n", + "\n", + "\n", + "def review_node(state: AgentState):\n", + " messages = [\n", + " HumanMessage(content=REVIEW_PROMPT.format(messages=state[\"messages\"])),\n", + " ]\n", + " response = model.invoke(messages)\n", + " return {\"messages\": response}\n", + "\n", + "\n", + "########################################\n", + "# Report Node: Generate a summary report\n", + "########################################\n", + "\n", + "\n", + "REPORT_PROMPT = \"\"\"Construct a summary report for a financial news\n", + "reporter covering current exchange rates. Include a table of results\n", + "comparing the rates over time. Do not use currency symbols in the\n", + "output since they might break the rendering of the output.\n", + "This is the conversation history so far:\n", + "{messages}\"\"\"\n", + "\n", + "\n", + "def report_node(state: AgentState):\n", + " messages = [\n", + " HumanMessage(content=REPORT_PROMPT.format(messages=state[\"messages\"])),\n", + " ]\n", + " response = model.invoke(messages)\n", + " return {\"messages\": response}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3994d1b07f65" + }, + "source": [ + "### Define and compile the graph\n", + "\n", + "This section defines the structure of the LangGraph workflow, connecting the nodes in a logical sequence.\n", + "\n", + "The graph is then compiled, incorporating your agent's memory for state management." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "id": "65732c3a628d" + }, + "outputs": [], + "source": [ + "# Initialize the LangGraph workflow, specifying the agent's state schema\n", + "workflow = StateGraph(AgentState)\n", + "\n", + "# Add nodes to the workflow, associating each node with its corresponding function\n", + "workflow.add_node(\"agent\", agent_node)\n", + "workflow.add_node(\"tools\", tool_node)\n", + "workflow.add_node(\"review\", review_node)\n", + "workflow.add_node(\"report\", report_node)\n", + "\n", + "# Define the flow of execution between nodes, creating the workflow's logic\n", + "workflow.add_edge(START, \"agent\")\n", + "workflow.add_conditional_edges(\"agent\", should_continue, [\"tools\", \"review\"])\n", + "workflow.add_edge(\"tools\", \"agent\")\n", + "workflow.add_edge(\"review\", \"report\")\n", + "workflow.add_edge(\"report\", END)\n", + "\n", + "# Compile the LangGraph workflow, enabling memory-based state management\n", + "graph = workflow.compile(checkpointer=memory)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1f02a671723e" + }, + "source": [ + "### Show the compiled graph\n", + "\n", + "You can visualize the compiled LangGraph workflow using a diagram, which provides a clear overview of your agent's execution flow." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "id": "27513ba58a26" + }, + "outputs": [], + "source": [ + "Image(graph.get_graph().draw_mermaid_png())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "a7c3daaeee31" + }, + "source": [ + "### Run the agent!\n", + "\n", + "Now you're ready to initiate the workflow with a system prompt and user prompt to retrieve current and historical currency exchange rates.\n", + "\n", + "Feel free to modify these prompts and see how the agent responds! Try switching countries, currencies, time periods, or other changes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "a551812eb672" + }, + "outputs": [], + "source": [ + "# Define the system prompt instructing the agent on how to answer the user's question.\n", + "SYSTEM_PROMPT = \"\"\"Use the tools provided to answer the user's question. \n", + "Also look up the exchange rate for all currencies from three months prior\n", + "and compare the values.\"\"\"\n", + "\n", + "# Define the user's initial question about exchange rates.\n", + "USER_PROMPT = \"\"\"What's the exchange rate from USD to (SEK, EUR, and JPY)\n", + "as of today? And how much would $100 USD be worth in those currencies?\"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ec077a30c366" + }, + "source": [ + "Now you're ready to execute your LangGraph agent!\n", + "\n", + "Now your agent will work through the nodes in the graph step-by-step to interact with the API, validate the data, and prepare a report." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "65d16afb3bba" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Agent Node: agent\n", + "\n", + "Agent Result:\n", + "{'messages': [AIMessage(content='', additional_kwargs={'function_call': {'name': 'get_exchange_rate', 'arguments': '{\"currency_from\": \"USD\", \"currency_to\": \"JPY\"}'}}, response_metadata={'is_blocked': False, 'safety_ratings': [], 'usage_metadata': {'prompt_token_count': 176, 'candidates_token_count': 39, 'total_token_count': 215, 'cached_content_token_count': 0}, 'finish_reason': 'STOP'}, id='run-1d509a3d-3b8e-4eb2-97d1-1d5822aaf4cd-0', tool_calls=[{'name': 'get_exchange_rate', 'args': {'currency_from': 'USD', 'currency_to': 'SEK'}, 'id': 'd31e6ab0-d00e-4e56-b14b-224745f943d1', 'type': 'tool_call'}, {'name': 'get_exchange_rate', 'args': {'currency_from': 'USD', 'currency_to': 'EUR'}, 'id': '62649ecf-c730-406b-9340-da13fce0ed83', 'type': 'tool_call'}, {'name': 'get_exchange_rate', 'args': {'currency_from': 'USD', 'currency_to': 'JPY'}, 'id': 'b4f74745-520f-4460-82f8-61f53a4e72f7', 'type': 'tool_call'}], usage_metadata={'input_tokens': 176, 'output_tokens': 39, 'total_tokens': 215})]}\n", + "\n", + "====================\n", + "\n", + "Agent Node: tools\n", + "\n", + "Agent Result:\n", + "{'messages': [ToolMessage(content='{\"amount\": 1.0, \"base\": \"USD\", \"date\": \"2024-10-15\", \"rates\": {\"SEK\": 10.365}}', name='get_exchange_rate', id='e1fbbbbf-5829-4ff2-a72d-1476a0171296', tool_call_id='d31e6ab0-d00e-4e56-b14b-224745f943d1'), ToolMessage(content='{\"amount\": 1.0, \"base\": \"USD\", \"date\": \"2024-10-15\", \"rates\": {\"EUR\": 0.91718}}', name='get_exchange_rate', id='f4e7b250-6022-4457-830a-f17b4bbe7815', tool_call_id='62649ecf-c730-406b-9340-da13fce0ed83'), ToolMessage(content='{\"amount\": 1.0, \"base\": \"USD\", \"date\": \"2024-10-15\", \"rates\": {\"JPY\": 149.36}}', name='get_exchange_rate', id='e1811e0b-d035-49f2-b6a6-e6c486906d2e', tool_call_id='b4f74745-520f-4460-82f8-61f53a4e72f7')]}\n", + "\n", + "====================\n", + "\n", + "Agent Node: agent\n", + "\n", + "Agent Result:\n", + "{'messages': [AIMessage(content='Today, October 15th, 2024, the exchange rates from USD are:\\n\\n* **USD to SEK:** 1 USD is equal to 10.365 SEK. $100 would be worth 1036.5 SEK.\\n* **USD to EUR:** 1 USD is equal to 0.91718 EUR. $100 would be worth 91.72 EUR.\\n* **USD to JPY:** 1 USD is equal to 149.36 JPY. $100 would be worth 14936 JPY.\\n\\n\\n', additional_kwargs={'function_call': {'name': 'get_exchange_rate', 'arguments': '{\"currency_from\": \"USD\", \"currency_date\": \"2024-07-15\", \"currency_to\": \"SEK\"}'}}, response_metadata={'is_blocked': False, 'safety_ratings': [], 'usage_metadata': {'prompt_token_count': 278, 'candidates_token_count': 164, 'total_token_count': 442, 'cached_content_token_count': 0}, 'finish_reason': 'STOP'}, id='run-02e44b91-e40e-41d0-ac77-24544186e2e9-0', tool_calls=[{'name': 'get_exchange_rate', 'args': {'currency_from': 'USD', 'currency_date': '2024-07-15', 'currency_to': 'SEK'}, 'id': '5b8f3fdf-3d49-4fb6-8471-94c8562bea58', 'type': 'tool_call'}], usage_metadata={'input\n", + "\n", + "====================\n", + "\n", + "Agent Node: tools\n", + "\n", + "Agent Result:\n", + "{'messages': [ToolMessage(content='{\"amount\": 1.0, \"base\": \"USD\", \"date\": \"2024-07-15\", \"rates\": {\"SEK\": 10.5781}}', name='get_exchange_rate', id='0af3940e-870e-42b3-b2cc-ddad93d9195f', tool_call_id='5b8f3fdf-3d49-4fb6-8471-94c8562bea58')]}\n", + "\n", + "====================\n", + "\n", + "Agent Node: agent\n", + "\n", + "Agent Result:\n", + "{'messages': [AIMessage(content='', additional_kwargs={'function_call': {'name': 'get_exchange_rate', 'arguments': '{\"currency_from\": \"USD\", \"currency_date\": \"2024-07-15\", \"currency_to\": \"EUR\"}'}}, response_metadata={'is_blocked': False, 'safety_ratings': [], 'usage_metadata': {'prompt_token_count': 463, 'candidates_token_count': 26, 'total_token_count': 489, 'cached_content_token_count': 0}, 'finish_reason': 'STOP'}, id='run-81e51399-ad4f-461b-883c-91e55f96a529-0', tool_calls=[{'name': 'get_exchange_rate', 'args': {'currency_from': 'USD', 'currency_date': '2024-07-15', 'currency_to': 'EUR'}, 'id': '0f1311d7-ad7b-4431-baca-90b490a2d0c5', 'type': 'tool_call'}], usage_metadata={'input_tokens': 463, 'output_tokens': 26, 'total_tokens': 489})]}\n", + "\n", + "====================\n", + "\n", + "Agent Node: tools\n", + "\n", + "Agent Result:\n", + "{'messages': [ToolMessage(content='{\"amount\": 1.0, \"base\": \"USD\", \"date\": \"2024-07-15\", \"rates\": {\"EUR\": 0.91684}}', name='get_exchange_rate', id='9a15d78d-6dab-47b9-a17f-bb3f664b2695', tool_call_id='0f1311d7-ad7b-4431-baca-90b490a2d0c5')]}\n", + "\n", + "====================\n", + "\n", + "Agent Node: agent\n", + "\n", + "Agent Result:\n", + "{'messages': [AIMessage(content='', additional_kwargs={'function_call': {'name': 'get_exchange_rate', 'arguments': '{\"currency_from\": \"USD\", \"currency_date\": \"2024-07-15\", \"currency_to\": \"JPY\"}'}}, response_metadata={'is_blocked': False, 'safety_ratings': [], 'usage_metadata': {'prompt_token_count': 510, 'candidates_token_count': 26, 'total_token_count': 536, 'cached_content_token_count': 0}, 'finish_reason': 'STOP'}, id='run-a78d7c8f-e4af-4697-946b-f363de34f2da-0', tool_calls=[{'name': 'get_exchange_rate', 'args': {'currency_from': 'USD', 'currency_date': '2024-07-15', 'currency_to': 'JPY'}, 'id': '4d0ea10c-f032-44a3-b3d5-f61716624216', 'type': 'tool_call'}], usage_metadata={'input_tokens': 510, 'output_tokens': 26, 'total_tokens': 536})]}\n", + "\n", + "====================\n", + "\n", + "Agent Node: tools\n", + "\n", + "Agent Result:\n", + "{'messages': [ToolMessage(content='{\"amount\": 1.0, \"base\": \"USD\", \"date\": \"2024-07-15\", \"rates\": {\"JPY\": 158.01}}', name='get_exchange_rate', id='dc4afaef-b019-4822-9c09-b32c197e5756', tool_call_id='4d0ea10c-f032-44a3-b3d5-f61716624216')]}\n", + "\n", + "====================\n", + "\n", + "Agent Node: agent\n", + "\n", + "Agent Result:\n", + "{'messages': [AIMessage(content='Three months prior, on July 15th, 2024, the exchange rates from USD were:\\n\\n* **USD to SEK:** 1 USD was equal to 10.5781 SEK.\\n* **USD to EUR:** 1 USD was equal to 0.91684 EUR.\\n* **USD to JPY:** 1 USD was equal to 158.01 JPY.\\n', additional_kwargs={}, response_metadata={'is_blocked': False, 'safety_ratings': [], 'usage_metadata': {'prompt_token_count': 557, 'candidates_token_count': 95, 'total_token_count': 652, 'cached_content_token_count': 0}, 'finish_reason': 'STOP'}, id='run-6a0d7a12-e856-47f7-bad8-d887f4ffb2bc-0', usage_metadata={'input_tokens': 557, 'output_tokens': 95, 'total_tokens': 652})]}\n", + "\n", + "====================\n", + "\n", + "Agent Node: review\n", + "\n", + "Agent Result:\n", + "{'messages': AIMessage(content=\"Here's an analysis of the provided exchange rates and their correctness:\\n\\n**Current Exchange Rates (October 15, 2024):**\\n\\n* **USD to SEK:** 1 USD = 10.365 SEK. $100 = 1036.5 SEK. *Calculation Correct.*\\n* **USD to EUR:** 1 USD = 0.91718 EUR. $100 = 91.72 EUR (rounded, actual is 91.718). *Calculation Correct.*\\n* **USD to JPY:** 1 USD = 149.36 JPY. $100 = 14936 JPY. *Calculation Correct.*\\n\\n**Historical Exchange Rates (July 15, 2024):**\\n\\n* **USD to SEK:** 1 USD = 10.5781 SEK.\\n* **USD to EUR:** 1 USD = 0.91684 EUR.\\n* **USD to JPY:** 1 USD = 158.01 JPY.\\n\\n**Analysis of Change:**\\n\\n* **SEK:** The Swedish Krona (SEK) has *strengthened* against the USD over the past three months. This means it takes fewer SEK to buy a USD. This is a relatively small change (10.5781 to 10.365).\\n* **EUR:** The Euro (EUR) has also *strengthened* slightly against the USD (0.91684 to 0.91718). Again, a minor fluctuation.\\n* **JPY:** The Japanese Yen (JPY) has *weak\n", + "\n", + "====================\n", + "\n", + "Agent Node: report\n", + "\n", + "Agent Result:\n", + "{'messages': AIMessage(content=\"**Exchange Rate Summary Report – October 15, 2024**\\n\\nThis report summarizes the current exchange rates for USD against several major currencies, comparing them to rates from three months prior. The data reveals notable shifts in the relative strength of the Yen against the US dollar.\\n\\n**Key Observations:**\\n\\n* The Japanese Yen (JPY) has weakened considerably against the USD over the past three months. This depreciation makes imports priced in USD more expensive for Japanese consumers and businesses.\\n* Both the Swedish Krona (SEK) and the Euro (EUR) have strengthened slightly against the USD, though these changes are less pronounced than the JPY's movement.\\n\\n**Exchange Rate Table:**\\n\\n| Currency Pair | Current Rate (Oct 15, 2024) | Previous Rate (Jul 15, 2024) | Change (%) |\\n|---|---|---|---|\\n| USD to SEK | 10.365 | 10.5781 | +2.01% |\\n| USD to EUR | 0.91718 | 0.91684 | -0.04% |\\n| USD to JPY | 149.36 | 158.01 | +5.47% |\\n\\n\\n**100 USD\n", + "\n", + "====================\n", + "\n" + ] + } + ], + "source": [ + "# Initialize a LangGraph thread with a unique ID for state management.\n", + "thread_config = {\"configurable\": {\"thread_id\": \"1\"}}\n", + "\n", + "# Execute the LangGraph workflow, streaming the results of each node.\n", + "for state in graph.stream(\n", + " {\n", + " \"messages\": [\n", + " SystemMessage(content=SYSTEM_PROMPT),\n", + " HumanMessage(content=USER_PROMPT),\n", + " ],\n", + " },\n", + " thread_config,\n", + "):\n", + " # Print the name of the current node and its output for each step.\n", + " for node_name, node_output in state.items():\n", + " print(f\"Agent Node: {node_name}\\n\")\n", + " print(\"Agent Result:\")\n", + " print(str(node_output)[:1000]) # Truncate output for display\n", + " print(\"\\n====================\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5d7d371f4fe5" + }, + "source": [ + "### Render the output\n", + "\n", + "Finally, you render the final report generated by your agent, displaying the results of the currency analysis in a human-readable way." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "id": "dc4ce48f0964" + }, + "outputs": [ + { + "data": { + "text/markdown": [ + "**Exchange Rate Summary Report – October 15, 2024**\n", + "\n", + "This report summarizes the current exchange rates for USD against several major currencies, comparing them to rates from three months prior. The data reveals notable shifts in the relative strength of the Yen against the US dollar.\n", + "\n", + "**Key Observations:**\n", + "\n", + "* The Japanese Yen (JPY) has weakened considerably against the USD over the past three months. This depreciation makes imports priced in USD more expensive for Japanese consumers and businesses.\n", + "* Both the Swedish Krona (SEK) and the Euro (EUR) have strengthened slightly against the USD, though these changes are less pronounced than the JPY's movement.\n", + "\n", + "**Exchange Rate Table:**\n", + "\n", + "| Currency Pair | Current Rate (Oct 15, 2024) | Previous Rate (Jul 15, 2024) | Change (%) |\n", + "|---|---|---|---|\n", + "| USD to SEK | 10.365 | 10.5781 | +2.01% |\n", + "| USD to EUR | 0.91718 | 0.91684 | -0.04% |\n", + "| USD to JPY | 149.36 | 158.01 | +5.47% |\n", + "\n", + "\n", + "**100 USD Equivalency:**\n", + "\n", + "| Currency | Current Value (Oct 15, 2024) | Previous Value (Jul 15, 2024) |\n", + "|---|---|---|\n", + "| SEK | 1036.5 | 1057.81 |\n", + "| EUR | 91.72 | 91.68 |\n", + "| JPY | 14936 | 15801 |\n", + "\n", + "**Data Source and Disclaimer:**\n", + "\n", + "Exchange rate data was obtained via a real-time data tool. While every effort has been made to ensure accuracy, it is essential to note that exchange rates are constantly fluctuating. For the most up-to-the-minute information, please consult a reputable financial institution or data provider. This report is for informational purposes only and should not be considered financial advice.\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "display(Markdown(state[\"report\"][\"messages\"].content))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "493869e2bc88" + }, + "source": [ + "## Conclusion\n", + "\n", + "This notebook demonstrates the successful implementation of a currency analysis agent using LangGraph and the Gemini API. By leveraging LangGraph's orchestration framework, you were able to build a multi-stage workflow that integrates and automates API interactions, data validation, and report generation.\n", + "\n", + "Feel free to customize the tools and prompts in this example, or adapt it to your use case and desired graph workflow. You can learn more about [LangGraph](https://langchain-ai.github.io/langgraph/), the [Gemini API in Vertex AI](https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models), or the [chat model provider for Vertex AI in LangChain](https://python.langchain.com/docs/integrations/chat/google_vertex_ai_palm/) in their respective documentation pages." + ] + } + ], + "metadata": { + "colab": { + "name": "intro_langgraph_gemini.ipynb", + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +}