By Sagar Shankaran, Founder of CallSphere
Learn the blackboard architectural pattern for multi-agent AI coordination. Build a shared knowledge space where specialized agents contribute partial solutions that converge into complete answers.
Key takeaways
The blackboard architecture is a problem-solving pattern where multiple specialist agents (called knowledge sources) collaborate by reading from and writing to a shared data structure — the blackboard. A control shell decides which agent should act next based on the current state of the blackboard.
Originally developed in the 1970s for speech recognition (the Hearsay-II system), this pattern maps perfectly to modern multi-agent AI systems. Instead of agents communicating directly with each other through messages, they communicate indirectly through the shared blackboard. This decouples agents from one another and makes it easy to add or remove specialists without changing the rest of the system.
A blackboard system has three parts:
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
flowchart TD
INPUT(["Task input"])
SUPER["Supervisor agent<br/>plans plus monitors"]
W1["Worker 1<br/>research"]
W2["Worker 2<br/>code"]
W3["Worker 3<br/>writing"]
CRITIC{"Output meets<br/>rubric?"}
REWORK["Rework or<br/>retry path"]
SHARED[("Shared scratchpad<br/>and memory")]
OUT(["Final result"])
INPUT --> SUPER
SUPER --> W1 --> CRITIC
SUPER --> W2 --> CRITIC
SUPER --> W3 --> CRITIC
W1 --> SHARED
W2 --> SHARED
W3 --> SHARED
SHARED --> SUPER
CRITIC -->|Pass| OUT
CRITIC -->|Fail| REWORK --> SUPER
style SUPER fill:#4f46e5,stroke:#4338ca,color:#fff
style CRITIC fill:#f59e0b,stroke:#d97706,color:#1f2937
style OUT fill:#059669,stroke:#047857,color:#fff
style SHARED fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
from dataclasses import dataclass, field
from typing import Any, Callable
from datetime import datetime
import json
@dataclass
class BlackboardEntry:
key: str
value: Any
source: str
confidence: float
timestamp: str = field(
default_factory=lambda: datetime.now().isoformat()
)
class Blackboard:
def __init__(self):
self._state: dict[str, BlackboardEntry] = {}
self._history: list[dict] = []
def read(self, key: str) -> BlackboardEntry | None:
return self._state.get(key)
def write(self, key: str, value: Any, source: str, confidence: float):
entry = BlackboardEntry(
key=key, value=value, source=source, confidence=confidence
)
self._state[key] = entry
self._history.append({
"action": "write",
"key": key,
"source": source,
"timestamp": entry.timestamp,
})
def read_all(self) -> dict[str, Any]:
return {k: v.value for k, v in self._state.items()}
def has_key(self, key: str) -> bool:
return key in self._state
def get_history(self) -> list[dict]:
return list(self._history)
Each knowledge source declares what conditions must be true on the blackboard before it can contribute (its preconditions) and what it produces (its contributions).
@dataclass
class KnowledgeSource:
name: str
preconditions: Callable[[Blackboard], bool]
action: Callable[[Blackboard], None]
priority: int = 0
# Example: an entity extraction agent
def entity_extractor_precondition(bb: Blackboard) -> bool:
return bb.has_key("raw_text") and not bb.has_key("entities")
def entity_extractor_action(bb: Blackboard):
raw_text = bb.read("raw_text").value
# In production, call an LLM or NER model here
entities = {
"people": ["Alice", "Bob"],
"organizations": ["Acme Corp"],
"dates": ["March 2026"],
}
bb.write("entities", entities, source="entity_extractor", confidence=0.88)
entity_ks = KnowledgeSource(
name="entity_extractor",
preconditions=entity_extractor_precondition,
action=entity_extractor_action,
priority=10,
)
# Example: a sentiment analysis agent
def sentiment_precondition(bb: Blackboard) -> bool:
return bb.has_key("raw_text") and not bb.has_key("sentiment")
def sentiment_action(bb: Blackboard):
raw_text = bb.read("raw_text").value
bb.write("sentiment", {"label": "positive", "score": 0.82},
source="sentiment_analyzer", confidence=0.82)
sentiment_ks = KnowledgeSource(
name="sentiment_analyzer",
preconditions=sentiment_precondition,
action=sentiment_action,
priority=5,
)
The control shell is the orchestration loop. It inspects the blackboard, finds all knowledge sources whose preconditions are met, selects the highest-priority one, and runs it.
class ControlShell:
def __init__(
self,
blackboard: Blackboard,
knowledge_sources: list[KnowledgeSource],
max_iterations: int = 50,
):
self.bb = blackboard
self.sources = knowledge_sources
self.max_iterations = max_iterations
def run(self) -> dict:
for i in range(self.max_iterations):
eligible = [
ks for ks in self.sources
if ks.preconditions(self.bb)
]
if not eligible:
return {
"status": "complete",
"iterations": i,
"result": self.bb.read_all(),
}
eligible.sort(key=lambda ks: ks.priority, reverse=True)
selected = eligible[0]
selected.action(self.bb)
return {
"status": "max_iterations_reached",
"result": self.bb.read_all(),
}
# A summarizer that depends on both entities and sentiment
def summarizer_precondition(bb: Blackboard) -> bool:
return (bb.has_key("entities") and bb.has_key("sentiment")
and not bb.has_key("summary"))
def summarizer_action(bb: Blackboard):
entities = bb.read("entities").value
sentiment = bb.read("sentiment").value
summary = (
f"Document mentions {len(entities['people'])} people and "
f"{len(entities['organizations'])} orgs. "
f"Overall sentiment: {sentiment['label']}."
)
bb.write("summary", summary, source="summarizer", confidence=0.90)
bb = Blackboard()
bb.write("raw_text", "Alice from Acme Corp reported great Q1 results.",
source="user_input", confidence=1.0)
shell = ControlShell(bb, [entity_ks, sentiment_ks,
KnowledgeSource("summarizer", summarizer_precondition,
summarizer_action, priority=1)])
result = shell.run()
print(result["result"]["summary"])
The blackboard pattern shines when the order of agent execution depends on what is already known. Agents self-select based on preconditions, making the system naturally adaptive.
A shared database stores data but has no control logic. The blackboard architecture includes the control shell that selects which agent to run based on the current state. This makes the execution order dynamic and data-driven rather than hardcoded. Agents do not need to know about each other — they only know about the blackboard.
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.
Yes. If two knowledge sources have met preconditions and operate on different keys, they can run concurrently. Add a locking mechanism to the blackboard (per-key locks or optimistic concurrency) to prevent write conflicts, then run eligible sources with non-overlapping outputs in parallel.
Choose blackboard when you have many specialists with complex dependencies between their outputs and when the problem-solving order is not known in advance. Direct messaging works better for linear pipelines or when agents have simple handoff relationships. If your agent graph looks more like a web than a chain, the blackboard pattern usually produces cleaner code.
#BlackboardArchitecture #MultiAgentSystems #KnowledgeSharing #DesignPatterns #Python #AgenticAI #LearnAI #AIEngineering

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.
How we built a fault-tolerant HVAC emergency triage and tech-dispatch platform on Kubernetes — three-tier CQRS, 11 micro-agents on the OpenAI Agents SDK + LangGraph, NATS JetStream, DTMF/SMS/WebSocket acceptance, circuit breakers, and an evaluation pipeline that catches regressions before they wake a tech at 3 AM.
Five proven multi-agent architecture patterns built on A2A — orchestrator, peer mesh, hub-and-spoke, marketplace, and tiered specialist.
Langgraph multi-agent supervisor handoffs docs: the supervisor pattern in LangGraph for coordinating specialist agents, with full code, an eval pipeline that scores routing accuracy, and the failure modes to watch for.
Handoffs done right — when one agent should hand control to another, how to preserve context, and how to evaluate the handoff decision itself.
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.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.