Build with Sarvam AI in LangChain

View as Markdown

Overview

LangChain is a Python framework for building LLM applications, giving you a single set of interfaces (invoke, stream, bind_tools, with_structured_output, and more) that work the same way across different model providers. Instead of learning each provider’s own SDK, you write your app logic once against LangChain’s BaseChatModel interface and swap providers by changing the model you instantiate.

langchain-sarvam is the official LangChain integration package for Sarvam AI. It wraps the sarvamai Python SDK’s chat completion API behind LangChain’s ChatSarvam class, so Sarvam’s sarvam-105b and sarvam-30b models work as a drop-in BaseChatModel that you can use in chains, agents, retrievers, tool-calling loops, and structured-output pipelines exactly like ChatOpenAI or ChatAnthropic (including LangSmith tracing support).

Quick start

1. Install

$pip install langchain-sarvam python-dotenv

Requires Python 3.10+. python-dotenv loads SARVAM_API_KEY from a local .env file, used throughout the examples below.

2. Set your API key

Get an API key from dashboard.sarvam.ai and add it to your environment:

.env
$SARVAM_API_KEY="your_api_key"

3. Create a chat model instance

1import os
2
3from dotenv import load_dotenv
4from langchain_sarvam import ChatSarvam
5
6load_dotenv()
7
8if not os.getenv("SARVAM_API_KEY"):
9 raise RuntimeError("Set SARVAM_API_KEY in your environment or .env file before running.")
10
11llm = ChatSarvam(model="sarvam-105b")

ChatSarvam reads SARVAM_API_KEY from the environment automatically, so no explicit client setup is needed. Pass api_key="..." directly if you’d rather not use an environment variable.

4. Invoke

1import os
2
3from dotenv import load_dotenv
4from langchain_sarvam import ChatSarvam
5
6load_dotenv()
7
8if not os.getenv("SARVAM_API_KEY"):
9 raise RuntimeError("Set SARVAM_API_KEY in your environment or .env file before running.")
10
11llm = ChatSarvam(model="sarvam-30b")
12
13try:
14 response = llm.invoke("Translate this to malayalam: 'Keep cooking, guys'")
15 print(response.content) # പാചകം തുടരൂ, സുഹൃത്തുക്കളേ
16except Exception as e:
17 print(f"Error: {e}")

If longer completions come back truncated mid-sentence, the model is hitting its output token limit. Raise max_tokens and check finish_reason to confirm when a response was truncated:

1import os
2
3from dotenv import load_dotenv
4from langchain_sarvam import ChatSarvam
5
6load_dotenv()
7
8if not os.getenv("SARVAM_API_KEY"):
9 raise RuntimeError("Set SARVAM_API_KEY in your environment or .env file before running.")
10
11llm = ChatSarvam(model="sarvam-30b", max_tokens=4096)
12
13try:
14 response = llm.invoke("Write a detailed explanation of...")
15 if response.response_metadata.get("finish_reason") == "length":
16 print("Response was truncated; consider raising max_tokens further.")
17except Exception as e:
18 print(f"Error: {e}")

Streaming

1import os
2
3from dotenv import load_dotenv
4from langchain_sarvam import ChatSarvam
5
6load_dotenv()
7
8if not os.getenv("SARVAM_API_KEY"):
9 raise RuntimeError("Set SARVAM_API_KEY in your environment or .env file before running.")
10
11llm = ChatSarvam(model="sarvam-105b", streaming=True)
12
13try:
14 for chunk in llm.stream("Count from 1 to 5."):
15 print(chunk.content, end="", flush=True)
16except Exception as e:
17 print(f"Error: {e}")

Token usage is emitted on the final chunk, so chunk.usage_metadata is populated once streaming completes, no extra configuration needed.

Async

1import asyncio
2import os
3
4from dotenv import load_dotenv
5from langchain_sarvam import ChatSarvam
6
7load_dotenv()
8
9if not os.getenv("SARVAM_API_KEY"):
10 raise RuntimeError("Set SARVAM_API_KEY in your environment or .env file before running.")
11
12llm = ChatSarvam(model="sarvam-105b")
13
14
15async def main():
16 try:
17 response = await llm.ainvoke("What is the capital of India?")
18 print(response.content)
19
20 async for chunk in llm.astream("Count from 1 to 3."):
21 print(chunk.content, end="", flush=True)
22 except Exception as e:
23 print(f"Error: {e}")
24
25
26asyncio.run(main())

Tool calling

ChatSarvam supports LangChain’s standard bind_tools() interface:

1import os
2
3from dotenv import load_dotenv
4from langchain_core.tools import tool
5from langchain_sarvam import ChatSarvam
6
7load_dotenv()
8
9if not os.getenv("SARVAM_API_KEY"):
10 raise RuntimeError("Set SARVAM_API_KEY in your environment or .env file before running.")
11
12
13@tool
14def get_weather(city: str) -> str:
15 """Get the weather for a city."""
16 return f"Sunny in {city}"
17
18
19llm = ChatSarvam(model="sarvam-105b")
20llm_with_tools = llm.bind_tools([get_weather])
21
22try:
23 response = llm_with_tools.invoke("What is the weather in Mumbai?")
24 print(response.tool_calls)
25except Exception as e:
26 print(f"Error: {e}")

Pass tool_choice="auto" (model decides), tool_choice="none" (disabled), tool_choice="required" (must call a tool), or a tool name string to force a specific tool.

Structured output

1import os
2
3from dotenv import load_dotenv
4from pydantic import BaseModel
5from langchain_sarvam import ChatSarvam
6
7load_dotenv()
8
9if not os.getenv("SARVAM_API_KEY"):
10 raise RuntimeError("Set SARVAM_API_KEY in your environment or .env file before running.")
11
12
13class CapitalCity(BaseModel):
14 city: str
15 country: str
16
17
18llm = ChatSarvam(model="sarvam-105b")
19structured_llm = llm.with_structured_output(CapitalCity)
20
21try:
22 result = structured_llm.invoke("What is the capital of France?")
23 print(result) # CapitalCity(city='Paris', country='France')
24except Exception as e:
25 print(f"Error: {e}")

with_structured_output() sends an explicit reasoning_effort=None by default, unless the model or the call already sets reasoning_effort. Sarvam’s reasoning models default to reasoning_effort="medium" server-side, and the resulting reasoning_content competes with the structured JSON payload for the same completion token budget. Disabling reasoning by default keeps that budget free for the structured output. Pass reasoning_effort="low", "medium", or "high" explicitly (on the model or the call) to combine reasoning with structured output.

Reasoning mode

Pass reasoning_effort to control how much effort the model puts into reasoning before responding: "low", "medium", or "high". Leaving it unset lets the API apply its own default.

1import os
2
3from dotenv import load_dotenv
4from langchain_sarvam import ChatSarvam
5
6load_dotenv()
7
8if not os.getenv("SARVAM_API_KEY"):
9 raise RuntimeError("Set SARVAM_API_KEY in your environment or .env file before running.")
10
11reasoning_llm = ChatSarvam(model="sarvam-105b", reasoning_effort="high")
12
13try:
14 response = reasoning_llm.invoke("Explain the Riemann hypothesis.")
15 print(response.additional_kwargs.get("reasoning_content"))
16 print(response.content)
17except Exception as e:
18 print(f"Error: {e}")

See Reasoning effort for details on the allowed values.


Capabilities at a glance

ChatSarvam interfaceLangChain conceptUnderlying Sarvam capability
invoke / ainvokeSync/async single-turn completionChat completion
stream / astreamSync/async token streamingChat completion (streaming)
bind_toolsTool/function callingChat completion (tool calling)
with_structured_outputSchema-constrained outputChat completion (Structured Outputs via response_format)
reasoning_effort paramExtended reasoningReasoning effort

Supported models: Sarvam 105B (flagship, 128K context) and Sarvam 30B (64K context).


Troubleshooting

Set SARVAM_API_KEY in the environment the process actually reads (.env loaded, no stray whitespace in the key), or pass api_key="..." explicitly when constructing ChatSarvam.

Sarvam’s API returns 403 (not 401) for auth failures; see Errors & Troubleshooting.

Set SARVAM_API_BASE_URL, or pass base_url="..." to ChatSarvam, to point at a different API base URL than https://api.sarvam.ai/v1.

Output length is capped by max_tokens (unset by default, so the API’s own default applies). Raise it and check response.response_metadata["finish_reason"] == "length" to confirm truncation; see the Invoke section above.

ChatSarvam only converts SystemMessage, HumanMessage, AIMessage, and ToolMessage. This surfaces when older-style FunctionMessages or a generic ChatMessage end up in the history, commonly from a prebuilt agent or migrated codebase, since those aren’t converted. Map them to ToolMessage/HumanMessage before passing the history to ChatSarvam.

ChatSarvam wraps every exception from the underlying sarvamai client, including auth, rate limit, and network errors, in a single ChatSarvamError. Catch ChatSarvamError rather than a provider-specific exception type, and inspect str(e) for the underlying cause.


Additional resources


Need help?