llm
On this page
A small, dependency-light unified interface for calling LLM providers from Python. One consistent shape — generate(), generate_async(), astream() — over seven backends, with unified tool/function-calling support across all seven.
All seven inherit from BaseLLMInterface, an ABC that defines the contract every provider follows.
[!NOTE] Scope of this documentation This documentation covers exactly what's in the
llm/package: 11 modules, ~2,100 lines. It does not describe a larger "Zerda" ecosystem — only what exists in this specific package is documented here, and every claim below is checked against the source inllm/.
Why this exists
Swapping LLM providers normally means rewriting call sites because every SDK has its own client shape, message format, streaming API, and function-calling schema. This package normalizes that: construct any interface with a model_name and api_key, then call the same three methods regardless of provider — and describe tools once, in one schema, regardless of provider.
from zerda.llm import OpenAIInterface, AnthropicInterface
for llm in [OpenAIInterface(api_key="sk-..."), AnthropicInterface(api_key="sk-ant-...")]:
print(llm.generate(prompt="Explain RAG in one sentence."))
Tool / function calling
All seven interfaces accept a tools argument (and an optional tool_choice) on generate() and generate_async(), using one unified schema regardless of provider:
tools = [
{
"name": "get_weather",
"description": "Get the current weather for a city.",
"input_schema": { # alias: "parameters"
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
}
]
result = llm.generate(prompt="What's the weather in Cairo?", tools=tools)
If the model doesn't call a tool, the return value is a plain string, exactly as without tools — fully backward compatible. If it does, the return value becomes a dict:
{
"content": "...", # or None
"tool_calls": [{"id": "...", "name": "get_weather", "arguments": {"city": "Cairo"}}],
"stop_reason": "...",
}
Each interface converts the unified schema and normalizes the response internally — see Tool Calling for the full contract, provider-by-provider conversion details, and the llm.tools module reference.
What it is not
- Not a prompt-templating or chain-orchestration layer — it only wraps
generatecalls. - Not a token-counting or cost-tracking layer — no usage/cost accounting is implemented.
- Not a routing/fallback layer — there is no automatic provider failover in this package; the caller chooses the provider explicitly.
- Not a tool-execution layer — the package converts tool schemas and parses tool-call responses, but it does not call your Python functions for you or manage a multi-turn tool-result loop; you still send the tool's result back yourself as a follow-up message.
Where to start
- New to the package? Start with Installation then Quickstart.
- Need the exact contract every interface follows? See Architecture.
- Calling tools/functions? See Tool Calling.
- Tuning defaults (temperature, max tokens, provider-specific model names)? See Configuration.
- Looking for one specific provider's behavior? Jump straight to its page under API Reference in the nav.
- Hitting an error? See Troubleshooting.