How to Configure External Tools (Different Repo/Server) with create_agent in LangChain v1.0?

Context:

I’m working with LangChain v1.0 and following the documentation on creating agents. The examples show tools defined in the same repository/file:

python

from langchain.agents import create_agent

tools = [my_tool_1, my_tool_2]
agent = create_agent(model, tools)

My Question:

What’s the best and ideal way to configure tools that are:

  • Defined in a different repository (e.g., a separate package/module)

  • Potentially external APIs or services I need to import

  • Third-party tools not in the same codebase

What I’m Looking For:

  1. Recommended architecture/pattern for organizing external tools

  2. Import strategies - should I create a tools registry/factory?

  3. Configuration management - how to handle tool credentials, endpoints, etc.

  4. Code examples showing external tool integration with create_agent

Example Scenario:

python

# Instead of defining tools locally, I want something like:
from external_tools_repo import DatabaseTool, APITool
from my_custom_package.tools import WeatherTool

# How to properly configure these with create_agent?
tools = [DatabaseTool(), APITool(), WeatherTool()]
agent = create_agent(model, tools)

Are there any official examples or community best practices for this pattern? Or if anyone has implemented this, I’d appreciate guidance on:

  • Tool packaging/distribution

  • Dependency management

  • Tool discovery/registration patterns

Thanks in advance!

hi @UK59

that is a very interesting question. Let me explain my understanding of your question.

General overview:

Q1 Recommended architecture/patterns

  • Package tools in separate modules/packages: Keep each tool independently installable (e.g., external_tools_repo) exposing either:

    • Plain functions with type hints and clear docstrings, or
    • Classes deriving from BaseTool/StructuredTool when you need validation, async, robust error handling.
  • Group related tools with a Toolkit: Use BaseToolkit to publish a cohesive set of tools with a get_tools() entry point, enabling a single import path for consumers.

class BaseToolkit(BaseModel, ABC):
    ...
    @abstractmethod
    def get_tools(self) -> list[BaseTool]:
        """Get all tools in the toolkit."""

Q2 Import strategies (registry/factory)

  • Direct imports when the tool set is small/stable.
  • Registry/Factory when tools come from many repos or are toggled by config/feature flags. This centralizes instantiation, avoids import cycles, and allows lazy imports for heavy dependencies.

Example registry:

# tools_registry.py
from typing import Iterable

def load_tools() -> Iterable:
    from external_tools_repo import DatabaseTool, APITool
    from my_custom_package.tools import WeatherTool
    return [DatabaseTool(), APITool(), WeatherTool()]

Q3 Configuration and credentials

  • Environment variables for keys/secrets (e.g., API_KEY, SERVICE_URL). Read them inside the tool constructor.
  • Config injection: Accept explicit parameters for endpoints/timeouts; wire via a factory.
  • No secrets in code: Keep .env/secret managers outside VCS (I know, that’s obvious :smiley: )
import os
from langchain_core.tools import StructuredTool
from pydantic import BaseModel, Field

class QueryArgs(BaseModel):
    query: str = Field(..., description="Search query")

class APITool(StructuredTool):
    name = "api_search"
    description = "Searches external API"
    args_schema = QueryArgs

    def __init__(self) -> None:
        super().__init__()
        self.endpoint = os.environ["API_ENDPOINT"]
        self.api_key = os.environ["API_KEY"]

    def _run(self, *, query: str, **_) -> str:
        # call external API with self.endpoint / self.api_key
        return "result"

Q4 Integrating external tools with create_agent

Using LangGraph prebuilt ReAct agent (recommended for production):

from langgraph.prebuilt import create_react_agent
from tools_registry import load_tools

# You can pass a model instance or a model name string (see docs models.md)
model = "anthropic:claude-3-7-sonnet-latest"
tools = list(load_tools())

agent = create_react_agent(model=model, tools=tools, prompt="You are a helpful assistant")

result = agent.invoke({"messages": [{"role": "user", "content": "Find weather in SF"}]})

If using classic LangChain ReAct (not recommended for production), see the deprecation note in the classic implementation:

    !!! warning
       This implementation is ... older and not well-suited for production ...
       we recommend using the `create_react_agent` function from the LangGraph library.

Packaging, distribution, discovery

  • Packaging: Ship external tools as installable Python packages with clear extras for optional dependencies.
  • Dependencies: Keep model/provider deps in the consumer app; keep API clients within tool packages.
  • Discovery: Expose load_tools() or a BaseToolkit.get_tools() in each package. Optional: use entry points for plugin-style discovery if you need dynamic loading.

Why this works

  • create_react_agent accepts Callable tools or BaseTool instances. External location does not matter as long as the objects conform to the tool interface and are importable at runtime.
  • Tool types and behaviors are standardized in LangChain Core (BaseTool, StructuredTool, @tool), ensuring compatibility.

Appendix

Entry points (plugin-style discovery)

Entry points let third‑party packages register a function (e.g., load_tools) that your app can auto‑discover at runtime. This avoids hardcoding imports and enables drop‑in plugins.

# pyproject.toml
[project]
name = "external-tools-weather"
version = "0.1.0"

[project.entry-points."langgraph_tools"]
weather = "external_tools_weather:load_tools"
# external_tools_weather/__init__.py
from typing import Iterable
from langchain_core.tools import tool

@tool
def weather(city: str) -> str:
    """Return current weather for a city."""
    return "It's always sunny in SF!"

def load_tools() -> Iterable:
    # Return plain callables or BaseTool instances
    return [weather]
  • Consumer app (discover and load all registered tool factories)
from importlib.metadata import entry_points
from langgraph.prebuilt import create_react_agent

def discover_tools(group: str = "langgraph_tools"):
    tools = []
    for ep in entry_points(group=group):
        factory = ep.load()  # resolves "pkg:object" to a callable
        tools.extend(factory())
    return tools

agent = create_react_agent(
    model="anthropic:claude-3-7-sonnet-latest",
    tools=discover_tools(),
    prompt="You are a helpful assistant",
)
  • Notes
    • Choose a unique entry point group name (e.g., langgraph_tools).
    • Each plugin exposes a factory (e.g., load_tools) returning a list of tools.
    • For Python < 3.10, you may need the backport: import importlib_metadata as metadata.