Metadata-Version: 2.4
Name: langchain-gigachat
Version: 0.5.1a2
Summary: An integration package connecting GigaChat and LangChain
Project-URL: Repository, https://github.com/ai-forever/langchain-gigachat
Project-URL: Source Code, https://github.com/ai-forever/langchain-gigachat/tree/master/libs/gigachat
License-Expression: MIT
License-File: LICENSE
Requires-Python: <4,>=3.10
Requires-Dist: gigachat<0.3,>=0.2.1
Requires-Dist: langchain-core<2,>=1
Description-Content-Type: text/markdown

<div align="center" id="top">

[![PyPI](https://img.shields.io/pypi/v/langchain-gigachat?style=flat-square)](https://pypi.org/project/langchain-gigachat/)
[![Python](https://img.shields.io/pypi/pyversions/langchain-gigachat?style=flat-square)](https://pypi.org/project/langchain-gigachat/)
[![CI](https://img.shields.io/github/actions/workflow/status/ai-forever/langchain-gigachat/check_diffs.yml?style=flat-square)](https://github.com/ai-forever/langchain-gigachat/actions/workflows/check_diffs.yml)
[![License](https://img.shields.io/github/license/ai-forever/langchain-gigachat?style=flat-square)](https://opensource.org/license/MIT)
[![Downloads](https://img.shields.io/pypi/dm/langchain-gigachat?style=flat-square)](https://pypistats.org/packages/langchain-gigachat)

</div>

# langchain-gigachat

LangChain integration for [GigaChat](https://giga.chat/) — a large language model.

This library is part of [GigaChain](https://github.com/ai-forever/gigachain) and wraps the [GigaChat Python SDK](https://github.com/ai-forever/gigachat) with LangChain-compatible interfaces.

## Table of Contents

- [Features](#features)
- [Installation](#installation)
- [Authentication](#authentication)
- [Usage Examples](#usage-examples)
  - [Chat](#chat)
  - [Streaming](#streaming)
  - [Async](#async)
  - [Embeddings](#embeddings)
  - [Reasoning Models](#reasoning-models)
- [Tool Calling](#tool-calling)
  - [Legacy `bind_functions()`](#legacy-bind_functions)
- [Structured Output](#structured-output)
- [Attachments](#attachments)
  - [File Operations](#file-operations)
- [Configuration](#configuration)
  - [Constructor Parameters](#constructor-parameters)
  - [Environment Variables](#environment-variables)
- [Error Handling](#error-handling)
- [Related Projects](#related-projects)
- [Contributing](#contributing)
- [License](#license)

## Features

- **Chat completions** — synchronous and asynchronous, with streaming
- **Embeddings** — text vectorization via `GigaChatEmbeddings`
- **Tool calling** — standard LangChain `@tool` with GigaChat metadata in `extras`
- **Structured output** — Pydantic models and JSON mode
- **Reasoning models** — `reasoning_effort` for thinking models
- **Attachments** — images, audio, and documents via the Files API
- **File operations** — upload, list, retrieve, and delete files
- **Configurable retry** — exponential backoff via the underlying SDK
- **Environment-based configuration** — all parameters configurable via `GIGACHAT_` env vars
- **Fully typed** — Pydantic V2 models with `py.typed` marker

## Installation

```bash
pip install -U langchain-gigachat
```

**Requirements:** Python 3.10+

> **Note:** In production, keep TLS verification enabled (default).
> See [Authentication](#authentication) for certificate setup.

## Authentication

Set environment variables and let the SDK pick them up:

```bash
export GIGACHAT_CREDENTIALS="your-authorization-key"
export GIGACHAT_SCOPE="GIGACHAT_API_PERS"  # GIGACHAT_API_B2B or GIGACHAT_API_CORP for enterprise
```

After this, `GigaChat()` works without any arguments in code.

If your environment requires a specific TLS certificate:

```bash
export GIGACHAT_CA_BUNDLE_FILE="/path/to/certs.pem"
```

> **Warning:** Disabling TLS verification (`verify_ssl_certs=False`) is for local development only and is not recommended for production.

For detailed instructions on obtaining credentials and certificates, see the [GigaChat SDK](https://github.com/ai-forever/gigachat) and [API docs](https://developers.sber.ru/docs/ru/gigachat).

## Usage Examples

> The examples below assume authentication is configured via environment variables.
> See [Authentication](#authentication).

### Chat

```python
from langchain_gigachat import GigaChat

llm = GigaChat(credentials="your-authorization-key")

msg = llm.invoke("Hello, GigaChat!")
print(msg.content)
```

### Streaming

Receive tokens as they are generated:

```python
from langchain_gigachat import GigaChat

llm = GigaChat()

for chunk in llm.stream("Write a short poem about programming"):
    print(chunk.content, end="", flush=True)
print()
```

> **Note:** Wrapper-side local `stop` handling was removed in `0.5.x`. The
> public methods still accept `stop` for LangChain signature compatibility, but
> `langchain-gigachat` no longer applies stop-sequence truncation itself. See
> [`MIGRATION.md`](MIGRATION.md) before carrying `stop=...` call sites forward.

### Async

Use async/await for non-blocking operations:

```python
import asyncio

from langchain_gigachat import GigaChat


async def main():
    llm = GigaChat()
    msg = await llm.ainvoke("Explain quantum computing in simple terms.")
    print(msg.content)


asyncio.run(main())
```

### Embeddings

Generate vector representations of text:

```python
from langchain_gigachat import GigaChatEmbeddings

emb = GigaChatEmbeddings(model="Embeddings")

vector = emb.embed_query("Привет!")
print(len(vector))
```

### Reasoning Models

Use `reasoning_effort` with reasoning-capable models:

```python
from langchain_gigachat import GigaChat

llm = GigaChat(model="GigaChat-2-Reasoning", reasoning_effort="high")

msg = llm.invoke("How many r's are in the word 'strawberry'?")
print(msg.content)
print(msg.additional_kwargs.get("reasoning_content"))  # model's chain-of-thought
```

> **Note:** `reasoning_content` is also available during streaming — each `AIMessageChunk` carries it in `additional_kwargs`.

## Tool Calling

Use the standard LangChain `@tool` decorator. Pass GigaChat-specific metadata via `extras`:

```python
from langchain_gigachat import GigaChat
from langchain_core.tools import tool


@tool(
    extras={
        "few_shot_examples": [{"request": "weather in Tokyo", "params": {"city": "Tokyo"}}]
    }
)
def get_weather(city: str) -> str:
    """Get current weather for a city."""
    return f"{city}: sunny, 22C"


llm = GigaChat()
llm_with_tools = llm.bind_tools([get_weather], tool_choice="auto")

msg = llm_with_tools.invoke("What's the weather in Tokyo?")
print(msg.tool_calls)
```

To configure function/tool ranking, pass `function_ranker` to `GigaChat`. For
example, disable ranking when binding tools:

```python
llm = GigaChat(function_ranker={"enabled": False})
llm_with_tools = llm.bind_tools([get_weather], tool_choice="auto")
```

> **Note:** `tool_choice="any"` is not supported by the GigaChat API. Use `"auto"`, `"none"`, or a specific tool name. If upstream code passes `"any"`, set `allow_any_tool_choice_fallback=True` to silently convert it to `"auto"`.

> **Note:** GigaChat API does not support parallel tool calls in a single assistant message. If `AIMessage` contains more than one `tool_calls` entry, a `ValueError` is raised.

### Legacy `bind_functions()`

For legacy LangChain function-calling flows, `bind_functions()` is still available:

```python
from langchain_gigachat import GigaChat


def get_weather(city: str) -> str:
    """Get current weather for a city."""
    return f"{city}: sunny, 22C"


llm = GigaChat()
llm_with_functions = llm.bind_functions(
    [get_weather],
    function_call="auto",
)
```

Use `bind_tools()` for new code. `bind_functions()` is kept as a compatibility layer over the provider's `function_call` transport and supports `None`, `"auto"`, `"none"`, or a specific function name.

Internally, the provider transport is still function-oriented. That is why
`ToolMessage` results are serialized back as provider `function` messages when
continuing a conversation.

## Structured Output

Extract typed data from model responses:

```python
from pydantic import BaseModel, Field

from langchain_gigachat import GigaChat


class Answer(BaseModel):
    """An answer with confidence score."""

    text: str = Field(description="Final answer")
    confidence: float = Field(ge=0, le=1, description="Confidence 0..1")


llm = GigaChat()
chain = llm.with_structured_output(Answer)

parsed = chain.invoke("What is the capital of France? Rate your confidence.")
print(parsed)
```

By default, `with_structured_output()` uses GigaChat function calling for
backward-compatible schema extraction. Native API-level JSON Schema constraints
are also available explicitly:

```python
llm.with_structured_output(Answer, method="json_schema")
```

> **Note:** `method="json_schema"` requires `gigachat>=0.2.1` and a model that
> supports the `response_format` API field. Support is currently in beta on
> GigaChat side and may not be available for every model — fall back to the
> default `method="function_calling"` if the API rejects the request.

The legacy `method="json_mode"` is still accepted for backward compatibility,
but it emits a `DeprecationWarning` — prefer `method="json_schema"` for new
code.

## Attachments

Upload a file via the Files API, then reference it in `content_blocks`:

```python
from langchain_core.messages import HumanMessage

from langchain_gigachat import GigaChat

llm = GigaChat()

with open("image.png", "rb") as f:
    uploaded = llm.upload_file(("image.png", f.read()))

msg = HumanMessage(
    content_blocks=[
        {"type": "text", "text": "Describe the image."},
        {"type": "image", "file_id": uploaded.id_},
    ]
)

reply = llm.invoke([msg])
print(reply.content)
```

> **Note:** Supported `content_blocks` types: `image`, `audio`, `file`. The pattern is identical for each — only the `type` field differs.

> **Note:** Base64 data URLs in `image_url` / `audio_url` / `document_url` blocks can be auto-uploaded with `auto_upload_attachments=True`, but prefer explicit `upload_file()` in production.

### File Operations

Manage files via the Files API:

```python
from langchain_gigachat import GigaChat

llm = GigaChat()

# Upload
with open("document.pdf", "rb") as f:
    uploaded = llm.upload_file(("document.pdf", f.read()))
print(f"Uploaded: {uploaded.id_}")

# List
files = llm.list_files()
for f in files.data:
    print(f"{f.id_}: {f.filename}")

# Delete
llm.delete_file(uploaded.id_)
```

`get_file()` returns file metadata, while `get_file_content()` downloads file content:

```python
metadata = llm.get_file(uploaded.id_)          # UploadedFile
content = llm.get_file_content(uploaded.id_)   # Image with base64 payload
print(metadata.filename)
print(content.content[:20])
```

All file methods have async variants (`aget_file`, `aget_file_content`, `alist_files`, `adelete_file`, etc.).

## Configuration

All parameters can be passed to `GigaChat(...)` / `GigaChatEmbeddings(...)` directly or via environment variables with the `GIGACHAT_` prefix.

### Constructor Parameters

Most commonly used parameters (all are optional):

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `model` | `str` | `None` | Model name (e.g. `"GigaChat-2-Max"`, `"GigaChat-2-Pro"`) |
| `temperature` | `float` | `None` | Sampling temperature |
| `max_tokens` | `int` | `None` | Maximum number of tokens to generate |
| `top_p` | `float` | `None` | Nucleus sampling threshold (0.0–1.0) |
| `repetition_penalty` | `float` | `None` | Penalty applied to repeated tokens |
| `reasoning_effort` | `str` | `None` | Reasoning effort for reasoning models |
| `function_ranker` | `dict` | `None` | Function/tool ranking settings, e.g. `{"enabled": False}` to disable ranking |
| `credentials` | `str` | `None` | OAuth authorization key |
| `access_token` | `str` | `None` | Pre-obtained JWT token (bypasses OAuth) |
| `scope` | `str` | `None` | API scope (`GIGACHAT_API_PERS` / `_B2B` / `_CORP`) |
| `base_url` | `str` | `None` | Custom API endpoint |
| `verify_ssl_certs` | `bool` | `None` | TLS certificate verification |
| `ca_bundle_file` | `str` | `None` | Path to CA certificate bundle |
| `timeout` | `float` | `None` | Request timeout in seconds |
| `max_retries` | `int` | `None` | Retry attempts for transient errors (SDK default: `0`) |
| `retry_backoff_factor` | `float` | `None` | Exponential backoff multiplier (SDK default: `0.5`) |
| `profanity_check` | `bool` | `None` | Enable profanity filtering |
| `streaming` | `bool` | `False` | Stream results by default |
| `auto_upload_attachments` | `bool` | `False` | Auto-upload base64 content from `image_url` / `audio_url` / `document_url` blocks |
| `allow_any_tool_choice_fallback` | `bool` | `False` | Silently convert `tool_choice="any"` to `"auto"` |

For the full list of parameters (auth, SSL/mTLS, retry, flags, etc.), see the [GigaChat SDK README](https://github.com/ai-forever/gigachat#constructor-parameters) — the LangChain wrapper accepts the same constructor arguments.

### Environment Variables

All parameters can be configured via environment variables with the `GIGACHAT_` prefix (e.g. `GIGACHAT_CREDENTIALS`, `GIGACHAT_MODEL`, `GIGACHAT_BASE_URL`). See the [GigaChat SDK README](https://github.com/ai-forever/gigachat#environment-variables) for the full list.

> **Note:** Retries are handled by the underlying `gigachat` SDK. Don't combine them with LangChain `.with_retry()` — the attempts multiply:
>
> ```python
> llm = GigaChat(max_retries=3, retry_backoff_factor=0.5)  # delays: 0.5s, 1s, 2s
> ```

## Error Handling

SDK exceptions propagate unchanged through the LangChain wrapper (aligned with the `langchain-openai` approach):

```python
from gigachat.exceptions import AuthenticationError, RateLimitError, GigaChatException
from langchain_gigachat import GigaChat

llm = GigaChat()

try:
    llm.invoke("Hello!")
except AuthenticationError as e:
    print(f"Authentication failed: {e}")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after}s")
except GigaChatException as e:
    print(f"GigaChat error: {e}")
```

For the full exception hierarchy and HTTP status code mapping, see the [GigaChat SDK — Error Handling](https://github.com/ai-forever/gigachat#error-handling).

## Tracing Metadata

When the provider returns tracing headers, the wrapper preserves them in both
non-streaming and streaming flows:

- `AIMessage.id` / `AIMessageChunk.id` carries `x-request-id`
- non-streaming responses keep full headers in `ChatResult.llm_output["x_headers"]`
- streaming responses expose full headers on the first chunk via
  `generation_info["x_headers"]`

This makes it possible to correlate LangChain runs with provider-side logs or
support requests without parsing SDK responses directly.

## Related Projects

- **[GigaChain](https://github.com/ai-forever/gigachain)** — a set of solutions for developing LLM applications and multi-agent systems, with support for LangChain, LangGraph, LangChain4j, GigaChat and other LLMs
- **[GigaChat Python SDK](https://github.com/ai-forever/gigachat)** — the underlying Python SDK that powers this integration
- [GigaChat API docs](https://developers.sber.ru/docs/ru/gigachat)

## Contributing

See [`CONTRIBUTING.md`](../../CONTRIBUTING.md). Development happens under `libs/gigachat`:

```bash
uv sync
make lint_package
make test
```

## License

This project is licensed under the MIT License.

Copyright © 2026 [GigaChain](https://github.com/ai-forever/gigachain)
