This is Part 1 of a series on adding AI-assisted decision-making to event-driven messaging systems. The architecture grew out of my ACM Summer Tech Talk on intelligent message routing and prioritization, and this article introduces the open-source reference implementation used throughout the series.
The problem with static routing logic
Most event-driven systems make the same handful of decisions repeatedly using deterministic rules.
That's often the right design — until those decisions start depending on context that changes faster than the rules do.
A message shows up. Some code decides:
- Which processing path it belongs in
- How urgently it needs to be processed
- What to do if processing fails
Traditionally, those decisions are implemented with fixed logic:
SQS → Consumer/Lambda → Fixed Logic → Process/Retry → DLQ
That logic might be a collection of if/elif statements, lookup tables, message attributes, or routing policies based on conditions known when the system was designed.
And for many workloads, that's exactly what you want.
If a decision can be expressed reliably with a few deterministic rules, an AI model probably shouldn't be involved.
The challenge appears when decisions depend on broader and continuously changing context.
What does "high priority" mean when a downstream dependency is degraded? Should two failures with completely different causes receive the same retry treatment? Should a message continue down its normal processing path when another approved processor is healthier?
Static rules can handle these scenarios, but as the number of contextual signals grows, the decision tree can become increasingly complex to maintain.
That's where AI-assisted decision-making becomes interesting.
Where contextual decision-making can help
There are three areas I wanted to explore.
Routing. Traditional routing often maps known message types to predetermined destinations:
Message Type A → Processor A
Message Type B → Processor B
But the appropriate processing path may depend on more than the message type. Message characteristics, downstream availability, workload conditions, or other operational context may also matter.
Prioritization. Priority is frequently encoded as a fixed message attribute or determined using predefined business rules. But urgency can sometimes depend on context. A message that is routine under normal operating conditions may deserve different treatment when the system is experiencing an incident, backlog, or downstream degradation.
Retry behavior. Failures are also not identical. A transient downstream timeout and a permanently invalid request should not necessarily receive the same retry strategy. Repeatedly retrying a request that is unlikely to succeed can waste resources, while retrying too slowly after a transient failure can unnecessarily increase recovery time.
The question becomes: can we use additional context to make better recommendations while preserving deterministic control over what the system actually does?
An AI-assisted approach
The architecture I explored does not replace deterministic rules with AI. Instead, it introduces AI as a decision-support layer.
SQS
↓
Lambda / Consumer
↓
Context Builder
↓
Amazon Bedrock
↓
AI Recommendation
↓
Policy Guardrails
↓
Action
One important distinction: Amazon Bedrock does not poll SQS or control the queue. In a Lambda-based implementation, the SQS event source mapping handles polling and invokes the Lambda consumer. The application builds the relevant context and invokes the model. The model participates in the decision, not the queue mechanics.
A decision request might contain information such as:
{
"message_type": "service_interruption",
"message_age_seconds": 45,
"attempt": 2,
"queue_backlog": 4200,
"downstream_health": "degraded",
"workload_tier": "critical"
}
The decision layer can return a structured recommendation such as:
{
"priority": "HIGH",
"route": "PROCESSOR_B",
"retry_delay_seconds": 120,
"confidence": 0.93
}
The application does not blindly execute that response. It validates the recommendation against deterministic policy first.
The principle that makes this practical
The entire pattern can be summarized in one sentence:
AI recommends. Policy decides. The messaging platform executes.
That separation is important. The model never receives unrestricted operational authority. Its recommendation passes through deterministic guardrails controlling things such as:
- Allowed routing destinations
- Valid priority levels
- Maximum retry attempts
- Bounded retry delays
- Minimum confidence thresholds
- Workload-specific restrictions
- Fallback behavior
If a recommendation violates policy, the application rejects it. If the model isn't available, the application falls back. If the response isn't valid, the application falls back. If the confidence indicator is below the configured threshold, the application falls back.
That's not a limitation bolted on as an afterthought. It's the design.
Pattern 1: Content-aware routing
Suppose the normal routing logic looks like this:
Message Type A → Processor A
Message Type B → Processor B
Now imagine that routing depends on additional context:
Message characteristics
+
Processing requirements
+
Downstream health
+
Operational conditions
↓
Routing Decision
Instead of expanding a static decision tree indefinitely, the consumer can provide that context to the AI decision layer. The model might recommend:
{
"route": "PROCESSOR_B",
"confidence": 0.94
}
But the recommendation still goes through policy:
if decision["route"] not in ALLOWED_ROUTES:
route = DEFAULT_ROUTE
else:
route = decision["route"]
Bedrock recommends PROCESSOR_B. The application determines whether PROCESSOR_B is permitted. The messaging layer executes the validated routing decision.
Pattern 2: AI-assisted priority scoring
Consider two messages.
Message A — Type: Account update. Age: 2 seconds. Workload tier: Standard. Queue backlog: Low.
Message B — Type: Service interruption. Age: 45 seconds. Workload tier: Critical. Queue backlog: High. Downstream risk: Elevated.
A fixed priority rule might only examine the message type. A context-aware decision layer can consider multiple signals and recommend an urgency level:
{
"priority": "HIGH",
"reason": "Critical workload with elevated downstream risk",
"confidence": 0.95
}
The application validates that recommendation and selects the appropriate processing path.
Priority itself is not implemented through an SQS visibility timeout. Visibility timeout controls how long a received message remains hidden from other consumers while it is being processed. In the reference implementation, different processing paths can have their own operational queue configuration, but queue selection represents prioritization; visibility timeout is a separate reliability configuration.
Pattern 3: Adaptive retry and backoff
Retry behavior becomes particularly interesting when additional failure context is available. An adaptive decision can consider error category, previous attempts, downstream health, queue backlog, message urgency, and historical failure context.
It might recommend:
{
"retry": true,
"retry_delay_seconds": 180,
"confidence": 0.89
}
Or:
{
"retry": false,
"route": "FALLBACK_PROCESSOR",
"confidence": 0.94
}
The model is recommending a retry strategy. Deterministic policy still enforces maximum attempts, allowed retry intervals, maximum delay, approved fallback destinations, and DLQ behavior.
The AI layer therefore does not replace SQS reliability mechanisms. It adds contextual decision support around them.
Confidence is a gate, not authority
The model response also includes a structured confidence indicator. That value should not be interpreted as a statistically calibrated probability of correctness unless you've specifically built and validated it that way.
In this pattern, it serves a simpler purpose: it's one input into the application's acceptance policy.
if decision["confidence"] < MIN_CONFIDENCE:
use_deterministic_fallback()
elif decision["route"] not in ALLOWED_ROUTES:
use_default_route()
else:
execute_validated_decision(decision)
In the reference implementation, responses below MIN_CONFIDENCE are rejected in favor of deterministic behavior.
What happens when Bedrock is unavailable?
The system should never become:
Bedrock unavailable
↓
Messaging stops
If Bedrock is unavailable, times out, returns malformed output, or produces a recommendation that doesn't satisfy policy, the application falls back to deterministic processing. The queue continues operating. The consumer continues processing. Existing retry and DLQ mechanisms remain available.
AI should enhance the system, not become a new single point of failure.
Should every message invoke an AI model?
Probably not.
Model invocation introduces additional considerations: latency, cost, throughput, quotas, availability, and operational complexity. A practical architecture can use AI selectively. Simple decisions stay deterministic. AI is reserved for situations where additional context provides enough value to justify the model invocation.
A working reference implementation
I built this architecture as an AWS SAM reference application: ai-message-queue-patterns.
It uses Amazon SQS, AWS Lambda, and Amazon Bedrock, and combines three related patterns into one message-processing pipeline.
| Pattern | What it does |
|---|---|
| Content-Aware Routing | Bedrock evaluates message context and recommends a downstream destination; deterministic policy validates the recommendation before routing. |
| AI-Assisted Priority Scoring | Evaluates message context and recommends an urgency level used to select the appropriate processing path. |
| Adaptive Retry & Backoff | On failure, classifies the failure context and recommends a retry strategy; deterministic policy enforces attempt limits, delay bounds, and DLQ behavior. |
A few implementation choices are particularly important.
Deterministic mode. Setting USE_BEDROCK=false allows the pipeline to operate using deterministic fallback logic without depending on model access. The messaging system doesn't have to depend on AI in order to function.
Confidence gating. The implementation uses a configurable threshold: MIN_CONFIDENCE=0.7. Recommendations below that threshold are rejected in favor of deterministic fallback. The threshold isn't proof that a recommendation is correct; it's an application policy controlling when the system is willing to consider the model's output.
Independent patterns. The Router, Priority Scorer, and Retry Handler are separate components. That means adopting this architecture doesn't require committing to every pattern at once.
Lambda isn't required. Although the reference implementation uses Lambda, the architecture isn't Lambda-specific. A consumer could run on AWS Lambda, Amazon EC2, Amazon ECS, Amazon EKS, or another application runtime. The architectural principle remains unchanged: the application invokes the AI decision engine. The AI model does not replace the messaging infrastructure.
The bigger pattern
Traditional automation often looks like this:
Event → Rule → Action
AI-assisted automation introduces another possibility:
Event → Context → AI Recommendation → Policy → Action
Adding AI doesn't eliminate deterministic engineering. If anything, it makes deterministic engineering more important.
Once a probabilistic component becomes part of a production decision path, the boundaries around that component need to become explicit:
- What is the model allowed to recommend?
- What is it never allowed to decide?
- What happens when it's wrong?
- What happens when it's unavailable?
- When should we avoid invoking it altogether?
For message-driven systems, routing, prioritization, and retry are three interesting places to explore contextual AI-assisted decision-making. But the architectural principle stays deliberately simple:
AI recommends. Policy decides. The messaging platform executes.
What's next
This article covered the architecture and the reasoning behind it. Part 2 will go deeper into policy guardrails, confidence thresholds, deterministic fallback, malformed model responses, and failure modes. After that, I'll walk through the implementation itself using the open-source repository.
If you want to explore the code now: 👉 AI-Assisted Message Queue Patterns on GitHub
The examples in this article are architectural patterns and reference implementations intended for experimentation and learning. Production systems should evaluate model behavior, latency, cost, security, failure modes, and workload-specific requirements before introducing AI-assisted decision-making into critical processing paths.
Top comments (0)