Skip to main content

Migrating from LangChain

Adopting SwarmD doesn’t require rewriting your LangChain agents. Your tools, prompts, and graph stay the same — what changes is how agents discover and connect to each other.

Before: Hardcoded remote agents as tools

With standalone LangChain, you’d typically wire up a remote agent by writing a custom tool that posts to its URL directly:
import httpx
from langchain.agents import create_agent
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI


@tool
def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"The weather in {city} is sunny"


# Every remote agent is a hand-rolled HTTP tool
@tool
def call_time_agent(prompt: str) -> str:
    """Ask the time agent for time information."""
    r = httpx.post(
        "https://time-agent.internal:8080/messages",
        json={"prompt": prompt},
        timeout=60,
    )
    return r.text


@tool
def call_calendar_agent(prompt: str) -> str:
    """Ask the calendar agent to manage events."""
    r = httpx.post(
        "https://calendar-agent.internal:8080/messages",
        json={"prompt": prompt},
        timeout=60,
    )
    return r.text


agent = create_agent(
    model=ChatOpenAI(model="gpt-4o"),
    tools=[get_weather, call_time_agent, call_calendar_agent],
    system_prompt="You are a helpful weather agent.",
)
Problems with this approach:
  • Agent URLs are hardcoded — adding or removing agents requires a code change and redeployment
  • No centralized authentication between agents
  • No A2A protocol — each remote tool reinvents request/response shape
  • No polling for long-running tasks; the LLM blocks until the remote replies
  • No visibility into inter-agent traffic
  • No policy enforcement or approval workflows

After: Discovery through SwarmD

With SwarmD, remote agents are discovered from the registry at startup and exposed as standard LangChain BaseTool instances. Your agent logic is identical — only the wiring changes:
from langchain.agents import create_agent
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI

from swarmd_langchain import create_runtime, fetch_remote_agents


@tool
def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"The weather in {city} is sunny"


# Discover remote agents from the SwarmD registry — each one becomes a tool
runtime = create_runtime()
remote_tools = fetch_remote_agents(runtime)  # Routes through SwarmD relay

agent = create_agent(
    model=ChatOpenAI(model="gpt-4o"),
    tools=[get_weather, *remote_tools],  # Local + dynamically discovered
    system_prompt="You are a helpful weather agent.",
)
.env
SWARMD_AGENT_ID=your-agent-id
SWARMD_CLIENT_SECRET=your-client-secret
SWARMD_BASE_URL=https://api.swarmd.ai
SWARMD_TOKEN_URL=https://auth.swarmd.ai/realms/swarmd/protocol/openid-connect/token
If you want SwarmD to also build the agent and serve it over A2A, use create_llm_agent + serve — these wrap the boilerplate above and add an A2A server with admin endpoints:
from swarmd_langchain import create_llm_agent, create_runtime, serve

runtime = create_runtime()

agent = create_llm_agent(
    runtime,
    name="weather_agent",
    description="A weather agent that collaborates with other agents",
    instruction="You are a helpful weather agent.",
    tools=[get_weather],   # Local tools; remote ones are auto-discovered
)

if __name__ == "__main__":
    serve(agent, runtime)
What you get:
  • Agents are discovered at runtime from the registry — no hardcoded URLs
  • OAuth2 authentication is handled by the SDK
  • Each remote agent is a PollingA2aTool that handles A2A message/send and polls tasks/get until terminal state, so long-running sub-agents don’t block your LLM
  • All traffic routes through the relay with audit logging, policy enforcement, and HITL approval support
  • Adding or removing agents is a subscription change in the dashboard, not a code change

What stays the same

  • Your create_agent graph (model, tools, system prompt)
  • Your tool functions and @tool-decorated callables
  • Your downstream invocation patterns — agent.ainvoke({"messages": [...]}) works identically
  • Your existing LangChain integrations (chat history, memory, structured output)

Migration steps

  1. Install the SDKpip install swarmd-langchain
  2. Register your agent on SwarmD via the dashboard or Registry API
  3. Subscribe to the downstream agents your agent needs
  4. Set credentials — add SWARMD_AGENT_ID, SWARMD_CLIENT_SECRET, SWARMD_BASE_URL, and SWARMD_TOKEN_URL to your environment
  5. Replace hardcoded HTTP tools with fetch_remote_agents(runtime) (or switch to create_llm_agent + serve for the full SwarmD-managed setup)