Skip to content

Commit 366f9c5

Browse files
authored
fix: migrate to langchain 1.0 (#110)
* Update code, examples and docs to use langchain.agents.create_agent instead of langgraph.prebuilt.create_react_agent * Replace 'prompt' parameter with 'system_prompt' parameter throughout codebase * Update imports from langchain_core to langchain for messages and tools * Fix Union type detection for Python 3.10+ compatibility * Resolve type checking and linting issues Since the migration to langchain v1 didn't seem to progress, I did the changes myself. Working correctly now, I let you judge, feel free to merge/fork or not. Closes #104
1 parent 6469854 commit 366f9c5

File tree

11 files changed

+920
-748
lines changed

11 files changed

+920
-748
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,20 @@ share/python-wheels/
2828
.installed.cfg
2929
*.egg
3030
MANIFEST
31+
.pdm-build
3132

3233
# Environments
3334
.venv
3435
.env
36+
.vscode
3537

3638
# mypy
3739
.mypy_cache/
3840
.dmypy.json
3941
dmypy.json
4042

43+
# Pytest
44+
.pytest_cache
45+
4146
.langgraph_api
4247
.idea

README.md

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@ A Python library for creating swarm-style multi-agent systems using [LangGraph](
44

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

7-
> [!NOTE]
8-
> 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.
9-
107
## Features
118

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

3431
from langgraph.checkpoint.memory import InMemorySaver
35-
from langgraph.prebuilt import create_react_agent
32+
from langchain.agents import create_agent
3633
from langgraph_swarm import create_handoff_tool, create_swarm
3734

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

44-
alice = create_react_agent(
41+
alice = create_agent(
4542
model,
46-
[add, create_handoff_tool(agent_name="Bob")],
47-
prompt="You are Alice, an addition expert.",
43+
tools=[
44+
add,
45+
create_handoff_tool(
46+
agent_name="Bob",
47+
description="Transfer to Bob",
48+
),
49+
],
50+
system_prompt="You are Alice, an addition expert.",
4851
name="Alice",
4952
)
5053

51-
bob = create_react_agent(
54+
bob = create_agent(
5255
model,
53-
[create_handoff_tool(agent_name="Alice", description="Transfer to Alice, she can help with math")],
54-
prompt="You are Bob, you speak like a pirate.",
56+
tools=[
57+
create_handoff_tool(
58+
agent_name="Alice",
59+
description="Transfer to Alice, she can help with math",
60+
),
61+
],
62+
system_prompt="You are Bob, you speak like a pirate.",
5563
name="Bob",
5664
)
5765

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

116124
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:
117125

118-
* change tool name and/or description
119-
* add tool call arguments for the LLM to populate, for example a task description for the next agent
120-
* 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.
126+
- change tool name and/or description
127+
- add tool call arguments for the LLM to populate, for example a task description for the next agent
128+
- 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.
121129

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

124132
```python
125133
from typing import Annotated
126134

127-
from langchain_core.tools import tool, BaseTool, InjectedToolCallId
128-
from langchain_core.messages import ToolMessage
135+
from langchain.tools import tool, BaseTool, InjectedToolCallId
136+
from langchain.messages import ToolMessage
129137
from langgraph.types import Command
130138
from langgraph.prebuilt import InjectedState
131139

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

166174
> [!IMPORTANT]
167175
> If you are implementing custom handoff tools that return `Command`, you need to ensure that:
168-
(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))
169-
(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`
176+
> (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))
177+
> (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`
170178
171179
### Customizing agent implementation
172180

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

181-
from langchain_core.messages import AnyMessage
189+
from langchain.messages import AnyMessage
182190
from langgraph.graph import StateGraph, add_messages
183191
from langgraph_swarm import SwarmState
184192

@@ -228,4 +236,3 @@ workflow = add_active_agent_router(
228236
# compile the workflow
229237
app = workflow.compile()
230238
```
231-

examples/customer_support/src/agent/customer_support.ipynb

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"\n",
6161
"from langchain_core.runnables import RunnableConfig\n",
6262
"from langgraph.checkpoint.memory import MemorySaver\n",
63-
"from langgraph.prebuilt import create_react_agent\n",
63+
"from langchain.agents import create_agent\n",
6464
"from langgraph_swarm import create_handoff_tool, create_swarm\n",
6565
"\n",
6666
"# Mock data for tools\n",
@@ -162,17 +162,17 @@
162162
"\n",
163163
"\n",
164164
"# Define agents\n",
165-
"flight_assistant = create_react_agent(\n",
165+
"flight_assistant = create_agent(\n",
166166
" model,\n",
167-
" [search_flights, book_flight, transfer_to_hotel_assistant],\n",
168-
" prompt=make_prompt(\"You are a flight booking assistant\"),\n",
167+
" tools=[search_flights, book_flight, transfer_to_hotel_assistant],\n",
168+
" system_prompt=make_prompt(\"You are a flight booking assistant\"),\n",
169169
" name=\"flight_assistant\",\n",
170170
")\n",
171171
"\n",
172-
"hotel_assistant = create_react_agent(\n",
172+
"hotel_assistant = create_agent(\n",
173173
" model,\n",
174-
" [search_hotels, book_hotel, transfer_to_flight_assistant],\n",
175-
" prompt=make_prompt(\"You are a hotel booking assistant\"),\n",
174+
" tools=[search_hotels, book_hotel, transfer_to_flight_assistant],\n",
175+
" system_prompt=make_prompt(\"You are a hotel booking assistant\"),\n",
176176
" name=\"hotel_assistant\",\n",
177177
")\n",
178178
"\n",

examples/customer_support/src/agent/customer_support.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
from collections import defaultdict
33
from typing import Callable
44

5+
from langchain.agents import create_agent
56
from langchain_core.runnables import RunnableConfig
67
from langchain_openai import ChatOpenAI
7-
from langgraph.prebuilt import create_react_agent
8+
89
from langgraph_swarm import create_handoff_tool, create_swarm
910

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

110111

111112
# Define agents
112-
flight_assistant = create_react_agent(
113+
flight_assistant = create_agent(
113114
model,
114-
[search_flights, book_flight, transfer_to_hotel_assistant],
115-
prompt=make_prompt("You are a flight booking assistant"),
115+
tools=[search_flights, book_flight, transfer_to_hotel_assistant],
116+
system_prompt=make_prompt("You are a flight booking assistant"),
116117
name="flight_assistant",
117118
)
118119

119-
hotel_assistant = create_react_agent(
120+
hotel_assistant = create_agent(
120121
model,
121-
[search_hotels, book_hotel, transfer_to_flight_assistant],
122-
prompt=make_prompt("You are a hotel booking assistant"),
122+
tools=[search_hotels, book_hotel, transfer_to_flight_assistant],
123+
system_prompt=make_prompt("You are a hotel booking assistant"),
123124
name="hotel_assistant",
124125
)
125126

examples/research/src/agent/agent.ipynb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
"source": [
3939
"# Imports\n",
4040
"from langchain.chat_models import init_chat_model\n",
41-
"from langgraph.prebuilt import create_react_agent\n",
41+
"from langchain.agents import create_agent\n",
4242
"from langgraph_swarm import create_handoff_tool, create_swarm\n",
4343
"\n",
4444
"# Chat model (OpenAI)\n",
@@ -245,17 +245,17 @@
245245
"from langgraph.checkpoint.memory import InMemorySaver\n",
246246
"\n",
247247
"# Planner agent\n",
248-
"planner_agent = create_react_agent(\n",
248+
"planner_agent = create_agent(\n",
249249
" model,\n",
250-
" prompt=planner_prompt_formatted,\n",
250+
" system_prompt=planner_prompt_formatted,\n",
251251
" tools=[fetch_doc, transfer_to_researcher_agent],\n",
252252
" name=\"planner_agent\",\n",
253253
")\n",
254254
"\n",
255255
"# Researcher agent\n",
256-
"researcher_agent = create_react_agent(\n",
256+
"researcher_agent = create_agent(\n",
257257
" model,\n",
258-
" prompt=researcher_prompt,\n",
258+
" system_prompt=researcher_prompt,\n",
259259
" tools=[fetch_doc, transfer_to_planner_agent],\n",
260260
" name=\"researcher_agent\",\n",
261261
")\n",
@@ -2025,7 +2025,7 @@
20252025
"metadata": {},
20262026
"outputs": [],
20272027
"source": [
2028-
"from langchain_core.messages import HumanMessage\n",
2028+
"from langchain.messages import HumanMessage\n",
20292029
"from langchain_openai import ChatOpenAI\n",
20302030
"from langgraph.graph import END, START, StateGraph\n",
20312031
"from typing_extensions import TypedDict\n",

examples/research/src/agent/agent.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1+
from langchain.agents import create_agent
12
from langchain.chat_models import init_chat_model
2-
from langgraph.prebuilt import create_react_agent
3-
from langgraph_swarm import create_handoff_tool, create_swarm
3+
from prompts import planner_prompt, researcher_prompt
4+
from utils import fetch_doc
45

5-
# from swarm_researcher.configuration import Configuration
6-
from swarm_researcher.prompts import planner_prompt, researcher_prompt
7-
from swarm_researcher.utils import fetch_doc
6+
from langgraph_swarm import create_handoff_tool, create_swarm
87

98
# LLM
109
model = init_chat_model(model="gpt-4o", model_provider="openai")
@@ -20,22 +19,22 @@
2019
)
2120

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

2726
# Planner agent
28-
planner_agent = create_react_agent(
27+
planner_agent = create_agent(
2928
model,
30-
prompt=planner_prompt_formatted,
29+
system_prompt=PLANNER_PROMPT_FORMATTED,
3130
tools=[fetch_doc, transfer_to_researcher_agent],
3231
name="planner_agent",
3332
)
3433

3534
# Researcher agent
36-
researcher_agent = create_react_agent(
35+
researcher_agent = create_agent(
3736
model,
38-
prompt=researcher_prompt,
37+
system_prompt=researcher_prompt,
3938
tools=[fetch_doc, transfer_to_planner_agent],
4039
name="researcher_agent",
4140
)

langgraph_swarm/handoff.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
from dataclasses import is_dataclass
33
from typing import Annotated, Any
44

5-
from langchain_core.messages import ToolMessage
6-
from langchain_core.tools import BaseTool, InjectedToolCallId, tool
5+
from langchain.messages import ToolMessage
6+
from langchain.tools import BaseTool, InjectedToolCallId, tool
77
from langgraph.graph.state import CompiledStateGraph
88
from langgraph.prebuilt import InjectedState, ToolNode
99
from langgraph.types import Command

0 commit comments

Comments
 (0)