Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,20 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
.pdm-build

# Environments
.venv
.env
.vscode

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pytest
.pytest_cache

.langgraph_api
.idea
45 changes: 26 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ A Python library for creating swarm-style multi-agent systems using [LangGraph](

![Swarm](static/img/swarm.png)

> [!NOTE]
> This library has been updated to support LangChain 1.0. However, it has **not** been tested with the new agents in `langchain.agents`. The library currently only supports the prebuilt `langgraph.prebuilt.create_react_agent`. This update allows users to migrate to LangChain 1.0 without changing their existing code. For users of the swarm package, we recommend continuing to use `langgraph.prebuilt.create_react_agent` rather than the new `langchain.agents` for now.

## Features

- 🤖 **Multi-agent collaboration** - Enable specialized agents to work together and hand off context to each other
Expand All @@ -32,7 +29,7 @@ export OPENAI_API_KEY=<your_api_key>
from langchain_openai import ChatOpenAI

from langgraph.checkpoint.memory import InMemorySaver
from langgraph.prebuilt import create_react_agent
from langchain.agents import create_agent
from langgraph_swarm import create_handoff_tool, create_swarm

model = ChatOpenAI(model="gpt-4o")
Expand All @@ -41,17 +38,28 @@ def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b

alice = create_react_agent(
alice = create_agent(
model,
[add, create_handoff_tool(agent_name="Bob")],
prompt="You are Alice, an addition expert.",
tools=[
add,
create_handoff_tool(
agent_name="Bob",
description="Transfer to Bob",
),
],
system_prompt="You are Alice, an addition expert.",
name="Alice",
)

bob = create_react_agent(
bob = create_agent(
model,
[create_handoff_tool(agent_name="Alice", description="Transfer to Alice, she can help with math")],
prompt="You are Bob, you speak like a pirate.",
tools=[
create_handoff_tool(
agent_name="Alice",
description="Transfer to Alice, she can help with math",
),
],
system_prompt="You are Bob, you speak like a pirate.",
name="Bob",
)

Expand Down Expand Up @@ -115,17 +123,17 @@ You can customize multi-agent swarm by changing either the [handoff tools](#cust

By default, the agents in the swarm are assumed to use handoff tools created with the prebuilt `create_handoff_tool`. You can also create your own, custom handoff tools. Here are some ideas on how you can modify the default implementation:

* change tool name and/or description
* add tool call arguments for the LLM to populate, for example a task description for the next agent
* change what data is passed to the next agent as part of the handoff: by default `create_handoff_tool` passes **full** message history (all of the messages generated in the swarm up to this point), as well as a tool message indicating successful handoff.
- change tool name and/or description
- add tool call arguments for the LLM to populate, for example a task description for the next agent
- change what data is passed to the next agent as part of the handoff: by default `create_handoff_tool` passes **full** message history (all of the messages generated in the swarm up to this point), as well as a tool message indicating successful handoff.

Here is an example of what a custom handoff tool might look like:

```python
from typing import Annotated

from langchain_core.tools import tool, BaseTool, InjectedToolCallId
from langchain_core.messages import ToolMessage
from langchain.tools import tool, BaseTool, InjectedToolCallId
from langchain.messages import ToolMessage
from langgraph.types import Command
from langgraph.prebuilt import InjectedState

Expand Down Expand Up @@ -165,8 +173,8 @@ def create_custom_handoff_tool(*, agent_name: str, name: str | None, description

> [!IMPORTANT]
> If you are implementing custom handoff tools that return `Command`, you need to ensure that:
(1) your agent has a tool-calling node that can handle tools returning `Command` (like LangGraph's prebuilt [`ToolNode`](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.tool_node.ToolNode))
(2) both the swarm graph and the next agent graph have the [state schema](https://langchain-ai.github.io/langgraph/concepts/low_level#schema) containing the keys you want to update in `Command.update`
> (1) your agent has a tool-calling node that can handle tools returning `Command` (like LangGraph's prebuilt [`ToolNode`](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.tool_node.ToolNode))
> (2) both the swarm graph and the next agent graph have the [state schema](https://langchain-ai.github.io/langgraph/concepts/low_level#schema) containing the keys you want to update in `Command.update`

### Customizing agent implementation

Expand All @@ -178,7 +186,7 @@ By default, individual agents are expected to communicate over a single `message
```python
from typing_extensions import TypedDict, Annotated

from langchain_core.messages import AnyMessage
from langchain.messages import AnyMessage
from langgraph.graph import StateGraph, add_messages
from langgraph_swarm import SwarmState

Expand Down Expand Up @@ -228,4 +236,3 @@ workflow = add_active_agent_router(
# compile the workflow
app = workflow.compile()
```

14 changes: 7 additions & 7 deletions examples/customer_support/src/agent/customer_support.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"\n",
"from langchain_core.runnables import RunnableConfig\n",
"from langgraph.checkpoint.memory import MemorySaver\n",
"from langgraph.prebuilt import create_react_agent\n",
"from langchain.agents import create_agent\n",
"from langgraph_swarm import create_handoff_tool, create_swarm\n",
"\n",
"# Mock data for tools\n",
Expand Down Expand Up @@ -162,17 +162,17 @@
"\n",
"\n",
"# Define agents\n",
"flight_assistant = create_react_agent(\n",
"flight_assistant = create_agent(\n",
" model,\n",
" [search_flights, book_flight, transfer_to_hotel_assistant],\n",
" prompt=make_prompt(\"You are a flight booking assistant\"),\n",
" tools=[search_flights, book_flight, transfer_to_hotel_assistant],\n",
" system_prompt=make_prompt(\"You are a flight booking assistant\"),\n",
" name=\"flight_assistant\",\n",
")\n",
"\n",
"hotel_assistant = create_react_agent(\n",
"hotel_assistant = create_agent(\n",
" model,\n",
" [search_hotels, book_hotel, transfer_to_flight_assistant],\n",
" prompt=make_prompt(\"You are a hotel booking assistant\"),\n",
" tools=[search_hotels, book_hotel, transfer_to_flight_assistant],\n",
" system_prompt=make_prompt(\"You are a hotel booking assistant\"),\n",
" name=\"hotel_assistant\",\n",
")\n",
"\n",
Expand Down
15 changes: 8 additions & 7 deletions examples/customer_support/src/agent/customer_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
from collections import defaultdict
from typing import Callable

from langchain.agents import create_agent
from langchain_core.runnables import RunnableConfig
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent

from langgraph_swarm import create_handoff_tool, create_swarm

model = ChatOpenAI(model="gpt-4o")
Expand Down Expand Up @@ -109,17 +110,17 @@ def prompt(state: dict, config: RunnableConfig) -> list:


# Define agents
flight_assistant = create_react_agent(
flight_assistant = create_agent(
model,
[search_flights, book_flight, transfer_to_hotel_assistant],
prompt=make_prompt("You are a flight booking assistant"),
tools=[search_flights, book_flight, transfer_to_hotel_assistant],
system_prompt=make_prompt("You are a flight booking assistant"),
name="flight_assistant",
)

hotel_assistant = create_react_agent(
hotel_assistant = create_agent(
model,
[search_hotels, book_hotel, transfer_to_flight_assistant],
prompt=make_prompt("You are a hotel booking assistant"),
tools=[search_hotels, book_hotel, transfer_to_flight_assistant],
system_prompt=make_prompt("You are a hotel booking assistant"),
name="hotel_assistant",
)

Expand Down
12 changes: 6 additions & 6 deletions examples/research/src/agent/agent.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"source": [
"# Imports\n",
"from langchain.chat_models import init_chat_model\n",
"from langgraph.prebuilt import create_react_agent\n",
"from langchain.agents import create_agent\n",
"from langgraph_swarm import create_handoff_tool, create_swarm\n",
"\n",
"# Chat model (OpenAI)\n",
Expand Down Expand Up @@ -245,17 +245,17 @@
"from langgraph.checkpoint.memory import InMemorySaver\n",
"\n",
"# Planner agent\n",
"planner_agent = create_react_agent(\n",
"planner_agent = create_agent(\n",
" model,\n",
" prompt=planner_prompt_formatted,\n",
" system_prompt=planner_prompt_formatted,\n",
" tools=[fetch_doc, transfer_to_researcher_agent],\n",
" name=\"planner_agent\",\n",
")\n",
"\n",
"# Researcher agent\n",
"researcher_agent = create_react_agent(\n",
"researcher_agent = create_agent(\n",
" model,\n",
" prompt=researcher_prompt,\n",
" system_prompt=researcher_prompt,\n",
" tools=[fetch_doc, transfer_to_planner_agent],\n",
" name=\"researcher_agent\",\n",
")\n",
Expand Down Expand Up @@ -2025,7 +2025,7 @@
"metadata": {},
"outputs": [],
"source": [
"from langchain_core.messages import HumanMessage\n",
"from langchain.messages import HumanMessage\n",
"from langchain_openai import ChatOpenAI\n",
"from langgraph.graph import END, START, StateGraph\n",
"from typing_extensions import TypedDict\n",
Expand Down
23 changes: 11 additions & 12 deletions examples/research/src/agent/agent.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langgraph.prebuilt import create_react_agent
from langgraph_swarm import create_handoff_tool, create_swarm
from prompts import planner_prompt, researcher_prompt
from utils import fetch_doc

# from swarm_researcher.configuration import Configuration
from swarm_researcher.prompts import planner_prompt, researcher_prompt
from swarm_researcher.utils import fetch_doc
from langgraph_swarm import create_handoff_tool, create_swarm

# LLM
model = init_chat_model(model="gpt-4o", model_provider="openai")
Expand All @@ -20,22 +19,22 @@
)

# LLMS.txt
llms_txt = "LangGraph:https://langchain-ai.github.io/langgraph/llms.txt"
num_urls = 3
planner_prompt_formatted = planner_prompt.format(llms_txt=llms_txt, num_urls=num_urls)
LLMS_TXT = "LangGraph:https://langchain-ai.github.io/langgraph/llms.txt"
NUM_URLS = 3
PLANNER_PROMPT_FORMATTED = planner_prompt.format(llms_txt=LLMS_TXT, num_urls=NUM_URLS)

# Planner agent
planner_agent = create_react_agent(
planner_agent = create_agent(
model,
prompt=planner_prompt_formatted,
system_prompt=PLANNER_PROMPT_FORMATTED,
tools=[fetch_doc, transfer_to_researcher_agent],
name="planner_agent",
)

# Researcher agent
researcher_agent = create_react_agent(
researcher_agent = create_agent(
model,
prompt=researcher_prompt,
system_prompt=researcher_prompt,
tools=[fetch_doc, transfer_to_planner_agent],
name="researcher_agent",
)
Expand Down
4 changes: 2 additions & 2 deletions langgraph_swarm/handoff.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
from dataclasses import is_dataclass
from typing import Annotated, Any

from langchain_core.messages import ToolMessage
from langchain_core.tools import BaseTool, InjectedToolCallId, tool
from langchain.messages import ToolMessage
from langchain.tools import BaseTool, InjectedToolCallId, tool
from langgraph.graph.state import CompiledStateGraph
from langgraph.prebuilt import InjectedState, ToolNode
from langgraph.types import Command
Expand Down
Loading