# `LangChain.ChatModels.ChatReqLLM`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L2)

ChatModel adapter using the `req_llm` library as the HTTP/LLM backend.

Provides access to any provider supported by req_llm (Anthropic, OpenAI, Google
Gemini, Groq, Ollama, AWS Bedrock, etc.) through the unified LangChain framework.

## Model Specification

The `model` field takes a req_llm-format specifier string: `"provider:model_id"`.

## Usage

    alias LangChain.ChatModels.ChatReqLLM
    alias LangChain.Chains.LLMChain
    alias LangChain.Message

    # Anthropic via req_llm
    llm = ChatReqLLM.new!(%{model: "anthropic:claude-haiku-4-5"})

    # OpenAI
    llm = ChatReqLLM.new!(%{model: "openai:gpt-4o"})

    # Ollama local model
    llm = ChatReqLLM.new!(%{model: "ollama:llama3", base_url: "http://localhost:11434"})

    # Groq with streaming
    llm = ChatReqLLM.new!(%{model: "groq:llama-3.3-70b-versatile", stream: true})

    {:ok, chain} =
      %{llm: llm}
      |> LLMChain.new!()
      |> LLMChain.add_message(Message.new_user!("Hello!"))
      |> LLMChain.run()

## Tool Use

Tools are translated to req_llm format automatically. The `callback` field in the
req_llm Tool struct is set to a stub — tool execution remains the LLMChain's
responsibility, as with all other ChatModel adapters.

## Provider Options

Provider-specific options (e.g. `thinking`, `tool_choice`, `seed`) can be passed
via `provider_opts`:

    ChatReqLLM.new!(%{
      model: "anthropic:claude-haiku-4-5",
      provider_opts: %{"thinking" => %{"type" => "enabled", "budget_tokens" => 2000}}
    })

## Connection Retry Behavior

The `retry_count` option controls how many times a request is retried when
a pooled HTTP connection turns out to be stale (server closed it between
requests). This is a transport-level issue where retrying with a fresh
connection is the correct response.

**Only closed-connection errors are retried.** Timeouts, rate limits (429),
overloaded (529), authentication errors, and invalid requests all return
immediately -- they are not problems that a simple retry will fix.

| `retry_count` | Total HTTP requests |
|---|---|
| `0` | 1 (no retries) |
| `1` | 2 (1 initial + 1 retry) |
| `2` (default) | 3 (1 initial + 2 retries) |

Req's built-in HTTP retry is disabled to prevent the two retry layers from
compounding. See [GitHub issue #503](https://github.com/brainlid/langchain/issues/503).

When running LLM calls from a background job queue (e.g., Oban) that has its
own retry logic, set `retry_count: 0` so there are no hidden retries:

    ChatReqLLM.new!(%{model: "...", retry_count: 0})

# `t`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L142)

```elixir
@type t() :: %LangChain.ChatModels.ChatReqLLM{
  api_key: term(),
  base_url: term(),
  callbacks: term(),
  max_tokens: term(),
  model: term(),
  provider_opts: term(),
  receive_timeout: term(),
  req_opts: term(),
  retry_count: term(),
  stream: term(),
  temperature: term(),
  verbose_api: term()
}
```

# `call`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L200)

Call the LLM via req_llm with a prompt or list of messages.

# `content_part_to_req_llm`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L855)

```elixir
@spec content_part_to_req_llm(LangChain.Message.ContentPart.t()) ::
  ReqLLM.Message.ContentPart.t() | nil
```

Convert a LangChain `ContentPart` to a `ReqLLM.Message.ContentPart`.

Returns `nil` for unsupported types (they are filtered out of the content list).

# `do_process_response`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L999)

```elixir
@spec do_process_response(t(), ReqLLM.Response.t()) ::
  LangChain.Message.t() | {:error, LangChain.LangChainError.t()}
```

Convert a `ReqLLM.Response` to a `LangChain.Message`.

# `function_to_req_llm_tool`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L953)

```elixir
@spec function_to_req_llm_tool(LangChain.Function.t()) :: ReqLLM.Tool.t()
```

Convert a single `LangChain.Function` to a `ReqLLM.Tool` with a stub callback.

The stub callback is never invoked in normal LangChain operation — the tool
definition is only used for schema generation (telling the LLM what tools exist).

The `:strict` flag is passed through so providers that support it (e.g. OpenAI
structured outputs) can enforce the parameter schema. Both the `:parameters`
(list of `LangChain.FunctionParam`) and `:parameters_schema` (raw JSONSchema
map) forms are supported, mirroring `LangChain.ChatModels.ChatOpenAI`.

# `functions_to_req_llm_tools`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L934)

```elixir
@spec functions_to_req_llm_tools([LangChain.Function.t()] | nil) :: [ReqLLM.Tool.t()]
```

Convert a list of LangChain `Function` structs to `ReqLLM.Tool` structs.

Each tool gets a stub callback — tool execution remains the LLMChain's responsibility.

# `message_to_req_llm_messages`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L811)

```elixir
@spec message_to_req_llm_messages(LangChain.Message.t()) :: [ReqLLM.Message.t()]
```

Convert a single LangChain `Message` to a list of `ReqLLM.Message` structs.

Most roles map 1-to-1. The `:tool` role expands to one message per `ToolResult`.

# `messages_to_req_llm_context`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L797)

```elixir
@spec messages_to_req_llm_context([LangChain.Message.t()]) :: ReqLLM.Context.t()
```

Convert a list of LangChain messages to a `ReqLLM.Context`.

Tool messages are expanded: a single LangChain `:tool` message (which may carry
multiple `ToolResult` structs) becomes one `ReqLLM.Message` per result, matching
the one-result-per-message convention expected by OpenAI-compatible providers.

# `new`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L165)

```elixir
@spec new(attrs :: map()) :: {:ok, t()} | {:error, Ecto.Changeset.t()}
```

Create a ChatReqLLM configuration.

# `new!`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L176)

```elixir
@spec new!(attrs :: map()) :: t() | no_return()
```

Create a ChatReqLLM configuration, raising on error if invalid.

# `retry_on_fallback?`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L250)

```elixir
@spec retry_on_fallback?(LangChain.LangChainError.t()) :: boolean()
```

Determine if an error should be retried via a fallback LLM.

# `translate_finish_reason`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L1159)

```elixir
@spec translate_finish_reason(atom() | nil) :: atom()
```

Translate a `req_llm` `finish_reason` atom to a `LangChain.Message` status atom.

# `translate_stream_chunk`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L624)

```elixir
@spec translate_stream_chunk(ReqLLM.StreamChunk.t()) :: [LangChain.MessageDelta.t()]
```

Translate a single `ReqLLM.StreamChunk` to a list of `LangChain.MessageDelta` structs.

Returns an empty list for chunks that produce no LangChain deltas (e.g. empty content,
non-terminal metadata).

# `translate_usage`
[🔗](https://github.com/brainlid/langchain/blob/v0.9.3/lib/chat_models/chat_req_llm.ex#L1178)

```elixir
@spec translate_usage(map() | nil) :: LangChain.TokenUsage.t() | nil
```

Translate a `req_llm` usage map to a `LangChain.TokenUsage` struct.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
