LLM is Function
The central insight of SimpleLLMFunc: an LLM call should be indistinguishable from a Python function call.The Problem with Existing Approaches
Most LLM frameworks introduce new abstractions between you and the model:- Chain frameworks make you think in terms of linked steps, each passing data to the next through a framework-defined protocol
- Graph frameworks make you define nodes and edges, routing data through a visual DAG
- Agent frameworks hide the LLM behind an “agent” abstraction that manages its own state
The Function Model
In SimpleLLMFunc, an LLM call IS a function call:- Has a name —
extract_entities - Has typed parameters —
text: str - Has a typed return value —
list[Entity] - Has a docstring that describes the behavior — this IS the prompt
- Is awaitable —
await extract_entities("...") - Is composable — call it from other functions, pass it around, test it
What You Gain
Type Safety at the Boundary
The return type annotation is a contract. The framework ensures the LLM output is parsed into your declared type — or raises a clear error. No manual JSON parsing, no “sometimes the model returns a string instead of an object”.Composability
Functions compose naturally. Build complex pipelines with plain Python:Testability
Mock it like any other function:IDE Support
Your IDE already knows how to work with async functions, type annotations, and docstrings. Autocomplete, jump-to-definition, inline docs — all free.The Extension: LLM as Agent
@llm_chat extends the function model to multi-turn agents. The agent is still just a function — it takes input, returns output. The difference is that it can use tools and maintain conversation state: