Comment construire un système de prospection à auto-amélioration sur Codex

@nifinet
ANGLAISil y a 2 jours · 19 juil. 2026
227K
358
22
13
1.7K

TL;DR

Nicolas Finet détaille un cadre technique pour construire un système de prospection commerciale à auto-amélioration. Le système utilise des agents IA pour analyser les taux de réponse et proposer des améliorations de messages via des pull requests.

Plus tôt cette année, Andrej Karpathy (@karpathy) a pointé un agent vers son propre code d’entraînement et l’a laissé tourner pendant deux jours. Il a lancé 700 expériences, gardé les 20 qui battaient le benchmark, et a accéléré l’entraînement du modèle de 11 %. Puis il a dit quelque chose de très intéressant : toute métrique que l’on peut évaluer à faible coût peut être confiée à un essaim d’agents.

Le taux de réponse est une métrique que l’on peut évaluer à faible coût. Depuis, j’ai passé du temps à réfléchir à ce à quoi ressemble cette boucle appliquée à l’outbound.

Mon montage :

Codex lit les résultats de la semaine précédente, modifie les fichiers de scoring et de plays que le système outbound utilise, lance un test, et ouvre une pull request. Il propose une modification du playbook avec la preuve et le score associé, puis attend l’approbation humaine. L’envoi et la fusion restent en dehors de la boucle.

J’ai déjà construit la première boucle plusieurs fois : détecter le marché, noter le compte, écrire à partir du signal, vérifier le message, enregistrer le résultat, apprendre de la réponse. Cet article parle de la deuxième boucle, celle qui modifie la première.

Voilà le montage : le GTM comme un code versionné qui s’améliore grâce au marché.

Nicolas Finet - inline image

Le dépôt

Commencez par le dossier. La structure compte, car Codex ne peut améliorer que ce qu’il peut lire et modifier.

text
1codex-self-improving-outbound/
2 AGENTS.md
3 README.md
4 config/
5 scoring.yaml
6 plays.yaml
7 prompts/
8 improve_scoring.md
9 improve_prompt.md
10 pr_summary.md
11 memory/
12 outcomes.jsonl
13 evals/
14 fixtures.yaml
15 score.py
16 scripts/
17 append_outcome.py
18 run_codex_step.sh
19 propose_improvement.py
20 open_pr.sh
21 weekly_tune.sh
22 examples/
23 outcomes.sample.jsonl
24 weekly-pr.md

Le dépôt est volontairement simple. config/scoring.yaml contient les règles qui décident quels signaux comptent. prompts/ contient les plays qui rédigent les messages. memory/outcomes.jsonl contient ce que le marché a fait. evals/score.py est la porte qui dit si une modification proposée a aidé. AGENTS.md est la loi que Codex lit avant de toucher à quoi que ce soit.

Exécutez la première version hors ligne. Pas de CRM, pas d’enrichissement, pas de système de livraison. La boucle d’amélioration doit se prouver sur des fichiers locaux avant d’approcher une vraie machine outbound.

Étape 1. Écrire la loi en premier

Avant le fichier de scoring, avant les fichiers de prompt, écrivez AGENTS.md. C’est le fichier qui garde l’agent utile et contenu.

markdown
1# Règles d’amélioration de l’outbound auto-apprenant
2
3Vous améliorez un système outbound à partir des résultats.
4
5Règles strictes :
6- N’envoyez jamais de messages.
7- Ne scrapez ni n’enrichissez jamais de vraies personnes.
8- Ne fusionnez jamais par vous-même.
9- Modifiez uniquement les fichiers de ce dépôt.
10- Changez un concept à la fois.
11- Citez les résultats de `memory/outcomes.jsonl` pour chaque modification proposée.
12- Améliorez `evals/score.py` avant qu’une modification ne devienne une PR.
13- Si l’évaluation ne s’améliore pas, annulez votre modification et arrêtez.
14
15Modifications autorisées :
16- `config/scoring.yaml`
17- `config/plays.yaml`
18- `prompts/*.md`
19
20Résultat requis :
21- fichiers modifiés
22- raison de chaque modification
23- score avant
24- score après
25- résumé de la pull request

La loi a un seul objectif : réduire le périmètre. Sans elle, Codex essaiera d’aider en élargissant le champ. Il ajoutera plus de données, touchera plus de fichiers, appellera plus d’outils, ou automatisera une étape qui devrait rester sous contrôle humain. Ici, le travail est plus petit : lire les résultats, proposer une modification de fichier, prouver qu’elle a aidé, puis attendre.

Ce à quoi ressemble un bon résultat. Vous pouvez lire la loi avant d’approuver une PR et savoir exactement ce que Codex était autorisé à faire.

Là où ça casse. La loi devient un document de conformité. Si AGENTS.md a besoin d’une table des matières, c’est qu’il est déjà trop long. Gardez-le opérationnel.

Étape 2. Mettre le jugement dans la configuration

La plupart du jugement outbound réside dans la tête de quelqu’un. Puis l’équipe achète un logiciel et s’attend à ce que le logiciel améliore une décision qu’il ne peut pas voir.

Mettez le jugement dans un fichier.

yaml
1signals:
2 competitor_comparison:
3 weight: 8
4 reason: "l'acheteur compare les alternatives"
5 implementation_page_visit:
6 weight: 6
7 reason: "l'acheteur vérifie si cela peut être installé"
8 job_repost:
9 weight: 5
10 reason: "le poste est toujours ouvert et urgent"
11 funding_event:
12 weight: 5
13 reason: "le budget ou le mandat a peut-être changé"
14 generic_download:
15 weight: 1
16 reason: "intérêt pour le contenu, faible intention d'achat"
17
18thresholds:
19 draft: 6
20 human_review: 10
21
22negative_signals:
23 student_research: -8
24 vendor_pitch: -6
25 competitor: -10

Ce fichier commence comme une hypothèse visible. Si un téléchargement générique ne devrait compter pour rien, l’équipe peut pointer la ligne exacte et la modifier. Si une visite de page d’implémentation est un signal plus fort que prévu, Codex peut proposer le diff et montrer les lignes de résultats qui le justifient.

N’enterrez pas cette logique dans une fonction Python. Si la règle est visible, l’équipe peut la réviser, la discuter et l’améliorer sans transformer un jugement commercial en refactoring d’ingénierie.

Ce à quoi ressemble un bon résultat. Le fichier est assez petit pour être discuté. Cinq signaux, c’est une bonne première version.

Là où ça casse. Le fichier de scoring devient un tiroir à bazar. Vingt signaux, six seuils et des règles d’exception pour chaque cas particulier feront surajuster l’amélioreur. Commencez modestement et laissez les résultats vous dire où placer le prochain bouton.

Étape 3. Écrire les résultats comme une mémoire

Le fichier le plus important est memory/outcomes.jsonl.

Une ligne par contact, écrite lorsque le résultat est connu :

javascript
1{"date":"2026-07-01","account":"Northwind Finance","signal":"competitor_comparison","play":"migration_note","score":8,"outcome":"reply","reason":"a demandé des notes de migration"}
2{"date":"2026-07-01","account":"Bluepeak Studio","signal":"generic_download","play":"resource_followup","score":1,"outcome":"no_reply","reason":"intention uniquement de contenu"}
3{"date":"2026-07-02","account":"KiteOps","signal":"implementation_page_visit","play":"implementation_angle","score":6,"outcome":"reply","reason":"a posé des questions sur le calendrier d'implémentation"}
4{"date":"2026-07-02","account":"Atlas Recruiting","signal":"job_repost","play":"hiring_angle","score":5,"outcome":"bad_fit","reason":"demande de recherche étudiante"}

Le champ reason est tout l’intérêt. no_reply ne vous apprend presque rien. intention uniquement de contenu indique à la prochaine exécution que ce signal ne mérite peut-être pas un brouillon. bad_fit n’est utile que lorsque la raison explique pourquoi. a posé des questions sur le calendrier d'implémentation est le genre de détail qui peut changer un poids.

Construisez le validateur avant de construire l’amélioreur :

text
1Construisez scripts/append_outcome.py.
2
3Il accepte :
4- date
5- account
6- signal
7- play
8- score
9- outcome : reply | meeting | no_reply | bad_fit | bounced
10- reason
11
12Il rejette :
13- les champs manquants
14- les outcomes inconnus
15- une raison vide
16- les dates dans le futur
17
18Ajoute les lignes valides à memory/outcomes.jsonl.
19Affiche la ligne ajoutée.

C’est là que la capitalisation commence. Un tableau de bord peut vous dire qu’une campagne est en baisse. Un journal de résultats propre peut dire à Codex quel signal, play ou phrase doit changer avant la prochaine exécution.

Ce à quoi ressemble un bon résultat. Après une semaine, un étranger peut lire le fichier et dire quels signaux ont généré des réponses, quels plays ont créé des conversations inadaptées, et quel favori interne le marché a ignoré.

Là où ça casse. L’équipe remplit les résultats le vendredi de mémoire. Les victoires survivent, les raisons de mauvais ajustement s’estompent, et le système apprend à partir de fiction. Écrivez la ligne quand le résultat atterrit.

Étape 4. Construire la porte d’évaluation

Avant que Codex ne modifie quoi que ce soit, il a besoin d’un test qu’il ne peut pas contourner.

Créez evals/fixtures.yaml :

yaml
1cases:
2 - account: Northwind Finance
3 signals: [competitor_comparison, implementation_page_visit]
4 expected: human_review
5 note: "deux signaux forts sur un seul compte"
6
7 - account: Bluepeak Studio
8 signals: [generic_download]
9 expected: ignore
10 note: "intention uniquement de contenu"
11
12 - account: KiteOps
13 signals: [implementation_page_visit]
14 expected: draft
15 note: "l'intention d'implémentation devrait franchir le seuil de brouillon"
16
17 - account: Atlas Recruiting
18 signals: [job_repost, student_research]
19 expected: ignore
20 note: "le marqueur de mauvais ajustement annule le signal"

Ensuite, créez evals/score.py :

text
1Construisez evals/score.py.
2
3Lisez config/scoring.yaml et evals/fixtures.yaml.
4
5Pour chaque cas :
61. Additionnez les poids de chaque signal.
72. Ajoutez les pénalités des signaux négatifs.
83. Acheminez le compte :
9 - score >= thresholds.human_review => human_review
10 - score >= thresholds.draft => draft
11 - sinon => ignore
124. Comparez l'acheminement à l'attendu.
13
14Affichez chaque prédiction.
15Affichez la précision finale sous forme score=0.00 à score=1.00.
16Sortie 0 uniquement lorsque la précision est 1.00.

La première porte doit être assez petite pour être comprise et assez tranchante pour détecter une vraie erreur. Lors de mon premier essai, la base a échoué sur un cas :

text
1Northwind Finance: predicted=human_review expected=human_review
2Bluepeak Studio: predicted=ignore expected=ignore
3KiteOps: predicted=ignore expected=draft
4Atlas Recruiting: predicted=ignore expected=ignore
5score=0.75

C’était bien. Le système avait l’intention d’implémentation en dessous du seuil de brouillon, donc il ignorait un compte que le fixture disait mériter un message. Mieux vaut le détecter dans un test qu’après un mois de comptes manqués.

Ce à quoi ressemble un bon résultat. Une commande donne un chiffre, et chaque cas échoué est facile à inspecter.

Là où ça casse. Le fixture ne contient que des victoires évidentes. Alors tout changement imprudent passe. Mettez des cas laids dans la porte : intention faible, mauvais ajustement, pas de réponse, signaux obsolètes, et les comptes que vous auriez aimé que le système saute.

Étape 5. Laisser Codex proposer un changement de scoring

Maintenant Codex peut modifier.

Créez prompts/improve_scoring.md :

markdown
1Vous améliorez le système de scoring outbound.
2
3Lisez :
4- AGENTS.md
5- config/scoring.yaml
6- memory/outcomes.jsonl
7- evals/fixtures.yaml
8
9Votre travail :
101. Trouvez une règle de scoring qui devrait changer.
112. La raison doit citer memory/outcomes.jsonl.
123. Modifiez uniquement config/scoring.yaml.
134. Exécutez python3 evals/score.py.
145. Si le score s'améliore, gardez la modification.
156. Si le score reste identique ou baisse, annulez votre modification et arrêtez.
16
17Sortie :
18- la ligne exacte modifiée
19- les lignes de résultats qui l'ont provoquée
20- score avant
21- score après
22- si la modification doit devenir une PR
23
24Ne modifiez pas les prompts.
25N'ajoutez pas de nouveaux signaux.
26Ne touchez pas à la livraison.

Exécutez-le via le wrapper du dépôt :

bash
1scripts/run_codex_step.sh improve_scoring

La première version de mon amélioreur a fait une erreur utile. Il a cherché le signal de réponse le plus propre. competitor_comparison avait le meilleur taux de réponse dans le petit journal de résultats, donc l’amélioreur voulait augmenter ce poids. L’évaluation est restée à 0.75, donc la modification a été rejetée.

C’est exactement pourquoi la porte existe. Un système plus faible aurait accepté l’histoire parce qu’elle semblait raisonnable. Celui-ci a posé une meilleure question : est-ce que la modification corrige l’erreur connue ?

Le deuxième passage a trouvé la plus petite modification qui aidait :

text
1- implementation_page_visit: 4
2+ implementation_page_visit: 6

L’évaluation a passé :

text
1Northwind Finance: predicted=human_review expected=human_review
2Bluepeak Studio: predicted=ignore expected=ignore
3KiteOps: predicted=draft expected=draft
4Atlas Recruiting: predicted=ignore expected=ignore
5score=1.00

C’est le moment où la boucle devient utile. Elle a changé une règle, pour une raison, et prouvé la modification par rapport à un fixture.

Nicolas Finet - inline image

Ce à quoi ressemble un bon résultat. Le diff proposé est ennuyeux et traçable : une ligne modifiée, une raison basée sur les résultats attachée, une évaluation améliorée.

Là où ça casse. Codex change trois poids et deux prompts à la fois. Maintenant personne ne peut dire quel changement a aidé. Gardez la loi stricte : un concept par proposition.

Étape 6. Améliorer les fichiers de prompt séparément

Le scoring n’est que la moitié du système. Les modèles de message se dégradent aussi.

Une ligne qui fonctionnait le mois dernier commence à sonner familier. Une question qui génère des réponses dans un segment est ignorée dans un autre. Une phrase qui semble percutante en interne est punie par le marché. Traitez l’amélioration des prompts comme une voie séparée pour que Codex ne mélange pas scoring et copy dans la même PR.

Créez config/plays.yaml :

yaml
1plays:
2 migration_note:
3 prompt_file: prompts/plays/migration_note.md
4 use_when:
5 - competitor_comparison
6 banned_lines:
7 - "j'ai pensé que cela pourrait être pertinent"
8 - "question rapide"
9
10 implementation_angle:
11 prompt_file: prompts/plays/implementation_angle.md
12 use_when:
13 - implementation_page_visit
14 banned_lines:
15 - "vous jetez un œil à notre solution"
16 - "j'aimerais échanger un peu"

Ensuite, créez prompts/improve_prompt.md :

markdown
1Vous améliorez un play outbound.
2
3Lisez :
4- AGENTS.md
5- config/plays.yaml
6- memory/outcomes.jsonl
7- le fichier de prompt du play choisi
8
9Choisissez un play avec au moins 10 résultats.
10
11Trouvez :
12- les lignes ou structures qui apparaissent dans les résultats positifs
13- les lignes ou structures qui apparaissent dans les résultats no_reply ou bad_fit
14- toute phrase qui devrait être bannie
15
16Faites une petite modification dans le prompt de ce play.
17
18Règles :
19- Ne modifiez pas le scoring.
20- Ne créez pas un nouveau play.
21- N'ajoutez pas un nouveau canal.
22- Citez les lignes de résultats.
23- Écrivez l'instruction avant et après.
24
25Exécutez ensuite l'évaluation de copy si elle existe.
26S'il n'y a pas d'évaluation de copy, ouvrez la PR en review_required.

Certaines améliorations peuvent être notées automatiquement. D’autres ont encore besoin de goût. S’il n’y a pas d’évaluation de copy, Codex peut proposer la modification du prompt, mais il doit marquer la PR pour révision au lieu de prétendre que la modification est prouvée.

Ce à quoi ressemble un bon résultat. Codex dit : « Cette phrase est apparue dans sept résultats sans réponse, donc je l’ai ajoutée aux banned_lines », ou « les réponses positives citaient le détail d’implémentation dans la première phrase, donc j’ai resserré le play pour exiger cela. »

Là où ça casse. L’amélioreur réécrit toute la voix parce qu’un message a reçu une réponse. Les modifications de prompt devraient être plus petites que votre instinct.

Étape 7. Livrer les modifications sous forme de pull requests

C’est la couche de contrôle. Codex modifie les fichiers, exécute l’évaluation et rédige le résumé de la PR. Un humain révise et fusionne.

Nicolas Finet - inline image

Créez prompts/pr_summary.md :

markdown
1Rédigez un résumé de pull request pour cette amélioration outbound.
2
3Incluez :
41. Ce qui a changé.
52. Pourquoi cela a changé, en citant les lignes de résultats.
63. Score avant.
74. Score après.
85. Fichiers modifiés.
96. Risque.
107. Ce que le relecteur humain doit vérifier.
11
12Gardez-le court.
13N'affirmez pas que la modification est en ligne.

Créez scripts/open_pr.sh :

bash
1#!/usr/bin/env bash
2set -euo pipefail
3
4branch="codex/weekly-tune-$(date +%Y-%m-%d)"
5
6git checkout -b "$branch"
7git add config prompts evals memory
8git commit -m "Codex weekly outbound tune"
9
10body="$(cat outputs/pr-summary.md)"
11
12python3 scripts/create_pr.py \
13 "$branch" \
14 "Codex weekly outbound tune" \
15 "$body"

La PR devrait se lire comme si un coéquipier l’avait écrite :

text
1Modification :
2- Augmentation de implementation_page_visit de 4 à 6.
3
4Pourquoi :
5- KiteOps avait une intention de page d'implémentation et a répondu avec le calendrier d'implémentation.
6- Le score précédent acheminait ce compte vers ignore.
7
8Avant :
9- score d'évaluation 0.75
10
11Après :
12- score d'évaluation 1.00
13
14Vérification du relecteur :
15- Assurez-vous que l'intention d'implémentation est suffisamment spécifique.
16- Gardez les téléchargements génériques bas.
17- Fusionnez uniquement si cela correspond au jugement commercial réel.

Voilà le système de sécurité. Codex fait le travail fastidieux. L’opérateur maintient le standard.

Ce à quoi ressemble un bon résultat. Une PR par semaine, petit diff, raison claire, évaluation réussie.

Là où ça casse. Quelqu’un donne à Codex la permission de fusionner parce que la révision semble être une friction. Cette minute sépare un système qui s’améliore d’un système qui dérive.

Étape 8. Mettre en cadence

Ne faites pas tourner cela après chaque réponse. C’est ainsi qu’un système surajuste à un seul compte bruyant.

Laissez la semaine se dérouler, laissez les résultats s’accumuler, puis ajustez.

Nicolas Finet - inline image

Créez scripts/weekly_tune.sh :

bash
1#!/usr/bin/env bash
2set -euo pipefail
3
4cd "$(dirname "$0")/.."
5
6python3 evals/score.py || true
7scripts/run_codex_step.sh improve_scoring
8python3 evals/score.py
9scripts/run_codex_step.sh pr_summary > outputs/pr-summary.md
10scripts/open_pr.sh

Ensuite, cron :

bash
10 8 * * MON cd ~/codex-self-improving-outbound && scripts/weekly_tune.sh

Si vous utilisez GitHub Actions, gardez la même forme :

yaml
1name: weekly-outbound-tune
2
3on:
4 schedule:
5 - cron: "0 8 * * 1"
6 workflow_dispatch:
7
8jobs:
9 tune:
10 runs-on: ubuntu-latest
11 steps:
12 - uses: actions/checkout@v4
13 - uses: actions/setup-python@v5
14 with:
15 python-version: "3.11"
16 - run: pip install -r requirements.txt
17 - run: python3 evals/score.py || true
18 - run: scripts/weekly_tune.sh

Exécutez les deux premiers ajustements à la main. Lisez chaque diff. Observez ce que Codex essaie de changer lorsque l’échantillon est mince. Une fois que les propositions sont ennuyeuses, mettez-les en planning.

Ce à quoi ressemble un bon résultat. Une PR hebdomadaire apparaît avec la preuve, le diff et le résultat de l’évaluation. Vous la fusionnez, modifiez ou fermez.

Là où ça casse. Le job tourne, personne ne révise, et les PR s’accumulent. Un système auto-apprenant a encore une habitude humaine : lire le diff.

La version clone-et-exécute

Le dépôt devrait livrer avec quatre commandes :

bash
1git clone <repo>
2cd codex-self-improving-outbound
3python3 -m venv .venv
4source .venv/bin/activate
5pip install -r requirements.txt
6python3 evals/score.py
7python3 scripts/propose_improvement.py

Première exécution attendue :

text
1score=0.75
2changed config/scoring.yaml
3implementation_page_visit: 4 -> 6
4score=1.00
5open PR for human review

La démo hors ligne prouve les contrats de fichiers. L’exécution Codex prouve la boucle d’édition. Après cela, remplacez les exemples de résultats par les vôtres, renommez les signaux, ajoutez vos plays, et construisez un fixture qui reflète les comptes que vous auriez aimé que le système achemine différemment.

Ne commencez pas par câbler la livraison. Commencez par prouver la boucle d’amélioration.

La version complète : max

Ce dépôt est la couche manuelle. Il fonctionne à partir de fichiers, de signaux publics et de votre plan Codex. Il enseigne la forme parce que chaque règle est exposée.

yourmax.ai est le même système avec les coutures cachées.

Au lieu d’un dépôt que vous bricolez vous-même, max est l’agent que vous utilisez directement. Il détecte les mouvements du marché, décide qui mérite d’être contacté et pourquoi maintenant, rédige le démarchage par email et LinkedIn pour votre approbation, et continue de s’améliorer à partir des résultats.

Le dépôt montre la couche d’auto-ajustement que la plupart des équipes ne construisent jamais : les résultats deviennent des propositions de changement de règles, les propositions passent par une porte, et la fusion humaine décide ce qui devient actif. max prend cette même logique opérationnelle et l’exécute comme un système géré.

Si vous voulez le dépôt complet, vous pouvez me le dire et je vous l’enverrai.

Remixer dans YouMind

Turn one viral article into a full content workflow

Collect the source, decode the pattern, create assets, draft the story, and distribute from one AI workspace.

Explore YouMind
Pour les créateurs

Transformez votre Markdown en un article 𝕏 impeccable

Quand vous publiez vos propres textes longs, la mise en forme 𝕏 des images, tableaux et blocs de code est pénible. YouMind transforme un brouillon Markdown complet en un article 𝕏 impeccable, prêt à publier.

Essayer Markdown vers 𝕏

D'autres patterns à décoder

Articles viraux récents

Explorer plus d'articles viraux