Skip to main content

Demo: Model Swap Prevention

This demo shows how IntentusNet's deterministic routing and execution recording prevent unexpected behavioral changes when underlying models are updated.

Scenario

A content moderation system uses multiple AI models. Overnight, one model is updated to a new version. Without IntentusNet, this could silently change routing decisions and moderation outcomes.

The Problem: Silent Model Drift

                    Monday                          Tuesday
────── ───────

Request ─────────────────────────────────────────────────
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Router │ │ Router │
│ (v1.0) │ │ (v1.0) │
└──────┬──────┘ └──────┬──────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Model A │ ◄── Selected │ Model B │ ◄── Selected
│ (GPT-4) │ │ (GPT-4.5) │ (Model updated!)
└─────────────┘ └─────────────┘

Result: "SAFE" Result: "FLAGGED"

Same content, different result. No log of change.

IntentusNet Solution

1. Deterministic Agent Selection

# Agents registered with explicit priorities
agents = [
AgentDefinition(
name="moderator-gpt4",
nodePriority=10, # Primary
capabilities=[Capability(intent=IntentRef(name="ModerateIntent"))]
),
AgentDefinition(
name="moderator-gpt4-turbo",
nodePriority=20, # Secondary
capabilities=[Capability(intent=IntentRef(name="ModerateIntent"))]
),
AgentDefinition(
name="moderator-claude",
nodePriority=30, # Tertiary
capabilities=[Capability(intent=IntentRef(name="ModerateIntent"))]
),
]

# Selection is ALWAYS deterministic:
# moderator-gpt4 → moderator-gpt4-turbo → moderator-claude

2. Recorded Routing Decisions

Every request records which agent was selected:

{
"execution_id": "exec-mod-001",
"routerDecision": {
"agent": "moderator-gpt4",
"intent": "ModerateIntent",
"reason": "deterministic_match",
"priority_order": [
"moderator-gpt4",
"moderator-gpt4-turbo",
"moderator-claude"
]
}
}

3. Behavioral Comparison

When a model is updated, compare outputs:

# Monday's execution
monday_result = replay("exec-mod-001")
# {"content_id": "post-123", "decision": "SAFE", "confidence": 0.95}

# Tuesday: same content, new model
tuesday_envelope = create_envelope(content="same content")
tuesday_result = runtime.router.route_intent(tuesday_envelope)

# Compare
if monday_result.payload != tuesday_result.payload:
alert("Behavioral drift detected!")
log_drift(
content="post-123",
before=monday_result.payload,
after=tuesday_result.payload,
model_change="gpt4 → gpt4.5"
)

Input Intent

{
"intent": {
"name": "ModerateIntent",
"version": "1.0"
},
"payload": {
"content_id": "post-123",
"content": "This is the content to moderate...",
"context": {
"platform": "social",
"user_age_group": "13-17"
}
}
}

Route Result (Consistent)

{
"routing": {
"strategy": "DIRECT",
"selected_agent": "moderator-gpt4",
"selection_reason": "deterministic_match",
"available_agents": [
{"name": "moderator-gpt4", "priority": 10},
{"name": "moderator-gpt4-turbo", "priority": 20},
{"name": "moderator-claude", "priority": 30}
]
}
}

Execution Trace

Monday (Before Model Update)

{
"execution_id": "exec-mod-monday-001",
"events": [
{"seq": 1, "type": "INTENT_RECEIVED"},
{"seq": 2, "type": "AGENT_ATTEMPT_START", "payload": {"agent": "moderator-gpt4"}},
{"seq": 3, "type": "AGENT_ATTEMPT_END", "payload": {
"agent": "moderator-gpt4",
"status": "success",
"model_version": "gpt-4-0613"
}},
{"seq": 4, "type": "FINAL_RESPONSE"}
],
"finalResponse": {
"payload": {
"decision": "SAFE",
"confidence": 0.95,
"flags": []
}
}
}

Tuesday (After Model Update)

If routing were non-deterministic, a different agent might be selected. With IntentusNet:

{
"execution_id": "exec-mod-tuesday-001",
"events": [
{"seq": 1, "type": "INTENT_RECEIVED"},
{"seq": 2, "type": "AGENT_ATTEMPT_START", "payload": {"agent": "moderator-gpt4"}},
{"seq": 3, "type": "AGENT_ATTEMPT_END", "payload": {
"agent": "moderator-gpt4",
"status": "success",
"model_version": "gpt-4-0125-preview"
}},
{"seq": 4, "type": "FINAL_RESPONSE"}
],
"finalResponse": {
"payload": {
"decision": "FLAGGED",
"confidence": 0.87,
"flags": ["potential_harmful_content"]
}
}
}

Drift Detection

def detect_drift(before_id: str, after_id: str) -> dict:
store = FileExecutionStore(".intentusnet/records")

before = store.load(before_id)
after = store.load(after_id)

# Same agent selected?
before_agent = before.routerDecision["agent"]
after_agent = after.routerDecision["agent"]

agent_changed = before_agent != after_agent

# Same output?
before_decision = before.finalResponse["payload"]["decision"]
after_decision = after.finalResponse["payload"]["decision"]

output_changed = before_decision != after_decision

return {
"routing_drift": agent_changed,
"behavioral_drift": output_changed,
"details": {
"before": {
"agent": before_agent,
"decision": before_decision,
"model": before.events[2].payload.get("model_version")
},
"after": {
"agent": after_agent,
"decision": after_decision,
"model": after.events[2].payload.get("model_version")
}
}
}

Drift Report

{
"routing_drift": false,
"behavioral_drift": true,
"details": {
"before": {
"agent": "moderator-gpt4",
"decision": "SAFE",
"model": "gpt-4-0613"
},
"after": {
"agent": "moderator-gpt4",
"decision": "FLAGGED",
"model": "gpt-4-0125-preview"
}
},
"alert": "Same agent, different output. Model was updated."
}

Replay for Verification

# Replay Monday's execution
$ intentusnet replay exec-mod-monday-001
{
"from_replay": true,
"payload": {
"decision": "SAFE",
"confidence": 0.95
}
}

# This is what the system returned on Monday
# Even if the model changed, replay returns the recorded output

Key Points

AspectBehavior
Agent selectionDeterministic by priority
Model versionRecorded in execution trace
OutputRecorded exactly as produced
Drift detectionCompare recorded outputs
ReplayReturns original output (not re-executed)

Preventing Surprise Changes

Strategy 1: Explicit Version Pinning

# Pin to specific model version in agent config
AgentDefinition(
name="moderator-gpt4-0613", # Version in name
capabilities=[...],
runtime=AgentRuntimeInfo(
model_version="gpt-4-0613" # Explicit version
)
)

Strategy 2: Gradual Rollout

# Deploy new model with lower priority
AgentDefinition(
name="moderator-gpt4-new",
nodePriority=100, # Lower priority = fallback only
...
)

# Gradually increase priority after validation

Strategy 3: Shadow Mode

# Run new model in shadow mode
response = runtime.route_intent(envelope)
shadow = runtime.route_intent(envelope, routing=RoutingOptions(
targetAgent="moderator-gpt4-new"
))

# Compare but don't use shadow result
if response.payload != shadow.payload:
log_shadow_drift(response, shadow)

Summary

ProtectionHow IntentusNet Helps
Routing stabilityDeterministic priority-based selection
Change detectionRecorded model versions in traces
Output stabilityReplay returns original output
AuditFull execution history
RollbackReplay historical behavior

See Also