Voir aussi : Exemple complet · Inventaire outils · Retour à l'index
Guide de portage — Méthodologie en 5 étapes
Ce guide détaille la méthodologie pour porter une application .NET existante vers une architecture d'équipes d'agents Orkeon.
Vue d'ensemble
Le portage consiste à décomposer les responsabilités d'une application monolithique ou modulaire en rôles d'agents spécialisés, équipés d'outils, et orchestrés par une ou plusieurs Crews.
Application source → Analyse des responsabilités → Mapping vers agents
→ Identification des outils → Définition des tasks → Plan de portage
Choix de l'approche : YAML-first ou Code-first
Orkeon supporte deux approches pour définir une crew. Le choix impacte le workflow de portage.
| Critère | YAML-first | Code-first (Fluent Builder) |
|---|---|---|
| Modification sans recompilation | Oui — éditer le YAML suffit | Non — recompilation nécessaire |
| Type safety | Validation au runtime (CrewFactory) | Validation à la compilation |
| Prompt engineering itératif | Rapide — éditer descriptions/backstories | Plus lent |
| Outils custom avec dépendances | Nécessite enregistrement DI séparé | Instanciation directe possible |
| Partage de configurations | Fichier YAML portable | Code C# à intégrer |
| Exemples de référence | 100+ exemples YAML dans examples/ (voir l'examples/INDEX.md généré) |
Builders documentés dans la doc |
Recommandation : privilégier l'approche YAML-first pour le portage. Le YAML permet d'itérer rapidement sur les prompts (descriptions, backstories) sans toucher au code. Les outils custom restent en C# et sont enregistrés via DI.
Workflow YAML-first
1. Écrire config.yaml (agents, tasks, process type)
2. Identifier les outils manquants
3. Coder les outils custom (ToolBase<TReq, TRes>)
4. Enregistrer via DI (AddSingleton<IBaseTool, MonTool>()) — **et** un registre
adossé à la DI, sans lequel les noms YAML se résolvent contre le stub vide :
services.AddSingleton<IToolRegistry, ServiceProviderToolRegistry>()
(Orkeon.Hosting ; orkeon run le fait pour vous)
5. Charger et exécuter :
var crew = await crewFactory.CreateFromFileAsync("config.yaml");
var output = await orchestrator.KickoffAsync(crew.Id, input);
6. Itérer sur les prompts dans le YAML
Étape 1 — Analyser les responsabilités de l'application source
1.1 Inventorier les composants
Lister tous les services, controllers, handlers et modules de l'application. Pour chaque composant, noter sa responsabilité principale, ses dépendances entrantes et sortantes, et le type de données qu'il manipule.
1.2 Identifier les flux de données
Tracer le parcours des données à travers l'application : d'où viennent-elles (fichiers, API, base de données), quelles transformations subissent-elles, où arrivent-elles (stockage, API, UI).
1.3 Classer les responsabilités
Catégoriser chaque responsabilité selon cette grille :
| Catégorie | Description | Exemples |
|---|---|---|
| Collecte | Acquisition de données depuis des sources externes | Appels API, lecture fichiers, scraping web, requêtes BDD |
| Analyse | Traitement, transformation, enrichissement des données | Parsing, calculs, agrégations, détection de patterns |
| Décision | Logique métier, règles, routing conditionnel | Validation, scoring, classification, priorisation |
| Production | Génération d'artefacts de sortie | Rapports, emails, fichiers, réponses API |
| Coordination | Orchestration de sous-processus | Workflow management, séquencement, parallélisation |
1.4 Identifier les interactions humaines
Repérer les points où l'application nécessite une intervention humaine (validation, saisie, approbation). Ces points deviendront des tasks avec HumanInput = true dans Orkeon.
Étape 2 — Mapper les responsabilités vers des rôles d'agents
2.1 Principes de découpage
Un bon agent Orkeon respecte ces principes :
- Responsabilité unique : chaque agent a un rôle clair et spécialisé (défini par
AgentRole) - Objectif mesurable : l'objectif (
AgentGoal) décrit un résultat concret et vérifiable - Autonomie : l'agent doit pouvoir accomplir ses tasks avec ses outils sans dépendre d'un autre agent pour chaque opération
- Granularité appropriée : ni trop large (agent "fait tout") ni trop fin (agent qui fait une seule opération triviale)
2.2 Template de mapping
Pour chaque responsabilité identifiée en Étape 1, remplir ce template :
Responsabilité source : [description]
→ Rôle agent : [AgentRole — nom concis du spécialiste]
→ Objectif agent : [AgentGoal — résultat attendu]
→ Backstory : [AgentBackstory — contexte et expertise]
→ Outils nécessaires : [liste des outils]
→ Contraintes : [MaxIterations, MaxRpm, AllowDelegation]
2.3 Patterns de mapping courants
| Pattern source | Mapping Orkeon |
|---|---|
| Service qui lit et transforme des données | Agent "Data Analyst" avec outils fichier/BDD |
| Service qui appelle des API externes | Agent "API Integrator" avec HttpApiTool |
| Service qui génère des rapports | Agent "Report Writer" avec FileWriteTool |
| Controller qui orchestre un workflow | Crew avec ProcessType.Sequential |
| Service de validation / review | Agent "Quality Reviewer" avec validation output JSON |
| Scheduler / batch processor | Crew avec KickoffForEachAsync (batch) |
| Service avec logique de branching complexe | Crew Hierarchical avec LlmBasedManager |
2.4 Quand créer un agent vs. un outil
| Créer un agent quand... | Créer un outil quand... |
|---|---|
| La responsabilité nécessite du raisonnement, de l'analyse ou de la créativité | L'opération est déterministe et mécanique |
| Le résultat varie selon le contexte et les données | L'opération suit toujours le même algorithme |
| Plusieurs étapes de réflexion sont nécessaires | C'est une opération atomique (entrée → sortie) |
| L'interaction avec un LLM apporte de la valeur | Un LLM n'apporterait rien de plus qu'un algorithme |
Étape 3 — Identifier les outils nécessaires
3.1 Inventorier les besoins en outils
Pour chaque agent défini en Étape 2, lister les opérations concrètes qu'il doit effectuer. Pour chaque opération, vérifier si un outil existant la couvre (voir Inventaire des outils).
3.2 Matrice de décision : réutiliser vs. créer
| Critère | Réutiliser l'existant | Créer un nouvel outil |
|---|---|---|
| L'opération est couverte par un outil Orkeon | Oui | — |
| L'opération existante est presque adaptée mais manque un paramètre | Envisager une contribution/extension | — |
| L'opération nécessite un appel à une API métier spécifique | — | Oui — hériter de HttpToolBase<> |
| L'opération manipule un format de fichier non supporté | — | Oui — hériter de FileToolBase<> |
| L'opération est un calcul métier pur | — | Oui — hériter de ToolBase<> |
3.3 Outils existants par besoin courant
| Besoin | Outil existant | Package |
|---|---|---|
| Lire un fichier texte/JSON/XML | FileReadTool |
Orkeon.Tools.FileSystem |
| Écrire un fichier | FileWriteTool |
Orkeon.Tools.FileSystem |
| Lister un répertoire | DirectoryReadTool |
Orkeon.Tools.FileSystem |
| Rechercher dans des fichiers | DirectorySearchTool |
Orkeon.Tools.FileSystem |
| Lire un CSV | CsvReaderTool |
Orkeon.Tools.Data |
| Lire un PDF | PdfReaderTool |
Orkeon.Tools.Data |
| Lire un DOCX | DocxReadTool |
Orkeon.Tools.Data |
| Lire / écrire un Excel (.xlsx) | XlsxReadTool / XlsxWriteTool |
Orkeon.Tools.Data |
| Manipuler du JSON | JsonTool |
Orkeon.Tools.Data |
| Requête SQL | RelationalDatabaseTool |
Orkeon.Tools.Data |
| Requête MongoDB | MongoDbTool |
Orkeon.Tools.Data |
| Recherche web | WebSearchTool / BraveSearchTool |
Orkeon.Tools.Web |
| Scraping web | WebScrapeTool |
Orkeon.Tools.Web |
| Appel API REST | HttpApiTool |
Orkeon.Tools.Web |
| Exécuter du code C# | SecureCodeInterpreterTool |
Orkeon.Infrastructure |
| Demander à un collègue | AskQuestionTool |
Orkeon.Infrastructure |
| Déléguer une tâche | DelegateWorkTool |
Orkeon.Infrastructure |
| Recherche sémantique | SearchTool |
Orkeon.Infrastructure |
| RAG sur documents | RagSearchTool |
Orkeon.Tools.Rag (opt-in : AddOrkeonRag + AddOrkeonRagTools) |
Étape 4 — Définir les tasks et le flux d'orchestration
4.1 Décomposer en tasks
Chaque sortie attendue de la crew devient une CrewTask. Une task est définie par sa TaskDescription (ce que l'agent doit faire) et son ExpectedOutput (format et contenu du résultat attendu).
4.2 Choisir le ProcessType
| Situation | ProcessType recommandé |
|---|---|
| Les étapes doivent s'enchaîner, chaque sortie alimentant l'entrée suivante | Sequential |
| Un manager doit router dynamiquement les tasks vers les agents les plus compétents | Hierarchical |
| Plusieurs tâches indépendantes peuvent s'exécuter simultanément | Parallel |
| Les agents doivent voter et atteindre un consensus | Consensual |
4.3 Définir les dépendances
Utiliser CrewTaskBuilder.DependsOn() pour exprimer les pré-requis entre tasks. En mode Sequential, l'ordre de déclaration suffit. En mode Parallel, les dépendances explicites contrôlent le séquencement.
4.4 Configurer les options d'exécution
Pour chaque task, décider de : la priorité (TaskPriority), l'exécution asynchrone (AsyncExecution), l'intervention humaine (HumanInput), le schéma de validation de sortie (OutputJson), le fichier de sortie (OutputFile).
Étape 5 — Produire le plan de portage
5.1 Template du plan
| Composant source | Responsabilité | Agent cible | Rôle | Outil(s) requis | Statut | Effort |
|---|---|---|---|---|---|---|
OrderService |
Validation commandes | Order Validator | "Order Validation Specialist" | RelationalDatabaseTool, outil custom ValidateOrderTool |
À créer (outil custom) | M |
PricingEngine |
Calcul des prix | Pricing Analyst | "Pricing Specialist" | CsvReaderTool, JsonTool |
Prêt (outils existants) | S |
| ... | ... | ... | ... | ... | ... | ... |
5.2 Légende effort
| Code | Signification | Durée estimée |
|---|---|---|
| XS | Mapping direct vers outil existant, aucun code | < 1h |
| S | Agent simple avec outils existants | 1-4h |
| M | Agent + 1 outil custom simple | 0.5-1 jour |
| L | Agent + outil custom complexe ou intégration externe | 1-3 jours |
| XL | Refactoring significatif, multiple outils custom | > 3 jours |
5.3 Colonnes Statut
| Statut | Signification |
|---|---|
| Prêt | Tous les outils existent, configuration uniquement |
| À créer (outil) | Un ou plusieurs outils custom doivent être développés |
| À créer (agent) | L'agent nécessite un backstory/prompt engineering spécifique |
| Bloqué | Dépendance externe non résolue |
5.4 Checklist de validation du plan
Avant de démarrer l'implémentation, vérifier que :
- Chaque responsabilité de l'application source est couverte par au moins un agent
- Chaque agent a au moins une task assignée
- Toutes les dépendances entre tasks sont explicites
- Les outils manquants sont identifiés avec un effort estimé
- Le
ProcessTypeest justifié par la nature du workflow - Les points d'intervention humaine sont identifiés (
HumanInput = true) - La mémoire est activée si le contexte inter-tasks est nécessaire (
EnableMemory(true)) - Les contraintes de rate limiting (
MaxRpm) sont compatibles avec les API externes utilisées
5.5 Setup DI minimal pour le portage
Tout portage nécessite ce setup d'injection de dépendances :
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
// Requis — couches Application et Infrastructure
services.AddOrkeonApplication();
services.AddOrkeonInfrastructure();
// Suites d'outils — ajouter uniquement celles nécessaires
services.AddOrkeonFileSystemTools(); // Si agents lisent/écrivent des fichiers
services.AddOrkeonDataTools(); // Si agents manipulent CSV, PDF, JSON, SQL, MongoDB
services.AddOrkeonWebTools(); // Si agents font du web search, scraping, HTTP API
services.AddOrkeonCodeTools(); // Si agents exécutent du shell
// Outils custom identifiés en Étape 3
services.AddSingleton<IBaseTool, MonOutilCustom1>();
services.AddSingleton<IBaseTool, MonOutilCustom2>();
// Configuration LLM (si pas de défaut)
services.Configure<LlmConfig>(context.Configuration.GetSection("Llm"));
})
.Build();
5.6 Pattern d'exécution
// Charger la crew depuis le YAML
var crewFactory = host.Services.GetRequiredService<ICrewFactory>();
var crew = await crewFactory.CreateFromFileAsync("config.yaml");
// Préparer l'input avec des variables d'exécution
var variables = new Dictionary<string, object>
{
["date"] = DateTime.Today.ToString("yyyy-MM-dd"),
["environment"] = "production"
};
var input = new CrewInput(
"Contexte initial pour l'exécution",
variables);
// Exécuter et récupérer les résultats
var orchestrator = host.Services.GetRequiredService<ICrewOrchestrationService>();
var output = await orchestrator.KickoffAsync(crew.Id, input);
// Exploiter les résultats
var failedTasks = output.TaskOutputs.Where(t => !t.Success).ToList();
if (failedTasks.Count == 0)
{
// Succès — traiter le résultat final
Console.WriteLine(output.FinalOutput);
}
else
{
// Échec — identifier les tasks en erreur
foreach (var failed in failedTasks)
Console.Error.WriteLine($"Task {failed.TaskId} failed: {failed.RawOutput}");
}