The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent: Towards Observable Multi-Agent Systems

Christian Cabrera Jojoa

University of Cambridge

chc79@cam.ac.uk

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

AI-based Systems

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

AI-based Systems

AI System
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

AI-based Systems

AI-based systems are data-driven. Unlike in traditional systems, developers cannot fully predefine their behaviour. ML components learn such behaviour from data, operating as black boxes that propagate uncertainty into complex software.

AI System
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

AI-based Systems

AI-based systems are data-driven. Unlike in traditional systems, developers cannot fully predefine their behaviour. ML components learn such behaviour from data, operating as black boxes that propagate uncertainty into complex software.

AI System
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

AI-based Systems

Intellectual Debt: Practitioners deploy data-driven systems that work in practice, but do not fully understand their inner workings. This threatens transparency, safety, and trust, increasing risks of AI's negative social impact (Zittrain, 2022).

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

AI as a Service

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

AI as a Service

AI System
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

AI as a Service

SOA is a design pattern in which services are provided between components, through a communication protocol over a network.


Microservices are an architectural style that structures an application as a collection of small, autonomous services. Each microservice is self-contained and exposes a business capability, which is implemented by an object (i.e., OOP).


The concept of "Everything as a Service" (XaaS) extends the principles of SOA and microservices by offering comprehensive services over the internet. XaaS encompasses a wide range of services, including infrastructure, platforms, and software.

AI System
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

AI as a Service

AI as a Service (AIaaS) enables us to access and expose AI capabilities over the internet. We can integrate AI tools such as machine learning models, natural language processing, and computer vision into our applications leveraging SOA and microservices features.

AI System
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

AI as a Service


from flask import Flask, request, jsonify
app = Flask(__name__)
class SentimentAnalysisService:
    def __init__(self, model):
        self.model = model

    def analyze_sentiment(self, text):
        sentiment_score = self.model.predict(text)
        if sentiment_score > 0.5:
            return "Positive"
        elif sentiment_score < -0.5:
            return "Negative"
        else:
            return "Neutral"
...
@app.route('/analyze', methods=['POST'])
def analyze():
    data = request.get_json()
    text_to_analyze = data.get('text', '')
    sentiment = service.analyze_sentiment(text_to_analyze)
    return jsonify({'sentiment': sentiment})
...
AI System
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

AI as a Service


from flask import Flask, request, jsonify
app = Flask(__name__)
class SentimentAnalysisService:
    def __init__(self, model):
        self.model = model

    def analyze_sentiment(self, text):
        sentiment_score = self.model.predict(text)
        if sentiment_score > 0.5:
            return "Positive"
        elif sentiment_score < -0.5:
            return "Negative"
        else:
            return "Neutral"
...
@app.route('/analyze', methods=['POST'])
def analyze():
    data = request.get_json()
    text_to_analyze = data.get('text', '')
    sentiment = service.analyze_sentiment(text_to_analyze)
    return jsonify({'sentiment': sentiment})
...

Focus on Operations:

  • Separation of concerns
  • High availability
  • Scalability
  • Low latency

Data is secondary and hidden behind services' interfaces.

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

AI as a Service


from flask import Flask, request, jsonify
app = Flask(__name__)
class SentimentAnalysisService:
    def __init__(self, model):
        self.model = model

    def analyze_sentiment(self, text):
        sentiment_score = self.model.predict(text)
        if sentiment_score > 0.5:
            return "Positive"
        elif sentiment_score < -0.5:
            return "Negative"
        else:
            return "Neutral"
...
@app.route('/analyze', methods=['POST'])
def analyze():
    data = request.get_json()
    text_to_analyze = data.get('text', '')
    sentiment = service.analyze_sentiment(text_to_analyze)
    return jsonify({'sentiment': sentiment})
...

The Data Dichotomy: “While data-driven systems are about exposing data, service-oriented architectures and object-oriented programming are about hiding data.” (Stopford, 2016).

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

Data-Orientation

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

Data-Orientation


Data-Oriented Architecture (DOA) is an architectural style developed to address the requirements of data-intensive systems that work in real-time without centralised servers (Vorhemus, 2017).

DOA Architecture

Data-First Systems

  • Data is available by design
  • Traceability and monitoring
  • Interpretability
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

Data-Orientation


Data-Oriented Architecture (DOA) is an architectural style developed to address the requirements of data-intensive systems that work in real-time without centralised servers (Vorhemus, 2017).

Prioritise Decentralisation

  • Super-low latency requirements
  • Privacy by design
Decentralisation
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

Data-Orientation


Data-Oriented Architecture (DOA) is an architectural style developed to address the requirements of data-intensive systems that work in real-time without centralised servers (Vorhemus, 2017).

Openness

Openness

  • Sustainable solutions
  • Data ownership
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

Data-Orientation


Data-Oriented Architecture (DOA) is an architectural style developed to address the requirements of data-intensive systems that work in real-time without centralised servers (Vorhemus, 2017).

DOA Survey

Most of the surveyed works partially adopt the DOA principles to handle data-intensive requirements. The survey results also show that diverse tools can support adopting DOA principles: Apache Kafka, Spark Streaming, Hadoop Distributed File System, MQTT, and RabbitMQ.

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

Data-Orientation

Data-Orientated Architectures make data available by design facilitating monitoring and maintenance. Decentralisation supports local data processing, reducing latency and improving privacy by respecting data ownership. Openness enables managing resource-constrained environments by exploiting the computing power of everyday devices (Cabrera et al., 2025).



How can we exploit these properties to address the intellectual debt problem in AI-based systems?

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

Multi-Agent Systems

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

Multi-Agent Systems

Multi-agent
Two rival teams of agents - Jordan K. Terry, CC BY-SA 4.0, via Wikimedia Commons

Multi-agent systems (MAS) have been studied for decades: BDI architectures, FIPA protocols, POMDP-based coordination, distributed problem solving.


MAS are AI-based systems. Agents make decisions using learned or programmed policies. When those decisions are opaque, the same intellectual debt applies.

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

Multi-Agent Systems

AI System

In a multi-agent system, the intellectual debt compounds:

  • Multiple agents making independent decisions
  • Interactions produce emergent behaviour
  • Coordination through implicit or explicit communication
  • Tracing which agent caused which outcome is hard

How can we design multi-agent systems where agent behaviour is observable, traceable, and interpretable?

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent

Multi-agent
Two rival teams of agents - Jordan K. Terry, CC BY-SA 4.0, via Wikimedia Commons
AI System
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent


!pip install -q git+https://github.com/cabrerac/doagent.git

from doagent import Session

session = Session.from_config({
    "shared_data": {"type": "file"},
    "scenario_name": "push",
    "output_base": "./output",
    "run_config": {"logging_level": 2},
    "policies": {
        "goal_seek": heuristic_goal_seek,
        "push_block": heuristic_push_block,
    },
})

Data-first Principle

Agents communicate through a shared data substrate.

  • Config-driven Session API: one entry point for env, agents, and policies
  • Shared data adapters: InMemory, File (JSONL), MongoDB
  • Logging levels control what is recorded (traces, provenance, reasoning)
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent


{
  "id": "au-abc123",
  "timestamp": "2026-03-28T10:00:00Z",
  "actor": "agent_0",
  "kind": "agent_update",
  "payload": {
    "decision": {
      "request": {"inputs": {"observation": {...}}},
      "response": {
        "choice": {"status": "act", "action": 2},
        "reasoning": {"steps": [...]}
      },
      "explanation": "Moved toward landmark."
    }
  },
  "provenance": {"agent": "agent_0", "sources": [...]},
  "accountability": {"owner": "team-a", "policy_id": "pol-1"}
}

Data Model

  • agent_update: decision envelope with request, response (choice + reasoning), and explanation
  • outcome: environment state after each step
  • trace: cause-effect links between outcomes via agent_updates

Logging levels:

  • Level 0: agent_update + outcome
  • Level 1: + trace + provenance + accountability
  • Level 2: + explanation + reasoning
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent


from doagent import Session

session = Session.from_config({
    ...
    "topology": {
        "mode": "peer_to_peer",
        "visibility": {
            "agent_0": ["agent_1"],
            "agent_1": ["agent_2"],
        }
    },
})
records = session.visible_records("agent_0",
    kind="agent_update")

Decentralisation Principle

Support for heterogeneous communication schemas.

  • Topology: centralised, federated, peer-to-peer
  • Visibility filters which records each agent sees
  • Same agent code runs under any topology — configuration, not code change
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent


session.register_participant("agent_0",
    capabilities=["map_discovery"])

if energy <= 0:
    session.deregister_participant("agent_0")

participants = session.participation_registry

Openness Principle

Agents can join and leave at any time.

  • ParticipationRegistry: register and query which agents are present
  • Capabilities and resources per agent
  • Session-level API for join/leave
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent

DOAgent Architecture
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent

Multi-agent
Two rival teams of agents - Jordan K. Terry, CC BY-SA 4.0, via Wikimedia Commons

What users provide

  • Environments: Use built-in (e.g. PettingZoo) or custom. The library wraps them so outcomes and traces are recorded
  • Agents: Define via config. The library creates them and connects them to shared data
  • Policies: Plug in any decision logic (heuristic, RL, LLM, or custom). The library records decisions and optional reasoning
  • Tools (optional): Per-agent callables. The library wraps them for transparent tool-use tracing
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent



from doagent import Session, make_env

session = Session.from_config(config)
env = make_env(create_push_env, max_cycles=100)
wrapped = session.wrap_env(env, env_actor="push_env")
agents = session.create_agents(configs,
    goal="push_towards_landmark")
observations = wrapped.reset(seed=42)

for round_id in range(1, 101):
    actions = {
        aid: agents[aid].decide(
            observations[aid], round_id
        )["action"]
        for aid in agents
    }
    step = wrapped.step(actions)
    observations = step["observations"]

Run loop

  • session.wrap_env records outcomes and traces automatically
  • session.create_agents binds policies from config
  • agent.decide() records the agent_update, wraps tools, merges reasoning
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent

Grid-world

GridWorld example

  • Dependency-free grid-world mapping scenario: agents discover cells and landmarks under partial observations
  • Each round agents publish an agent_update. They read the shared map (from visible records) and choose a move
  • Configurable topology and visibility. Optional energy-based participation (join/leave)
  • Run from config. Session records outcomes, traces, and agent_updates transparently
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent


{"id":"out-1","kind":"outcome",
"actor":"env","payload":{...}}
{"id":"au-1","kind":"agent_update",
"actor":"agent_0","payload":{
  "decision":{"response":{"choice":{"status":"act","action":2}}}
}}
{"id":"tr-1","kind":"trace",
"payload":{"from_id":"out-0","to_id":"out-1",
"enabled_by_id":"au-1","round":1}}

Stored records

  • outcome: env state after each step (observations per agent, done flags)
  • agent_update: per-agent decision envelope with choice, optional reasoning, explanation
  • trace: from_id, to_id, enabled_by_id — links outcome-to-outcome via the agent_update that caused the transition
  • Collection-per-kind (e.g. outcome.jsonl, agent_update.jsonl, trace.jsonl)
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent


from doagent.analysis import (
    provenance, traceability,
    accountability, interpretability,
)

# DOAgent Analysis Module
provenance.render_chain_tree("last", run_id,
    output_base="output", write_output=True)
traceability.build_trace_graph(run_id,
    output_base="output", write_output=True)
accountability.causal_attribution(run_id,
    output_base="output", write_output=True)
interpretability.build_atomic_explanations(
    "last", run_id, output_base="output",
    write_output=True)

Analysis from records alone

  • Traceability: cause-effect graph across the run
  • Provenance: chain of records leading to an outcome
  • Accountability: causal attribution — which agent caused which state transitions
  • Interpretability: atomic explanation units from traces and decisions

All analysis uses only shared records. No access to policy or env internals. Same tools for any policy type.

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent

Trace graph
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent

Provenance Tree
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent

Causal attribution results

Causal attribution results: Left: per-agent cumulative discovery over rounds. Centre: total cells discovered per agent. Right: decision effectiveness (productive vs redundant transitions). All derived from shared records.

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent


def heuristic_goal_seek(params):
    def decide(request):
        obs = request["inputs"]["observation"]
        action = compute_best_move(obs)
        return {
            "choice": {"status": "act", "action": action}
        }
    return decide

Policies in MAS are functions that map an agent's observations to actions:



Agents have always had policies: rules, heuristics, RL, symbolic planners. A policy receives a observations and returns an action


DOAgent is model-agnostic: the library coordinates decisions, not how they are made.

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent

Policy Factorisation decomposes the agent's policy into reasoning and action (Wei et al., 2026).



: history at step ; : internal reasoning; : external action.


  • z (reasoning): chain-of-thought, tool-use traces, confidence scores
  • a (action): the environment-specific primitive

LLM-based policies produce z in natural language. Is that a particular feature of Agentic AI?


{
  "actor": "agent_3",
  "kind": "agent_update",
  "payload": {
    "decision": {
      "response": {
        "choice": {"status": "act", "action": 1},
        "reasoning": {
          "confidence": 0.8,
          "source": "llm",
          "text": "Moving left is the least
            explored direction...",
          "tool_steps": [{"kind": "tool",
            "name": "llm", "elapsed_s": 1.24}]
        }
      },
      "explanation": "Moving left — least explored."
    }
  }
}

LLM record: action + observable reasoning (z).

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

DOAgent


{
  "actor": "agent_3",
  "kind": "agent_update",
  "payload": {
    "decision": {
      "response": {
        "choice": {
          "status": "abstain",
          "action": null
        },
        "reasoning": {
          "confidence": 0.0,
          "source": "llm",
          "text": "All surrounding cells explored.
            Cannot determine best move."
        }
      },
      "explanation": "Abstained: low confidence."
    }
  }
}

The "I Don't Know" Function


The Consistent Reasoning Paradox (CRP): a trustworthy intelligent system cannot simultaneously maintain consistent reasoning and always produce an answer. The resolution is the ability to say "I don't know"(Bastounis et al., 2024).


  • "I don't know" is not a special feature — it is a natural product of factorised reasoning
  • The LLM reasons, concludes low confidence then abstains
  • Factorisation makes abstention observable
  • The reasoning trace explains why the agent abstained
The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

Conclusions

The Sorrento Meeting - DOAgent: Towards Observable Multi-Agent Systems

Many Thanks!

chc79@cam.ac.uk

_script: true

This script will only execute in HTML slides

_script: true