removing empty cells (#1624)

This commit is contained in:
Isaac Francisco
2024-09-05 14:46:37 -07:00
committed by GitHub
parent 46b6cd45e2
commit d1f06d6771
13 changed files with 4383 additions and 304 deletions
@@ -26,7 +26,10 @@
"id": "0d7b6dcc-c985-46e2-8457-7e6b0298b950",
"metadata": {},
"outputs": [],
"source": ["%%capture --no-stderr\n%pip install -U langchain langchain_openai langsmith pandas langchain_experimental matplotlib langgraph langchain_core"]
"source": [
"%%capture --no-stderr\n",
"%pip install -U langchain langchain_openai langsmith pandas langchain_experimental matplotlib langgraph langchain_core"
]
},
{
"cell_type": "code",
@@ -34,7 +37,24 @@
"id": "743c19df-6da9-4d1e-b2d2-ea40080b9fdc",
"metadata": {},
"outputs": [],
"source": ["import getpass\nimport os\n\n\ndef _set_if_undefined(var: str):\n if not os.environ.get(var):\n os.environ[var] = getpass.getpass(f\"Please provide your {var}\")\n\n\n_set_if_undefined(\"OPENAI_API_KEY\")\n_set_if_undefined(\"LANGCHAIN_API_KEY\")\n_set_if_undefined(\"TAVILY_API_KEY\")\n\n# Optional, add tracing in LangSmith\nos.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\nos.environ[\"LANGCHAIN_PROJECT\"] = \"Multi-agent Collaboration\""]
"source": [
"import getpass\n",
"import os\n",
"\n",
"\n",
"def _set_if_undefined(var: str):\n",
" if not os.environ.get(var):\n",
" os.environ[var] = getpass.getpass(f\"Please provide your {var}\")\n",
"\n",
"\n",
"_set_if_undefined(\"OPENAI_API_KEY\")\n",
"_set_if_undefined(\"LANGCHAIN_API_KEY\")\n",
"_set_if_undefined(\"TAVILY_API_KEY\")\n",
"\n",
"# Optional, add tracing in LangSmith\n",
"os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n",
"os.environ[\"LANGCHAIN_PROJECT\"] = \"Multi-agent Collaboration\""
]
},
{
"cell_type": "markdown",
@@ -54,7 +74,38 @@
"id": "4325a10e-38dc-4a98-9004-e1525eaba377",
"metadata": {},
"outputs": [],
"source": ["from langchain_core.messages import (\n BaseMessage,\n HumanMessage,\n ToolMessage,\n)\nfrom langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n\nfrom langgraph.graph import END, StateGraph, START\n\n\ndef create_agent(llm, tools, system_message: str):\n \"\"\"Create an agent.\"\"\"\n prompt = ChatPromptTemplate.from_messages(\n [\n (\n \"system\",\n \"You are a helpful AI assistant, collaborating with other assistants.\"\n \" Use the provided tools to progress towards answering the question.\"\n \" If you are unable to fully answer, that's OK, another assistant with different tools \"\n \" will help where you left off. Execute what you can to make progress.\"\n \" If you or any of the other assistants have the final answer or deliverable,\"\n \" prefix your response with FINAL ANSWER so the team knows to stop.\"\n \" You have access to the following tools: {tool_names}.\\n{system_message}\",\n ),\n MessagesPlaceholder(variable_name=\"messages\"),\n ]\n )\n prompt = prompt.partial(system_message=system_message)\n prompt = prompt.partial(tool_names=\", \".join([tool.name for tool in tools]))\n return prompt | llm.bind_tools(tools)"]
"source": [
"from langchain_core.messages import (\n",
" BaseMessage,\n",
" HumanMessage,\n",
" ToolMessage,\n",
")\n",
"from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n",
"\n",
"from langgraph.graph import END, StateGraph, START\n",
"\n",
"\n",
"def create_agent(llm, tools, system_message: str):\n",
" \"\"\"Create an agent.\"\"\"\n",
" prompt = ChatPromptTemplate.from_messages(\n",
" [\n",
" (\n",
" \"system\",\n",
" \"You are a helpful AI assistant, collaborating with other assistants.\"\n",
" \" Use the provided tools to progress towards answering the question.\"\n",
" \" If you are unable to fully answer, that's OK, another assistant with different tools \"\n",
" \" will help where you left off. Execute what you can to make progress.\"\n",
" \" If you or any of the other assistants have the final answer or deliverable,\"\n",
" \" prefix your response with FINAL ANSWER so the team knows to stop.\"\n",
" \" You have access to the following tools: {tool_names}.\\n{system_message}\",\n",
" ),\n",
" MessagesPlaceholder(variable_name=\"messages\"),\n",
" ]\n",
" )\n",
" prompt = prompt.partial(system_message=system_message)\n",
" prompt = prompt.partial(tool_names=\", \".join([tool.name for tool in tools]))\n",
" return prompt | llm.bind_tools(tools)"
]
},
{
"cell_type": "markdown",
@@ -72,7 +123,35 @@
"id": "ca076f3b-a729-4ca9-8f91-05c2ba58d610",
"metadata": {},
"outputs": [],
"source": ["from typing import Annotated\n\nfrom langchain_community.tools.tavily_search import TavilySearchResults\nfrom langchain_core.tools import tool\nfrom langchain_experimental.utilities import PythonREPL\n\ntavily_tool = TavilySearchResults(max_results=5)\n\n# Warning: This executes code locally, which can be unsafe when not sandboxed\n\nrepl = PythonREPL()\n\n\n@tool\ndef python_repl(\n code: Annotated[str, \"The python code to execute to generate your chart.\"],\n):\n \"\"\"Use this to execute python code. If you want to see the output of a value,\n you should print it out with `print(...)`. This is visible to the user.\"\"\"\n try:\n result = repl.run(code)\n except BaseException as e:\n return f\"Failed to execute. Error: {repr(e)}\"\n result_str = f\"Successfully executed:\\n```python\\n{code}\\n```\\nStdout: {result}\"\n return (\n result_str + \"\\n\\nIf you have completed all tasks, respond with FINAL ANSWER.\"\n )"]
"source": [
"from typing import Annotated\n",
"\n",
"from langchain_community.tools.tavily_search import TavilySearchResults\n",
"from langchain_core.tools import tool\n",
"from langchain_experimental.utilities import PythonREPL\n",
"\n",
"tavily_tool = TavilySearchResults(max_results=5)\n",
"\n",
"# Warning: This executes code locally, which can be unsafe when not sandboxed\n",
"\n",
"repl = PythonREPL()\n",
"\n",
"\n",
"@tool\n",
"def python_repl(\n",
" code: Annotated[str, \"The python code to execute to generate your chart.\"],\n",
"):\n",
" \"\"\"Use this to execute python code. If you want to see the output of a value,\n",
" you should print it out with `print(...)`. This is visible to the user.\"\"\"\n",
" try:\n",
" result = repl.run(code)\n",
" except BaseException as e:\n",
" return f\"Failed to execute. Error: {repr(e)}\"\n",
" result_str = f\"Successfully executed:\\n```python\\n{code}\\n```\\nStdout: {result}\"\n",
" return (\n",
" result_str + \"\\n\\nIf you have completed all tasks, respond with FINAL ANSWER.\"\n",
" )"
]
},
{
"cell_type": "markdown",
@@ -100,7 +179,19 @@
"id": "290c91d4-f6f4-443c-8181-233d39102974",
"metadata": {},
"outputs": [],
"source": ["import operator\nfrom typing import Annotated, Sequence, TypedDict\n\nfrom langchain_openai import ChatOpenAI\n\n\n# This defines the object that is passed between each node\n# in the graph. We will create different nodes for each agent and tool\nclass AgentState(TypedDict):\n messages: Annotated[Sequence[BaseMessage], operator.add]\n sender: str"]
"source": [
"import operator\n",
"from typing import Annotated, Sequence, TypedDict\n",
"\n",
"from langchain_openai import ChatOpenAI\n",
"\n",
"\n",
"# This defines the object that is passed between each node\n",
"# in the graph. We will create different nodes for each agent and tool\n",
"class AgentState(TypedDict):\n",
" messages: Annotated[Sequence[BaseMessage], operator.add]\n",
" sender: str"
]
},
{
"cell_type": "markdown",
@@ -118,7 +209,46 @@
"id": "71b790ca-9cef-4b22-b469-4b1d5d8424d6",
"metadata": {},
"outputs": [],
"source": ["import functools\n\nfrom langchain_core.messages import AIMessage\n\n\n# Helper function to create a node for a given agent\ndef agent_node(state, agent, name):\n result = agent.invoke(state)\n # We convert the agent output into a format that is suitable to append to the global state\n if isinstance(result, ToolMessage):\n pass\n else:\n result = AIMessage(**result.dict(exclude={\"type\", \"name\"}), name=name)\n return {\n \"messages\": [result],\n # Since we have a strict workflow, we can\n # track the sender so we know who to pass to next.\n \"sender\": name,\n }\n\n\nllm = ChatOpenAI(model=\"gpt-4o\")\n\n# Research agent and node\nresearch_agent = create_agent(\n llm,\n [tavily_tool],\n system_message=\"You should provide accurate data for the chart_generator to use.\",\n)\nresearch_node = functools.partial(agent_node, agent=research_agent, name=\"Researcher\")\n\n# chart_generator\nchart_agent = create_agent(\n llm,\n [python_repl],\n system_message=\"Any charts you display will be visible by the user.\",\n)\nchart_node = functools.partial(agent_node, agent=chart_agent, name=\"chart_generator\")"]
"source": [
"import functools\n",
"\n",
"from langchain_core.messages import AIMessage\n",
"\n",
"\n",
"# Helper function to create a node for a given agent\n",
"def agent_node(state, agent, name):\n",
" result = agent.invoke(state)\n",
" # We convert the agent output into a format that is suitable to append to the global state\n",
" if isinstance(result, ToolMessage):\n",
" pass\n",
" else:\n",
" result = AIMessage(**result.dict(exclude={\"type\", \"name\"}), name=name)\n",
" return {\n",
" \"messages\": [result],\n",
" # Since we have a strict workflow, we can\n",
" # track the sender so we know who to pass to next.\n",
" \"sender\": name,\n",
" }\n",
"\n",
"\n",
"llm = ChatOpenAI(model=\"gpt-4o\")\n",
"\n",
"# Research agent and node\n",
"research_agent = create_agent(\n",
" llm,\n",
" [tavily_tool],\n",
" system_message=\"You should provide accurate data for the chart_generator to use.\",\n",
")\n",
"research_node = functools.partial(agent_node, agent=research_agent, name=\"Researcher\")\n",
"\n",
"# chart_generator\n",
"chart_agent = create_agent(\n",
" llm,\n",
" [python_repl],\n",
" system_message=\"Any charts you display will be visible by the user.\",\n",
")\n",
"chart_node = functools.partial(agent_node, agent=chart_agent, name=\"chart_generator\")"
]
},
{
"cell_type": "markdown",
@@ -136,7 +266,12 @@
"id": "d9a79c76-5c7c-42f6-91cf-635bc8305804",
"metadata": {},
"outputs": [],
"source": ["from langgraph.prebuilt import ToolNode\n\ntools = [tavily_tool, python_repl]\ntool_node = ToolNode(tools)"]
"source": [
"from langgraph.prebuilt import ToolNode\n",
"\n",
"tools = [tavily_tool, python_repl]\n",
"tool_node = ToolNode(tools)"
]
},
{
"cell_type": "markdown",
@@ -154,7 +289,23 @@
"id": "4f4b4d37-e8a3-4abb-8d42-eaea26016f35",
"metadata": {},
"outputs": [],
"source": ["# Either agent can decide to end\nfrom typing import Literal\n\n\ndef router(state) -> Literal[\"call_tool\", \"__end__\", \"continue\"]:\n # This is the router\n messages = state[\"messages\"]\n last_message = messages[-1]\n if last_message.tool_calls:\n # The previous agent is invoking a tool\n return \"call_tool\"\n if \"FINAL ANSWER\" in last_message.content:\n # Any agent decided the work is done\n return \"__end__\"\n return \"continue\""]
"source": [
"# Either agent can decide to end\n",
"from typing import Literal\n",
"\n",
"\n",
"def router(state) -> Literal[\"call_tool\", \"__end__\", \"continue\"]:\n",
" # This is the router\n",
" messages = state[\"messages\"]\n",
" last_message = messages[-1]\n",
" if last_message.tool_calls:\n",
" # The previous agent is invoking a tool\n",
" return \"call_tool\"\n",
" if \"FINAL ANSWER\" in last_message.content:\n",
" # Any agent decided the work is done\n",
" return \"__end__\"\n",
" return \"continue\""
]
},
{
"cell_type": "markdown",
@@ -172,7 +323,39 @@
"id": "4dce3901-6ad5-4df5-8528-6e865cf96cb0",
"metadata": {},
"outputs": [],
"source": ["workflow = StateGraph(AgentState)\n\nworkflow.add_node(\"Researcher\", research_node)\nworkflow.add_node(\"chart_generator\", chart_node)\nworkflow.add_node(\"call_tool\", tool_node)\n\nworkflow.add_conditional_edges(\n \"Researcher\",\n router,\n {\"continue\": \"chart_generator\", \"call_tool\": \"call_tool\", \"__end__\": END},\n)\nworkflow.add_conditional_edges(\n \"chart_generator\",\n router,\n {\"continue\": \"Researcher\", \"call_tool\": \"call_tool\", \"__end__\": END},\n)\n\nworkflow.add_conditional_edges(\n \"call_tool\",\n # Each agent node updates the 'sender' field\n # the tool calling node does not, meaning\n # this edge will route back to the original agent\n # who invoked the tool\n lambda x: x[\"sender\"],\n {\n \"Researcher\": \"Researcher\",\n \"chart_generator\": \"chart_generator\",\n },\n)\nworkflow.add_edge(START, \"Researcher\")\ngraph = workflow.compile()"]
"source": [
"workflow = StateGraph(AgentState)\n",
"\n",
"workflow.add_node(\"Researcher\", research_node)\n",
"workflow.add_node(\"chart_generator\", chart_node)\n",
"workflow.add_node(\"call_tool\", tool_node)\n",
"\n",
"workflow.add_conditional_edges(\n",
" \"Researcher\",\n",
" router,\n",
" {\"continue\": \"chart_generator\", \"call_tool\": \"call_tool\", \"__end__\": END},\n",
")\n",
"workflow.add_conditional_edges(\n",
" \"chart_generator\",\n",
" router,\n",
" {\"continue\": \"Researcher\", \"call_tool\": \"call_tool\", \"__end__\": END},\n",
")\n",
"\n",
"workflow.add_conditional_edges(\n",
" \"call_tool\",\n",
" # Each agent node updates the 'sender' field\n",
" # the tool calling node does not, meaning\n",
" # this edge will route back to the original agent\n",
" # who invoked the tool\n",
" lambda x: x[\"sender\"],\n",
" {\n",
" \"Researcher\": \"Researcher\",\n",
" \"chart_generator\": \"chart_generator\",\n",
" },\n",
")\n",
"workflow.add_edge(START, \"Researcher\")\n",
"graph = workflow.compile()"
]
},
{
"cell_type": "code",
@@ -191,7 +374,15 @@
"output_type": "display_data"
}
],
"source": ["from IPython.display import Image, display\n\ntry:\n display(Image(graph.get_graph(xray=True).draw_mermaid_png()))\nexcept Exception:\n # This requires some extra dependencies and is optional\n pass"]
"source": [
"from IPython.display import Image, display\n",
"\n",
"try:\n",
" display(Image(graph.get_graph(xray=True).draw_mermaid_png()))\n",
"except Exception:\n",
" # This requires some extra dependencies and is optional\n",
" pass"
]
},
{
"cell_type": "markdown",
@@ -290,15 +481,24 @@
]
}
],
"source": ["events = graph.stream(\n {\n \"messages\": [\n HumanMessage(\n content=\"Fetch the UK's GDP over the past 5 years,\"\n \" then draw a line graph of it.\"\n \" Once you code it up, finish.\"\n )\n ],\n },\n # Maximum number of steps to take in the graph\n {\"recursion_limit\": 150},\n)\nfor s in events:\n print(s)\n print(\"----\")"]
},
{
"cell_type": "code",
"execution_count": null,
"id": "010fc36e-4116-4758-bcac-b02c7dcd405d",
"metadata": {},
"outputs": [],
"source": [""]
"source": [
"events = graph.stream(\n",
" {\n",
" \"messages\": [\n",
" HumanMessage(\n",
" content=\"Fetch the UK's GDP over the past 5 years,\"\n",
" \" then draw a line graph of it.\"\n",
" \" Once you code it up, finish.\"\n",
" )\n",
" ],\n",
" },\n",
" # Maximum number of steps to take in the graph\n",
" {\"recursion_limit\": 150},\n",
")\n",
"for s in events:\n",
" print(s)\n",
" print(\"----\")"
]
}
],
"metadata": {