ms-ai-architect/skills/ms-ai-engineering/references/agent-orchestration/agent-routing-and-specialization.md
Kjell Tore Guttormsen 3a73eeafdc refactor(ms-ai-architect): R13 del 1 — nøytraliser Cosmo-personaen i ref-korpusets headinger, etter å ha rettet en gate som var målt usann to ganger
Ordre 20260912T193441Z-7358817909. Steg 1 var ikke transformen, men å rette
roadmapens R13-gate og få den ratifisert. Gaten `grep -rl "Cosmo"
skills/*/references -> 0` var usann på to uavhengige måter:

1. Ordren fanget den første: 451 av forekomstene er Azure Cosmos DB, ekte
   produktinnhold. Diskriminatoren er ikke bokstaven «s» — `Cosmos <norsk
   substantiv>` er genitiv av personaen (`### Cosmos tonalitet`), mens
   `Cosmos DB`/`CosmosClient`/`cosmos_ru` er produkt.
2. Denne økten fant den andre: 132 persona-forekomster ligger i prosa,
   tabeller, dialog-replikker og proveniens-linjer. Heading-nøytralisering
   kan ikke nå dem, så «0 persona» er uoppnåelig også under den ratifiserte
   formen. Operatøren ratifiserte alternativ A: gaten speiler formen, og de
   132 bokføres til R13b/R14.

Tre korreksjoner av premisser som sto i ordren og STATE:
  «ca 320 produkt»   -> 451 (case-sensitivt nett manglet 327 lowercase
                        TOC-ankre + 99 identifikatorer; sann nevner 1 638)
  «169 headinger»    -> 401. 169 var `^## For Cosmo`-prefikset (168) og var
                        internt inkonsistent med sin egen topp-variant (204)
  «417 matcher ingen
   populasjon»       -> 417 er cosmo-headinger utenfor kodefences; briefens
                        nevner var reell hele tiden

Fence-bevissthet er målt skadelig, ikke nødvendig: begge toggle-regler er
gale på dette korpuset (naiv toggle skjuler en ekte heading i
chain-of-thought-prompting.md, CommonMark-regelen ubalanserer
service-level-documentation-dr.md). Fence-agnostisk deteksjon finner 401
heading-linjer i nøyaktig de samme 40 variantene som fence-bevisst finner
400 i — ingen kodeblokk-linje er byte-identisk til en persona-heading. Derfor
nøkles transformen på 40 enumererte heading-tekster og ignorerer fences. En
ukjent variant kaster; en slug-kollisjon kaster. Ingenting auto-fikses.

TOC-en regenereres ikke, den rettes kirurgisk: alle 327 persona-lenker hadde
lenketekst lik én av de 40 heading-tekstene og anker lik slugify av den
(327/327, 0 avvik), så heading og TOC-entry skrives i samme operasjon og
ingen mellomtilstand etterlater en død lenke.

Ratifisert målform: `For Cosmo`, `For Cosmo Skyberg` og `For arkitekten
(Cosmo)` konvergerer på `For arkitekten`. To filer kolliderte og er adjudisert
ved å lese dem, ikke ved regel.

Verifisering (alle 7 kriterier fra ordren):
  G1 persona på heading-linjer   401 -> 0
  G2 døde fragmentlenker         1 -> 1 (pre-eksisterende, unntatt)
  G3 produkt-forekomster         451 -> 451; `Cosmos DB|Azure Cosmos` 308 = 308
  de 3 kun-produkt-filene        byte-identiske
  nettet validert begge veier    injisert persona feller G1; genitiv feller G1;
                                 produkt-heading og de 3 filene passerer
  hele diffen                    802 heading-linjer + 654 TOC-linjer, ANNET = 0
  linjeantall                    728 lagt til = 728 slettet
  suite                          1120/1120 (1097 + 23 nye)
  validate-plugin                250 PASS / 0 FAIL
  stikkprøve                     10 filer, alle 5 skills, inkl. de 3 mest
                                 produkt-tunge (26/20/19) — kun heading+TOC

Utenfor scope, urørt: de 4 SKILL.md, de 23 commands, CLAUDE.md, README.md,
NOTICE.md, docs/ (alt R14).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 22:12:28 +02:00

16 KiB

Agent Routing and Task Specialization

Last updated: 2026-02 Status: GA Category: Agent Orchestration & Automation Type: reference


Innhold

Introduksjon

Intelligent routing mellom spesialiserte agenter er en av de mest kritiske arkitekturbeslutningene i multi-agent-systemer. Istedenfor å bygge en "god nok til alt"-agent, deler man ansvarsområder mellom spesialiserte agenter som hver mestrer sitt domene. En router-agent eller orkestrator analyserer innkommende forespørsler og dirigerer dem til riktig spesialist basert på intent-klassifisering, kontekstuell matching og kapabilitets-deklarasjoner.

Microsoft Agent Framework og Semantic Kernel tilbyr flere routing-mekanismer gjennom orkestreringsmønstrene Handoff, Group Chat og Magentic. Handoff-mønsteret er spesielt designet for agent-til-agent delegering, der en agent kan overføre en samtale til en mer kvalifisert agent basert på brukerens behov. Group Chat bruker en manager-agent til å dirigere samtaler, mens Magentic bruker en planbasert tilnærming med dynamisk oppgavefordeling.

For komplekse enterprise-scenarier er routing-strategien avgjørende for brukeropplevelse, kostnadseffektivitet og systemets evne til å skalere. Feil routing betyr enten at brukeren møter en agent som ikke kan svare godt nok, eller at en dyr premium-modell brukes på enkle oppgaver. Riktig routing balanserer kvalitet, kostnad og responstid.

Kjernekomponenter

Komponent Formål Teknologi
Intent Classifier Klassifiser brukerens hensikt Azure AI Language, LLM-basert klassifisering
Capability Registry Registrer agent-kapabiliteter Agent manifest, Semantic Kernel plugins
Router Agent Dirigér forespørsler til rett agent Handoff orchestration, custom routing logic
Load Balancer Fordel last mellom agentinstanser Azure APIM, Azure Load Balancer
Fallback Handler Håndtér situasjoner der ingen agent matcher Default agent, human escalation
Skill Matcher Match oppgave-krav til agent-ferdigheter Semantic matching, capability scoring

Intent Classification Routing

LLM-basert intent-klassifisering

from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion

# Router-agent som klassifiserer intent og velger spesialist
ROUTER_PROMPT = """
Du er en routing-agent. Analyser brukerens forespørsel og klassifiser den.

Tilgjengelige agenter:
1. HR-Agent: Spørsmål om ansettelse, ferie, lønn, personalhåndbok
2. IT-Support-Agent: Tekniske problemer, tilganger, programvare
3. Økonomi-Agent: Faktura, budsjett, reiseregning, innkjøp
4. Juridisk-Agent: Kontrakter, personvern, compliance, anskaffelser
5. General-Agent: Alt annet

Svar med JSON:
{
    "intent": "<kort beskrivelse>",
    "target_agent": "<agent-navn>",
    "confidence": <0.0-1.0>,
    "reasoning": "<kort begrunnelse>"
}

Brukerforespørsel: {{$query}}
"""

async def route_query(kernel: Kernel, query: str) -> dict:
    result = await kernel.invoke_prompt(
        ROUTER_PROMPT,
        input_vars={"query": query}
    )
    routing = json.loads(str(result))

    # Fallback hvis confidence er lav
    if routing["confidence"] < 0.6:
        routing["target_agent"] = "General-Agent"
        routing["needs_clarification"] = True

    return routing

Azure AI Language for intent-klassifisering

# CLU (Conversational Language Understanding) for deterministisk routing
from azure.ai.language.conversations import ConversationAnalysisClient
from azure.core.credentials import AzureKeyCredential

client = ConversationAnalysisClient(
    endpoint=os.environ["LANGUAGE_ENDPOINT"],
    credential=AzureKeyCredential(os.environ["LANGUAGE_KEY"])
)

def classify_intent(query: str) -> dict:
    result = client.analyze_conversation(
        task={
            "kind": "Conversation",
            "analysisInput": {
                "conversationItem": {
                    "id": "1",
                    "participantId": "user",
                    "text": query
                }
            },
            "parameters": {
                "projectName": "agent-routing",
                "deploymentName": "production"
            }
        }
    )

    prediction = result["result"]["prediction"]
    return {
        "intent": prediction["topIntent"],
        "confidence": prediction["intents"][0]["confidenceScore"],
        "entities": prediction.get("entities", [])
    }

Agent Capability Matching

Capability Registry Pattern

// Definer agent-kapabiliteter som et registrer
public class AgentCapabilityRegistry
{
    private readonly List<AgentCapability> _capabilities = new();

    public void Register(AgentCapability capability)
    {
        _capabilities.Add(capability);
    }

    public AgentCapability FindBestMatch(
        string intent,
        Dictionary<string, string> context)
    {
        return _capabilities
            .Where(c => c.CanHandle(intent))
            .OrderByDescending(c => c.CalculateScore(intent, context))
            .FirstOrDefault();
    }
}

public class AgentCapability
{
    public string AgentName { get; set; }
    public string[] SupportedIntents { get; set; }
    public string[] RequiredEntities { get; set; }
    public string[] SupportedLanguages { get; set; }
    public int MaxComplexity { get; set; }  // 1-5
    public decimal CostPerRequest { get; set; }

    public bool CanHandle(string intent)
        => SupportedIntents.Any(i =>
            intent.Contains(i, StringComparison.OrdinalIgnoreCase));

    public double CalculateScore(
        string intent, Dictionary<string, string> context)
    {
        double score = 0;
        // Eksakt intent-match gir høy score
        if (SupportedIntents.Contains(intent)) score += 10;
        // Språkmatch
        if (SupportedLanguages.Contains(context.GetValueOrDefault("lang", "no")))
            score += 5;
        // Lavere kostnad gir bonus (for like-kapable agenter)
        score += (1.0 / (double)(CostPerRequest + 0.01));
        return score;
    }
}

// Registrering
var registry = new AgentCapabilityRegistry();
registry.Register(new AgentCapability
{
    AgentName = "HR-Specialist",
    SupportedIntents = new[] { "ferie", "lønn", "ansettelse", "permisjon" },
    RequiredEntities = new[] { "ansatt-id" },
    SupportedLanguages = new[] { "no", "en" },
    MaxComplexity = 3,
    CostPerRequest = 0.02m
});

Semantic Kernel Handoff Pattern

Handoff-mønsteret i Semantic Kernel er designet for agent-til-agent delegering:

from semantic_kernel.agents import ChatCompletionAgent, HandoffOrchestration
from semantic_kernel.agents.orchestration.handoffs import HandoffBuilder

# Definer spesialiserte agenter
triage_agent = ChatCompletionAgent(
    name="Triage",
    instructions="""
    Du er en triage-agent. Analyser brukerens forespørsel og
    overfør til riktig spesialist:
    - HR-spørsmål → transfer_to_hr
    - IT-problemer → transfer_to_it_support
    - Økonomi → transfer_to_finance
    """,
    kernel=kernel
)

hr_agent = ChatCompletionAgent(
    name="HR-Specialist",
    instructions="Du er en HR-ekspert. Svar på HR-relaterte spørsmål.",
    kernel=kernel
)

it_agent = ChatCompletionAgent(
    name="IT-Support",
    instructions="Du er IT-support. Hjelp med tekniske problemer.",
    kernel=kernel
)

# Konfigurer handoff-regler
handoffs = (
    HandoffBuilder()
    .add(source=triage_agent, target=hr_agent, description="HR-spørsmål")
    .add(source=triage_agent, target=it_agent, description="IT-problemer")
    .add(source=hr_agent, target=triage_agent, description="Ikke HR-relatert")
    .add(source=it_agent, target=triage_agent, description="Ikke IT-relatert")
    .build()
)

# Opprett orkestrering
orchestration = HandoffOrchestration(
    members=[triage_agent, hr_agent, it_agent],
    handoffs=handoffs
)

# Kjør
result = await orchestration.invoke(
    task="Hvordan søker jeg om foreldrepermisjon?",
    runtime=runtime
)

Load Balancing Strategies

Multi-instans agent routing via APIM

<!-- APIM policy for intelligent agent routing -->
<policies>
    <inbound>
        <!-- Klassifiser intent basert på header eller body -->
        <set-variable name="agentType"
            value="@{
                var body = context.Request.Body.As<JObject>();
                var query = body["query"]?.ToString() ?? "";
                if (query.Contains("HR") || query.Contains("ferie"))
                    return "hr-agent";
                if (query.Contains("IT") || query.Contains("tilgang"))
                    return "it-agent";
                return "general-agent";
            }" />

        <!-- Route til riktig backend basert på agent-type -->
        <choose>
            <when condition="@(context.Variables.GetValueOrDefault<string>("agentType") == "hr-agent")">
                <set-backend-service
                    backend-id="hr-agent-pool" />
            </when>
            <when condition="@(context.Variables.GetValueOrDefault<string>("agentType") == "it-agent")">
                <set-backend-service
                    backend-id="it-agent-pool" />
            </when>
            <otherwise>
                <set-backend-service
                    backend-id="general-agent-pool" />
            </otherwise>
        </choose>
    </inbound>
</policies>

Fallback Routing

Graceful degradation ved routing-feil

class FallbackRouter:
    """Router med multi-level fallback"""

    def __init__(self, agents: dict, default_agent: str):
        self.agents = agents
        self.default = default_agent
        self.escalation_threshold = 2  # Maks antall re-routes

    async def route(self, query: str, context: dict) -> AgentResponse:
        attempts = 0
        current_agent = self._classify_and_select(query)

        while attempts < self.escalation_threshold:
            try:
                response = await self.agents[current_agent].invoke(query)

                # Sjekk om agenten selv indikerer at den ikke kan svare
                if response.confidence < 0.4:
                    attempts += 1
                    current_agent = self._get_fallback(current_agent)
                    continue

                return response

            except AgentUnavailableError:
                attempts += 1
                current_agent = self._get_fallback(current_agent)

        # Ultimat fallback: default agent eller menneskelig eskalering
        return await self.agents[self.default].invoke(query)

    def _get_fallback(self, current: str) -> str:
        fallback_chain = {
            "HR-Specialist": "General-Agent",
            "IT-Support": "General-Agent",
            "Økonomi-Agent": "General-Agent",
            "General-Agent": "Human-Escalation"
        }
        return fallback_chain.get(current, self.default)

Specialization Hierarchies

Tre-nivå spesialiseringshierarki

                    ┌──────────────┐
                    │   Triage     │  L0: Intent classification
                    │   Router     │
                    └──────┬───────┘
                           │
            ┌──────────────┼──────────────┐
            │              │              │
    ┌───────▼──────┐ ┌────▼────┐ ┌──────▼───────┐
    │  HR Domain   │ │   IT    │ │   Finance    │  L1: Domain
    │  Agent       │ │  Agent  │ │   Agent      │
    └───────┬──────┘ └────┬────┘ └──────┬───────┘
            │              │              │
    ┌───────▼──────┐      │       ┌──────▼───────┐
    │ Rekruttering │      │       │   Faktura    │  L2: Specialist
    │ Onboarding   │      │       │   Budsjett   │
    │ Permisjon    │      │       │   Innkjøp    │
    └──────────────┘      │       └──────────────┘
                          │
                   ┌──────▼───────┐
                   │ Nettverks-   │  L2: Specialist
                   │ Applikasjons-│
                   │ Tilgangs-    │
                   └──────────────┘

Norsk offentlig sektor

Routing-hensyn for offentlig sektor

Aspekt Krav Implementering
Sakstype-basert routing Ulike sakstyper krever ulik behandling Map sakstyper til agent-spesialister
Sikkerhetsnivå Gradert informasjon krever spesielle agenter Rout gradert info til isolerte agenter
Språk Bokmål, nynorsk, samisk Språkdeteksjon i router + dedikerte agenter
Arkivering Alle agent-interaksjoner skal journalføres Logging av routing-beslutninger
Innsynsrett Borgere har rett til innsyn i saksbehandling Dokumentér hvilken agent som behandlet saken

Eksempel: Norsk kommune agent-routing

KOMMUNE_AGENT_MAP = {
    "byggesak": {
        "agent": "byggesak-agent",
        "model": "gpt-4o",  # Kompleks regulering
        "knowledge": ["plan-og-bygningsloven", "kommuneplan"],
        "requires_human_review": True
    },
    "barnehageplass": {
        "agent": "barnehage-agent",
        "model": "gpt-4o-mini",  # Enklere forespørsler
        "knowledge": ["barnehageloven", "lokale-vedtekter"],
        "requires_human_review": False
    },
    "sosialtjenester": {
        "agent": "sosial-agent",
        "model": "gpt-4o",  # Sensitive opplysninger
        "knowledge": ["sosialtjenesteloven", "NAV-retningslinjer"],
        "requires_human_review": True,
        "data_classification": "fortrolig"
    }
}

Beslutningsrammeverk

Scenario Anbefaling Begrunnelse
< 5 agenttyper, lavt volum Enkel LLM-basert router Lav kompleksitet, rask å implementere
5-20 agenttyper, middels volum CLU + capability registry Deterministisk + skalerbar
> 20 agenttyper, høyt volum APIM-basert routing + hierarkisk Ytelse + kostnadseffektivitet
Sensitive domener med compliance Handoff med human-in-the-loop Sikkerhet + etterprøvbarhet
Dynamisk agentøkosystem Capability advertisement + discovery Agenter kan registreres/fjernes uten kodeendring

For arkitekten

  • Handoff-mønsteret i Semantic Kernel er den mest naturlige routing-mekanismen for multi-agent-systemer -- triage-agenten klassifiserer og delegerer, spesialistene behandler.
  • Kombiner LLM-basert og deterministisk routing for best resultat: Bruk CLU for kjente intenter med høy volum, LLM for edge cases og nye scenarier.
  • Capability Registry er nøkkelen til skalerbar arkitektur -- nye agenter registrerer sine kapabiliteter, og routeren oppdager dem automatisk uten kodeendringer.
  • Fallback er like viktig som routing -- design alltid en graceful degradation-kjede fra spesialist via generalist til menneskelig eskalering.
  • For norsk offentlig sektor: Map sakstyper til agenter, respekter sikkerhetsnivåer i routing, og sørg for at alle routing-beslutninger logges for etterprøvbarhet.