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

418 lines
16 KiB
Markdown

# Agent Routing and Task Specialization
**Last updated:** 2026-02
**Status:** GA
**Category:** Agent Orchestration & Automation
**Type:** reference
---
## Innhold
- [Introduksjon](#introduksjon)
- [Kjernekomponenter](#kjernekomponenter)
- [Intent Classification Routing](#intent-classification-routing)
- [Agent Capability Matching](#agent-capability-matching)
- [Semantic Kernel Handoff Pattern](#semantic-kernel-handoff-pattern)
- [Load Balancing Strategies](#load-balancing-strategies)
- [Fallback Routing](#fallback-routing)
- [Specialization Hierarchies](#specialization-hierarchies)
- [Norsk offentlig sektor](#norsk-offentlig-sektor)
- [Beslutningsrammeverk](#beslutningsrammeverk)
- [For arkitekten](#for-arkitekten)
## 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
```python
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
```python
# 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
```csharp
// 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:
```python
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
```xml
<!-- 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
```python
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
```python
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.