Skip to main content

Lightweight server for LangChain and LangGraph agents. Serve any agent as a REST API with invoke and streaming endpoints.

Project description

langchain-agent-server

Lightweight server for LangChain and LangGraph agents. Serve any agent as a REST API with invoke and streaming endpoints.

No vendor lock-in. No paid platform. Just FastAPI + SSE.

Install

pip install langchain-agent-server

Quick Start

from langchain_agent_server import create_app, NoAuth
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent

# Build your agent
llm = ChatOpenAI(model="gpt-4o")
agent = create_react_agent(llm, tools=[...])

# Wrap it in a server
async def agent_factory(auth_context):
    return agent

app = create_app(
    title="My Agent API",
    agent_factory=agent_factory,
    auth=NoAuth(),
)

Run with any ASGI server:

uvicorn myapp:app --host 0.0.0.0 --port 8000

Or directly:

if __name__ == "__main__":
    host = os.getenv("HOST", "0.0.0.0")
    port = int(os.getenv("PORT", "8124"))

    uvicorn.run(app, host=host, port=port, log_level="info")

Endpoints

GET /health

Health check. Returns {"status": "ok"}.

POST /invoke

Invoke the agent and get all response messages at once.

Request:

{
  "input": {
    "messages": [
      {"role": "user", "content": "What's the weather in NYC?"}
    ]
  }
}

Response:

{
  "result": {
    "messages": [
      {"type": "human", "role": "user", "content": "What's the weather in NYC?"},
      {"type": "ai", "role": "assistant", "content": "", "tool_calls": [
        {"name": "get_weather", "args": {"city": "NYC"}}
      ]},
      {"type": "tool", "role": "tool", "name": "get_weather", "content": "72°F, sunny"},
      {"type": "ai", "role": "assistant", "content": "It's 72°F and sunny in NYC!"}
    ]
  }
}

POST /stream

Invoke the agent and stream events via Server-Sent Events (SSE).

Same request format as /invoke. Returns text/event-stream.

Events:

data: {"type": "token", "content": "It's"}

data: {"type": "token", "content": " 72"}

data: {"type": "tool_start", "name": "get_weather", "input": {"city": "NYC"}}

data: {"type": "tool_end", "name": "get_weather", "output": "72°F, sunny"}

data: {"type": "token", "content": "It's 72°F and sunny!"}

data: {"type": "end", "messages": [...]}

Event types:

Type Description
token A text chunk streamed from the LLM
tool_start Agent is calling a tool (includes name and input)
tool_end Tool returned a result (includes name and output)
error An error occurred (includes error and error_type)
end Stream complete (includes final messages array)

Authentication

Bearer Token (default)

from langchain_agent_server import create_app, BearerAuth

async def agent_factory(token: str):
    # token is the Bearer token from the Authorization header
    # Use it to create a per-request agent with user context
    return build_agent_for_user(token)

app = create_app(
    title="My Agent API",
    agent_factory=agent_factory,
    auth=BearerAuth(),  # this is the default
)

Returns 403 if no Authorization header is provided.

No Auth

from langchain_agent_server import create_app, NoAuth

async def agent_factory(auth_context):
    # auth_context is always None
    return my_agent

app = create_app(
    title="My Agent API",
    agent_factory=agent_factory,
    auth=NoAuth(),
)

Custom Auth

Implement the AuthDependency protocol:

from fastapi import HTTPException

class ApiKeyAuth:
    def __init__(self, valid_keys: set[str]):
        self.valid_keys = valid_keys

    async def __call__(self, authorization: str | None) -> str:
        if authorization not in self.valid_keys:
            raise HTTPException(status_code=401, detail="Invalid API key")
        return authorization

app = create_app(
    title="My Agent API",
    agent_factory=agent_factory,
    auth=ApiKeyAuth({"sk-secret-key-1", "sk-secret-key-2"}),
)

The auth callable receives the raw Authorization header and returns whatever your agent_factory needs.

Message Conversion

The package includes utilities for converting between OpenAI and LangChain message formats:

from langchain_agent_server import (
    convert_openai_to_langchain_messages,
    convert_langchain_to_openai_message,
)

# OpenAI format -> LangChain objects
messages = convert_openai_to_langchain_messages([
    {"role": "user", "content": "Hello"},
    {"role": "assistant", "content": "Hi!"},
])

# LangChain object -> OpenAI format dict
from langchain_core.messages import AIMessage
msg_dict = convert_langchain_to_openai_message(AIMessage(content="Hi!"))
# {"type": "ai", "role": "assistant", "content": "Hi!"}

Why?

LangChain's official options for serving agents are:

  • LangServe — maintenance mode, no new features
  • LangGraph Platform — paid managed service (self-hosted requires Enterprise license)

This package is a lightweight alternative: ~200 lines of code, zero vendor lock-in, MIT licensed. You own your infrastructure.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

langchain_agent_server-0.1.0.tar.gz (58.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

langchain_agent_server-0.1.0-py3-none-any.whl (9.3 kB view details)

Uploaded Python 3

File details

Details for the file langchain_agent_server-0.1.0.tar.gz.

File metadata

File hashes

Hashes for langchain_agent_server-0.1.0.tar.gz
Algorithm Hash digest
SHA256 91323eab9afd592f796a08cbb04703f04e5f7256f0b3d9cf84fe76944b116984
MD5 185c26fe4651f0cf9c0903f756b78dd8
BLAKE2b-256 72d7208a2c9a9ec87944a16e706a255275318572a3001a7702d289e2fc3187a1

See more details on using hashes here.

File details

Details for the file langchain_agent_server-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for langchain_agent_server-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1a32d3bd3f4f2e43bc347adc9174e7981e4f4324200a8b7a9222950cc5a249e3
MD5 51ba3b75a0576a8604a912b5e14fa086
BLAKE2b-256 4b16710d8d04de40fe483c891e7aa0d9204fd1ef887e108c49f14d90925f6ed1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page