2023-08-10 14:52:54 +00:00
{
"cells": [
2023-09-06 22:46:33 +00:00
{
"cell_type": "raw",
"id": "ea5c61b2-8b52-4270-bdb0-c4df88608f15",
"metadata": {},
"source": [
"---\n",
"sidebar_position: 1\n",
"title: Interacting with APIs\n",
"---"
]
},
2023-08-10 14:52:54 +00:00
{
"cell_type": "markdown",
"id": "a15e6a18",
"metadata": {},
"source": [
"[![Open In Collab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain/blob/master/docs/extras/use_cases/apis.ipynb)\n",
"\n",
"## Use case \n",
"\n",
"Suppose you want an LLM to interact with external APIs.\n",
"\n",
"This can be very useful for retrieving context for the LLM to utilize.\n",
"\n",
2023-09-03 20:00:22 +00:00
"And, more generally, it allows us to interact with APIs using natural language! \n",
2023-08-10 14:52:54 +00:00
" \n",
"\n",
"## Overview\n",
"\n",
"There are two primary ways to interface LLMs with external APIs:\n",
" \n",
"* `Functions`: For example, [OpenAI functions](https://platform.openai.com/docs/guides/gpt/function-calling) is one popular means of doing this.\n",
"* `LLM-generated interface`: Use an LLM with access to API documentation to create an interface.\n",
"\n",
"![Image description](/img/api_use_case.png)"
]
},
{
"cell_type": "markdown",
"id": "abbd82f0",
"metadata": {},
"source": [
"## Quickstart \n",
"\n",
2023-08-17 09:06:43 +00:00
"Many APIs are already compatible with OpenAI function calling.\n",
2023-08-10 14:52:54 +00:00
"\n",
"For example, [Klarna](https://www.klarna.com/international/press/klarna-brings-smoooth-shopping-to-chatgpt/) has a YAML file that describes its API and allows OpenAI to interact with it:\n",
"\n",
"```\n",
"https://www.klarna.com/us/shopping/public/openai/v0/api-docs/\n",
"```\n",
"\n",
"Other options include:\n",
"\n",
"* [Speak](https://api.speak.com/openapi.yaml) for translation\n",
"* [XKCD](https://gist.githubusercontent.com/roaldnefs/053e505b2b7a807290908fe9aa3e1f00/raw/0a212622ebfef501163f91e23803552411ed00e4/openapi.yaml) for comics\n",
"\n",
"We can supply the specification to `get_openapi_chain` directly in order to query the API with OpenAI functions:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5a218fcc",
"metadata": {},
"outputs": [],
"source": [
"pip install langchain openai \n",
"\n",
"# Set env var OPENAI_API_KEY or load from a .env file:\n",
"# import dotenv\n",
2023-08-29 03:52:50 +00:00
"# dotenv.load_dotenv()"
2023-08-10 14:52:54 +00:00
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "30b780e3",
2023-09-06 22:46:33 +00:00
"metadata": {},
2023-08-10 14:52:54 +00:00
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Attempting to load an OpenAPI 3.0.1 spec. This may result in degraded performance. Convert your OpenAPI spec to 3.1.* spec for better support.\n"
]
},
{
"data": {
"text/plain": [
"{'query': \"What are some options for a men's large blue button down shirt\",\n",
" 'response': {'products': [{'name': 'Cubavera Four Pocket Guayabera Shirt',\n",
" 'url': 'https://www.klarna.com/us/shopping/pl/cl10001/3202055522/Clothing/Cubavera-Four-Pocket-Guayabera-Shirt/?utm_source=openai&ref-site=openai_plugin',\n",
" 'price': '$13.50',\n",
" 'attributes': ['Material:Polyester,Cotton',\n",
" 'Target Group:Man',\n",
" 'Color:Red,White,Blue,Black',\n",
" 'Properties:Pockets',\n",
" 'Pattern:Solid Color',\n",
" 'Size (Small-Large):S,XL,L,M,XXL']},\n",
" {'name': 'Polo Ralph Lauren Plaid Short Sleeve Button-down Oxford Shirt',\n",
" 'url': 'https://www.klarna.com/us/shopping/pl/cl10001/3207163438/Clothing/Polo-Ralph-Lauren-Plaid-Short-Sleeve-Button-down-Oxford-Shirt/?utm_source=openai&ref-site=openai_plugin',\n",
" 'price': '$52.20',\n",
" 'attributes': ['Material:Cotton',\n",
" 'Target Group:Man',\n",
" 'Color:Red,Blue,Multicolor',\n",
" 'Size (Small-Large):S,XL,L,M,XXL']},\n",
" {'name': 'Brixton Bowery Flannel Shirt',\n",
" 'url': 'https://www.klarna.com/us/shopping/pl/cl10001/3202331096/Clothing/Brixton-Bowery-Flannel-Shirt/?utm_source=openai&ref-site=openai_plugin',\n",
" 'price': '$27.48',\n",
" 'attributes': ['Material:Cotton',\n",
" 'Target Group:Man',\n",
" 'Color:Gray,Blue,Black,Orange',\n",
" 'Properties:Pockets',\n",
" 'Pattern:Checkered',\n",
" 'Size (Small-Large):XL,3XL,4XL,5XL,L,M,XXL']},\n",
" {'name': 'Vineyard Vines Gingham On-The-Go brrr Classic Fit Shirt Crystal',\n",
" 'url': 'https://www.klarna.com/us/shopping/pl/cl10001/3201938510/Clothing/Vineyard-Vines-Gingham-On-The-Go-brrr-Classic-Fit-Shirt-Crystal/?utm_source=openai&ref-site=openai_plugin',\n",
" 'price': '$80.64',\n",
" 'attributes': ['Material:Cotton',\n",
" 'Target Group:Man',\n",
" 'Color:Blue',\n",
" 'Size (Small-Large):XL,XS,L,M']},\n",
" {'name': \"Carhartt Men's Loose Fit Midweight Short Sleeve Plaid Shirt\",\n",
" 'url': 'https://www.klarna.com/us/shopping/pl/cl10001/3201826024/Clothing/Carhartt-Men-s-Loose-Fit-Midweight-Short-Sleeve-Plaid-Shirt/?utm_source=openai&ref-site=openai_plugin',\n",
" 'price': '$17.99',\n",
" 'attributes': ['Material:Cotton',\n",
" 'Target Group:Man',\n",
" 'Color:Red,Brown,Blue,Green',\n",
" 'Properties:Pockets',\n",
" 'Pattern:Checkered',\n",
" 'Size (Small-Large):S,XL,L,M']}]}}"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from langchain.chains.openai_functions.openapi import get_openapi_chain\n",
"chain = get_openapi_chain(\"https://www.klarna.com/us/shopping/public/openai/v0/api-docs/\")\n",
"chain(\"What are some options for a men's large blue button down shirt\")"
]
},
{
"cell_type": "markdown",
"id": "9162c91c",
"metadata": {},
"source": [
"## Functions \n",
"\n",
2023-08-29 21:53:00 +00:00
"We can unpack what is happening when we use the functions to call external APIs.\n",
2023-08-10 14:52:54 +00:00
"\n",
"Let's look at the [LangSmith trace](https://smith.langchain.com/public/76a58b85-193f-4eb7-ba40-747f0d5dd56e/r):\n",
"\n",
"* See [here](https://github.com/langchain-ai/langchain/blob/7fc07ba5df99b9fa8bef837b0fafa220bc5c932c/libs/langchain/langchain/chains/openai_functions/openapi.py#L279C9-L279C19) that we call the OpenAI LLM with the provided API spec:\n",
"\n",
"```\n",
"https://www.klarna.com/us/shopping/public/openai/v0/api-docs/\n",
"```\n",
"\n",
2023-08-29 21:53:00 +00:00
"* The prompt then tells the LLM to use the API spec with input question:\n",
2023-08-10 14:52:54 +00:00
"\n",
"```\n",
2023-08-29 21:53:00 +00:00
"Use the provided APIs to respond to this user query:\n",
2023-08-10 14:52:54 +00:00
"What are some options for a men's large blue button down shirt\n",
"```\n",
"\n",
"* The LLM returns the parameters for the function call `productsUsingGET`, which is [specified in the provided API spec](https://www.klarna.com/us/shopping/public/openai/v0/api-docs/):\n",
"```\n",
"function_call:\n",
" name: productsUsingGET\n",
" arguments: |-\n",
" {\n",
" \"params\": {\n",
" \"countryCode\": \"US\",\n",
" \"q\": \"men's large blue button down shirt\",\n",
" \"size\": 5,\n",
" \"min_price\": 0,\n",
" \"max_price\": 100\n",
" }\n",
" }\n",
" ```\n",
" \n",
"![Image description](/img/api_function_call.png)\n",
" \n",
"* This `Dict` above split and the [API is called here](https://github.com/langchain-ai/langchain/blob/7fc07ba5df99b9fa8bef837b0fafa220bc5c932c/libs/langchain/langchain/chains/openai_functions/openapi.py#L215)."
]
},
{
"cell_type": "markdown",
"id": "1fe49a0d",
"metadata": {},
"source": [
"## API Chain \n",
"\n",
"We can also build our own interface to external APIs using the `APIChain` and provided API documentation."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "4ef0c3d0",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new APIChain chain...\u001b[0m\n",
"\u001b[32;1m\u001b[1;3mhttps://api.open-meteo.com/v1/forecast?latitude=48.1351&longitude=11.5820&hourly=temperature_2m&temperature_unit=fahrenheit¤t_weather=true\u001b[0m\n",
"\u001b[33;1m\u001b[1;3m{\"latitude\":48.14,\"longitude\":11.58,\"generationtime_ms\":1.0769367218017578,\"utc_offset_seconds\":0,\"timezone\":\"GMT\",\"timezone_abbreviation\":\"GMT\",\"elevation\":521.0,\"current_weather\":{\"temperature\":52.9,\"windspeed\":12.6,\"winddirection\":239.0,\"weathercode\":3,\"is_day\":0,\"time\":\"2023-08-07T22:00\"},\"hourly_units\":{\"time\":\"iso8601\",\"temperature_2m\":\"°F\"},\"hourly\":{\"time\":[\"2023-08-07T00:00\",\"2023-08-07T01:00\",\"2023-08-07T02:00\",\"2023-08-07T03:00\",\"2023-08-07T04:00\",\"2023-08-07T05:00\",\"2023-08-07T06:00\",\"2023-08-07T07:00\",\"2023-08-07T08:00\",\"2023-08-07T09:00\",\"2023-08-07T10:00\",\"2023-08-07T11:00\",\"2023-08-07T12:00\",\"2023-08-07T13:00\",\"2023-08-07T14:00\",\"2023-08-07T15:00\",\"2023-08-07T16:00\",\"2023-08-07T17:00\",\"2023-08-07T18:00\",\"2023-08-07T19:00\",\"2023-08-07T20:00\",\"2023-08-07T21:00\",\"2023-08-07T22:00\",\"2023-08-07T23:00\",\"2023-08-08T00:00\",\"2023-08-08T01:00\",\"2023-08-08T02:00\",\"2023-08-08T03:00\",\"2023-08-08T04:00\",\"2023-08-08T05:00\",\"2023-08-08T06:00\",\"2023-08-08T07:00\",\"2023-08-08T08:00\",\"2023-08-08T09:00\",\"2023-08-08T10:00\",\"2023-08-08T11:00\",\"2023-08-08T12:00\",\"2023-08-08T13:00\",\"2023-08-08T14:00\",\"2023-08-08T15:00\",\"2023-08-08T16:00\",\"2023-08-08T17:00\",\"2023-08-08T18:00\",\"2023-08-08T19:00\",\"2023-08-08T20:00\",\"2023-08-08T21:00\",\"2023-08-08T22:00\",\"2023-08-08T23:00\",\"2023-08-09T00:00\",\"2023-08-09T01:00\",\"2023-08-09T02:00\",\"2023-08-09T03:00\",\"2023-08-09T04:00\",\"2023-08-09T05:00\",\"2023-08-09T06:00\",\"2023-08-09T07:00\",\"2023-08-09T08:00\",\"2023-08-09T09:00\",\"2023-08-09T10:00\",\"2023-08-09T11:00\",\"2023-08-09T12:00\",\"2023-08-09T13:00\",\"2023-08-09T14:00\",\"2023-08-09T15:00\",\"2023-08-09T16:00\",\"2023-08-09T17:00\",\"2023-08-09T18:00\",\"2023-08-09T19:00\",\"2023-08-09T20:00\",\"2023-08-09T21:00\",\"2023-08-09T22:00\",\"2023-08-09T23:00\",\"2023-08-10T00:00\",\"2023-08-10T01:00\",\"2023-08-10T02:00\",\"2023-08-10T03:00\",\"2023-08-10T04:00\",\"2023-08-10T05:00\",\"2023-08-10T06:00\",\"2023-08-10T07:00\",\"2023-08-10T08:00\",\"2023-08-10T09:00\",\"2023-08-10T10:00\",\"2023-08-10T11:00\",\"2023-08-10T12:00\",\"2023-08-10T13:00\",\"2023-08-10T14:00\",\"2023-08-10T15:00\",\"2023-08-10T16:00\",\"2023-08-10T17:00\",\"2023-08-10T18:00\",\"2023-08-10T19:00\",\"2023-08-10T20:00\",\"2023-08-10T21:00\",\"2023-08-10T22:00\",\"2023-08-10T23:00\",\"2023-08-11T00:00\",\"2023-08-11T01:00\",\"2023-08-11T02:00\",\"2023-08-11T03:00\",\"2023-08-11T04:00\",\"2023-08-11T05:00\",\"2023-08-11T06:00\",\"2023-08-11T07:00\",\"2023-08-11T08:00\",\"2023-08-11T09:00\",\"2023-08-11T10:00\",\"2023-08-11T11:00\",\"2023-08-11T12:00\",\"2023-08-11T13:00\",\"2023-08-11T14:00\",\"2023-08-11T15:00\",\"2023-08-11T16:00\",\"2023-08-11T17:00\",\"2023-08-11T18:00\",\"2023-08-11T19:00\",\"2023-08-11T20:00\",\"2023-08-11T21:00\",\"2023-08-11T22:00\",\"2023-08-11T23:00\",\"2023-08-12T00:00\",\"2023-08-12T01:00\",\"2023-08-12T02:00\",\"2023-08-12T03:00\",\"2023-08-12T04:00\",\"2023-08-12T05:00\",\"2023-08-12T06:00\",\"2023-08-12T07:00\",\"2023-08-12T08:00\",\"2023-08-12T09:00\",\"2023-08-12T10:00\",\"2023-08-12T11:00\",\"2023-08-12T12:00\",\"2023-08-12T13:00\",\"2023-08-12T14:00\",\"2023-08-12T15:00\",\"2023-08-12T16:00\",\"2023-08-12T17:00\",\"2023-08-12T18:00\",\"2023-08-12T19:00\",\"2023-08-12T20:00\",\"2023-08-12T21:00\",\"2023-08-12T22:00\",\"2023-08-12T23:00\",\"2023-08-13T00:00\",\"2023-08-13T01:00\",\"2023-08-13T02:00\",\"2023-08-13T03:00\",\"2023-08-13T04:00\",\"2023-08-13T05:00\",\"2023-08-13T06:00\",\"2023-08-13T07:00\",\"2023-08-13T08:00\",\"2023-08-13T09:00\",\"2023-08-13T10:00\",\"2023-08-13T11:00\",\"2023-08-13T12:00\",\"2023-08-13T13:00\",\"2023-08-13T14:00\",\"2023-08-13T15:00\",\"2023-08-13T16:00\",\"2023-08-13T17:00\",\"2023-08-13T18:00\",\"2023-08-13T19:00\",\"2023-08-13T20:00\",\"2023-08-13T21:00\",\"2023-08-13T22:00\",\"2023-08-13T23:00\"],\"temperature_2m\":[53.0,51.2,50.9,50.4,50.7,51.3,51.7,52.9,54.3,56.1,57.4,59.3,59.1,60.7,59.7,58.8,58.8,57.8,56.6,55.3
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"' The current temperature in Munich, Germany is 52.9°F.'"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from langchain.llms import OpenAI\n",
"from langchain.chains import APIChain\n",
"from langchain.chains.api import open_meteo_docs\n",
"llm = OpenAI(temperature=0)\n",
"chain = APIChain.from_llm_and_api_docs(llm, open_meteo_docs.OPEN_METEO_DOCS, verbose=True)\n",
"chain.run('What is the weather like right now in Munich, Germany in degrees Fahrenheit?')"
]
},
{
"cell_type": "markdown",
"id": "5b179318",
"metadata": {},
"source": [
"Note that we supply information about the API:"
]
},
{
"cell_type": "code",
"execution_count": 37,
"id": "a9e03cc2",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'BASE URL: https://api.open-meteo.com/\\n\\nAPI Documentation\\nThe API endpoint /v1/forecast accepts a geographical coordinate, a list of weather variables and responds with a JSON hourly weather forecast for 7 days. Time always starts at 0:00 today and contains 168 hours. All URL parameters are listed below:\\n\\nParameter\\tFormat\\tRequired\\tDefault\\tDescription\\nlatitude, longitude\\tFloating point\\tYes\\t\\tGeographical WGS84 coordinate of the location\\nhourly\\tString array\\tNo\\t\\tA list of weather variables which shou'"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"open_meteo_docs.OPEN_METEO_DOCS[0:500]"
]
},
{
"cell_type": "markdown",
"id": "3fab7930",
"metadata": {},
"source": [
"Under the hood, we do two things:\n",
" \n",
"* `api_request_chain`: Generate an API URL based on the input question and the api_docs\n",
"* `api_answer_chain`: generate a final answer based on the API response\n",
"\n",
"We can look at the [LangSmith trace](https://smith.langchain.com/public/1e0d18ca-0d76-444c-97df-a939a6a815a7/r) to inspect this:\n",
"\n",
"* The `api_request_chain` produces the API url from our question and the API documentation:\n",
"\n",
"![Image description](/img/api_chain.png)\n",
"\n",
"* [Here](https://github.com/langchain-ai/langchain/blob/bbd22b9b761389a5e40fc45b0570e1830aabb707/libs/langchain/langchain/chains/api/base.py#L82) we make the API request with the API url.\n",
2023-08-29 21:53:00 +00:00
"* The `api_answer_chain` takes the response from the API and provides us with a natural language response:\n",
2023-08-10 14:52:54 +00:00
"\n",
"![Image description](/img/api_chain_response.png)"
]
},
{
"cell_type": "markdown",
"id": "2511f446",
"metadata": {},
"source": [
"### Going deeper\n",
"\n",
"**Test with other APIs**"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1e1cf418",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"os.environ['TMDB_BEARER_TOKEN'] = \"\"\n",
"from langchain.chains.api import tmdb_docs\n",
"headers = {\"Authorization\": f\"Bearer {os.environ['TMDB_BEARER_TOKEN']}\"}\n",
"chain = APIChain.from_llm_and_api_docs(llm, tmdb_docs.TMDB_DOCS, headers=headers, verbose=True)\n",
"chain.run(\"Search for 'Avatar'\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dd80a717",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"from langchain.llms import OpenAI\n",
"from langchain.chains.api import podcast_docs\n",
"from langchain.chains import APIChain\n",
" \n",
"listen_api_key = 'xxx' # Get api key here: https://www.listennotes.com/api/pricing/\n",
"llm = OpenAI(temperature=0)\n",
"headers = {\"X-ListenAPI-Key\": listen_api_key}\n",
"chain = APIChain.from_llm_and_api_docs(llm, podcast_docs.PODCAST_DOCS, headers=headers, verbose=True)\n",
"chain.run(\"Search for 'silicon valley bank' podcast episodes, audio length is more than 30 minutes, return only 1 results\")"
]
},
{
"cell_type": "markdown",
"id": "a5939be5",
"metadata": {},
"source": [
"**Web requests**\n",
"\n",
2023-09-03 20:00:22 +00:00
"URL requests are such a common use-case that we have the `LLMRequestsChain`, which makes an HTTP GET request. "
2023-08-10 14:52:54 +00:00
]
},
{
"cell_type": "code",
"execution_count": 39,
"id": "0b158296",
"metadata": {},
"outputs": [],
"source": [
"from langchain.llms import OpenAI\n",
"from langchain.prompts import PromptTemplate\n",
"from langchain.chains import LLMRequestsChain, LLMChain"
]
},
{
"cell_type": "code",
"execution_count": 40,
"id": "d49c33e4",
"metadata": {},
"outputs": [],
"source": [
"template = \"\"\"Between >>> and <<< are the raw search result text from google.\n",
"Extract the answer to the question '{query}' or say \"not found\" if the information is not contained.\n",
"Use the format\n",
"Extracted:<answer or \"not found\">\n",
">>> {requests_result} <<<\n",
"Extracted:\"\"\"\n",
"\n",
"PROMPT = PromptTemplate(\n",
" input_variables=[\"query\", \"requests_result\"],\n",
" template=template,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 43,
"id": "d0fd4aab",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'query': 'What are the Three (3) biggest countries, and their respective sizes?',\n",
" 'url': 'https://www.google.com/search?q=What+are+the+Three+(3)+biggest+countries,+and+their+respective+sizes?',\n",
" 'output': ' Russia (17,098,242 km²), Canada (9,984,670 km²), China (9,706,961 km²)'}"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"chain = LLMRequestsChain(llm_chain=LLMChain(llm=OpenAI(temperature=0), prompt=PROMPT))\n",
"question = \"What are the Three (3) biggest countries, and their respective sizes?\"\n",
"inputs = {\n",
" \"query\": question,\n",
" \"url\": \"https://www.google.com/search?q=\" + question.replace(\" \", \"+\"),\n",
"}\n",
"chain(inputs)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
2023-09-06 22:46:33 +00:00
"version": "3.9.1"
2023-08-10 14:52:54 +00:00
}
},
"nbformat": 4,
"nbformat_minor": 5
}