By Sagar Shankaran, Founder of CallSphere
Understand the MRKL (Modular Reasoning, Knowledge, and Language) architecture that combines LLMs with specialized expert modules, intelligent routing, and structured knowledge retrieval for building powerful AI systems.
Key takeaways
MRKL — pronounced "miracle" — stands for Modular Reasoning, Knowledge, and Language. Introduced by Karpas et al. (2022), the MRKL architecture recognizes that no single neural model excels at everything. Instead, it pairs a large language model as a central router with a collection of specialized expert modules — calculators, databases, APIs, symbolic reasoners — each handling the tasks it does best.
Think of it like a hospital: the triage nurse (the LLM) evaluates your symptoms and routes you to the right specialist (an expert module). The nurse does not perform surgery, and the surgeon does not do triage.
A MRKL system has three layers:
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
flowchart LR
PR(["PR opened"])
UNIT["Unit tests"]
EVAL["Eval harness<br/>PromptFoo or Braintrust"]
GOLD[("Golden set<br/>200 tagged cases")]
JUDGE["LLM as judge<br/>plus regex graders"]
SCORE["Aggregate score<br/>and per slice"]
GATE{"Score regress<br/>more than 2 percent?"}
BLOCK(["Block merge"])
MERGE(["Merge to main"])
PR --> UNIT --> EVAL --> GOLD --> JUDGE --> SCORE --> GATE
GATE -->|Yes| BLOCK
GATE -->|No| MERGE
style EVAL fill:#4f46e5,stroke:#4338ca,color:#fff
style GATE fill:#f59e0b,stroke:#d97706,color:#1f2937
style BLOCK fill:#dc2626,stroke:#b91c1c,color:#fff
style MERGE fill:#059669,stroke:#047857,color:#fff
from dataclasses import dataclass
from typing import Callable, Any
from openai import OpenAI
client = OpenAI()
@dataclass
class ExpertModule:
name: str
description: str
execute: Callable[[str], str]
class MRKLSystem:
def __init__(self, experts: list[ExpertModule]):
self.experts = {e.name: e for e in experts}
def route(self, query: str) -> tuple[str, str]:
"""Use LLM to select the right expert and extract the sub-query."""
expert_descriptions = "\n".join(
f"- {e.name}: {e.description}" for e in self.experts.values()
)
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": (
"You are a routing agent. Given a user query, select "
"the best expert module and extract the sub-query "
"for that expert.\n\n"
f"Available experts:\n{expert_descriptions}\n\n"
"Return JSON: {expert, sub_query}"
)},
{"role": "user", "content": query},
],
response_format={"type": "json_object"},
)
import json
data = json.loads(response.choices[0].message.content)
return data["expert"], data["sub_query"]
Each module handles a narrow domain. Here are some practical examples:
import math
def calculator_expert(expression: str) -> str:
"""Safely evaluate mathematical expressions."""
allowed = set("0123456789+-*/().^ ")
cleaned = expression.replace("^", "**")
if not all(c in allowed for c in cleaned):
return "Error: invalid characters in expression"
try:
result = eval(cleaned, {"__builtins__": {}}, {"math": math})
return str(result)
except Exception as e:
return f"Calculation error: {e}"
def database_expert(sql_description: str) -> str:
"""Convert natural language to SQL and execute."""
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": (
"Convert the description to a PostgreSQL query. "
"Only SELECT queries are allowed."
)},
{"role": "user", "content": sql_description},
],
)
sql = response.choices[0].message.content
# Execute against actual DB connection in production
return f"Generated SQL: {sql}"
experts = [
ExpertModule("calculator", "Performs math calculations", calculator_expert),
ExpertModule("database", "Queries structured data", database_expert),
]
After routing and execution, the system synthesizes the expert output into a final response:
def answer(self, query: str) -> str:
expert_name, sub_query = self.route(query)
expert = self.experts.get(expert_name)
if not expert:
return "No suitable expert found for this query."
expert_output = expert.execute(sub_query)
# Synthesize final answer
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": (
"Combine the expert's output with the original "
"question to provide a clear, complete answer."
)},
{"role": "user", "content": (
f"Question: {query}\n"
f"Expert ({expert_name}) output: {expert_output}"
)},
],
)
return response.choices[0].message.content
Complex queries often require multiple experts in sequence. For example, "What percentage of our revenue comes from customers in California?" needs the database expert first (to query revenue by state), then the calculator expert (to compute the percentage). The router must recognize this and chain calls accordingly.
Modern tool-use agents (like those built with OpenAI function calling) are essentially MRKL systems with a standardized interface. The MRKL paper laid the conceptual foundation — tools as expert modules, the LLM as the router. Understanding the MRKL framing helps you design better tool interfaces and routing logic.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
RAG (Retrieval-Augmented Generation) is a specific pattern where the expert module is a document retriever. MRKL is a broader architecture — RAG is one possible expert within a MRKL system, alongside calculators, APIs, databases, and other specialists.
Implement a fallback chain. If the selected expert returns an error or low-confidence result, route to the next most likely expert. You can also ask the LLM to select its top 3 experts ranked by relevance, then try them in order.
Absolutely. A smaller, faster model (GPT-4o-mini) can handle routing since the task is classification-like. Reserve the larger model for the synthesis step where nuanced reasoning matters most.
#MRKL #ModularAI #ExpertSystems #AIArchitecture #AgenticAI #KnowledgeRetrieval #PythonAI #ToolUse

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
Step-by-step build of a working agent with the OpenAI Agents SDK — Agent class, tools, handoffs, tracing — plus an eval pipeline that catches regressions before merge.
Smolagents lets agents write Python instead of JSON. Why code-as-action reduces tool errors and where the security trade-offs are for production deployments.
Modal turns a Python function into autoscaling serverless compute with optional GPU. Deploy a LiveKit Agent with one command and get pay-per-second billing.
Pydantic AI's April release tightens the typed-agent loop and adds structured tool definitions. Why type-safe agents reduce production bugs and speed iteration.
Index a knowledge base with text-embedding-3-large into ChromaDB, expose a retrieve tool to your voice agent, and ground every answer in real documents — full Python tutorial.
Shrink an AI voice agent image from 950MB to 80MB with a Python 3.13 multi-stage build, uv for deps, and gcr.io/distroless/python3 nonroot. Real Dockerfile + benchmarks.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco