SHADOW AI

Image
A Hybrid Neural-Symbolic Architecture for Compact Multilingual Intelligence Project Type Experimental AI Model / Research Architecture / Foundational Language Model Model Family SHADOW AI Proposed Architecture SHADOW-HSR — Hybrid Symbolic Representation Architecture Core Objective SHADOW AI is a proposed experimental AI architecture designed to investigate whether useful multilingual language understanding, symbolic reasoning, contextual memory, and structured generation can be achieved with a more compact architecture than extremely large conventional language models. The architecture is designed around four primary components: > Neural Representation + Symbolic Reasoning + Dynamic State + Efficient Decoding SHADOW AI is intended to explore an alternative design philosophy rather than reproduce an existing commercial AI system. The project does not claim that training can be eliminated. A model capable of general language understanding still requires learning from data. Instead,...

ACAI — Chapter 9: Multi-Provider AI Integration and Fallback Architecture

Post cover

9.1 Objective

ACAI should not depend permanently on a single AI provider.

A robust architecture should separate:

ACAI Core
   ↓
Provider Interface
   ↓
Provider Adapters
   ├── Cloud Provider A
   ├── Cloud Provider B
   ├── Local Model
   └── Future Providers

The important design principle is:

The core system should know how to request an AI capability, not how every individual provider implements that capability.


9.2 Why a Provider Abstraction Is Necessary

Without an abstraction, the application can become:

Planner
   ↓
OpenAI-specific code
   ↓
OpenAI API

Then changing providers requires modifying many parts of the system.

A better design is:

Planner
   ↓
Model Router
   ↓
Provider Interface
   ↓
Selected Provider

Now the planner does not need to know whether the model is:

Cloud
Local
Open-source
Hosted

9.3 Provider Interface

Create:

app/providers/base.py

Example:

from abc import ABC, abstractmethod


class AIProvider(ABC):

    @abstractmethod
    async def generate(
        self,
        prompt: str,
        **kwargs,
    ) -> str:
        raise NotImplementedError

    @abstractmethod
    async def health_check(
        self,
    ) -> bool:
        raise NotImplementedError

Every provider must implement the same basic contract.


9.4 Provider Adapter

A provider adapter converts ACAI's internal request into the provider's API format.

Architecture:

ACAI Request
     │
     ▼
Provider Interface
     │
     ▼
Provider Adapter
     │
     ▼
External API

This prevents provider-specific implementation details from spreading throughout the application.


9.5 Mock Provider

Before connecting real services, create a mock provider.

Create:

app/providers/mock.py
from app.providers.base import AIProvider


class MockProvider(AIProvider):

    async def generate(
        self,
        prompt: str,
        **kwargs,
    ) -> str:

        return (
            "Mock response generated "
            "for: "
            f"{prompt}"
        )

    async def health_check(
        self,
    ) -> bool:

        return True

This is extremely useful for development because the application can be tested without spending API credits.


9.6 Provider Registry

Create:

app/providers/registry.py
from app.providers.base import AIProvider


class ProviderRegistry:

    def __init__(self):

        self.providers: dict[
            str,
            AIProvider
        ] = {}

    def register(
        self,
        name: str,
        provider: AIProvider,
    ) -> None:

        self.providers[name] = provider

    def get(
        self,
        name: str,
    ) -> AIProvider | None:

        return self.providers.get(name)

    def names(self) -> list[str]:

        return list(
            self.providers.keys()
        )

Example:

registry.register(
    "mock",
    MockProvider(),
)

9.7 Model Router

The model router selects a provider.

Conceptually:

                 REQUEST
                    │
                    ▼
               MODEL ROUTER
                    │
       ┌────────────┼────────────┐
       ▼            ▼            ▼
    Provider A   Provider B   Local Model
       │            │            │
       └────────────┼────────────┘
                    ▼
                 RESULT

The router can consider:

Task type
Model capability
Latency
Cost
Availability
User configuration
Provider health

9.8 Routing Policy

Create:

app/services/model_router.py
class ModelRouter:

    def __init__(
        self,
        registry,
    ):

        self.registry = registry

    async def generate(
        self,
        prompt: str,
        provider_name: str = "mock",
        **kwargs,
    ) -> str:

        provider = (
            self.registry.get(
                provider_name
            )
        )

        if provider is None:

            raise ValueError(
                f"Unknown provider: "
                f"{provider_name}"
            )

        return await provider.generate(
            prompt,
            **kwargs,
        )

This provides one internal interface:

router.generate(...)

regardless of the underlying provider.


9.9 Provider Health

Before selecting a provider, ACAI can check its health.

Conceptually:

Provider A
   │
   ▼
Healthy?
 ┌─┴─┐
YES  NO
 │    │
 ▼    ▼
Use  Fallback

However, repeatedly calling a provider's health endpoint before every request can add latency.

A production system should generally maintain cached health information rather than performing a fresh health check for every generation.


9.10 Provider Status

A provider can have:

healthy
degraded
unavailable
unknown

Example:

class ProviderStatus:

    HEALTHY = "healthy"

    DEGRADED = "degraded"

    UNAVAILABLE = "unavailable"

    UNKNOWN = "unknown"

9.11 Fallback Architecture

Suppose the preferred provider is:

Provider A

and it fails.

The router can attempt:

Provider A
   ↓
Failure
   ↓
Provider B
   ↓
Failure
   ↓
Local Model

Conceptually:

                    REQUEST
                       │
                       ▼
                  Provider A
                       │
                 ┌─────┴─────┐
                 ▼           ▼
              SUCCESS      FAILURE
                 │           │
                 ▼           ▼
               RESULT    Provider B
                              │
                        ┌─────┴─────┐
                        ▼           ▼
                     SUCCESS      FAILURE
                        │           │
                        ▼           ▼
                      RESULT    Local Model

9.12 Fallback Must Be Controlled

Fallback should not mean:

Try providers forever.

It should have:

Maximum attempts
Timeout
Allowed providers
Error classification
Logging
Termination condition

Example:

MAX_PROVIDER_ATTEMPTS = 3

9.13 Provider Error Classification

Not every failure should trigger fallback.

Examples:

Authentication failure
Invalid request
Rate limit
Timeout
Temporary server error
Network error

A policy can classify them as:

Transient
Permanent

For example:

Timeout
→ potentially transient
→ fallback may be appropriate

Invalid request
→ permanent
→ fallback may not solve the underlying problem

9.14 Provider Result Object

Instead of returning only a string, create a structured result.

from dataclasses import dataclass


@dataclass
class ProviderResult:

    text: str

    provider: str

    model: str | None = None

    latency_ms: float | None = None

    success: bool = True

    error: str | None = None

Now ACAI can record how the result was generated.


9.15 Measuring Latency

Use a timer:

import time


start = time.perf_counter()

result = await provider.generate(
    prompt
)

elapsed = (
    time.perf_counter()
    - start
)

latency_ms = elapsed * 1000

This provides measurable provider performance.


9.16 Cost Awareness

Different providers can have different pricing.

The router can eventually maintain metadata:

provider_info = {

    "provider_a": {
        "cost_class": "high",
        "latency_class": "low",
    },

    "provider_b": {
        "cost_class": "low",
        "latency_class": "medium",
    },

    "local": {
        "cost_class": "compute_only",
        "latency_class": "variable",
    },
}

The actual prices should come from current provider pricing documentation rather than being hardcoded as permanent assumptions.


9.17 Task-Aware Routing

Not every task requires the same model.

For example:

Simple classification
→ Smaller model

Complex reasoning
→ More capable model

Local/private processing
→ Local model

High-volume inexpensive task
→ Lower-cost provider

The architecture becomes:

                 TASK
                   │
                   ▼
             TASK CLASSIFIER
                   │
          ┌────────┼────────┐
          ▼        ▼        ▼
        Simple   Complex   Private
          │        │        │
          ▼        ▼        ▼
       Model A   Model B   Local

9.18 Router Policy

A basic policy might be:

ROUTING_POLICY = {

    "simple": [
        "provider_a",
        "provider_b",
    ],

    "complex": [
        "provider_b",
        "provider_a",
    ],

    "private": [
        "local",
    ],
}

The important point is that the routing policy is configuration rather than hardcoded throughout the application.


9.19 Fallback Router

A simple implementation:

class FallbackRouter:

    def __init__(
        self,
        registry,
    ):

        self.registry = registry

    async def generate(
        self,
        prompt: str,
        providers: list[str],
        **kwargs,
    ):

        errors = []

        for name in providers:

            provider = (
                self.registry.get(name)
            )

            if provider is None:

                errors.append(
                    f"{name}: not registered"
                )

                continue

            try:

                result = (
                    await provider.generate(
                        prompt,
                        **kwargs,
                    )
                )

                return result

            except Exception as exc:

                errors.append(
                    f"{name}: {exc}"
                )

        raise RuntimeError(
            "All providers failed: "
            + "; ".join(errors)
        )

This is a prototype and should later be enhanced with explicit timeout and error classification.


9.20 Timeout-Aware Provider Calls

Use:

import asyncio


result = await asyncio.wait_for(
    provider.generate(
        prompt,
        **kwargs,
    ),
    timeout=60,
)

Then a provider that exceeds the limit does not block the complete workflow indefinitely.


9.21 Complete Provider Pipeline

The resulting architecture is:

                         USER REQUEST
                              │
                              ▼
                           PLANNER
                              │
                              ▼
                         TASK TYPE
                              │
                              ▼
                        MODEL ROUTER
                              │
                    ┌─────────┼─────────┐
                    ▼         ▼         ▼
                Provider A Provider B Local
                    │         │         │
                    └─────────┼─────────┘
                              ▼
                           RESULT
                              │
                              ▼
                         VERIFICATION
                              │
                         ┌────┴────┐
                         ▼         ▼
                       PASS      REVISE
                         │         │
                         ▼         ▼
                       FINAL     RETRY

9.22 Local Model Integration

A local provider should follow exactly the same interface.

class LocalProvider(AIProvider):

    async def generate(
        self,
        prompt: str,
        **kwargs,
    ) -> str:

        # Connect to the configured
        # local model server here.

        return "Local model response"

    async def health_check(
        self,
    ) -> bool:

        return True

The important architectural property is:

ACAI Core
   ↓
AIProvider
   ↓
LocalProvider

rather than:

ACAI Core
   ↓
Local-model-specific implementation

everywhere.


9.23 Environment-Based Provider Selection

Configuration:

ACAI_DEFAULT_PROVIDER=mock
ACAI_FALLBACK_PROVIDERS=mock

For development:

mock

For a real deployment:

provider_a
provider_b
local

can be configured according to the actual providers and credentials available.


9.24 API Key Management

Provider credentials must be loaded from environment variables or a secure secret manager.

Example:

PROVIDER_A_API_KEY=...
PROVIDER_B_API_KEY=...

Do not put keys directly into:

Python source
Git repository
Frontend JavaScript
Public documentation
Screenshots

The backend should be the component that communicates with privileged provider APIs.


9.25 Frontend Security

A browser application should never receive a private provider API key simply because the frontend needs to generate an AI response.

Instead:

Browser
   ↓
ACAI Backend
   ↓
Provider API

not:

Browser
   ↓
Private API Key
   ↓
Provider API

9.26 Provider Usage Logging

Each generation should ideally record:

request_id
provider
model
task_type
latency
success
error

Example:

logger.info(
    "AI generation completed",
    extra={
        "request_id": request_id,
        "provider": provider_name,
        "model": model_name,
        "latency_ms": latency_ms,
    },
)

This enables later analysis.


9.27 Provider Metrics

Useful metrics include:

Requests
Success rate
Failure rate
Average latency
P95 latency
Timeout count
Rate-limit count
Fallback count

Example:

Provider A
Success: 98%
Fallback: 2%
Average latency: measured from production

These numbers must come from actual measurements, not assumptions.


9.28 Fallback Metrics

One particularly important metric is:

fallback_rate

If:

1000 requests
50 required fallback

then:

fallback_rate = 5%

A high fallback rate may indicate:

Provider instability
Bad timeout configuration
Rate limiting
Incorrect routing
Credential problems
Network issues

9.29 Testing the Mock Provider

Create:

tests/test_provider.py
import pytest

from app.providers.mock import (
    MockProvider,
)


@pytest.mark.asyncio
async def test_mock_provider():

    provider = MockProvider()

    result = await provider.generate(
        "Hello"
    )

    assert "Hello" in result

Health test:

@pytest.mark.asyncio
async def test_mock_health():

    provider = MockProvider()

    assert (
        await provider.health_check()
        is True
    )

9.30 Testing Fallback

Create a failing provider:

class FailingProvider:

    async def generate(
        self,
        prompt,
        **kwargs,
    ):

        raise RuntimeError(
            "Provider unavailable"
        )

Then configure:

Failing Provider
      ↓
Mock Provider

Expected:

First provider
→ FAIL

Fallback provider
→ SUCCESS

9.31 Fallback Test

Conceptually:

@pytest.mark.asyncio
async def test_fallback():

    registry = ProviderRegistry()

    registry.register(
        "failing",
        FailingProvider(),
    )

    registry.register(
        "mock",
        MockProvider(),
    )

    router = FallbackRouter(
        registry
    )

    result = await router.generate(
        prompt="hello",
        providers=[
            "failing",
            "mock",
        ],
    )

    assert "hello" in result

9.32 Testing All Providers

The system should eventually have tests for:

Provider registration
Unknown provider
Successful generation
Timeout
Transient failure
Permanent failure
Fallback
All providers failing
Health state
Logging
Metrics

9.33 Provider Independence

The most important architectural outcome of Chapter 9 is:

             ACAI CORE
                 │
          AIProvider Interface
                 │
       ┌─────────┼─────────┐
       ▼         ▼         ▼
   Provider A Provider B Local

This means adding another provider should require primarily:

New Adapter
+
Configuration
+
Tests

rather than rewriting the entire application.


9.34 Complete ACAI Architecture

After Chapter 9:

                                  USER
                                    │
                                    ▼
                               API GATEWAY
                                    │
                        ┌───────────┴───────────┐
                        ▼                       ▼
                   RATE LIMITER             REQUEST ID
                        │                       │
                        └───────────┬───────────┘
                                    ▼
                              ORCHESTRATOR
                                    │
                 ┌──────────────────┼──────────────────┐
                 ▼                  ▼                  ▼
              PLANNER            MEMORY            RETRIEVAL
                 │                  │                  │
                 │                  ▼                  │
                 │              DATABASE               │
                 │                                     │
                 └──────────────────┬──────────────────┘
                                    ▼
                              WORKFLOW ENGINE
                                    │
                                    ▼
                               MODEL ROUTER
                                    │
                     ┌──────────────┼──────────────┐
                     ▼              ▼              ▼
                 Provider A      Provider B       Local
                     │              │              │
                     └──────────────┼──────────────┘
                                    ▼
                               GENERATION
                                    │
                                    ▼
                               VERIFICATION
                                    │
                              ┌─────┴─────┐
                              ▼           ▼
                            PASS        REVISE
                              │           │
                              ▼           ▼
                            RESULT      RETRY
                              │
                  ┌───────────┼───────────┐
                  ▼           ▼           ▼
                CACHE        LOGS       METRICS

9.35 What ACAI Can Now Demonstrate

The architecture can now demonstrate a realistic modular AI pipeline:

User
 ↓
Request Validation
 ↓
Planning
 ↓
Workflow Creation
 ↓
Memory / Retrieval
 ↓
Task Routing
 ↓
Provider Selection
 ↓
AI Generation
 ↓
Fallback if appropriate
 ↓
Verification
 ↓
Result
 ↓
Persistent Logging

This is a meaningful engineering architecture.

It is not, by itself, proof of AGI or human-level intelligence.


9.36 Chapter 9 Success Criteria

Chapter 9 is complete when:

[✓] Provider interface exists
[✓] Mock provider works
[✓] Provider registry works
[✓] Model router exists
[✓] Fallback router exists
[✓] Timeout handling exists
[✓] Provider health is defined
[✓] Provider errors are classified
[✓] API keys are externalized
[✓] Provider usage is logged
[✓] Provider metrics are defined
[✓] Fallback is tested
[✓] Local-provider architecture is supported

9.37 Next Chapter

The system now has:

Planning
Retrieval
Memory
Routing
Verification
Workflow
Persistence
Infrastructure
Multi-provider execution
Fallback

The next major problem is evaluation.

An AI system cannot be considered reliable merely because:

API returns 200

or:

Model generated text

We need to measure whether the system actually performs its intended tasks correctly.

Therefore the next chapter is:

Chapter 10 — Evaluation, Benchmarking, Quality Measurement, and Research Validation

It will cover:

Evaluation datasets
Test cases
Task success metrics
Accuracy
Factuality
Latency
Reliability
Regression testing
Human evaluation
Automated evaluation
Benchmark design
A/B testing
Failure analysis
Reproducibility
Research reporting

The architecture will move from:

"It works."

to:

"Here is what it does,
how well it does it,
where it fails,
and how we measured it."

End of Chapter 9


Comments

Popular posts from this blog

Adaptive Cognitive AI (ACAI): Chapter 1 — Introduction & System Vision

ACAI — Chapter 27: Database + Authentication + Real User Accounts + Persistent Conversations

Chapter 2 (Part 2) Knowledge Retrieval Engine