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

# Agri & Rural Voice Agents

> Architecture, model configuration, and pitfalls for building farmer-advisory and rural voice agents with Sarvam AI, tuned for low-bandwidth, feature-phone-first users.

Farmer-advisory bots (crop guidance, mandi/market prices, weather alerts, government scheme status) serve users who are frequently on 2G/3G connections, basic phones, and regional-language-only speech. Voice is often the *only* accessible interface here, not a convenience layer on top of an app. This vertical shares a lot with [Government Services](/api-reference-docs/api-guides-tutorials/speech-to-text/use-cases/government-services), the same accessibility bar and the same need to avoid stating unverified facts as certain, but adds connectivity constraints and domain content (crops, weather, mandi prices) that the other guides don't cover.

There's no dedicated example agent for this vertical yet in the cookbook, so this guide includes a full one, built on the same pattern as the [Government Scheme Agent](/api-reference-docs/cookbook/Examples/Government_Scheme_Agent_LiveKit), which already covers PM-Kisan and other farmer-relevant schemes.

**In short:** design for a bad connection first, ground every price/weather answer with a live tool call instead of the model's memory, and reuse the Government Services pattern for scheme questions instead of duplicating it.

## Architecture

```
Farmer Audio (often PSTN/2G) → STT (streaming, 8kHz-tolerant) → LLM (simple language, tool-grounded facts) → TTS (streaming, mulaw for low-bandwidth) → Farmer
```

* **Tool calls from the LLM step:** mandi price lookup, weather API, scheme status

Assume PSTN or low-bandwidth mobile data, not a stable broadband WebRTC session. Use 8kHz telephony-friendly audio formats (`mulaw`/`alaw` for PSTN legs) and design conversations to survive occasional dropped audio: short turns and a willingness to repeat.

Mandi prices, weather, and pest advisories are exactly the kind of facts that are wrong the moment they're not live. Use [tool calling](/api-reference-docs/chat-completion/overview#tool-calling-function-calling) to hit a real prices/weather API rather than letting the LLM guess from training data. This matters even more here than in Government Services, because a number like today's mandi price goes stale in hours, not months.

Same principle as citizen-services bots: short, plain-language turns beat long explanations for a low-literacy, audio-only interface.

Questions about PM-Kisan status or other scheme eligibility should route to the same grounded-answer pattern as [Government Services](/api-reference-docs/api-guides-tutorials/speech-to-text/use-cases/government-services) rather than maintaining a second, possibly inconsistent copy of scheme knowledge.

## Recommended models & params

| Layer        | Setting                                                                                                                                                                          | Why                                                                                                                                           |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| STT          | `saaras:v3`, `mode="transcribe"`, `language="unknown"`                                                                                                                           | Regional-language-first callers. Auto-detect avoids forcing Hindi on a Tamil- or Telugu-speaking farmer                                       |
| LLM          | `sarvam-30b`, `reasoning_effort=None` for routine advisory turns                                                                                                                 | Most turns are lookup-and-explain (price, weather, basic crop guidance), not deep reasoning. Keep latency low over an already-slow connection |
| Tool calling | Wire mandi price and weather lookups as [tools](/api-reference-docs/chat-completion/overview#tool-calling-function-calling) rather than prompting for "current" data             | The model has no live data access. Tool calling is the only way to get an actually-current mandi price into the response                      |
| TTS          | `bulbul:v3`, `pace=0.85–0.9`, warm speaker matched to the [regional-language recommendation](/api-reference-docs/text-to-speech/best-practices#10-speaker-selection-by-language) | Same accessibility reasoning as Government Services: slower, warmer, and in the farmer's own language beats a brisk, generic voice            |
| TTS format   | `mulaw`/`alaw` at 8kHz for PSTN/IVR delivery; fall back gracefully if the connection can't sustain WebSocket streaming                                                           | Matches [Output Format Recommendations](/api-reference-docs/text-to-speech/best-practices#12-output-format-recommendations) for telephony     |

## Latency targets

The connection is usually the bottleneck here, not the model. Use streaming STT and TTS as the default, but design your retry/reconnect logic assuming the network will drop mid-call more often than in an urban contact-center deployment.

* Keep tool-call round-trips (mandi price, weather) fast and cached where possible. For example, cache a mandi's price for the trading day so a live lookup doesn't stack latency on top of an already-slow connection.
* Prefer `sarvam-30b` over `sarvam-105b` by default here, specifically because the added latency of a bigger model compounds with network latency in a way it doesn't on a stable connection.

## Pitfalls

This is the biggest risk in this vertical. A farmer acting on yesterday's mandi price or a stale weather forecast has real financial consequences. Always ground these answers with a live tool call, and never let the LLM state a specific number from memory.

Test against 8kHz telephony audio and degraded network conditions, not just a WebRTC demo on office wifi. What works in a browser tab doesn't necessarily survive a real rural PSTN call.

A single hardcoded `target_language_code` will exclude farmers outside that language's region. Auto-detect on STT and pick the TTS voice/language per caller, rather than shipping a single-language deployment and calling it done.

Pesticide/fertilizer names, scheme acronyms, and technical crop terminology need the same plain-language treatment as [Government Services](/api-reference-docs/api-guides-tutorials/speech-to-text/use-cases/government-services#pitfalls) content. Don't assume agricultural literacy any more than you'd assume digital literacy.

If your agri bot also answers PM-Kisan or scheme questions, reuse the grounded, verification-pointing pattern from the [Government Scheme Agent](/api-reference-docs/cookbook/Examples/Government_Scheme_Agent_LiveKit) rather than writing a second, possibly drifting version of the same facts.

## Full example

There's no published cookbook example for this vertical yet. Here's a complete agent following the same LiveKit pattern as the [Government Scheme Agent](/api-reference-docs/cookbook/Examples/Government_Scheme_Agent_LiveKit), with agri-specific instructions and a tool-calling stub for live mandi prices:

```python
import logging
from dotenv import load_dotenv
from livekit.agents import JobContext, WorkerOptions, cli, function_tool
from livekit.agents.llm import RunContext
from livekit.agents.voice import Agent, AgentSession
from livekit.plugins import sarvam

load_dotenv()

logger = logging.getLogger("krishi-mitra")
logger.setLevel(logging.INFO)


class KrishiMitraAgent(Agent):
    def __init__(self) -> None:
        super().__init__(
            instructions="""
                You are Krishi Mitra, a voice assistant that helps Indian farmers with
                crop advisory, mandi (market) prices, weather, and government scheme queries.

                Your responsibilities:
                - Answer questions about crop care, sowing/harvest timing, and common pest/disease symptoms in simple terms
                - Use the get_mandi_price tool for any current price question. Never state a price from memory
                - Use the get_weather_forecast tool for any weather question. Never guess conditions
                - For government scheme questions (PM-Kisan, crop insurance, etc.), give general guidance and
                  always direct the farmer to their nearest Krishi Vigyan Kendra or the official portal to confirm details
                - If you don't know something, say so plainly rather than guessing

                Communication guidelines:
                - Use simple, everyday language. Avoid technical agronomic or bureaucratic jargon
                - Speak slowly and clearly. Be willing to repeat
                - Be patient and respectful. Many callers may have limited formal education
                - Keep answers short and concrete: a specific action, not a lecture

                Start by greeting the farmer warmly and asking what they need help with today.
            """,
            stt=sarvam.STT(
                language="unknown",  # Auto-detect across regional languages
                model="saaras:v3",
                mode="transcribe",
            ),
            llm=sarvam.LLM(model="sarvam-30b"),
            tts=sarvam.TTS(
                target_language_code="hi-IN",  # Set per deployment region
                model="bulbul:v3",
                speaker="simran",
                pace=0.9,
            ),
        )

    @function_tool
    async def get_mandi_price(self, context: RunContext, crop: str, mandi: str) -> dict:
        """Look up today's price for a crop at a given mandi. Replace with a real market-price API call."""
        # TODO: call your mandi price provider (e.g. Agmarknet) here
        return {"crop": crop, "mandi": mandi, "price_per_quintal": None, "as_of": "today"}

    @function_tool
    async def get_weather_forecast(self, context: RunContext, location: str) -> dict:
        """Look up the weather forecast for a location. Replace with a real weather API call."""
        # TODO: call your weather provider here
        return {"location": location, "forecast": None}

    async def on_enter(self):
        self.session.generate_reply()


async def entrypoint(ctx: JobContext):
    logger.info(f"Farmer connected to room: {ctx.room.name}")
    session = AgentSession()
    await session.start(agent=KrishiMitraAgent(), room=ctx.room)


if __name__ == "__main__":
    cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))
```

`get_mandi_price` and `get_weather_forecast` above are stubs. Wiring them to real data sources is what makes this agent safe to deploy. Without that, don't let the LLM answer price/weather questions from its own knowledge. See [Tool Calling](/api-reference-docs/chat-completion/overview#tool-calling-function-calling) for the full request/response flow.

Install the same dependencies as the other LiveKit examples:

```bash
pip install "livekit-agents[sarvam,silero]" python-dotenv
```

**See also:** [Government Services](/api-reference-docs/api-guides-tutorials/speech-to-text/use-cases/government-services) for the scheme-awareness portion of this audience.