> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.asi1.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.asi1.ai/_mcp/server.

# Using ASI:One with LangChain

> Point LangChain at ASI:One and use chat, streaming, structured output and tool calling.

## Overview

ASI:One is [OpenAI-compatible](/documentation/build-with-asi-one/openai-compatibility),
so LangChain works against it with no adapter. Use `ChatOpenAI` and point it at
`https://api.asi1.ai/v1`.

```bash
pip install langchain-openai
```

Every example below reads the key from the environment:

```bash
export ASI_ONE_API_KEY="your-api-key"
```

## Connecting

```python
import os
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage

llm = ChatOpenAI(
    model="asi1",
    base_url="https://api.asi1.ai/v1",
    api_key=os.getenv("ASI_ONE_API_KEY"),
    temperature=0.7,
)

messages = [
    SystemMessage(content="You are a helpful AI assistant."),
    HumanMessage(content="What is agentic AI?"),
]

response = llm.invoke(messages)
print(response.content)
```

Swap `model` for `asi1-ultra` or `asi1-mini` to trade depth against speed. See
[ASI:One Models](/documentation/models).

## Streaming

```python
import os
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage

llm = ChatOpenAI(
    model="asi1",
    base_url="https://api.asi1.ai/v1",
    api_key=os.getenv("ASI_ONE_API_KEY"),
    streaming=True,
)

for chunk in llm.stream([HumanMessage(content="Explain blockchain in simple terms")]):
    print(chunk.content, end="", flush=True)
```

## Structured output

`with_structured_output` takes a Pydantic model and gives you back a typed object
instead of a string. This is usually cleaner than handling `response_format`
yourself. See [Structured Data](/documentation/build-with-asi-one/structured-data)
for the raw API.

```python
import os
from typing import List

from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field


class Product(BaseModel):
    """A product extracted from text."""

    name: str = Field(description="Product name")
    price: float = Field(description="Price in USD")
    category: str = Field(description="Product category")


class ProductList(BaseModel):
    """A list of products."""

    products: List[Product] = Field(description="List of extracted products")


llm = ChatOpenAI(
    model="asi1",
    base_url="https://api.asi1.ai/v1",
    api_key=os.getenv("ASI_ONE_API_KEY"),
)

structured_llm = llm.with_structured_output(ProductList)

text = """
Our store has the following items:
- Wireless Mouse ($29.99) - Electronics
- Organic Coffee Beans ($14.50) - Groceries
- Running Shoes ($89.00) - Sports
"""

result = structured_llm.invoke(f"Extract all products from this text:\n{text}")

for product in result.products:
    print(f"- {product.name}: ${product.price} ({product.category})")
```

## Tool calling

Decorate your functions with `@tool` and bind them to the model. ASI:One decides
which to call and returns the calls for you to execute. See [Tool Calling](/documentation/build-with-asi-one/tool-calling) for the underlying
protocol.

```python
import os

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."""
    # In production, call a real weather API
    return f"The weather in {city} is sunny, 22°C"


@tool
def search_restaurants(city: str, cuisine: str) -> str:
    """Search for restaurants in a city by cuisine type."""
    return f"Found 5 {cuisine} restaurants in {city}"


llm = ChatOpenAI(
    model="asi1",
    base_url="https://api.asi1.ai/v1",
    api_key=os.getenv("ASI_ONE_API_KEY"),
)

llm_with_tools = llm.bind_tools([get_weather, search_restaurants])

response = llm_with_tools.invoke(
    "What's the weather in Tokyo and find me some sushi restaurants there?"
)
print(response.tool_calls)
```

## Using ASI:One's own parameters

LangChain sends the parameters the OpenAI API defines, so ASI:One's own
parameters go through `extra_body`:

```python
llm = ChatOpenAI(
    model="asi1",
    base_url="https://api.asi1.ai/v1",
    api_key=os.getenv("ASI_ONE_API_KEY"),
    extra_body={"enable_thinking": True, "thinking_budget": 2048},
)
```

[Planner mode](/documentation/build-with-asi-one/planner) needs one more thing:
its `x-session-id` is a header rather than a body field, so it goes through
`default_headers` instead.

```python
llm = ChatOpenAI(
    model="asi1",
    base_url="https://api.asi1.ai/v1",
    api_key=os.getenv("ASI_ONE_API_KEY"),
    extra_body={"planner_mode": True},
    default_headers={"x-session-id": "4f9c2b18-6d1e-4a77-9f30-2c5b8e7a1d64"},
)
```

Use a fresh session id for each new job and keep it constant for every request
belonging to that job. See [Reasoning](/documentation/build-with-asi-one/reasoning)
and [Planner Mode](/documentation/build-with-asi-one/planner).

> **Info**
>
> Each endpoint supports its own set of OpenAI parameters, so check [OpenAI Compatibility](/documentation/build-with-asi-one/openai-compatibility) before
> relying on a LangChain setting that maps onto one of them.

## Next steps

1. **[Chat Completions API](/documentation/build-with-asi-one/chat-completions)** - The endpoint `ChatOpenAI` talks to, in full
2. **[OpenAI Compatibility](/documentation/build-with-asi-one/openai-compatibility)** - Which parameters are supported on each endpoint
3. **[ASI:One Models](/documentation/models)** - Choosing between `asi1`, `asi1-ultra` and `asi1-mini`
4. **[Tool Calling](/documentation/build-with-asi-one/tool-calling)** - The raw tool-calling protocol