Skip to content

Commit

Permalink
update example ipynb && openai_function_agent
Browse files Browse the repository at this point in the history
  • Loading branch information
arcosx committed Aug 7, 2023
1 parent 9ec9bee commit 3caa5b8
Show file tree
Hide file tree
Showing 6 changed files with 411 additions and 151 deletions.
167 changes: 125 additions & 42 deletions examples/langchain/agent/agent.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count": 29,
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -26,37 +26,16 @@
"metadata": {},
"outputs": [],
"source": [
"from pydantic import BaseModel\n",
"from langchain.tools import StructuredTool\n",
"\n",
"def code_run(code:str):\n",
" output = sandbox.run(code=code)\n",
" return output.content"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"from langchain.tools import StructuredTool"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [],
"source": [
"from pydantic import BaseModel\n",
" return output.content\n",
"\n",
"class CodeInput(BaseModel):\n",
" code: str\n"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
" code: str\n",
"\n",
"tools = [\n",
" StructuredTool(\n",
" name=\"python\",\n",
Expand All @@ -67,26 +46,90 @@
" func=code_run,\n",
" args_schema=CodeInput,\n",
" )\n",
"]"
"]\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 25,
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"from langchain.chat_models import ChatOpenAI\n",
"from langchain.agents import initialize_agent, Tool\n",
"from langchain.agents import AgentType\n",
"from langchain.agents import AgentExecutor\n",
"from langchain.memory import ConversationBufferMemory\n",
"from codeinterpreter.agent.openai_functions_agent.base import CustomOpenAIFunctionsAgent\n",
"\n",
"\n",
"llm = ChatOpenAI(temperature=0, model=\"gpt-3.5-turbo-0613\")\n",
"agent = initialize_agent(tools, llm, agent=AgentType.OPENAI_FUNCTIONS, verbose=True)"
"\n",
"agent = CustomOpenAIFunctionsAgent.from_llm_and_tools(llm=llm,tools=tools)\n",
"\n",
"agent_executor = AgentExecutor(agent=agent, tools=tools, memory=ConversationBufferMemory(\n",
" memory_key=\"chat_history\", return_messages=True\n",
" ), verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m\n",
"Invoking: `python` with `import random\n",
"\n",
"# Generate two random numbers\n",
"random_number1 = random.randint(1, 100)\n",
"random_number2 = random.randint(1, 100)\n",
"\n",
"# Print the random numbers\n",
"print(random_number1)\n",
"print(random_number2)`\n",
"\n",
"\n",
"\u001b[0m\u001b[36;1m\u001b[1;3m27\n",
"11\u001b[0m\u001b[32;1m\u001b[1;3mThe two random numbers are 27 and 11.\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"{'input': 'print two random number',\n",
" 'chat_history': [HumanMessage(content='create two random number, add them with 100', additional_kwargs={}, example=False),\n",
" AIMessage(content='The sum of two random numbers, added with 100, is 230.', additional_kwargs={}, example=False),\n",
" HumanMessage(content='create two random number, add them with 100', additional_kwargs={}, example=False),\n",
" AIMessage(content='The sum of two random numbers, added with 100, is 160.', additional_kwargs={}, example=False),\n",
" HumanMessage(content='print two random number', additional_kwargs={}, example=False),\n",
" AIMessage(content='The two random numbers are 77 and 12.', additional_kwargs={}, example=False),\n",
" HumanMessage(content='print two random number', additional_kwargs={}, example=False),\n",
" AIMessage(content='The two random numbers are 31 and 17.', additional_kwargs={}, example=False),\n",
" HumanMessage(content='print two random number', additional_kwargs={}, example=False),\n",
" AIMessage(content='The two random numbers are 27 and 11.', additional_kwargs={}, example=False)],\n",
" 'output': 'The two random numbers are 27 and 11.'}"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"agent_executor({\"input\": \"print two random number\"})"
]
},
{
"cell_type": "code",
"execution_count": 34,
"execution_count": 10,
"metadata": {},
"outputs": [
{
Expand All @@ -97,35 +140,75 @@
"\n",
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m\n",
"Invoking: `python` with `{'code': \"print('Blue')\"}`\n",
"responded: {content}\n",
"Invoking: `python` with `import requests\n",
"from PIL import Image\n",
"from io import BytesIO\n",
"\n",
"# Send a GET request to google.com\n",
"response = requests.get(\"https://www.google.com\")\n",
"\n",
"# Get the logo image URL from the response\n",
"logo_url = \"https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png\"\n",
"\n",
"\u001b[0m\u001b[36;1m\u001b[1;3mBlue\u001b[0m\u001b[32;1m\u001b[1;3mThe color I picked to print is blue.\u001b[0m\n",
"# Send a GET request to the logo image URL\n",
"logo_response = requests.get(logo_url)\n",
"\n",
"# Create an Image object from the logo image data\n",
"logo_image = Image.open(BytesIO(logo_response.content))\n",
"\n",
"# Display the logo image\n",
"logo_image.show()`\n",
"\n",
"\n",
"\u001b[0m\u001b[36;1m\u001b[1;3mModuleNotFoundError: No module named 'PIL'\u001b[0m\u001b[32;1m\u001b[1;3mIt seems that the `PIL` (Python Imaging Library) module is not installed in the current environment. This module is required to process and display the image.\n",
"\n",
"To install the `PIL` module, you can use the following command:\n",
"\n",
"```\n",
"!pip install pillow\n",
"```\n",
"\n",
"Once the module is installed, you can run the code again to request google.com and display the logo image.\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"'The color I picked to print is blue.'"
"{'input': 'can you request google.com and show me the logo in the website',\n",
" 'chat_history': [HumanMessage(content='create two random number, add them with 100', additional_kwargs={}, example=False),\n",
" AIMessage(content='The sum of two random numbers, added with 100, is 230.', additional_kwargs={}, example=False),\n",
" HumanMessage(content='create two random number, add them with 100', additional_kwargs={}, example=False),\n",
" AIMessage(content='The sum of two random numbers, added with 100, is 160.', additional_kwargs={}, example=False),\n",
" HumanMessage(content='print two random number', additional_kwargs={}, example=False),\n",
" AIMessage(content='The two random numbers are 77 and 12.', additional_kwargs={}, example=False),\n",
" HumanMessage(content='print two random number', additional_kwargs={}, example=False),\n",
" AIMessage(content='The two random numbers are 31 and 17.', additional_kwargs={}, example=False),\n",
" HumanMessage(content='print two random number', additional_kwargs={}, example=False),\n",
" AIMessage(content='The two random numbers are 27 and 11.', additional_kwargs={}, example=False),\n",
" HumanMessage(content='can you request google.com and show me the logo in the website', additional_kwargs={}, example=False),\n",
" AIMessage(content='It seems that the `PIL` (Python Imaging Library) module is not installed in the current environment. This module is required to process and display the image.\\n\\nTo install the `PIL` module, you can use the following command:\\n\\n```\\n!pip install pillow\\n```\\n\\nOnce the module is installed, you can run the code again to request google.com and display the logo image.', additional_kwargs={}, example=False)],\n",
" 'output': 'It seems that the `PIL` (Python Imaging Library) module is not installed in the current environment. This module is required to process and display the image.\\n\\nTo install the `PIL` module, you can use the following command:\\n\\n```\\n!pip install pillow\\n```\\n\\nOnce the module is installed, you can run the code again to request google.com and display the logo image.'}"
]
},
"execution_count": 34,
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"agent.run(\"pick a color to print ! red,blue,yellow\")\n"
"agent_executor({\"input\": \"can you request google.com and show me the logo in the website\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
"source": [
"sandbox.run(\"!!pip install pillow\")"
]
}
],
"metadata": {
Expand Down
Empty file.
Empty file.
144 changes: 144 additions & 0 deletions src/codeinterpreter/agent/openai_functions_agent/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
from langchain.agents.openai_functions_agent.base import OpenAIFunctionsAgent

import json
from json import JSONDecodeError
from typing import Union


from langchain.schema import (
AgentAction,
AgentFinish,
OutputParserException,
)
from langchain.schema.messages import (
AIMessage,
BaseMessage,
)

from typing import Any, List, Tuple, Union, Dict


from langchain.agents.openai_functions_agent.base import (
OpenAIFunctionsAgent,
_FunctionsAgentAction,
_format_intermediate_steps,
)
from langchain.schema import (
AgentAction,
AgentFinish,
AIMessage,
BaseMessage,
)
from typing import Union
from json import JSONDecodeError


from langchain.callbacks.manager import Callbacks


def _parse_ai_message(message: BaseMessage) -> Union[AgentAction, AgentFinish]:
"""Parse an AI message."""
if not isinstance(message, AIMessage):
raise TypeError(f"Expected an AI message got {type(message)}")

function_call = message.additional_kwargs.get("function_call", {})

if function_call:
function_name = function_call["name"]
try:
_tool_input = json.loads(function_call["arguments"])
except JSONDecodeError:
_tool_input = function_call["arguments"]
# HACK HACK HACK:
# The code that encodes tool input into Open AI uses a special variable
# name called `__arg1` to handle old style tools that do not expose a
# schema and expect a single string argument as an input.
# We unpack the argument here if it exists.
# Open AI does not support passing in a JSON array as an argument.
if "__arg1" in _tool_input:
tool_input = _tool_input["__arg1"]
else:
tool_input = _tool_input

content_msg = "responded: {content}\n" if message.content else "\n"

return _FunctionsAgentAction(
tool=function_name,
tool_input=tool_input,
log=f"\nInvoking: `{function_name}` with `{tool_input}`\n{content_msg}\n",
message_log=[message],
)

return AgentFinish(return_values={"output": message.content}, log=message.content)


class CustomOpenAIFunctionsAgent(OpenAIFunctionsAgent):
"""
https://github.com/langchain-ai/langchain/issues/6364
"""

def plan(
self,
intermediate_steps: List[Tuple[AgentAction, str]],
callbacks: Callbacks = None,
with_functions: bool = True,
**kwargs: Any,
) -> Union[AgentAction, AgentFinish]:
"""Given input, decided what to do.
Args:
intermediate_steps: Steps the LLM has taken to date, along with observations
**kwargs: User inputs.
Returns:
Action specifying what tool to use.
"""
agent_scratchpad = _format_intermediate_steps(intermediate_steps)
selected_inputs = {
k: kwargs[k] for k in self.prompt.input_variables if k != "agent_scratchpad"
}
full_inputs = dict(**selected_inputs, agent_scratchpad=agent_scratchpad)
prompt = self.prompt.format_prompt(**full_inputs)
messages = prompt.to_messages()
if with_functions:
predicted_message = self.llm.predict_messages(
messages,
functions=self.functions,
callbacks=callbacks,
)
else:
predicted_message = self.llm.predict_messages(
messages,
callbacks=callbacks,
)
agent_decision = _parse_ai_message(predicted_message)
return agent_decision

async def aplan(
self,
intermediate_steps: List[Tuple[AgentAction, str]],
callbacks: Callbacks = None,
**kwargs: Any,
) -> Union[AgentAction, AgentFinish]:
"""Given input, decided what to do.
Args:
intermediate_steps: Steps the LLM has taken to date,
along with observations
**kwargs: User inputs.
Returns:
Action specifying what tool to use.
"""
agent_scratchpad = _format_intermediate_steps(intermediate_steps)
selected_inputs = {
k: kwargs[k] for k in self.prompt.input_variables if k != "agent_scratchpad"
}
full_inputs = dict(**selected_inputs, agent_scratchpad=agent_scratchpad)
prompt = self.prompt.format_prompt(**full_inputs)
messages = prompt.to_messages()
predicted_message = await self.llm.apredict_messages(
messages, functions=self.functions, callbacks=callbacks
)
agent_decision = _parse_ai_message(predicted_message)
return agent_decision
Loading

0 comments on commit 3caa5b8

Please sign in to comment.