forked from Archives/langchain
82baecc892
This PR adds * `ZeroShotAgent.as_sql_agent`, which returns an agent for interacting with a sql database. This builds off of `SQLDatabaseChain`. The main advantages are 1) answering general questions about the db, 2) access to a tool for double checking queries, and 3) recovering from errors * `ZeroShotAgent.as_json_agent` which returns an agent for interacting with json blobs. * Several examples in notebooks --------- Co-authored-by: Harrison Chase <hw.chase.17@gmail.com>
243 lines
12 KiB
Plaintext
243 lines
12 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "85fb2c03-ab88-4c8c-97e3-a7f2954555ab",
|
|
"metadata": {},
|
|
"source": [
|
|
"# OpenAPI Agent\n",
|
|
"\n",
|
|
"This notebook showcases an agent designed to interact with an OpenAPI spec and make a correct API request based on the information it has gathered from the spec.\n",
|
|
"\n",
|
|
"In the below example, we are using the OpenAPI spec for the OpenAI API, which you can find [here](https://github.com/openai/openai-openapi/blob/master/openapi.yaml)."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "893f90fd-f8f6-470a-a76d-1f200ba02e2f",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Initialization"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "ff988466-c389-4ec6-b6ac-14364a537fd5",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"import os\n",
|
|
"import yaml\n",
|
|
"\n",
|
|
"from langchain.agents import create_openapi_agent\n",
|
|
"from langchain.agents.agent_toolkits import OpenAPIToolkit\n",
|
|
"from langchain.llms.openai import OpenAI\n",
|
|
"from langchain.requests import RequestsWrapper\n",
|
|
"from langchain.tools.json.tool import JsonSpec"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "9ecd1ba0-3937-4359-a41e-68605f0596a1",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"with open(\"openai_openapi.yml\") as f:\n",
|
|
" data = yaml.load(f, Loader=yaml.FullLoader)\n",
|
|
"json_spec=JsonSpec(dict_=data, max_value_length=4000)\n",
|
|
"headers = {\n",
|
|
" \"Authorization\": f\"Bearer {os.getenv('OPENAI_API_KEY')}\"\n",
|
|
"}\n",
|
|
"requests_wrapper=RequestsWrapper(headers=headers)\n",
|
|
"openapi_toolkit = OpenAPIToolkit.from_llm(OpenAI(temperature=0), json_spec, requests_wrapper, verbose=True)\n",
|
|
"openapi_agent_executor = create_openapi_agent(\n",
|
|
" llm=OpenAI(temperature=0),\n",
|
|
" toolkit=openapi_toolkit,\n",
|
|
" verbose=True\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "f111879d-ae84-41f9-ad82-d3e6b72c41ba",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Example: agent capable of analyzing OpenAPI spec and making requests"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"id": "548db7f7-337b-4ba8-905c-e7fd58c01799",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"\n",
|
|
"\n",
|
|
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
|
|
"\u001b[32;1m\u001b[1;3mAction: json_explorer\n",
|
|
"Action Input: What is the base url for the API?\u001b[0m\n",
|
|
"\n",
|
|
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
|
|
"\u001b[32;1m\u001b[1;3mAction: json_spec_list_keys\n",
|
|
"Action Input: data\u001b[0m\n",
|
|
"Observation: \u001b[36;1m\u001b[1;3m['openapi', 'info', 'servers', 'tags', 'paths', 'components', 'x-oaiMeta']\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should look at the servers key to see what the base url is\n",
|
|
"Action: json_spec_list_keys\n",
|
|
"Action Input: data[\"servers\"][0]\u001b[0m\n",
|
|
"Observation: \u001b[36;1m\u001b[1;3mValueError('Value at path `data[\"servers\"][0]` is not a dict, get the value directly.')\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should get the value of the servers key\n",
|
|
"Action: json_spec_get_value\n",
|
|
"Action Input: data[\"servers\"][0]\u001b[0m\n",
|
|
"Observation: \u001b[33;1m\u001b[1;3m{'url': 'https://api.openai.com/v1'}\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I now know the base url for the API\n",
|
|
"Final Answer: The base url for the API is https://api.openai.com/v1\u001b[0m\n",
|
|
"\n",
|
|
"\u001b[1m> Finished chain.\u001b[0m\n",
|
|
"\n",
|
|
"Observation: \u001b[33;1m\u001b[1;3mThe base url for the API is https://api.openai.com/v1\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should find the path for the /completions endpoint.\n",
|
|
"Action: json_explorer\n",
|
|
"Action Input: What is the path for the /completions endpoint?\u001b[0m\n",
|
|
"\n",
|
|
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
|
|
"\u001b[32;1m\u001b[1;3mAction: json_spec_list_keys\n",
|
|
"Action Input: data\u001b[0m\n",
|
|
"Observation: \u001b[36;1m\u001b[1;3m['openapi', 'info', 'servers', 'tags', 'paths', 'components', 'x-oaiMeta']\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should look at the paths key to see what endpoints exist\n",
|
|
"Action: json_spec_list_keys\n",
|
|
"Action Input: data[\"paths\"]\u001b[0m\n",
|
|
"Observation: \u001b[36;1m\u001b[1;3m['/engines', '/engines/{engine_id}', '/completions', '/edits', '/images/generations', '/images/edits', '/images/variations', '/embeddings', '/engines/{engine_id}/search', '/files', '/files/{file_id}', '/files/{file_id}/content', '/answers', '/classifications', '/fine-tunes', '/fine-tunes/{fine_tune_id}', '/fine-tunes/{fine_tune_id}/cancel', '/fine-tunes/{fine_tune_id}/events', '/models', '/models/{model}', '/moderations']\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I now know the path for the /completions endpoint\n",
|
|
"Final Answer: data[\"paths\"][2]\u001b[0m\n",
|
|
"\n",
|
|
"\u001b[1m> Finished chain.\u001b[0m\n",
|
|
"\n",
|
|
"Observation: \u001b[33;1m\u001b[1;3mdata[\"paths\"][2]\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should find the required parameters for the POST request.\n",
|
|
"Action: json_explorer\n",
|
|
"Action Input: What are the required parameters for a POST request to the /completions endpoint?\u001b[0m\n",
|
|
"\n",
|
|
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
|
|
"\u001b[32;1m\u001b[1;3mAction: json_spec_list_keys\n",
|
|
"Action Input: data\u001b[0m\n",
|
|
"Observation: \u001b[36;1m\u001b[1;3m['openapi', 'info', 'servers', 'tags', 'paths', 'components', 'x-oaiMeta']\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should look at the paths key to see what endpoints exist\n",
|
|
"Action: json_spec_list_keys\n",
|
|
"Action Input: data[\"paths\"]\u001b[0m\n",
|
|
"Observation: \u001b[36;1m\u001b[1;3m['/engines', '/engines/{engine_id}', '/completions', '/edits', '/images/generations', '/images/edits', '/images/variations', '/embeddings', '/engines/{engine_id}/search', '/files', '/files/{file_id}', '/files/{file_id}/content', '/answers', '/classifications', '/fine-tunes', '/fine-tunes/{fine_tune_id}', '/fine-tunes/{fine_tune_id}/cancel', '/fine-tunes/{fine_tune_id}/events', '/models', '/models/{model}', '/moderations']\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should look at the /completions endpoint to see what parameters are required\n",
|
|
"Action: json_spec_list_keys\n",
|
|
"Action Input: data[\"paths\"][\"/completions\"]\u001b[0m\n",
|
|
"Observation: \u001b[36;1m\u001b[1;3m['post']\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should look at the post key to see what parameters are required\n",
|
|
"Action: json_spec_list_keys\n",
|
|
"Action Input: data[\"paths\"][\"/completions\"][\"post\"]\u001b[0m\n",
|
|
"Observation: \u001b[36;1m\u001b[1;3m['operationId', 'tags', 'summary', 'requestBody', 'responses', 'x-oaiMeta']\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should look at the requestBody key to see what parameters are required\n",
|
|
"Action: json_spec_list_keys\n",
|
|
"Action Input: data[\"paths\"][\"/completions\"][\"post\"][\"requestBody\"]\u001b[0m\n",
|
|
"Observation: \u001b[36;1m\u001b[1;3m['required', 'content']\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should look at the content key to see what parameters are required\n",
|
|
"Action: json_spec_list_keys\n",
|
|
"Action Input: data[\"paths\"][\"/completions\"][\"post\"][\"requestBody\"][\"content\"]\u001b[0m\n",
|
|
"Observation: \u001b[36;1m\u001b[1;3m['application/json']\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should look at the application/json key to see what parameters are required\n",
|
|
"Action: json_spec_list_keys\n",
|
|
"Action Input: data[\"paths\"][\"/completions\"][\"post\"][\"requestBody\"][\"content\"][\"application/json\"]\u001b[0m\n",
|
|
"Observation: \u001b[36;1m\u001b[1;3m['schema']\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should look at the schema key to see what parameters are required\n",
|
|
"Action: json_spec_list_keys\n",
|
|
"Action Input: data[\"paths\"][\"/completions\"][\"post\"][\"requestBody\"][\"content\"][\"application/json\"][\"schema\"]\u001b[0m\n",
|
|
"Observation: \u001b[36;1m\u001b[1;3m['$ref']\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should look at the $ref key to see what parameters are required\n",
|
|
"Action: json_spec_list_keys\n",
|
|
"Action Input: data[\"paths\"][\"/completions\"][\"post\"][\"requestBody\"][\"content\"][\"application/json\"][\"schema\"][\"$ref\"]\u001b[0m\n",
|
|
"Observation: \u001b[36;1m\u001b[1;3mValueError('Value at path `data[\"paths\"][\"/completions\"][\"post\"][\"requestBody\"][\"content\"][\"application/json\"][\"schema\"][\"$ref\"]` is not a dict, get the value directly.')\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should look at the $ref key to get the value directly\n",
|
|
"Action: json_spec_get_value\n",
|
|
"Action Input: data[\"paths\"][\"/completions\"][\"post\"][\"requestBody\"][\"content\"][\"application/json\"][\"schema\"][\"$ref\"]\u001b[0m\n",
|
|
"Observation: \u001b[33;1m\u001b[1;3m#/components/schemas/CreateCompletionRequest\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should look at the CreateCompletionRequest schema to see what parameters are required\n",
|
|
"Action: json_spec_list_keys\n",
|
|
"Action Input: data[\"components\"][\"schemas\"][\"CreateCompletionRequest\"]\u001b[0m\n",
|
|
"Observation: \u001b[36;1m\u001b[1;3m['type', 'properties', 'required']\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I should look at the required key to see what parameters are required\n",
|
|
"Action: json_spec_get_value\n",
|
|
"Action Input: data[\"components\"][\"schemas\"][\"CreateCompletionRequest\"][\"required\"]\u001b[0m\n",
|
|
"Observation: \u001b[33;1m\u001b[1;3m['model']\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
|
|
"Final Answer: The required parameters for a POST request to the /completions endpoint are 'model'.\u001b[0m\n",
|
|
"\n",
|
|
"\u001b[1m> Finished chain.\u001b[0m\n",
|
|
"\n",
|
|
"Observation: \u001b[33;1m\u001b[1;3mThe required parameters for a POST request to the /completions endpoint are 'model'.\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I now know the parameters needed to make the request.\n",
|
|
"Action: requests_post\n",
|
|
"Action Input: { \"url\": \"https://api.openai.com/v1/completions\", \"data\": { \"model\": \"davinci\", \"prompt\": \"tell me a joke\" } }\u001b[0m\n",
|
|
"Observation: \u001b[33;1m\u001b[1;3m{\"id\":\"cmpl-6oeEcNETfq8TOuIUQvAct6NrBXihs\",\"object\":\"text_completion\",\"created\":1677529082,\"model\":\"davinci\",\"choices\":[{\"text\":\"\\n\\n\\n\\nLove is a battlefield\\n\\n\\n\\nIt's me...And some\",\"index\":0,\"logprobs\":null,\"finish_reason\":\"length\"}],\"usage\":{\"prompt_tokens\":4,\"completion_tokens\":16,\"total_tokens\":20}}\n",
|
|
"\u001b[0m\n",
|
|
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer.\n",
|
|
"Final Answer: Love is a battlefield. It's me...And some.\u001b[0m\n",
|
|
"\n",
|
|
"\u001b[1m> Finished chain.\u001b[0m\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"\"Love is a battlefield. It's me...And some.\""
|
|
]
|
|
},
|
|
"execution_count": 3,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"openapi_agent_executor.run(\"Make a post request to openai /completions. The prompt should be 'tell me a joke.'\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "6ec9582b",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": []
|
|
}
|
|
],
|
|
"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",
|
|
"version": "3.10.9"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|