From e156921b73acee55588beeafa8299ed5ebd434b9 Mon Sep 17 00:00:00 2001 From: isaac hershenson Date: Wed, 7 Aug 2024 14:48:27 -0700 Subject: [PATCH] refactoring --- .env.example | 1 - README.md | 2 +- .../project_one/my_agent}/__init__.py | 0 .../my_project/project_one/my_agent/main.py | 3 + .../project_one/my_agent}/utils/__init__.py | 0 .../my_agent}/utils/build_graph.py | 0 .../my_project/project_one/pyproject.toml | 0 .../project_two/my_other_agent/__init__.py | 0 .../project_two/my_other_agent/main.py | 3 + .../my_other_agent/utils/__init__.py | 0 .../my_other_agent/utils/build_graph.py | 97 +++++++++++++++++++ all_projects/project_two/pyproject.toml | 18 ++++ langgraph.json | 5 +- my_agent/main.py | 3 - 14 files changed, 125 insertions(+), 7 deletions(-) rename {my_agent => all_projects/my_project/project_one/my_agent}/__init__.py (100%) create mode 100644 all_projects/my_project/project_one/my_agent/main.py rename {my_agent => all_projects/my_project/project_one/my_agent}/utils/__init__.py (100%) rename {my_agent => all_projects/my_project/project_one/my_agent}/utils/build_graph.py (100%) rename pyproject.toml => all_projects/my_project/project_one/pyproject.toml (100%) create mode 100644 all_projects/project_two/my_other_agent/__init__.py create mode 100644 all_projects/project_two/my_other_agent/main.py create mode 100644 all_projects/project_two/my_other_agent/utils/__init__.py create mode 100644 all_projects/project_two/my_other_agent/utils/build_graph.py create mode 100644 all_projects/project_two/pyproject.toml delete mode 100644 my_agent/main.py diff --git a/.env.example b/.env.example index 5bf9c21..97ecfb2 100644 --- a/.env.example +++ b/.env.example @@ -2,4 +2,3 @@ OPENAI_API_KEY="..." LANGCHAIN_API_KEY="..." TAVILY_API_KEY="..." ANTHROPIC_API_KEY="..." -PYTHONPATH="./my_agent" diff --git a/README.md b/README.md index 71c8817..10b3b4c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # Setup -Edit the `.env.example` file to create a proper `.env` file with your API keys. The only thing to copy over exactly is the `PYTHONPATH`, because without it LangGraph will not be able to find the `utils` module when you import it in `main.py`. If you wish to add more modules, just ensure that you add them to your `PYTHONPATH` environment variable. \ No newline at end of file +Edit the `.env.example` file to create a proper `.env` file with your API keys. \ No newline at end of file diff --git a/my_agent/__init__.py b/all_projects/my_project/project_one/my_agent/__init__.py similarity index 100% rename from my_agent/__init__.py rename to all_projects/my_project/project_one/my_agent/__init__.py diff --git a/all_projects/my_project/project_one/my_agent/main.py b/all_projects/my_project/project_one/my_agent/main.py new file mode 100644 index 0000000..5a2227f --- /dev/null +++ b/all_projects/my_project/project_one/my_agent/main.py @@ -0,0 +1,3 @@ +from my_agent.utils.build_graph import workflow + +graph = workflow.compile() \ No newline at end of file diff --git a/my_agent/utils/__init__.py b/all_projects/my_project/project_one/my_agent/utils/__init__.py similarity index 100% rename from my_agent/utils/__init__.py rename to all_projects/my_project/project_one/my_agent/utils/__init__.py diff --git a/my_agent/utils/build_graph.py b/all_projects/my_project/project_one/my_agent/utils/build_graph.py similarity index 100% rename from my_agent/utils/build_graph.py rename to all_projects/my_project/project_one/my_agent/utils/build_graph.py diff --git a/pyproject.toml b/all_projects/my_project/project_one/pyproject.toml similarity index 100% rename from pyproject.toml rename to all_projects/my_project/project_one/pyproject.toml diff --git a/all_projects/project_two/my_other_agent/__init__.py b/all_projects/project_two/my_other_agent/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/all_projects/project_two/my_other_agent/main.py b/all_projects/project_two/my_other_agent/main.py new file mode 100644 index 0000000..63a85ac --- /dev/null +++ b/all_projects/project_two/my_other_agent/main.py @@ -0,0 +1,3 @@ +from my_other_agent.utils.build_graph import workflow + +graph = workflow.compile() \ No newline at end of file diff --git a/all_projects/project_two/my_other_agent/utils/__init__.py b/all_projects/project_two/my_other_agent/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/all_projects/project_two/my_other_agent/utils/build_graph.py b/all_projects/project_two/my_other_agent/utils/build_graph.py new file mode 100644 index 0000000..731a2b6 --- /dev/null +++ b/all_projects/project_two/my_other_agent/utils/build_graph.py @@ -0,0 +1,97 @@ +from typing import TypedDict, Annotated, Sequence, Literal + +from functools import lru_cache +from langchain_core.messages import BaseMessage +from langchain_anthropic import ChatAnthropic +from langchain_openai import ChatOpenAI +from langchain_community.tools.tavily_search import TavilySearchResults +from langgraph.prebuilt import ToolNode +from langgraph.graph import StateGraph, END, add_messages + +tools = [TavilySearchResults(max_results=1)] + +@lru_cache(maxsize=4) +def _get_model(model_name: str): + if model_name == "openai": + model = ChatOpenAI(temperature=0, model_name="gpt-4o") + elif model_name == "anthropic": + model = ChatAnthropic(temperature=0, model_name="claude-3-sonnet-20240229") + else: + raise ValueError(f"Unsupported model type: {model_name}") + + model = model.bind_tools(tools) + return model + + +class AgentState(TypedDict): + messages: Annotated[Sequence[BaseMessage], add_messages] + + +# Define the function that determines whether to continue or not +def should_continue(state): + messages = state["messages"] + last_message = messages[-1] + # If there are no tool calls, then we finish + if not last_message.tool_calls: + return "end" + # Otherwise if there is, we continue + else: + return "continue" + + +system_prompt = """Be a helpful assistant""" + +# Define the function that calls the model +def call_model(state, config): + messages = state["messages"] + messages = [{"role": "system", "content": system_prompt}] + messages + model_name = config.get('configurable', {}).get("model_name", "anthropic") + model = _get_model(model_name) + response = model.invoke(messages) + # We return a list, because this will get added to the existing list + return {"messages": [response]} + + +# Define the function to execute tools +tool_node = ToolNode(tools) + +# Define the config +class GraphConfig(TypedDict): + model_name: Literal["anthropic", "openai"] + + +# Define a new graph +workflow = StateGraph(AgentState, config_schema=GraphConfig) + +# Define the two nodes we will cycle between +workflow.add_node("agent", call_model) +workflow.add_node("action", tool_node) + +# Set the entrypoint as `agent` +# This means that this node is the first one called +workflow.set_entry_point("agent") + +# We now add a conditional edge +workflow.add_conditional_edges( + # First, we define the start node. We use `agent`. + # This means these are the edges taken after the `agent` node is called. + "agent", + # Next, we pass in the function that will determine which node is called next. + should_continue, + # Finally we pass in a mapping. + # The keys are strings, and the values are other nodes. + # END is a special node marking that the graph should finish. + # What will happen is we will call `should_continue`, and then the output of that + # will be matched against the keys in this mapping. + # Based on which one it matches, that node will then be called. + { + # If `tools`, then we call the tool node. + "continue": "action", + # Otherwise we finish. + "end": END, + }, +) + +# We now add a normal edge from `tools` to `agent`. +# This means that after `tools` is called, `agent` node is called next. +workflow.add_edge("action", "agent") \ No newline at end of file diff --git a/all_projects/project_two/pyproject.toml b/all_projects/project_two/pyproject.toml new file mode 100644 index 0000000..d42c6b8 --- /dev/null +++ b/all_projects/project_two/pyproject.toml @@ -0,0 +1,18 @@ +[tool.poetry] +name = "my-other-agent" +version = "0.0.1" +description = "An excellent agent build for LangGraph cloud." +authors = ["Polly the parrot <1223+polly@users.noreply.github.com>"] +license = "MIT" + +[tool.poetry.dependencies] +python = ">=3.9.0,<3.13" +langgraph = "^0.1.7" +langchain-openai = ">=0.1.17" +langchain-anthropic = ">=0.1.20" +langchain-community = ">=0.2.11" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" \ No newline at end of file diff --git a/langgraph.json b/langgraph.json index 6c32bce..4262aab 100644 --- a/langgraph.json +++ b/langgraph.json @@ -1,7 +1,8 @@ { - "dependencies": ["."], + "dependencies": ["./all_projects/my_project/project_one","./all_projects/project_two"], "graphs": { - "my_fantastic_agent": "./my_agent/main.py:graph" + "my_first_agent": "./all_projects/my_project/project_one/my_agent/main.py:graph", + "my_second_agent": "./all_projects/project_two/my_other_agent/main.py:graph" }, "env": "./.env" } \ No newline at end of file diff --git a/my_agent/main.py b/my_agent/main.py deleted file mode 100644 index 0e40b96..0000000 --- a/my_agent/main.py +++ /dev/null @@ -1,3 +0,0 @@ -from utils.build_graph import workflow - -graph = workflow.compile() \ No newline at end of file