From 238ee0207265350d4dd0a3233e61c53a3bedb2df Mon Sep 17 00:00:00 2001 From: vizsatiz Date: Tue, 3 Sep 2024 18:44:55 +0530 Subject: [PATCH] Adding support for Tool Agent --- examples/agent_of_flo_ai.ipynb | 90 +++++++++++++++++++++++++------- flo_ai/factory/agent_factory.py | 17 +++--- flo_ai/models/flo_agent.py | 2 +- flo_ai/models/flo_llm_agent.py | 1 + flo_ai/models/flo_node.py | 17 ++---- flo_ai/models/flo_routed_team.py | 2 +- flo_ai/models/flo_transformer.py | 6 +++ flo_ai/state/flo_session.py | 6 --- 8 files changed, 95 insertions(+), 46 deletions(-) create mode 100644 flo_ai/models/flo_transformer.py diff --git a/examples/agent_of_flo_ai.ipynb b/examples/agent_of_flo_ai.ipynb index 26209ba9..06d6dc29 100644 --- a/examples/agent_of_flo_ai.ipynb +++ b/examples/agent_of_flo_ai.ipynb @@ -14,12 +14,12 @@ "\n", "2. LLM Agents (`kind: llm`): These agents are simply an LLM which can answer any questions asked to it. The agents dont except tools. If tool is passed to an agent of type llm, they are ignored.\n", "\n", - "3. Tool LLM (`kind: tool`): These agents are just tools or functions that can be executed on the current state. Within the tool will be given the current state as the input, meaning the history of what happened in the network right now" + "3. Tool LLM (`kind: tool`): These agents are just tools or functions that can be executed on the current state. Within the tool will be given the current state as the input, meaning the history of what happened in the flo until now" ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -28,7 +28,7 @@ "True" ] }, - "execution_count": 1, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -52,16 +52,16 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 2, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -91,7 +91,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -111,7 +111,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -125,17 +125,19 @@ "Invoking: `tavily_search_results_json` with `{'query': 'California weather October 2023'}`\n", "\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[{'url': 'https://www.weatherapi.com/', 'content': \"{'location': {'name': 'California City', 'region': 'California', 'country': 'United States of America', 'lat': 35.13, 'lon': -117.99, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1725356198, 'localtime': '2024-09-03 02:36'}, 'current': {'last_updated_epoch': 1725355800, 'last_updated': '2024-09-03 02:30', 'temp_c': 25.3, 'temp_f': 77.5, 'is_day': 0, 'condition': {'text': 'Clear', 'icon': '//cdn.weatherapi.com/weather/64x64/night/113.png', 'code': 1000}, 'wind_mph': 3.8, 'wind_kph': 6.1, 'wind_degree': 230, 'wind_dir': 'SW', 'pressure_mb': 1016.0, 'pressure_in': 29.99, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 28, 'cloud': 0, 'feelslike_c': 24.9, 'feelslike_f': 76.9, 'windchill_c': 24.1, 'windchill_f': 75.4, 'heatindex_c': 24.3, 'heatindex_f': 75.7, 'dewpoint_c': 5.8, 'dewpoint_f': 42.4, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 1.0, 'gust_mph': 9.9, 'gust_kph': 15.9}}\"}, {'url': 'https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023', 'content': 'Weather reports from October 2023 in Los Angeles, California, USA with highs and lows. Sign in. News. News Home; Astronomy News; Time Zone News; Calendar & Holiday News; Newsletter; Live events. ... High & Low Weather Summary for October 2023 Temperature Humidity Pressure; High: 92 °F (Oct 5, 11:53 am) 100% (Oct 7, 9:02 am) 30.11 \"Hg (Oct 7, 9 ...'}, {'url': 'https://world-weather.info/forecast/usa/california/october-2023/', 'content': 'Detailed ⚡ California Weather Forecast for October 2023 - day/night 🌡️ temperatures, precipitations - World-Weather.info'}, {'url': 'https://www.meteoprog.com/weather/California-california/month/october/', 'content': 'California (United States) weather in October 2023 ☀️ Accurate weather forecast for California in October ⛅ Detailed forecast By month Current temperature \"near me\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG'}, {'url': 'https://www.latimes.com/environment/story/2023-10-18/california-heat-wave-2023-when-will-it-end', 'content': 'October heat wave could break records in California, but chance of rain awaits next week. Oct. 19, 2023. The unseasonably hot weather brings increased concern for heat-related illness, especially ...'}]\u001b[0m\u001b[32;1m\u001b[1;3mThe weather in California during October 2023 has been characterized by unseasonably high temperatures. For example, in Los Angeles, temperatures reached a high of 92°F (approximately 33°C) on October 5. The weather has been mostly clear, with low humidity levels and little to no precipitation reported.\n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[{'url': 'https://www.weatherapi.com/', 'content': \"{'location': {'name': 'California City', 'region': 'California', 'country': 'United States of America', 'lat': 35.13, 'lon': -117.99, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1725364509, 'localtime': '2024-09-03 04:55'}, 'current': {'last_updated_epoch': 1725363900, 'last_updated': '2024-09-03 04:45', 'temp_c': 23.1, 'temp_f': 73.6, 'is_day': 0, 'condition': {'text': 'Clear', 'icon': '//cdn.weatherapi.com/weather/64x64/night/113.png', 'code': 1000}, 'wind_mph': 2.2, 'wind_kph': 3.6, 'wind_degree': 10, 'wind_dir': 'N', 'pressure_mb': 1016.0, 'pressure_in': 30.0, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 31, 'cloud': 0, 'feelslike_c': 23.8, 'feelslike_f': 74.9, 'windchill_c': 22.7, 'windchill_f': 72.9, 'heatindex_c': 23.7, 'heatindex_f': 74.7, 'dewpoint_c': 5.0, 'dewpoint_f': 41.0, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 1.0, 'gust_mph': 8.5, 'gust_kph': 13.6}}\"}, {'url': 'https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023', 'content': 'Weather reports from October 2023 in Los Angeles, California, USA with highs and lows. Sign in. News. News Home; Astronomy News; Time Zone News; Calendar & Holiday News; Newsletter; Live events. ... High & Low Weather Summary for October 2023 Temperature Humidity Pressure; High: 92 °F (Oct 5, 11:53 am) 100% (Oct 7, 9:02 am) 30.11 \"Hg (Oct 7, 9 ...'}, {'url': 'https://world-weather.info/forecast/usa/california/october-2023/', 'content': 'Detailed ⚡ California Weather Forecast for October 2023 - day/night 🌡️ temperatures, precipitations - World-Weather.info'}, {'url': 'https://www.meteoprog.com/weather/California-california/month/october/', 'content': 'California (United States) weather in October 2023 ☀️ Accurate weather forecast for California in October ⛅ Detailed forecast By month Current temperature \"near me\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG'}, {'url': 'https://www.latimes.com/environment/story/2023-10-18/california-heat-wave-2023-when-will-it-end', 'content': 'October heat wave could break records in California, but chance of rain awaits next week. Oct. 19, 2023. The unseasonably hot weather brings increased concern for heat-related illness, especially ...'}]\u001b[0m\u001b[32;1m\u001b[1;3mThe weather in California during October 2023 has been characterized by some unseasonably hot days. For instance, on October 5, temperatures reached a high of 92°F (approximately 33°C). The humidity levels have also varied, with reports indicating a peak of 100% on October 7.\n", "\n", - "As of now, the current temperature in California City is about 25.3°C (77.5°F) with clear skies and a light breeze. The humidity is relatively low at 28%, and there is no precipitation expected.\n", + "Currently, in California City, the temperature is around 73.6°F (23.1°C) with clear skies, low humidity (31%), and no precipitation. The weather is generally pleasant, but there have been concerns about heat-related illnesses due to the heat wave affecting the region.\n", "\n", "For more detailed forecasts and updates, you can check the following sources:\n", "- [Weather API](https://www.weatherapi.com/)\n", "- [Time and Date](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\n", - "- [World Weather Info](https://world-weather.info/forecast/usa/california/october-2023/)\u001b[0m\n", + "- [World Weather Info](https://world-weather.info/forecast/usa/california/october-2023/)\n", + "- [Meteoprog](https://www.meteoprog.com/weather/California-california/month/october/)\n", + "- [LA Times](https://www.latimes.com/environment/story/2023-10-18/california-heat-wave-2023-when-will-it-end)\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n", - "{'messages': [HumanMessage(content='Whats the whether in california')], 'output': 'The weather in California during October 2023 has been characterized by unseasonably high temperatures. For example, in Los Angeles, temperatures reached a high of 92°F (approximately 33°C) on October 5. The weather has been mostly clear, with low humidity levels and little to no precipitation reported.\\n\\nAs of now, the current temperature in California City is about 25.3°C (77.5°F) with clear skies and a light breeze. The humidity is relatively low at 28%, and there is no precipitation expected.\\n\\nFor more detailed forecasts and updates, you can check the following sources:\\n- [Weather API](https://www.weatherapi.com/)\\n- [Time and Date](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\\n- [World Weather Info](https://world-weather.info/forecast/usa/california/october-2023/)'}\n" + "{'messages': [HumanMessage(content='Whats the whether in california')], 'output': 'The weather in California during October 2023 has been characterized by some unseasonably hot days. For instance, on October 5, temperatures reached a high of 92°F (approximately 33°C). The humidity levels have also varied, with reports indicating a peak of 100% on October 7.\\n\\nCurrently, in California City, the temperature is around 73.6°F (23.1°C) with clear skies, low humidity (31%), and no precipitation. The weather is generally pleasant, but there have been concerns about heat-related illnesses due to the heat wave affecting the region.\\n\\nFor more detailed forecasts and updates, you can check the following sources:\\n- [Weather API](https://www.weatherapi.com/)\\n- [Time and Date](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\\n- [World Weather Info](https://world-weather.info/forecast/usa/california/october-2023/)\\n- [Meteoprog](https://www.meteoprog.com/weather/California-california/month/october/)\\n- [LA Times](https://www.latimes.com/environment/story/2023-10-18/california-heat-wave-2023-when-will-it-end)'}\n" ] } ], @@ -149,7 +151,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Agentic Agent (agentic)\n", + "## LLM Agent (agentic)\n", "\n", "Here we are gonna create a simple llm math assitant flo agent that can check answer any math question\n", "\n", @@ -158,11 +160,11 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ - "simple_ll_agent = \"\"\"\n", + "simple_llm_agent = \"\"\"\n", "apiVersion: flo/alpha-v1\n", "kind: FloAgent\n", "name: llm-assistant\n", @@ -176,7 +178,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -198,7 +200,7 @@ } ], "source": [ - "flo = Flo.build(session, simple_ll_agent)\n", + "flo = Flo.build(session, simple_llm_agent)\n", "\n", "print(flo.invoke(\"What is pythagorus theorum\"))" ] @@ -206,7 +208,59 @@ { "cell_type": "markdown", "metadata": {}, - "source": [] + "source": [ + "#" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'messages': [HumanMessage(content='Print what I am saying')]}\n", + "Tool call success\n" + ] + } + ], + "source": [ + "from typing import Optional, Type\n", + "from langchain.pydantic_v1 import BaseModel, Field\n", + "from langchain.tools import BaseTool, StructuredTool, tool\n", + "\n", + "class PrintStateTool(BaseTool):\n", + " name = \"printStateTool\"\n", + " description = \"Just print the state\"\n", + "\n", + " def _run(\n", + " self, **kwargs\n", + " ) -> str:\n", + " print(kwargs)\n", + " return \"Tool call success\"\n", + " \n", + "session.register_tool(\n", + " name=\"printStateTool\", \n", + " tool=PrintStateTool()\n", + ")\n", + " \n", + "simple_tool_agent = \"\"\"\n", + "apiVersion: flo/alpha-v1\n", + "kind: FloAgent\n", + "name: llm-assistant\n", + "agent:\n", + " name: tool-to-print-state\n", + " kind: tool\n", + " tools:\n", + " - name: printStateTool\n", + "\"\"\"\n", + "\n", + "flo = Flo.build(session, simple_tool_agent)\n", + "\n", + "print(flo.invoke(\"Print what I am saying\"))" + ] } ], "metadata": { diff --git a/flo_ai/factory/agent_factory.py b/flo_ai/factory/agent_factory.py index bcb58b02..949f18b3 100644 --- a/flo_ai/factory/agent_factory.py +++ b/flo_ai/factory/agent_factory.py @@ -2,14 +2,14 @@ from flo_ai.yaml.flo_team_builder import (AgentConfig) from flo_ai.models.flo_agent import FloAgent from flo_ai.models.flo_llm_agent import FloLLMAgent +from flo_ai.models.flo_executable import ExecutableFlo from enum import Enum class AgentKinds(Enum): - executable = "executable" - agentic = "agentic" llm = "llm" - + tool = "tool" + function = "function" class AgentFactory(): @@ -23,8 +23,8 @@ def create(session: FloSession, agent: AgentConfig, tool_map): match(agent_kind): case AgentKinds.llm: return AgentFactory.__create_llm_agent(session, agent) - case AgentKinds.executable: - raise ValueError("un-supported") + case AgentKinds.tool: + return AgentFactory.__create_runnable_agent(session, agent) return AgentFactory.__create_agentic_agent(session, agent, tool_map) @staticmethod @@ -42,4 +42,9 @@ def __create_agentic_agent(session: FloSession, agent: AgentConfig, tool_map) -> def __create_llm_agent(session: FloSession, agent: AgentConfig) -> FloLLMAgent: builder = FloLLMAgent.Builder(session, agent.name, agent.job, agent.role) llm_agent: FloLLMAgent = builder.build() - return llm_agent \ No newline at end of file + return llm_agent + + @staticmethod + def __create_runnable_agent(session: FloSession, agent: AgentConfig) -> FloLLMAgent: + runnable = session.tools[agent.tools[0].name] + return ExecutableFlo(agent.name, runnable, "agent") \ No newline at end of file diff --git a/flo_ai/models/flo_agent.py b/flo_ai/models/flo_agent.py index 260cbb9a..b82083a3 100644 --- a/flo_ai/models/flo_agent.py +++ b/flo_ai/models/flo_agent.py @@ -10,7 +10,7 @@ from typing import Union, Optional class FloAgent(ExecutableFlo): - def __init__(self, + def __init__(self, agent: Runnable, executor: AgentExecutor, name: str) -> None: diff --git a/flo_ai/models/flo_llm_agent.py b/flo_ai/models/flo_llm_agent.py index 8886866a..5b3b9111 100644 --- a/flo_ai/models/flo_llm_agent.py +++ b/flo_ai/models/flo_llm_agent.py @@ -11,6 +11,7 @@ from langchain_core.output_parsers import StrOutputParser class FloLLMAgent(ExecutableFlo): + def __init__(self, executor: Runnable, name: str) -> None: diff --git a/flo_ai/models/flo_node.py b/flo_ai/models/flo_node.py index acbdb6f0..692059ae 100644 --- a/flo_ai/models/flo_node.py +++ b/flo_ai/models/flo_node.py @@ -4,7 +4,6 @@ from langchain.agents import AgentExecutor from flo_ai.state.flo_state import TeamFloAgentState from langchain_core.messages import HumanMessage -from langchain_core.runnables import Runnable class FloNode(): @@ -19,14 +18,8 @@ class Builder(): @staticmethod def teamflo_agent_node(state: TeamFloAgentState, agent: AgentExecutor, name: str): result = agent.invoke(state) - return {"messages": [HumanMessage(content=result["output"], name=name)]} - - @staticmethod - def teamflo_tool_node(state: TeamFloAgentState, tool: Runnable, name): - # TODO see if you want to send the entire data or not - result = tool.invoke(state["messages"][-1]) - return {"messages": [HumanMessage(content=result, name=name)]} - + return { "messages": [HumanMessage(content=result["output"], name=name)] } + @staticmethod def get_last_message(state: TeamFloAgentState) -> str: return state["messages"][-1].content @@ -51,8 +44,4 @@ def build_from_team(self, flo_team: FloRoutedTeam): return FloNode(( FloNode.Builder.get_last_message | functools.partial(FloNode.Builder.teamflo_team_node, members=flo_team.graph.nodes) | flo_team.graph | FloNode.Builder.join_graph - ), flo_team.name) - - # TODO add type to tool - def build_from_tool(self, tool: Runnable, name: str): - return FloNode(functools.partial(FloNode.Builder.teamflo_tool_node, tool=tool, name=name)) \ No newline at end of file + ), flo_team.name) \ No newline at end of file diff --git a/flo_ai/models/flo_routed_team.py b/flo_ai/models/flo_routed_team.py index 95994aaa..0eb4270e 100644 --- a/flo_ai/models/flo_routed_team.py +++ b/flo_ai/models/flo_routed_team.py @@ -7,4 +7,4 @@ def __init__(self, name: str, graph: CompiledGraph) -> None: super().__init__(name, graph) def draw(self, xray=True): - return self.graph.get_graph(xray=xray).draw_mermaid_png() \ No newline at end of file + return self.runnable.get_graph(xray=xray).draw_mermaid_png() \ No newline at end of file diff --git a/flo_ai/models/flo_transformer.py b/flo_ai/models/flo_transformer.py new file mode 100644 index 00000000..715b7169 --- /dev/null +++ b/flo_ai/models/flo_transformer.py @@ -0,0 +1,6 @@ +from flo_ai.models.flo_node import FloNode + +class FloTransformer(FloNode): + + def __init__(self, func: object, name: str) -> None: + super().__init__(func, name) \ No newline at end of file diff --git a/flo_ai/state/flo_session.py b/flo_ai/state/flo_session.py index f5203302..a177ce79 100644 --- a/flo_ai/state/flo_session.py +++ b/flo_ai/state/flo_session.py @@ -1,12 +1,10 @@ from langchain_core.language_models import BaseLanguageModel from langchain_core.tools import BaseTool -from langchain_core.runnables import Runnable class FloSession: def __init__(self, llm: BaseLanguageModel, loop_size: int = 2, max_loop: int = 3) -> None: self.llm = llm self.tools = dict() - self.executables = dict() self.counter = dict() self.navigation: list[str] = list() self.pattern_series = dict() @@ -16,10 +14,6 @@ def __init__(self, llm: BaseLanguageModel, loop_size: int = 2, max_loop: int = 3 def register_tool(self, name: str, tool: BaseTool): self.tools[name] = tool return self - - def register_executable(self, name: str, tool: Runnable): - self.executables[name] = dict() - return self def append(self, node: str) -> int: self.counter[node] = self.counter.get(node, 0) + 1