LangServe Documentation
repository·main·Indexed 25 days ago
https://github.com/langchain-ai/langserveA framework for deploying LangChain runnables and chains as REST APIs using FastAPI and Pydantic. It provides standardized endpoints for invocation, batching, and streaming (/invoke, /batch, /stream, /stream_log), automatic schema inference, an interactive playground, and client SDKs for Python and TypeScript via RemoteRunnable.
What's inside LangServe
- LangServe is a library designed to deploy LangChain runnables and chains as a REST API. It is built on top of FastAPI and uses Pydantic for data validation. LangServe provides both a server for hosting runnables and a client for calling them. For JavaScript environments, a client is available via LangChain.js.
LangGraph Compatibility and Limitations
mainLangGraph Compatibility
LangServe is primarily designed for simple Runnables and standard
langchain-coreprimitives. If you are deploying LangGraph applications, it is recommended to use LangGraph Cloud (beta) instead of LangServe.Limitations
- Client Callbacks: Client-side callbacks are not currently supported for events originating on the server.
- Pydantic V2 Compatibility: In LangServe versions <= 0.2.0, OpenAPI docs may not generate properly when using Pydantic V2 due to FastAPI limitations. To resolve this, either upgrade to
langserve>=0.3.0or downgrade topydantic<2.0.
Configure Playground Widgets
mainYou can define custom UI widgets for the LangServe playground by adding an
extrafield to your Pydantic model's field definitions. A widget is identified by atypekey.Available Manual Widgets:
base64file: Creates a file upload input for base64 encoded strings.chat: Creates a chat interface. RequiresinputandoutputJSONPaths to map the request/response fields to the chat UI.
Widget Schema Structure:
type JsonPath = number | string | (number | string)[]; type NameSpacedPath = { title: string; path: JsonPath }; type OneOfPath = { oneOf: JsonPath[] }; type Widget = { type: string; // e.g., 'base64file', 'chat' [key: string]: JsonPath | NameSpacedPath | OneOfPath; };Key features of LangServe
mainLangServe provides several automated and developer-friendly features for deploying LangChain objects:
- Automatic Schema Inference: Input and output schemas are automatically inferred from your LangChain object and enforced on every API call with rich error messages.
- Standardized Endpoints: Efficient
/invoke,/batch, and/streamendpoints supporting high concurrency. - Streaming Support:
/stream_log: Streams all or some intermediate steps from your chain/agent./stream_events: (Available since v0.0.40) A simplified way to stream without parsing/stream_logoutput.
- Interactive Playground: A
/playground/page with streaming output and intermediate steps. - API Documentation: Automatically generated API docs page with JSONSchema and Swagger.
- Tracing: Built-in optional tracing to LangSmith via API key configuration.
- Client SDK: A client SDK that allows you to call a LangServe server as if it were a local Runnable.
Use the LangServe Playground
mainEvery route added via
add_routesincludes a playground at/{path}/playground/. This UI allows you to configure and invoke your runnable with streaming output and view intermediate steps.For configurable runnables, the playground allows you to save and share a link containing your specific configuration.
Handle File Uploads via Base64 Encoding
mainLangServe does not currently support
multipart/form-datafor file uploads. To upload files by value to a runnable, you must use base64 encoding.Alternatively, you can upload files by reference (e.g., an S3 URL) or use a dedicated FastAPI endpoint to handle
multipart/form-databefore passing the data to your LangChain logic.try: from pydantic.v1 import Field except ImportError: from pydantic import Field from langserve import CustomUserType class FileProcessingRequest(CustomUserType): """Request including a base64 encoded file.""" # The extra field is used to specify a widget for the playground UI. file: str = Field(..., extra={"widget": {"type": "base64file"}}) num_chars: int = 100Refactor LCEL chains into LangGraph nodes
mainFor more advanced features (like persistence, memory, and better debugging), it is recommended to refactor complex LCEL (LangChain Expression Language) chains into discrete LangGraph nodes.
Instead of a single long chain, break the logic into separate nodes for long-running or critical steps (e.g., a
retriever_nodeand agenerator_node). This allows you to monitor, debug, and manage the state of each step independently within theStateGraph.@dataclass class InputState: """Input question from the user.""" question: str @dataclass class OutputState: """The output from the graph.""" answer: str @dataclass class SharedState: question: str docs: List[str] response: str async def retriever_node(state: InputState) -> SharedState: """Rettrieve documents based on the user's question.""" documents = await retriever.ainvoke({"context": state.question}) return { "docs": documents } async def generator_node(state: SharedState) -> OutputState: """Generate an answer using an LLM based on the retrieved documents and question.""" context = " -- DOCUMENT -- ".join(state.docs) prompt = [ SystemMessage( content=( "Answer the user's question based on the list of documents " "that were retrieved. Here are the documents: \n\n" f"{context}" ) ), HumanMessage(content=state.question), ] ai_message = await llm.ainvoke(prompt) return {"answer": ai_message.content} # Define a new graph builder = StateGraph( SharedState, config_schema=Configuration, input=InputState, output=OutputState ) builder.add_node("retriever", retriever_node) builder.add_node("generator", generator_node) builder.add_edge("__start__", "retriever") builder.add_edge("retriever", "generator") graph = builder.compile() graph.name = "RAG Graph"Configure and serve a LangServe application
mainAfter bootstrapping your app, follow these steps to define your logic and run the server. Note that this project uses
poetryfor dependency management.- Define the runnable: Edit
server.pyand useadd_routesto register your LangChain object:
add_routes(app, your_runnable)- Add dependencies: Use
poetryto add any required third-party packages (e.g.,langchain-openai):
poetry add langchain-openai- Set environment variables: Configure necessary keys, such as your provider API keys:
export OPENAI_API_KEY="sk-..."- Run the server: Start the application using the
langchain servecommand:
poetry run langchain serve --port=8100- Define the runnable: Edit
Explore LangServe implementation examples
mainLangServe provides a variety of reference implementations in its
examplesdirectory to help you get started with different patterns. These include:- LLMs: Minimal examples using OpenAI and Anthropic with support for async, batching, and streaming.
- Retrieval: Simple retriever servers, Conversational Retrievers, and Configurable Runnables (e.g., changing index names at runtime).
- Agents: Implementations of agents with and without conversation history using OpenAI tools.
- Persistence: Using
RunnableWithMessageHistoryto implement backend-persisted chat keyed bysession_idorconversation_idanduser_id. - Advanced Configuration: Using
Configurable Runnablefor runtime field and alternative configuration. - Custom API Patterns: Using
APIHandlerinstead ofadd_routesfor more flexible endpoint definitions and FastAPI integration. - Authentication: Various patterns including global dependencies, path dependencies, per-request config modifiers, and per-user logic (e.g., searching only within user-owned documents).
- UI/Playground Widgets: Examples of custom widgets for the LangServe playground, such as chat interfaces and file upload widgets.
Configure type-aware ESLint rules for production
mainWhen developing a production application with this template, it is recommended to enable type-aware lint rules to improve code quality.
Update the
parserOptionsin your ESLint configuration to includeprojectandtsconfigRootDir:Update the
extendslist in your ESLint configuration:- Replace
plugin:@typescript-eslint/recommendedwithplugin:@typescript-eslint/recommended-type-checkedorplugin:@typescript-eslint/strict-type-checked. - Optionally add
plugin:@typescript-eslint/stylistic-type-checked. - Install
eslint-plugin-reactand addplugin:react/recommendedandplugin:react/jsx-runtimeto theextendslist.
- Replace
parserOptions: { ecmaVersion: 'latest', sourceType: 'module', project: ['./tsconfig.json', './tsconfig.node.json'], tsconfigRootDir: __dirname, },Migrate from LangServe to LangGraph Platform (Quick Wrap)
mainIf you have an existing LangServe application using
add_routes, the fastest way to migrate to LangGraph Platform is to wrap your existingRunnableinside a LangGraph node.This approach involves:
- Defining
InputState,OutputState, andSharedStateusing@dataclassto represent your original input/output schemas and the internal graph state. - Creating an asynchronous node function that calls your existing
runnable.ainvoke(). - Building a
StateGraphusing the defined states, adding the node, and setting the entrypoint. - Compiling the graph.
@dataclass class InputState: input: str foo: Optional[str] = None @dataclass class OutputState: output: Any @dataclass class SharedState: input: str foo: Optional[str] = None output: Any runnable = ... # Your existing Runnable async def my_node(state: InputState, config: RunnableConfig) -> OutputState: """Each node does work.""" return await runnable.ainvoke({"input": state.input, "foo": state.foo}) # Define a new graph builder = StateGraph( SharedState, config_schema=Configuration, input=InputState, output=OutputState ) # Add the node to the graph builder.add_node("my_node", my_node) # Set the entrypoint builder.add_edge("__start__", "my_node") # Compile the workflow into an executable graph graph = builder.compile() graph.name = "New Graph"- Defining
Install LangServe
mainYou can install LangServe using
pip. You can choose to install the full suite or specific components for client or server use.To install everything (client and server):
pip install "langserve[all]"To install only the client components:
pip install "langserve[client]"To install only the server components:
pip install "langserve[server]"