◆ Output Preview
Guide d'Architecture et Prompt Engineering
0. État Actuel de Notre Système
Ce qui existe déjà
Architecture modulaire (déjà en place) :
- 15+ fichiers
.mddansshared/prompts/(numérotés 01-99) - 6 prompts agent-spécifiques dans
shared/prompts/agents/ - Système de chargement dynamique :
load_system_prompt(exclude_patterns=...) - Factory pattern :
create_agent(name, instructions, model, tools) - Filtrage manuel des tools :
get_mcp_tools_by_names(["snow", "grafana"]) - Workflows séquentiels avec gates d'eligibilité
Problèmes actuels
1. Duplication massive de contexte
12.sre.md(enrichment) vs16.sre_resolution.md(resolution) : 80% de duplication- Contexte Michelin (
01.instructions.md) répété dans plusieurs compositions - Pour changer un comportement → modifier 2-4 fichiers différents
2. Scalabilité limitée
- Ajouter un nouveau scénario = créer de nouveaux fichiers
- Pas de template réutilisable
- Risque d'incohérence entre scénarios similaires
1. Vision Cible
Principes d'Architecture (inspirés de Semantic Kernel, AutoGen, Alpha Berkeley)
Les grandes entreprises convergent vers :
- Composition déclarative : assembler le contexte via configuration, pas via code
- Context as versioned artifacts : blocs de contexte versionnés et testables
- Skill registry : registre centralisé des capacités avec métadonnées
- Single source of truth : un bloc = un fichier, pas de duplication
- Lazy loading : charger uniquement le contexte nécessaire
- Observabilité : traçabilité de ce qui est injecté dans chaque requête
C. Skill Registry pour MCP Tools
Distinction Importante
| Concept | Définition | Usage |
|---|---|---|
| MCP (Model Context Protocol) | Protocole d'échange | Couche technique |
| Skill | Capacité métier documentée | Couche sémantique |
Problème actuel : Trop d'investissement dans le protocole, pas assez dans la documentation des capacités.
Créer un Registre de Skills
Fichier : mcp-servers/mcp_skills_registry.json
graph TB
Registry["Skill Registry<br/>mcp_skills_registry.json"]
subgraph SNOW["bibops_mcp_snow"]
SNOW_Name["ServiceNow Operations"]
SNOW_Desc["Query/update ServiceNow tables"]
SNOW_Use["When: incidents, changes, CMDB"]
SNOW_Limit["Limits: 5 results max, 30s timeout"]
SNOW_Cost["Cost: medium"]
end
subgraph GRAFANA["bibops_mcp_grafana"]
GRAF_Name["Grafana Monitoring"]
GRAF_Desc["Query Prometheus, Loki, Azure Monitor"]
GRAF_Use["When: metrics, logs, alerts"]
GRAF_Limit["Limits: 7 days max, 60s timeout"]
GRAF_Cost["Cost: high"]
end
subgraph SPLUNK["bibops_mcp_splunk"]
SPL_Name["Splunk Logs"]
SPL_Use["When: log analysis, search"]
SPL_Limit["Limits: 10 results, indexing"]
end
Registry --> SNOW
Registry --> GRAFANA
Registry --> SPLUNK
Registry -.-> Others["... 11 autres MCP servers"]
style Registry fill:#e1f5ff
style SNOW fill:#fff4e1
style GRAFANA fill:#ffe1f5
style SPLUNK fill:#e1ffe1
Sélection Dynamique des Tools
graph LR
subgraph Phase1["Phase 1: Manuel (actuel)"]
Code1["Code Python hardcodé"] --> Tools1["tools = [snow, grafana]"]
end
subgraph Phase2["Phase 2: Déclaratif (court terme)"]
YAML["YAML Scénario"] --> Required["Required: [snow]"]
YAML --> Optional["Optional: [grafana, splunk]"]
end
subgraph Phase3["Phase 3: Intelligent (long terme)"]
Incident["Incident Description<br/>Database timeout"] --> Classifier["LLM Classifier"]
Registry2["Skill Registry"] --> Classifier
Classifier --> Selected["Selected: [snow, grafana, splunk]<br/>Rejected: [ldap, 4ip]"]
end
Phase1 -.->|"Migration"| Phase2
Phase2 -.->|"Évolution"| Phase3
style Phase1 fill:#ffe1e1
style Phase2 fill:#fff4e1
style Phase3 fill:#e1ffe1
Bénéfices :
- Documentation centralisée des capacités
- Réduction du contexte (moins de tools injectés)
- Moins d'hallucinations (descriptions claires)
- Meilleure traçabilité (pourquoi ce tool ?)
Comment les Skills sont Introduits aux Agents
sequenceDiagram
participant YAML as Scénario YAML
participant Loader as Prompt Loader
participant Registry as Skill Registry
participant PromptParts as Prompt Builder
participant MCPTools as MCP Tool Loader
participant Agent as Agent Final
YAML->>Loader: scenarios/incident_enrichment.yaml<br/>(composition + tools + skill_context:true)
Loader->>PromptParts: Charger blocs de base<br/>(core/**, domain/**, roles/**)
alt skill_context = true
Loader->>Registry: load_skill_documentation([snow, grafana, splunk])
Registry-->>Loader: Doc formatée des 3 skills
Loader->>PromptParts: Ajouter doc skills au prompt
end
Loader->>MCPTools: get_mcp_tools_by_names([snow, grafana, splunk])
MCPTools-->>Loader: 3 MCP Tool instances
Loader->>Agent: Créer Agent<br/>Instructions: prompt complet<br/>Tools: 3 MCP tools
Note over Agent: Agent avec contexte enrichi<br/>+ documentation des tools
Agent->>MCPTools: Utilise tools avec meilleur contexte
Avantages de cette approche :
graph TB
subgraph Avec_skill_context_true["skill_context: true"]
Context1["Contexte dynamique<br/>Seuls 3/14 tools documentés"]
Single1["Single source of truth<br/>Registry JSON unique"]
Reduce1["Réduction contexte<br/>Doc ciblée"]
Maintain1["Maintenabilité<br/>1 changement = 1 fichier"]
end
subgraph Avec_skill_context_false["skill_context: false (actuel)"]
Context2["Pas de surcharge prompt"]
Light2["Tools chargés sans doc"]
Registry2["Registry pour sélection<br/>Phase 3 uniquement"]
end
Choice{"Besoin de guidance<br/>pour l'agent ?"}
Choice -->|"Oui<br/>Agent complexe"| Avec_skill_context_true
Choice -->|"Non<br/>Économie contexte"| Avec_skill_context_false
style Avec_skill_context_true fill:#e1ffe1
style Avec_skill_context_false fill:#ffe1e1
Recommandation :
- Phase 1 :
skill_context: false(pas de surcharge du prompt) - Phase 2 :
skill_context: truepour les agents complexes qui ont besoin de guidance - Le registry sert d'abord à documenter pour les humains, puis éventuellement à enrichir le prompt
3. Scalabilité et Nouveaux Scénarios
Architecture Actuelle
Workflows existants :
- Incident Enrichment : 3 agents (eligibility → solver → validator)
- Incident Resolution : 3 agents (eligibility → resolution_solver → validator)
- Change Impact : 3 agents (eligibility → analyzer → report_generator)
Total actuel : 3 workflows × 3 agents = 9 configurations d'agents
Problème de Scalabilité
graph TB
subgraph Current["Approche Actuelle: Explosion Exponentielle"]
direction LR
W1["3 Workflows actuels"] --> A1["9 configurations d'agents"]
Variations["Variations souhaitées:<br/>• Incident réseau<br/>• Incident database<br/>• Incident cloud<br/>• Change multi-user<br/>• Validation externe<br/>..."]
W2["10 Workflows"] --> A2["30 agents à maintenir"]
Problem["Problème:<br/>Duplication massive<br/>Maintenance impossible"]
A2 --> Problem
end
subgraph Proposed["Approche Proposée: Composition"]
direction LR
Core["10 blocs core<br/>(réutilisés)"]
Domain["15 blocs domain<br/>(combinables)"]
Roles["8 blocs roles<br/>(réutilisables)"]
Behaviors["6 blocs behaviors<br/>(modificateurs)"]
YAML["10 fichiers YAML<br/>(scénarios)"]
Core --> YAML
Domain --> YAML
Roles --> YAML
Behaviors --> YAML
Solution["Solution:<br/>Réutilisation maximale<br/>Maintenance simple"]
YAML --> Solution
end
Current -.->|"Migration vers"| Proposed
style Problem fill:#ffe1e1
style Solution fill:#e1ffe1
Exemple : Ajouter un Nouveau Scénario
Besoin : Analyse d'incident réseau spécifique
graph TB
subgraph Actuel["Approche Actuelle"]
direction TB
A1["1. network_eligibility_checker.py"]
A2["2. network_incident_solver.py"]
A3["3. network_validator.py"]
A4["4. prompts/agents/network_solver.md<br/>(copie de 12.sre.md - DUPLICATION)"]
A5["5. crews/network_incident_resolution.py"]
A1 --> A2 --> A3 --> A4 --> A5
Result1["Total: 5 fichiers<br/>Beaucoup de duplication<br/>Code Python + Prompts"]
A5 --> Result1
end
subgraph Propose["Approche Proposée"]
direction TB
P1["1. domain/network/troubleshooting.md<br/>(nouvelles spécificités uniquement)"]
P2["2. scenarios/network_incident.yaml<br/>(composition déclarative)"]
P1 --> P2
Reuse["Réutilise:<br/>✓ core/**<br/>✓ domain/servicenow/**<br/>✓ roles/sre_investigator.md<br/>✓ behaviors/with_resolution.md"]
P2 --> Reuse
Result2["Total: 2 fichiers<br/>Zéro duplication<br/>Réutilisation maximale"]
Reuse --> Result2
end
Compare["Gain: 5 → 2 fichiers<br/>Maintenance -60%"]
Actuel -.->|"vs"| Compare
Propose -.->|"vs"| Compare
style Actuel fill:#ffe1e1
style Propose fill:#e1ffe1
style Compare fill:#e1f5ff
4. Architecture Cible en Couches
Layer 1 : Contexte (Prompts)
- Core : Blocs de base (Michelin, personality, tools best practices)
- Domain : Contexte métier par domaine (ServiceNow, monitoring, infrastructure)
- Roles : Rôles réutilisables (investigator, validator, analyzer)
- Behaviors : Modificateurs (enrichment_only, with_resolution, conversational)
- Scenarios : Assemblage déclaratif (YAML)
Layer 2 : Skills (MCP Tools)
- Registry : Documentation centralisée (
mcp_skills_registry.json) - MCP Servers : 14 serveurs existants (snow, grafana, splunk, etc.)
- Dynamic Loading : Chargement selon scénario (via YAML)
Layer 3 : Orchestration (Workflows)
- Sequential Execution : Workflows 3-agents existants (à conserver)
- Gates : Eligibility checks entre agents
- Error Handling : Classification et retry logic
Layer 4 : Observabilité
- Structured Logging : Déjà en place via
shared/observability.py - Context Snapshots : À améliorer (capturer le prompt final envoyé)
- Metadata Tracking : Déjà en place via
shared/metadata.py
Layer 5 : Interfaces
- API REST :
api_server.py(JSON structuré) - Teams Bot :
teamsbot/(conversationnel) - AG-UI :
frontend/(CopilotKit web)
5. Diagramme d'Architecture
flowchart TB
%% =========================
%% USER INPUT
%% =========================
User["User / Event Trigger"] --> Orchestrator
%% =========================
%% ORCHESTRATION LAYER
%% =========================
subgraph Orchestration_Layer
Orchestrator["Central Orchestrator<br/>Plan-First Execution<br/>Checkpointing<br/>Error Handling"]
Plan["Execution Plan - DAG"]
end
Orchestrator --> Plan
%% =========================
%% CONTEXT LAYER
%% =========================
subgraph Context_Layer
ContextAssembler["Context Assembler<br/>Runtime Prompt Builder"]
subgraph Context_Blocks
CompanyContext["Company Base Context"]
ToneContext["Tone and Style"]
MissionContext["Mission Specific Context"]
RoleTemplate["Role Template"]
OutputTemplate["Output Format Template"]
end
VectorDB[("Vector Database<br/>Long-Term Memory")]
end
ContextAssembler --> CompanyContext
ContextAssembler --> ToneContext
ContextAssembler --> MissionContext
ContextAssembler --> RoleTemplate
ContextAssembler --> OutputTemplate
ContextAssembler --> VectorDB
%% =========================
%% AGENT LAYER
%% =========================
subgraph Agent_Layer
Agent1["Agent 1 - Analysis"]
Agent2["Agent 2 - Validation"]
Agent3["Agent 3 - Formatting"]
end
Orchestrator --> Agent1
Agent1 --> Agent2
Agent2 --> Agent3
Agent1 --> ContextAssembler
Agent2 --> ContextAssembler
Agent3 --> ContextAssembler
%% =========================
%% SKILL LAYER
%% =========================
subgraph Skill_Layer
SkillRegistry["Skill Registry<br/>JSON Schema + Versioning"]
subgraph Business_APIs
API1["Eligibility API"]
API2["Search API"]
API3["Database API"]
end
end
Agent1 --> SkillRegistry
Agent2 --> SkillRegistry
Agent3 --> SkillRegistry
SkillRegistry --> API1
SkillRegistry --> API2
SkillRegistry --> API3
%% =========================
%% OBSERVABILITY
%% =========================
subgraph Observability
Logs["Structured Logs"]
Snapshots["Context Snapshots"]
Metrics["Monitoring and Metrics"]
end
Orchestrator --> Logs
Orchestrator --> Snapshots
Orchestrator --> Metrics
6. Architecture de Dossiers Proposée
Structure Actuelle (à migrer)
shared/prompts/
├── 01.instructions.md
├── 02.personality.md
├── 03.tools_preamble.md
├── ...
├── 99.final_answer_formatting.md
└── agents/
├── eligibility_checker.md
├── validator.md
└── ...
Structure Cible (alignée avec notre architecture)
shared/prompts/
│
├── core/
│ ├── 01.michelin_context.md
│ ├── 02.personality.md
│ ├── 03.tools_best_practices.md
│ ├── 04.planning.md
│ ├── 05.task_execution.md
│ └── 06.output_formatting.md
│
├── domain/
│ ├── servicenow/
│ │ ├── tables_reference.md
│ │ ├── query_limits.md
│ │ ├── kb_search.md
│ │ └── service_matching.md
│ │
│ ├── monitoring/
│ │ ├── splunk_indexes.md
│ │ ├── grafana_datasources.md
│ │ └── log_analysis_tips.md
│ │
│ ├── infrastructure/
│ │ ├── deploy_plans.md
│ │ ├── environments.md
│ │ ├── sites.md
│ │ └── networking.md
│ │
│ └── access_management/
│ ├── ldap_structure.md
│ └── group_memberships.md
│
├── roles/
│ ├── eligibility_validator.md
│ ├── output_validator.md
│ ├── impact_analyzer.md
│ └── report_generator.md
│
├── behaviors/
│ ├── enrichment_only.md
│ ├── with_resolution.md
│ ├── user_scoped.md
│ ├── conversational_mode.md
│ ├── structured_output.md
│ └── tool_preambles.md
│
├── scenarios/
│ ├── incident_enrichment.yaml
│ ├── incident_resolution.yaml
│ ├── change_impact.yaml
│ ├── sre_agent_interactive.yaml
│ └── teams_bot.yaml
│
├── __init__.py
└── README.md
mcp-servers/
│
├── mcp_skills_registry.json
│
├── skills/
│ ├── snow.md
│ ├── grafana.md
│ ├── splunk.md
│ ├── ldap.md
│ ├── 4ip.md
│ ├── abs.md
│ ├── d4x.md
│ ├── gitlab.md
│ ├── gravitee.md
│ ├── sli.md
│ ├── ad.md
│ ├── dgd.md
│ ├── inventory.md
│ └── networktools.md
│
├── mcp-snow/
├── mcp-grafana/
├── mcp-splunk/
└── ...
Exemple de Composition YAML
graph TB
subgraph Scenario1["scenarios/incident_enrichment.yaml"]
direction TB
subgraph Agent1["0ps_Eligibility_Checker (mini)"]
A1_Core1["core/01.michelin_context.md"]
A1_Core2["core/02.personality.md"]
A1_Domain["domain/servicenow/query_limits.md"]
A1_Role["roles/eligibility_validator.md"]
A1_Tools["Tools: [snow]"]
end
subgraph Agent2["0ps_Incident_Solver (premium)"]
A2_Core1["core/01.michelin_context.md"]
A2_Core2["core/02.personality.md"]
A2_Core3["core/03.tools_best_practices.md"]
A2_Domain["domain/servicenow/**<br/>domain/monitoring/**"]
A2_Role["roles/sre_investigator.md"]
A2_Behavior["behaviors/enrichment_only.md"]
A2_Tools["Tools: [snow, grafana, splunk, ldap, 4ip]"]
end
subgraph Agent3["0ps_Validator (mini)"]
A3_Core["core/02.personality.md"]
A3_Role["roles/output_validator.md"]
A3_Tools["Tools: [snow]"]
end
end
subgraph Scenario2["scenarios/incident_resolution.yaml"]
direction TB
subgraph Agent4["0ps_Resolution_Solver (premium)"]
A4_Core["core/** (identique)"]
A4_Domain2["domain/** (identique)"]
A4_Role2["roles/sre_investigator.md (identique)"]
A4_Behavior["behaviors/with_resolution.md"]
A4_Tools2["Tools: (identique)"]
end
end
Diff["Différence clé:<br/>enrichment_only.md<br/>vs<br/>with_resolution.md"]
A2_Behavior -.->|"Enrichment"| Diff
A4_Behavior -.->|"Resolution"| Diff
style A2_Behavior fill:#ffe1e1
style A4_Behavior fill:#e1ffe1
style Diff fill:#e1f5ff
Points clés :
- Réutilisation maximale : core, domain, roles identiques entre scénarios
- Différence minimale : 1 seul fichier behavior change (enrichment vs resolution)
- Composition déclarative : YAML décrit l'assemblage, pas de code Python