feat(ultraplan-local): v1.6.0 — /ultraresearch-local deep research command
Add /ultraresearch-local for structured research combining local codebase analysis with external knowledge via parallel agent swarms. Produces research briefs with triangulation, confidence ratings, and source quality assessment. New command: /ultraresearch-local with modes --quick, --local, --external, --fg. New agents: research-orchestrator (opus), docs-researcher, community-researcher, security-researcher, contrarian-researcher, gemini-bridge (all sonnet). New template: research-brief-template.md. Integration: --research flag in /ultraplan-local accepts pre-built research briefs (up to 3), enriches the interview and exploration phases. Planning orchestrator cross-references brief findings during synthesis. Design principle: Context Engineering — right information to right agent at right time. Research briefs are structured artifacts in the pipeline: ultraresearch → brief → ultraplan --research → plan → ultraexecute. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
baa2d0220b
488 changed files with 213221 additions and 0 deletions
|
|
@ -0,0 +1,403 @@
|
|||
# Agent Routing and Task Specialization
|
||||
|
||||
**Last updated:** 2026-02
|
||||
**Status:** GA
|
||||
**Category:** Agent Orchestration & Automation
|
||||
|
||||
---
|
||||
|
||||
## 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 Cosmo
|
||||
|
||||
- **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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue