PromptABCD
FeaturesLearnGuideBlogContext Blocks
Sign inGet started free
Sign inSign up
PromptABCD

A calm home for your best AI prompts. Save them once, find them in seconds, reuse them forever.

Product

  • Features
  • Chrome Extension
  • Free Courses
  • How it works
  • Use cases
  • Blog
  • Context Blocks
  • Export Anywhere
  • FAQ

Resources

  • User guide
  • Learn prompting
  • Sign in
  • Get started free

© 2026 PromptABCD. All rights reserved.

AboutPrivacy PolicyTerms and Conditions
Home/Blog/Multi-Agent Systems/Blackboard Architecture for AI Agents
Multi-Agent Systems

Blackboard Architecture for AI Agents

Blackboard architecture is one of the oldest multi-agent coordination patterns — and one of the most underused in LLM systems. When agents need to collaborate without tight coupling, a shared workspace outperforms direct message passing.

September 23, 2026·12 min read
ShareShare
⚡Featured Prompt— copy and use right now
import json
import time
from anthropic import Anthropic

client = Anthropic()

class Blackboard:
    def __init__(self):
        self.state = {
            "problem": "",
            "facts": [],
            "hypotheses": [],
            "evidence": [],
            "conclusion": None,
            "confidence": 0.0,
            "history": []
        }
    
    def read(self) -> dict:
        return self.state.copy()
    
    def write(self, updates: dict, agent_name: str):
        for key, value in updates.items():
            if key in ("facts", "hypotheses", "evidence"):
                # Append to lists rather than overwrite
                self.state[key].extend(value if isinstance(value, list) else [value])
            else:
                self.state[key] = value
        self.state["history"].append({
            "agent": agent_name,
            "timestamp": time.time(),
            "updates": list(updates.keys())
        })
    
    def summary(self) -> str:
        """Compact representation for agent context windows."""
        return json.dumps({
            "problem": self.state["problem"],
            "facts_count": len(self.state["facts"]),
            "facts": self.state["facts"][-5:],  # Most recent 5
            "hypotheses": self.state["hypotheses"],
            "conclusion": self.state["conclusion"],
            "confidence": self.state["confidence"]
        }, indent=2)


def research_agent(blackboard: Blackboard) -> bool:
    """Contributes when facts list is empty or thin."""
    state = blackboard.read()
    if len(state["facts"]) >= 5:
        return False  # No contribution needed
    
    response = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        system="You are a research agent. Extract 3-5 specific, verifiable facts relevant to the problem. Return JSON: {\"facts\": [\"fact1\", ...]}",
        messages=[{"role": "user", "content": f"Problem: {state['problem']}\n\nCurrent facts: {state['facts']}\n\nAdd new facts not already listed."}]
    )
    data = json.loads(response.content[0].text)
    blackboard.write({"facts": data["facts"]}, "researcher")
    return True


def hypothesis_agent(blackboard: Blackboard) -> bool:
    """Contributes when facts exist but hypotheses are sparse."""
    state = blackboard.read()
    if len(state["facts"]) < 3 or len(state["hypotheses"]) >= 3:
        return False
    
    response = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        system="You are a hypothesis agent. Generate 2-3 candidate explanations or solutions based on available facts. Return JSON: {\"hypotheses\": [\"hypothesis1\", ...]}",
        messages=[{"role": "user", "content": f"Problem: {state['problem']}\nFacts: {json.dumps(state['facts'])}\n\nGenerate hypotheses not already listed: {state['hypotheses']}"}]
    )
    data = json.loads(response.content[0].text)
    blackboard.write({"hypotheses": data["hypotheses"]}, "hypothesis_generator")
    return True


def evidence_agent(blackboard: Blackboard) -> bool:
    """Evaluates hypotheses against facts."""
    state = blackboard.read()
    if not state["hypotheses"] or len(state["evidence"]) >= len(state["hypotheses"]):
        return False
    
    unevaluated = state["hypotheses"][len(state["evidence"]):]
    response = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        system="You are an evidence evaluator. Assess how well the facts support each hypothesis. Return JSON: {\"evidence\": [{\"hypothesis\": \"...\", \"support\": \"strong|moderate|weak\", \"reasoning\": \"...\"}]}",
        messages=[{"role": "user", "content": f"Facts: {json.dumps(state['facts'])}\nEvaluate these hypotheses: {json.dumps(unevaluated)}"}]
    )
    data = json.loads(response.content[0].text)
    blackboard.write({"evidence": data["evidence"]}, "evidence_evaluator")
    return True


def conclusion_agent(blackboard: Blackboard) -> bool:
    """Produces conclusion when evidence is complete."""
    state = blackboard.read()
    if (len(state["evidence"]) < len(state["hypotheses"]) or 
        not state["hypotheses"] or 
        state["conclusion"] is not None):
        return False
    
    response = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        system="You are a synthesis agent. Produce a final conclusion and confidence score. Return JSON: {\"conclusion\": \"...\", \"confidence\": 0.0-1.0}",
        messages=[{"role": "user", "content": f"Problem: {state['problem']}\nEvidence: {json.dumps(state['evidence'])}"}]
    )
    data = json.loads(response.content[0].text)
    blackboard.write({"conclusion": data["conclusion"], "confidence": data["confidence"]}, "synthesizer")
    return True


def run_blackboard_system(problem: str, max_cycles: int = 8) -> dict:
    board = Blackboard()
    board.write({"problem": problem}, "system")
    
    agents = [research_agent, hypothesis_agent, evidence_agent, conclusion_agent]
    
    for cycle in range(max_cycles):
        state = board.read()
        if state["conclusion"] is not None and state["confidence"] > 0.7:
            break
        
        acted = False
        for agent in agents:
            if agent(board):
                acted = True
                break  # One agent per cycle
        
        if not acted:
            break  # No agent had anything to contribute
    
    return board.read()

result = run_blackboard_system("Why might a microservice application have increasing memory usage under constant load?")
print(f"Conclusion: {result['conclusion']}")
print(f"Confidence: {result['confidence']}")
print(f"Agent history: {[h['agent'] for h in result['history']]}")

The blackboard multi agent architecture originated in AI research in the 1970s, designed for problems where no single solving strategy was adequate and multiple knowledge sources needed to cooperate without being tightly coupled. The name is literal: agents coordinate by reading and writing to a shared data structure — the blackboard — rather than passing messages directly to each other.

In LLM-based systems, the blackboard pattern solves a specific coordination problem: how do multiple agents contribute to a shared solution when the order of their contributions depends on what's already been discovered? Direct message passing requires knowing in advance which agent should run next. The blackboard pattern lets agents self-select based on what the current workspace state needs.

How Blackboard Architecture Works

The blackboard pattern has three components:

The blackboard: A shared, mutable data structure that holds the current state of the problem — partial solutions, intermediate findings, hypotheses, and any supporting evidence agents have contributed. All agents read from and write to the same blackboard.

Knowledge sources (agents): Specialized agents that watch the blackboard for conditions they can act on. When an agent detects that the current blackboard state matches its capability — it has something to contribute — it applies its knowledge and updates the blackboard.

The control component (scheduler): Determines which knowledge source should act next, based on what the blackboard currently needs. The scheduler can be a separate agent, a rule-based system, or a simple priority queue.

The key structural difference from sequential pipelines: in a sequential pipeline, the orchestrator decides upfront what happens next. In blackboard architecture, agents respond to the current state of the shared workspace.

⚡ Pro tip: Blackboard architecture excels when the problem-solving path isn't predictable upfront. If you can enumerate the exact sequence of operations that solves your task, a sequential pipeline is simpler. Use blackboard when the path depends on intermediate discoveries — when what you find in step 2 determines whether step 3 is needed and which step 4 makes sense.

Implementing a Blackboard System in Python

python
[object Object], json
,[object Object], time
,[object Object], anthropic ,[object Object], Anthropic

client = Anthropic()

,[object Object], ,[object Object],:
    ,[object Object], ,[object Object],(,[object Object],):
        ,[object Object],.state = {
            ,[object Object],: ,[object Object],,
            ,[object Object],: [],
            ,[object Object],: [],
            ,[object Object],: [],
            ,[object Object],: ,[object Object],,
            ,[object Object],: ,[object Object],,
            ,[object Object],: []
        }
    
    ,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
        ,[object Object], ,[object Object],.state.copy()
    
    ,[object Object], ,[object Object],(,[object Object],):
        ,[object Object], key, value ,[object Object], updates.items():
            ,[object Object], key ,[object Object], (,[object Object],, ,[object Object],, ,[object Object],):
                ,[object Object],
                ,[object Object],.state[key].extend(value ,[object Object], ,[object Object],(value, ,[object Object],) ,[object Object], [value])
            ,[object Object],:
                ,[object Object],.state[key] = value
        ,[object Object],.state[,[object Object],].append({
            ,[object Object],: agent_name,
            ,[object Object],: time.time(),
            ,[object Object],: ,[object Object],(updates.keys())
        })
    
    ,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
        ,[object Object],
        ,[object Object], json.dumps({
            ,[object Object],: ,[object Object],.state[,[object Object],],
            ,[object Object],: ,[object Object],(,[object Object],.state[,[object Object],]),
            ,[object Object],: ,[object Object],.state[,[object Object],][-,[object Object],:],  ,[object Object],
            ,[object Object],: ,[object Object],.state[,[object Object],],
            ,[object Object],: ,[object Object],.state[,[object Object],],
            ,[object Object],: ,[object Object],.state[,[object Object],]
        }, indent=,[object Object],)


,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
    ,[object Object],
    state = blackboard.read()
    ,[object Object], ,[object Object],(state[,[object Object],]) >= ,[object Object],:
        ,[object Object], ,[object Object],  ,[object Object],
    
    response = client.messages.create(
        model=,[object Object],,
        max_tokens=,[object Object],,
        system=,[object Object],,
        messages=[{,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],}]
    )
    data = json.loads(response.content[,[object Object],].text)
    blackboard.write({,[object Object],: data[,[object Object],]}, ,[object Object],)
    ,[object Object], ,[object Object],


,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
    ,[object Object],
    state = blackboard.read()
    ,[object Object], ,[object Object],(state[,[object Object],]) < ,[object Object], ,[object Object], ,[object Object],(state[,[object Object],]) >= ,[object Object],:
        ,[object Object], ,[object Object],
    
    response = client.messages.create(
        model=,[object Object],,
        max_tokens=,[object Object],,
        system=,[object Object],,
        messages=[{,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],}]
    )
    data = json.loads(response.content[,[object Object],].text)
    blackboard.write({,[object Object],: data[,[object Object],]}, ,[object Object],)
    ,[object Object], ,[object Object],


,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
    ,[object Object],
    state = blackboard.read()
    ,[object Object], ,[object Object], state[,[object Object],] ,[object Object], ,[object Object],(state[,[object Object],]) >= ,[object Object],(state[,[object Object],]):
        ,[object Object], ,[object Object],
    
    unevaluated = state[,[object Object],][,[object Object],(state[,[object Object],]):]
    response = client.messages.create(
        model=,[object Object],,
        max_tokens=,[object Object],,
        system=,[object Object],,
        messages=[{,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],}]
    )
    data = json.loads(response.content[,[object Object],].text)
    blackboard.write({,[object Object],: data[,[object Object],]}, ,[object Object],)
    ,[object Object], ,[object Object],


,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
    ,[object Object],
    state = blackboard.read()
    ,[object Object], (,[object Object],(state[,[object Object],]) < ,[object Object],(state[,[object Object],]) ,[object Object], 
        ,[object Object], state[,[object Object],] ,[object Object], 
        state[,[object Object],] ,[object Object], ,[object Object], ,[object Object],):
        ,[object Object], ,[object Object],
    
    response = client.messages.create(
        model=,[object Object],,
        max_tokens=,[object Object],,
        system=,[object Object],,
        messages=[{,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],}]
    )
    data = json.loads(response.content[,[object Object],].text)
    blackboard.write({,[object Object],: data[,[object Object],], ,[object Object],: data[,[object Object],]}, ,[object Object],)
    ,[object Object], ,[object Object],


,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
    board = Blackboard()
    board.write({,[object Object],: problem}, ,[object Object],)
    
    agents = [research_agent, hypothesis_agent, evidence_agent, conclusion_agent]
    
    ,[object Object], cycle ,[object Object], ,[object Object],(max_cycles):
        state = board.read()
        ,[object Object], state[,[object Object],] ,[object Object], ,[object Object], ,[object Object], ,[object Object], state[,[object Object],] > ,[object Object],:
            ,[object Object],
        
        acted = ,[object Object],
        ,[object Object], agent ,[object Object], agents:
            ,[object Object], agent(board):
                acted = ,[object Object],
                ,[object Object],  ,[object Object],
        
        ,[object Object], ,[object Object], acted:
            ,[object Object],  ,[object Object],
    
    ,[object Object], board.read()

result = run_blackboard_system(,[object Object],)
,[object Object],(,[object Object],)
,[object Object],(,[object Object],)
,[object Object],(,[object Object],)

What this does: Each agent checks the blackboard state and decides whether it has something to contribute. The research agent fills facts. The hypothesis agent generates explanations once enough facts exist. The evidence agent evaluates hypotheses once they're generated. The conclusion agent synthesizes once evidence is complete. The scheduler (the run_blackboard_system loop) cycles through agents and stops when a conclusion with sufficient confidence is reached, or when no agent has anything to add.

⚡ Pro tip: The blackboard summary method is critical for production systems. Full blackboard state passed to every agent grows exponentially with problem complexity. Build compact summary representations that give agents the context they need without flooding their context windows with data they won't use.

When Blackboard Multi Agent Beats Direct Messaging

The blackboard multi agent pattern outperforms direct message passing in three scenarios:

Open-ended investigation tasks. When you don't know upfront how many agents need to contribute or what order they should run in, the blackboard pattern lets agents self-select based on the current state of knowledge. A research pipeline where early findings might trigger additional research, new hypothesis generation, or immediate conclusions benefits from this flexibility.

Collaborative refinement. When multiple agents can improve a shared artifact iteratively — a draft document that a researcher improves, a critic annotates, and a reviser refines across multiple passes — the blackboard provides a natural shared workspace. Each agent contributes when the current state of the artifact matches its capability.

Asynchronous agent execution. In systems where agents run at different speeds or have different availability, the blackboard decouples producers from consumers. A fast agent doesn't wait for a slow one; it writes what it knows and checks back when the slow agent has contributed.

Where Blackboard Architecture Adds Complexity Without Value

For sequential pipelines with a fixed, known task order, blackboard architecture adds unnecessary complexity. If your pipeline is always: classify → research → analyze → report, a simple sequential orchestrator is easier to reason about and debug. The blackboard earns its complexity when the path through the problem is discovered, not predefined.

⚠️ Common mistake: Implementing a blackboard system without a confidence threshold or termination condition. Without a stopping criterion, the system will cycle until it hits max_cycles even after reaching a correct answer, wasting API calls and adding latency. Always define what "done" means before the system starts.

Connecting Blackboard to Modern Agent Systems

The blackboard pattern maps directly to how several modern multi-agent frameworks handle shared state. LangGraph's state object is a structured blackboard. CrewAI's shared context between tasks is a simplified blackboard. The underlying concept predates these frameworks by decades because it solves a real coordination problem.

Implementing a blackboard system from scratch is not mandatory — using LangGraph's state for a blackboard-style workflow is a legitimate approach. The value of understanding the raw blackboard pattern is conceptual: it explains why LangGraph's state-centric design works, why CrewAI's task context passing feels natural, and what both are trying to achieve. When a framework's built-in state management isn't flexible enough for your coordination problem, building a custom blackboard gives you the full pattern without the framework's constraints.

In LLM applications, the most practical implementation keeps the blackboard as a typed Python dictionary with append-only list fields and scalar overwrite fields. Full event sourcing (storing every write as an event) is useful for debugging complex systems but unnecessary for most applications.

Blackboard Pattern for Knowledge Discovery Tasks

The blackboard architecture excels at open-ended knowledge discovery where the path to the answer isn't known in advance. Consider a root cause analysis system for software incidents: the problem is known (the system is slow), but whether the cause is a database issue, a memory leak, a network bottleneck, or an external service dependency isn't known until specialist agents investigate.

python
[object Object], json
,[object Object], anthropic ,[object Object], Anthropic

client = Anthropic()

,[object Object], ,[object Object],:
    ,[object Object], ,[object Object],(,[object Object],):
        ,[object Object],.state = {
            ,[object Object],: incident,
            ,[object Object],: [],
            ,[object Object],: [],
            ,[object Object],: {},
            ,[object Object],: [],
            ,[object Object],: ,[object Object],
        }
    
    ,[object Object], ,[object Object],(,[object Object],):
        ,[object Object],.state[,[object Object],].extend(symptoms)
        ,[object Object],(,[object Object],)
    
    ,[object Object], ,[object Object],(,[object Object],):
        ,[object Object],.state[,[object Object],].append({
            ,[object Object],: hypothesis, ,[object Object],: confidence, ,[object Object],: agent
        })
    
    ,[object Object], ,[object Object],(,[object Object],):
        key = hypothesis[:,[object Object],]
        ,[object Object], key ,[object Object], ,[object Object], ,[object Object],.state[,[object Object],]:
            ,[object Object],.state[,[object Object],][key] = []
        ,[object Object],.state[,[object Object],][key].append({
            ,[object Object],: evidence, ,[object Object],: supports, ,[object Object],: agent
        })
    
    ,[object Object], ,[object Object],(,[object Object],):
        ,[object Object],.state[,[object Object],].append({,[object Object],: hypothesis, ,[object Object],: reason})
    
    ,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
        active_hypotheses = [
            h ,[object Object], h ,[object Object], ,[object Object],.state[,[object Object],]
            ,[object Object], h[,[object Object],][:,[object Object],] ,[object Object], ,[object Object], [r[,[object Object],][:,[object Object],] ,[object Object], r ,[object Object], ,[object Object],.state[,[object Object],]]
        ]
        ,[object Object], json.dumps({
            ,[object Object],: ,[object Object],.state[,[object Object],],
            ,[object Object],: ,[object Object],.state[,[object Object],][-,[object Object],:],
            ,[object Object],: active_hypotheses,
            ,[object Object],: ,[object Object],(,[object Object],(v) ,[object Object], v ,[object Object], ,[object Object],.state[,[object Object],].values()),
            ,[object Object],: ,[object Object],(,[object Object],.state[,[object Object],])
        }, indent=,[object Object],)

,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
    ,[object Object], ,[object Object],(board.state[,[object Object],]) >= ,[object Object],:
        ,[object Object], ,[object Object],
    response = client.messages.create(
        model=,[object Object],, max_tokens=,[object Object],,
        system=,[object Object],,
        messages=[{,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],}]
    )
    data = json.loads(response.content[,[object Object],].text)
    board.add_symptoms(data[,[object Object],], ,[object Object],)
    ,[object Object], ,[object Object],

,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
    ,[object Object], ,[object Object],(board.state[,[object Object],]) < ,[object Object], ,[object Object], ,[object Object],(board.state[,[object Object],]) >= ,[object Object],:
        ,[object Object], ,[object Object],
    symptom_text = ,[object Object],.join(board.state[,[object Object],])
    response = client.messages.create(
        model=,[object Object],, max_tokens=,[object Object],,
        system=,[object Object],,
        messages=[{,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],}]
    )
    data = json.loads(response.content[,[object Object],].text)
    ,[object Object], h ,[object Object], data[,[object Object],]:
        board.add_hypothesis(h[,[object Object],], h[,[object Object],], ,[object Object],)
    ,[object Object], ,[object Object],

,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
    unevaluated = [
        h ,[object Object], h ,[object Object], board.state[,[object Object],]
        ,[object Object], h[,[object Object],][:,[object Object],] ,[object Object], ,[object Object], board.state[,[object Object],]
    ]
    ,[object Object], ,[object Object], unevaluated:
        ,[object Object], ,[object Object],
    h = unevaluated[,[object Object],]
    response = client.messages.create(
        model=,[object Object],, max_tokens=,[object Object],,
        system=,[object Object],,
        messages=[{,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],}]
    )
    data = json.loads(response.content[,[object Object],].text)
    board.add_evidence(h[,[object Object],], data[,[object Object],], data[,[object Object],], ,[object Object],)
    ,[object Object], ,[object Object], data[,[object Object],] ,[object Object], data[,[object Object],] > ,[object Object],:
        board.rule_out(h[,[object Object],], data[,[object Object],])
    ,[object Object], ,[object Object],

,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
    board = IncidentBlackboard(incident)
    agents = [symptom_collector, hypothesis_generator, evidence_evaluator]
    
    ,[object Object], cycle ,[object Object], ,[object Object],(max_cycles):
        acted = ,[object Object],
        ,[object Object], agent ,[object Object], agents:
            ,[object Object], agent(board):
                acted = ,[object Object],
                ,[object Object],
        ,[object Object], ,[object Object], acted:
            ,[object Object],
    
    ,[object Object], board.state

What this does: The incident blackboard accumulates symptoms, generates hypotheses based on what's been observed, and evaluates evidence for each hypothesis — ruling out hypotheses where evidence clearly contradicts them. Each agent contributes when it has something to add; the cycle continues until no agent has a contribution. The blackboard's state at termination is the investigation record: what was observed, what was hypothesized, what was ruled out, and what remains active.

⚡ Pro tip: Initialize the blackboard with any structured data you already have before starting the agent cycle. System metrics, log samples, alert history — seed the blackboard with this data so the symptom collector starts with a richer information set than it would have from the incident description alone. Richer initial state produces better hypotheses in the first few cycles.

Blackboard vs Event-Driven Architecture

Both blackboard and event-driven architectures allow agents to coordinate without tight coupling. The key difference: in event-driven systems, each event triggers specific handler agents. In blackboard systems, agents self-select based on the current state of a shared workspace.

Event-driven architecture is better for: well-defined trigger conditions where the relationship between an event and its handler is fixed; high-throughput systems where many events need to be processed efficiently; and pipelines where the event sequence is predictable.

Blackboard architecture is better for: open-ended problems where agent contribution order isn't predictable; tasks where agents need to read the full investigation state (not just the triggering event); and collaborative refinement where multiple agents improve the same shared artifact.

Scaling Blackboard Coordination

As the number of knowledge sources (agents) grows beyond five or six, the per-cycle agent polling becomes a bottleneck. Each cycle checks every agent to find who has something to contribute. At ten agents, this is ten LLM calls per cycle to identify one contributing agent — nine of which return "no contribution needed."

Two scaling strategies address this:

Condition-based subscription. Rather than polling all agents each cycle, agents register the blackboard conditions that trigger their contribution. When the blackboard state changes, only agents subscribed to the changed condition are polled. This reduces polling overhead from N agents per cycle to only the agents whose contribution conditions might now be met.

Prioritized agent ordering. Within each cycle, agents that have contributed recently or that have high-priority contributions are polled first. If a high-priority agent has something to contribute, lower-priority agents aren't polled in that cycle. This is a heuristic optimization that works well when there's a natural priority order among knowledge sources.

python
[object Object], ,[object Object],:
    ,[object Object], ,[object Object],(,[object Object],):
        ,[object Object],.state = {}
        ,[object Object],.agent_priorities = {}
        ,[object Object],.contribution_counts = {}
    
    ,[object Object], ,[object Object],(,[object Object],):
        ,[object Object],.agent_priorities[agent_name] = priority
        ,[object Object],
    
    ,[object Object], ,[object Object],(,[object Object],) -> ,[object Object],:
        ready = [
            name ,[object Object], name, _ ,[object Object], ,[object Object],(
                ,[object Object],.agent_priorities.items(), key=,[object Object], x: x[,[object Object],], reverse=,[object Object],
            )
        ]
        ,[object Object], ready

What this does: The PrioritizedBlackboard tracks agent priorities and sorts polling order accordingly. High-priority agents (typically those with narrower, more certain contribution conditions) are polled first. Once any high-priority agent contributes, the cycle ends — lower-priority agents wait for the next cycle. This preserves the blackboard's self-organizing property while reducing the per-cycle polling cost. For systems with ten or more knowledge sources, combining priority ordering with condition-based filtering typically reduces polling overhead by sixty to eighty percent while maintaining the same contribution quality. Start with simple round-robin polling during development — add prioritization only when polling overhead becomes a measurable latency factor in production.

The agent definitions for a well-functioning blackboard system — their contribution conditions, their output schemas, their context summaries — are worth saving across projects. The blackboard pattern appears in research, diagnosis, collaborative writing, and investigation tasks. A well-tuned set of blackboard agents transfers with minimal modification. PromptABCD is the natural place to keep them.

multi-agent-systemsblackboard-architectureagent-patternsshared-memoryllm-engineering

Continue Reading

A Reusable Prompt Kit for Agent Teams
Multi-Agent Systems

A Reusable Prompt Kit for Agent Teams

A team rebuilt their agent prompts from memory every project, and every project drifted a little worse. That failure is why a multi agent prompt kit matters. Here's the reusable set of role prompts every team should keep.

October 2, 2026·9 min read
Multi-Agent Systems on a Budget: An Interactive Guide
Multi-Agent Systems

Multi-Agent Systems on a Budget: An Interactive Guide

Most multi-agent tutorials assume you'll burn tokens freely. That's wrong for anyone shipping on real constraints. A cheap multi agent system can match an expensive one with the right moves. Here's how to build one.

October 2, 2026·9 min read
The Manager Agent Anti-Pattern: A Teardown
Multi-Agent Systems

The Manager Agent Anti-Pattern: A Teardown

Why does your orchestrator agent keep becoming a bottleneck that mangles every handoff? You've hit the manager agent anti pattern — one agent trying to coordinate everything. Here's why it fails and what replaces it.

October 2, 2026·9 min read

Save the prompts from this post

PromptABCD is a free prompt manager. Paste, organize, and reuse your best AI prompts — no more hunting through chat history.

Start free →
← PreviousHow Many Agents Is Too Many?Next →The Planner-Executor Split in Multi-Agent Systems
Share this post:
ShareShare