Darkwood Blog Blog
  • Articles
  • Veille
  • Releases
  • CrĂ©ateurs
fr
  • de
  • en
Connexion
  • Blog
  • Articles
  • Veille
  • Releases
  • CrĂ©ateurs

đŸ€“ Nolife Tokens - rĂ©duire le contexte LLM sans compromettre la capacitĂ© de rĂ©cupĂ©ration

le 16 août 2026

Connectez-vous pour réagir à cet article

🚀 1

Les agents de codage IA ont inversé un problÚme de performance bien connu.

Pendant des annĂ©es, nous avons luttĂ© contre les limitations liĂ©es au dĂ©bit de donnĂ©es, aux allers-retours HTTP, Ă  la latence et Ă  la mĂ©moire des processus. Ces contraintes restent importantes. Ce qui a changĂ©, c'est qu'une part importante du coĂ»t et des dĂ©faillances d'une session d'agent rĂ©side dĂ©sormais dans l'invite de commande : rĂ©sultats des outils, journaux, diffĂ©rences, arborescences du dĂ©pĂŽt, bruit du compilateur, objets JSON et les mĂȘmes lignes d'information rĂ©pĂ©tĂ©es des centaines de fois.

Le processus naïf est simple :

Tool → giant stdout → LLM context

Cela fonctionne jusqu'Ă  ce que le contexte soit saturĂ© d'informations sans grande valeur et que le modĂšle doive encore trouver la seule ligne d'erreur pertinente. Des fenĂȘtres de contexte plus larges permettent d'envoyer toutes les donnĂ©es, mais ne rendent pas cette pratique judicieuse.

Cet article décrit nolife-tokens, une expérience volontairement modeste avec Symfony et Flow. La thÚse est ciblée et vérifiable :

Supprimer des informations du contexte LLM actif ne signifie pas nĂ©cessairement les perdre. Le contexte peut ĂȘtre fortement compressĂ©, tandis que les donnĂ©es omises restent rĂ©cupĂ©rables de maniĂšre dĂ©terministe grĂące Ă  des rĂ©fĂ©rences lĂ©gĂšres.

Nous avons mesuré le volume, la rétention du signal et la récupération au bit prÚs sur les équipements de test. Nous n'avons pas encore mesuré les jetons facturés par le fournisseur, la latence de bout en bout des agents ni le coût en dollars. Ces distinctions sont importantes.

Inspiration sans clonage de produits

Plusieurs projets ouverts explorent des idĂ©es connexes : RTK (compression des commandes et des sorties avant leur lecture par l’agent), context-mode (conserver les donnĂ©es brutes et les rĂ©cupĂ©rer Ă  la demande), Headroom (compression adaptĂ©e au contenu avec stockage rĂ©versible), Claude-mem (divulgation progressive de la mĂ©moire).

Vous n’avez pas besoin de connaĂźtre ces bases de code. L’idĂ©e commune utile n’est pas « un autre framework d’agents », mais plutĂŽt :

Effectuez un travail plus déterministe avant d'envoyer les données au LLM.

La dĂ©duplication des journaux, la suppression des clĂ©s de tĂ©lĂ©mĂ©trie, la classification des diffĂ©rences Git, le hachage d'une section omise : aucune de ces opĂ©rations ne nĂ©cessite de modĂšle. Le budget de contexte du modĂšle doit ĂȘtre consacrĂ© Ă  la gestion des ambiguĂŻtĂ©s et Ă  la prise de dĂ©cision, et non Ă  cinq cents copies de « [INFO] requĂȘte dĂ©marrĂ©e ».

nolife-tokens est un laboratoire pour cette idĂ©e au sein de la pile Darkwood : PHP 8.5, Symfony Console et darkwood/flow. Pas d’embeddings, pas de base de donnĂ©es vectorielle, pas de MCP, pas de Redis, pas de LangChain.

Point de départ : un squelette et un pipeline observable

Le projet a débuté avec une structure Symfony 8.1 minimale. Le code de l'application se résumait essentiellement à un noyau. Flow était déjà une dépendance de Composer, mais inutilisée.

La premiÚre étape, TOKEN_PIPELINE_POC, a permis de connecter un pipeline Flow minimal via un ContextPacket mutable :

Load
→ Classify
→ MeasureRaw
→ Optimize
→ MeasureOpt
→ EvaluateSignals

Interface de ligne de commande :

bin/console tokens:analyze fixtures/sample.log
bin/console tokens:benchmark

Le flux est utile ici non pas parce que nous avons besoin d'une orchestration simultanée, mais parce que chaque étape est observable. Le paquet accumule une trace : octets et jetons estimés aprÚs le chargement, type de contenu aprÚs la classification, taille aprÚs l'optimisation, réussite/échec aprÚs les vérifications de signaux. Le lecteur (et l'ingénieur) voit :

raw → classified → reduced → evaluated

au lieu d'une fonction optimizeContext() opaque qui masque l'endroit oĂč le volume a disparu.

Voici à quoi ressemble, dans l'esprit, une trace typique de tokens:analyze :

LOAD         | fixtures/sample.log | 19,354 bytes
CLASSIFY     | log
MEASURE_RAW  | 19,354 bytes        | ~4,839 tokens
OPTIMIZE     | log refs=1          | 4,813 bytes
MEASURE_OPT  | markers~4 referenced~3671 | ~1,204 tokens
SIGNAL       | PASS
RECOVERY     | PASS

Cette liste d'étapes constitue le produit. En cas de problÚme (économies insuffisantes, signal défaillant, nombre excessif de références), vous pouvez identifier l'étape responsable sans avoir recours à une plateforme de métriques supplémentaire.

Pourquoi limiter la taille du projet ? Parce que les systĂšmes contextuels ont tendance Ă  se transformer en frameworks avant mĂȘme que l’on ait pu vĂ©rifier la viabilitĂ© de l’idĂ©e de base. nolife-tokens se rapproche volontairement davantage d’un laboratoire en console que d’une API de bibliothĂšque. Pas de ports, d’adaptateurs ni d’interfaces spĂ©culatives. Uniquement des classes PHP, des services Symfony via l’injection automatique de dĂ©pendances, et des fichiers dans le rĂ©pertoire var/.

Jetons estimés, et non jetons facturés

La mesure utilise une approximation documentĂ©e, la mĂȘme heuristique que RTK documente publiquement :

// TokenEstimator.php (excerpt)
estimatedTokens: (int) ceil($bytes / 4),

Les pourcentages entre les valeurs brutes et optimisées sont utiles à des fins de comparaison. Les valeurs absolues ne correspondent pas aux jetons facturés par le fournisseur. Les modÚles de tokenisation diffÚrent. Dans cet article, le terme « jetons » désigne cette estimation, sauf indication contraire.

Classification déterministe en premier

La stratégie de compression dépend du type de contenu. La classification est heuristique et sans LLM.

Type Croquis de détection
json json_decode réussit sur { / [ racine
git_diff diff --git ou @@ en-tĂȘtes de bloc
log suffisamment de lignes correspondant aux modĂšles de niveau/horodatage
file_list lignes contenant principalement des chemins d'accĂšs
texte repli

Cette distinction n'est pas purement théorique. Différents types de bruit se compressent différemment.

  • Journaux : les lignes rĂ©pĂ©titives et les messages de faible intensitĂ© doivent rester affichĂ©es ; les lignes ERROR / WARNING importantes doivent rester affichĂ©es.
  • JSON : tĂ©lĂ©mĂ©trie, remplissage, identifiants de requĂȘte ; les champs de dĂ©cision (id, status, error) doivent rester
  • DiffĂ©rences Git : de nombreuses lignes + / - contiennent des informations utiles ; un Ă©lagage agressif est dangereux
  • Listes de fichiers : peuvent se dĂ©composer en arbres avec des dĂ©comptes
  • Texte : espaces blancs lĂ©gers uniquement dans le POC actuel

Premier test de performance : volume vs signal

Les fixtures insÚrent intentionnellement des chaßnes critiques. Une optimisation se contentant de tronquer la fin de la chaßne permettrait souvent de « gagner des jetons » tout en supprimant l'erreur insérée. Le test de performance suit donc SIGNAL : chaque sous-chaßne attendue doit toujours apparaßtre dans le texte visible optimisé.

RĂ©sultats de la premiĂšre Ă©tape (optimisation avec perte — les donnĂ©es omises n'Ă©taient pas encore enregistrĂ©es) :

CAS Octets bruts Jetons bruts* Octets optimisĂ©s Jetons optimisĂ©s* ENREGISTRÉ SIGNAL
sample.log 19 354 4 839 4 759 1 190 75,4 % RÉUSSI
sample.diff 12 742 3 186 9 684 2 421 24,0 % RÉUSSI
sample.json 27 118 6 780 265 67 99,0 % RÉUSSI

* estimé en octets / 4

Les signaux implantés comprenaient :

  • ERREUR PaymentService ligne 421 dans le journal des modifications
  • authentication check removed et src/Security/AuthGuard.php dans le diff
  • l'identifiant du paiement, le statut « échec » et le message d'erreur au format JSON.

L'indicateur clé de performance qui compte n'est pas « combien avons-nous supprimé ? », mais plutÎt : les informations nécessaires à la prise de décision ont-elles été préservées ?

JSON : le bruit structurĂ© s’effondre bien

Le format JSON s'est avéré le plus simple. Les clés structurées ont permis à un filtre déterministe de supprimer ou de référencer ultérieurement les données de télémétrie tout en conservant les champs de décision. Une charge utile composée principalement de trames de remplissage et de débogage est passée d'environ 6 800 jetons estimés à quelques dizaines de jetons JSON visibles lors de la premiÚre étape, avec la validation du protocole SIGNAL PASS.

C’est lĂ  l’avantage structurel du bruit typé : on peut nommer ce qui est jetable.

Journal : la rĂ©pĂ©tition, c'est de l'argent facile — jusqu'Ă  ce que les signaux se rompent

Les journaux sont compressĂ©s car les agents voient la mĂȘme ligne de maniĂšre rĂ©pĂ©tĂ©e :

[INFO] request started
[INFO] request started
[INFO] request started
[INFO] request started

devient :

[INFO] request started ×4

Les lignes Ă  signal Ă©levĂ© restent inchangĂ©es. Cela paraĂźt anodin jusqu'Ă  ce qu'on Ă©crive un test de rĂ©tention dĂ©terministe. Une version prĂ©liminaire utilisait [ERROR] PaymentService ligne 421 alors que le signal attendu Ă©tait ERROR PaymentService ligne 421. La sous-chaĂźne Ă©chouait Ă  cause du ] entre ERROR et PaymentService. La leçon est simple mais importante : les tests de signal sont sensibles au formatage, et les lignes Ă  signal Ă©levĂ© doivent rester suffisamment stables pour ĂȘtre interprĂ©tĂ©es par les humains et pour les vĂ©rifications.

Différences Git : un résultat utilement faible

La comparaison des différences n'a permis de réduire le temps de traitement que d'environ 24 %. Il ne s'agit pas d'un échec de l'expérience. Si la plupart des données d'entrée contiennent des modifications significatives, le bruit sûr est négligeable. Viser aveuglément une « réduction de 90 % » risquerait de fausser la surface de décision (par exemple, la suppression d'une vérification d'authentification dans AuthGuard.php).

Les différences Git révÚlent une limite de compression naturelle. C'est le type de résultat que l'on attend d'un laboratoire : ne pas forcer les choses.

Ce que la premiĂšre Ă©tape a permis de comprendre, en une phrase : la rĂ©duction du nombre de jetons sans test de signal est vaine. Un test de signal permet de distinguer « nous avons Ă©liminĂ© le bruit » et « nous avons corrigĂ© l’erreur ».

PropriĂ©tĂ© manquante : supprimer ≠ dĂ©truire

Le premier prototype présentait une faiblesse structurelle. Une fois le contenu supprimé, il disparaissait du contexte actif et devenait inaccessible. Si un agent décidait ultérieurement que les données de télémétrie supprimées étaient pertinentes, il n'y avait rien à récupérer.

Cela nous amÚne à la deuxiÚme étape importante : REVERSIBLE_CONTEXT_POC.

Principe:

REMOVE FROM CONTEXT
≠
DESTROY INFORMATION

Les optimiseurs renvoient désormais un OptimizeResult :

// OptimizeResult.php
final class OptimizeResult
{
    /**
     * @param list<array{reason: string, content: string, marker_placeholder?: string}> $omissions
     */
    public function __construct(
        public readonly string $visible,
        public readonly array $omissions = [],
    ) {}
}

ContextOptimizer conserve chaque omission sous var/context/ .json` et insÚre un court marqueur dans le texte visible :

// ContextOptimizer.php (excerpt)
$id = $this->store->makeId($packet->sourcePath, $omission['reason'], $omission['content']);
$ref = new ContextReference(
    id: $id,
    source: $packet->sourcePath,
    type: $packet->type->value,
    reason: $omission['reason'],
    content: $omission['content'],
);
$this->store->put($ref);
// ...
$visible = str_replace($placeholder, $ref->marker(), $visible);

Les identifiants sont déterministes et courts : ctx_ plus les premiers chiffres hexadécimaux de sha256(source|reason|content).

Forme réelle stockée (abrégée) :

{
  "id": "ctx_31154f",
  "source": "fixtures/sample.log",
  "type": "log",
  "reason": "deduplicated repeated lines",
  "content": "[INFO] request started\n..."
}

Le contexte actif ne nécessite que :

#ref:ctx_31154f

Lors de l'exécution grossiÚre du journal, ce marqueur coûte environ quatre jetons estimés tandis que ~3,6k jetons estimés restent hors contexte sur le disque.

La récupération est une commande de console, pas un moteur de recherche :

bin/console tokens:show-ref ctx_31154f
// TokensShowRefCommand.php (excerpt)
$ref = $this->store->get($id);
$io->writeln(sprintf('Source: %s', $ref->source));
$io->writeln(sprintf('Type: %s', $ref->type));
$io->writeln(sprintf('Reason: %s', $ref->reason));
$io->writeln('--- RAW CONTENT ---');
$io->writeln($ref->content);

La fonction ContextStore::get normalise les identifiants #ref:ctx_
 ou les identifiants bruts et lit le fichier JSON. La rĂ©cupĂ©ration dans le pipeline est exacte au bit prĂšs : chaque rĂ©fĂ©rence est rechargĂ©e et son contenu est comparĂ© Ă  celui Ă©crit lors de l’optimisation.

Pipeline de flux mis Ă  jour

Load
→ Classify
→ MeasureRaw
→ Optimize (+ store refs)
→ MeasureOpt
→ EvaluateSignals
→ EvaluateRecovery

La construction reste un générateur FlowFactory de fermetures sur ContextPacket :

// TokenPipelineFactory.php (excerpt)
return $this->flowFactory->create(static function () use (...) {
    yield static function (ContextPacket $packet): ContextPacket {
        $packet->type = $classifier->classify($packet->raw);
        $packet->addTrace('CLASSIFY', $packet->type->value);
        return $packet;
    };

    yield static function (ContextPacket $packet) use ($optimizer): ContextPacket {
        $optimizer->optimize($packet);
        $packet->addTrace('OPTIMIZE', sprintf('%s refs=%d', $packet->type->value, count($packet->references)));
        return $packet;
    };

    // 
 MEASURE_OPT, SIGNAL 


    yield static function (ContextPacket $packet) use ($store): ContextPacket {
        foreach ($packet->references as $ref) {
            $loaded = $store->get($ref->id);
            if ($loaded === null || $loaded->content !== $ref->content) {
                $missing[] = $ref->id;
            }
        }
        $packet->recoveryPass = $missing === [];
        $packet->addTrace('RECOVERY', $packet->recoveryPass ? 'PASS' : 'FAIL');
        return $packet;
    };
});

Deux invariants :

  1. SIGNAL — Les chaĂźnes de caractĂšres critiques insĂ©rĂ©es restent dans le texte optimisĂ© visible
  2. RÉCUPÉRATION — chaque #ref effectue un aller-retour octet par octet depuis var/context/

Référence réversible

Résultats mesurés actuels :

FICHIERS BRUT VISIBLES MARQUEURS RÉFÉRENCE ENREGISTRÉ RÉF. SIGNAL RÉCUPÉRATION
sample.log@coarse 4 839 1 204 4 3 671 75,1 % 1 RÉUSSI RÉUSSI
sample.log@fine 4 839 1 202 12 3 670 75,2 % 3 RÉUSSI RÉUSSI
sample.json 6 780 146 36 6 191 97,8 % 9 RÉUSSI RÉUSSI
sample.diff 3 186 2 434 4 749 23,6 % 1 RÉUSSI RÉUSSI

Comment lire les colonnes :

  • BRUT — nombre estimĂ© de jetons de l'entrĂ©e originale
  • VISIBLE — jetons estimĂ©s encore dans le contexte actif (y compris les marqueurs #ref)
  • MARQUEURS — coĂ»t estimĂ© des marqueurs seuls
  • RÉFÉRÉ — jetons estimĂ©s stockĂ©s hors contexte
  • ENREGISTRÉ — rĂ©duction du visible par rapport au brut
  • SIGNAL / RÉCUPÉRATION — les deux invariants rĂ©ussite/Ă©chec

Le format JSON se compresse toujours fortement (réduction visible d'environ 98 %) tout en conservant les champs de décision et en stockant environ 6 200 jetons estimés derriÚre des références structurelles. Les différences restent le cas le plus résistant (environ 24 %), avec désormais une seule référence grossiÚre pour le contexte inchangé compressé au lieu de dizaines de micro-références.

Granularité grossiÚre vs granularité fine : la granularité de référence a un coût

Pour les journaux, le test de performance s'exécute avec les deux niveaux de granularité.

Mode RÉF. MARQUEURS VISIBLES
grossier 1 4 1 204
amende 3 12 1 202

Le mode fin a triplé le nombre de références et la surcharge des marqueurs pour économiser environ deux jetons visibles. Pour cette charge de travail, le mode grossier s'est avéré le plus performant : récupération simplifiée, moins d'identifiants à suivre pour l'agent et contexte actif quasi identique.

Ce n'est pas une rĂšgle absolue. La granularitĂ© doit suivre le modĂšle de rĂ©cupĂ©ration attendu. Les journaux nĂ©cessitent souvent un seul bloc contenant toutes les donnĂ©es agrĂ©gĂ©es. Le JSON structurĂ© exige souvent des rĂ©fĂ©rences aux positions des champs, afin que le modĂšle puisse toujours voir oĂč se trouvaient les donnĂ©es de tĂ©lĂ©mĂ©trie.

Émission grossiùre logarithmique (extrait) :

// LogOptimizer.php (coarse branch excerpt)
$out[] = sprintf('%s ×%d', $prev, $count);
$coarseParts[] = $expanded;
// 

$visible .= "\n\nRepeated informational logs omitted.\n" . $placeholder;
$omissions[] = [
    'reason' => 'deduplicated repeated lines',
    'content' => implode("\n\n", $coarseParts),
    'marker_placeholder' => $placeholder,
];

Références JSON structurelles

Conceptuellement :

{
  "id": 42,
  "status": "failed",
  "error": "PaymentService timeout",
  "telemetry": { "... huge payload ..." }
}

devient :

{
  "id": 42,
  "status": "failed",
  "error": "PaymentService timeout",
  "telemetry": "#ref:ctx_xxxxxx"
}

Le modĂšle conserve la position sĂ©mantique, les identifiants, l'Ă©tat et les erreurs. Environ six mille jetons de tĂ©lĂ©mĂ©trie restent disponibles hors de la fenĂȘtre. La configuration actuelle fournit neuf rĂ©fĂ©rences (clĂ©s de bruit + remplissage groupĂ©), environ 36 jetons de marqueur, et les instructions SIGNAL PASS et RECOVERY PASS.

C'est plus efficace que la suppression de clĂ©s : la structure subsiste mĂȘme lorsque les valeurs quittent l'invite.

Dans le code, les clĂ©s de bruit ne sont pas supprimĂ©es ; leurs valeurs deviennent des espaces rĂ©servĂ©s que ContextOptimizer réécrit ensuite en #ref:
. Les clĂ©s de remplissage correspondant Ă  padding_* / noise_* sont regroupĂ©es en une seule omission lorsque cela est possible, afin qu'un gros bloc ne se transforme pas en quatre-vingts petites rĂ©fĂ©rences :

// JsonOptimizer.php (excerpt)
if ($this->isPaddingKey($key)) {
    $paddingBucket[$key] = $item;
    continue;
}

if ($this->isNoiseKey($key)) {
    $placeholder = '{' . '{REF_' . count($omissions) . '}' . '}';
    $omissions[] = [
        'reason' => 'omitted json field: ' . $key,
        'content' => json_encode($item, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) ?: '',
        'marker_placeholder' => $placeholder,
    ];
    $result[$key] = $placeholder;
    continue;
}

Le JSON visible ressemble donc toujours à la réponse de l'API. C'est important pour les agents qui raisonnent autant sur les noms de champs que sur le texte.

Ceci n'est pas un chiffon

nolife-tokens n'utilise pas d'embeddings, de recherche vectorielle, de récupération sémantique, de bases de données externes, de LangChain, de MCP ou de Redis.

La récupération aujourd'hui est :

reference id → local JSON file → exact bytes

Cette simplicité est intentionnelle. Nous voulons démontrer qu'une réduction structurelle peu coûteuse élimine déjà la majeure partie du gaspillage évident. La recherche sémantique peut attendre que des mesures indiquent sa nécessité.

Implications pour les agents de codage

Un processus plus rigoureux ressemble à ceci :

Tool
  → deterministic reducer
  → high-signal context (+ #ref markers)
  → LLM

          ↓ (only if needed)
     tokens:show-ref / expand
          ↓
       raw source

Cela ne nĂ©cessite ni de remplacer Cursor ni d'inventer un autre EDI. Une future intĂ©gration pourrait ĂȘtre aussi simple que :

bin/console tokens:context 


et en intégrant le résultat optimisé à un agent existant. L'objectif est d'offrir un meilleur contexte aux outils que nous utilisons déjà, et non de créer une nouvelle interface pour les agents.

Coût et latence (affirmations prudentes)

RĂ©duire le nombre de jetons d'entrĂ©e peut diminuer les coĂ»ts pour le fournisseur, la charge de prĂ©traitement, la latence et le bruit. Nous n'avons pas comparĂ© ces effets avec une API de fournisseur en production dans le cadre de ce projet. Jusqu'Ă  prĂ©sent, nous avons mesurĂ© le volume de contexte, la rĂ©tention du signal et la rĂ©cupĂ©ration. ConsidĂ©rer la rĂ©duction du volume comme une rĂ©duction de facture avĂ©rĂ©e serait malhonnĂȘte.

Il existe Ă©galement un effet de second ordre qui importe aux agents : la distraction. MĂȘme lorsqu’un modĂšle « dĂ©tecte » l’erreur dans un journal de 20 Ko, son attention peut ĂȘtre dĂ©tournĂ©e par les rĂ©pĂ©titions environnantes. La rĂ©duction dĂ©terministe ne se rĂ©sume pas Ă  une simple question d’économie ; elle vise aussi Ă  offrir au modĂšle une surface de dĂ©cision plus claire. Cet effet est plus difficile Ă  quantifier que la simple rĂ©duction de la taille des fichiers, et nous n’avons pas prĂ©tendu le faire ici.

L'utilisation pratique Ă  court terme au sein des flux de travail de type Darkwood reste pour l'instant hors ligne : exĂ©cuter tokens:analyze sur un fixture ou un dump d'outil capturĂ©, examiner la trace de la scĂšne et dĂ©terminer si le contexte visible est suffisant pour ĂȘtre collĂ© dans Cursor. L'intĂ©gration qui intercepte chaque commande shell (Ă  la maniĂšre de RTK) est explicitement exclue du pĂ©rimĂštre de ces Ă©tapes.

Philosophie de l'ingénierie

Avant d'appeler un mannequin, demandez :

PHP peut-il résoudre cette partie de maniÚre déterministe ?

Ce code source inclut : la classification du contenu, la dĂ©duplication des journaux, la suppression ou la rĂ©fĂ©rence du bruit JSON, la rĂ©duction des arborescences de fichiers, la suppression des mĂ©tadonnĂ©es git et du contexte inchangĂ© long, les omissions de hachage, la persistance des rĂ©fĂ©rences, la mesure des tailles, l’assertion des signaux, l’assertion de rĂ©cupĂ©ration.

Composants (responsabilités, pas un simple fichier) :

PiĂšce RĂŽle
ContextPacket Charge utile du pipeline : texte brut/optimisé, métriques, références, trace
ContentClassifier Détection déterministe du type
TokenEstimator / ContextMetrics octets, lignes, jetons estimés
OptimizeResult Texte visible + omissions
ContextReference / ContextStore Marqueur + var/context/<id> .json
ContextOptimizer Distribution par type, persistance des références, injection de marqueurs
LogOptimizer / JsonOptimizer / GitDiffOptimizer / 
 Réduction spécifique au contenu
SignalEvaluator Vérifications de sous-chaßnes insérées
TokenPipelineFactory Étapes du flux
tokens:analyze / benchmark / show-ref CLI

Modes de défaillance que nous avons déjà rencontrés ou que nous prévoyons

Surcompression

Une ligne, rare mais cruciale, peut se confondre avec du bruit. Les projecteurs de signalisation en captent une partie ; les agents réels repÚrent les cas que les projecteurs ne détectent pas.

Explosion de référence

Une premiÚre approche de Git générait environ 36 petites références pour les contextes réduits. La surcharge liée aux marqueurs augmentait considérablement et l'expérience utilisateur s'en trouvait dégradée. La solution consistait à utiliser une seule référence globale pour tout le contexte inchangé omis. Mieux vaut moins de références utiles que de nombreuses micro-références.

Perte sémantique

La préservation d'une chaßne de caractÚres ne garantit pas toujours sa bonne interprétabilité. Un code d'état sans contexte narratif peut encore perturber un modÚle. Les filtres déterministes optimisent le volume et les signaux explicites, et non la compréhension.

Fausse confiance de bytes / 4

Les pourcentages comparatifs sont fiables pour ce laboratoire. Les « économies absolues sur la facture » ​​ne le sont pas.

Dépendance de récupération

Une fois que l'agent s'appuie sur #ref, il faut lui apprendre à développer cette fonctionnalité. Actuellement, c'est un humain qui exécute tokens:show-ref. La divulgation progressive automatique est la prochaine étape expérimentale ; il ne s'agit pas d'une fonctionnalité finalisée.

Collisions d'identification et hygiĂšne des magasins

Les identifiants de rĂ©fĂ©rence sont adressables par contenu. Les collisions avec un contenu diffĂ©rent augmentent la longueur du hachage et gĂ©nĂšrent une erreur. Les collisions avec un contenu identique sont réécrites de maniĂšre idempotente. Le stockage se trouve dans le rĂ©pertoire var/, ignorĂ© par Git ; il s'agit d'un cache d'espace de travail, et non d'une base de connaissances persistante. Cela convient pour une preuve de concept, mais s'avĂšre insuffisant pour la mĂ©moire de production multi-utilisateurs — une raison supplĂ©mentaire de ne pas confondre cela avec la persistance de type Claude-mem.

Posture de sécurité

ConsidĂ©rez le contenu analysĂ© comme des donnĂ©es, et jamais comme des instructions Ă  exĂ©cuter. Les optimiseurs ne font que réécrire les chaĂźnes de caractĂšres. Les journaux et les fichiers JSON peuvent contenir du texte ressemblant Ă  des directives d'agent (« ignorer les instructions prĂ©cĂ©dentes
 »). Le pipeline ne doit en aucun cas interprĂ©ter ce texte comme un Ă©lĂ©ment de contrĂŽle. Aujourd'hui, il s'agit principalement d'une question d'implĂ©mentation : pas d'Ă©valuation, pas d'analyse du contenu, et surtout, ne vous fiez pas aux instructions de test comme Ă  une politique.

Ce que nous avons délibérément omis

Il est utile de lister les objectifs secondaires pour que l'expérience reste lisible :

  • Pas de rĂ©sumĂ© des sections omises basĂ© sur LLM (pour l'instant). Les rĂ©sumĂ©s seraient incomplets d'une autre maniĂšre et plus difficiles Ă  reconstituer exactement.
  • Pas de crochet de curseur automatique ni d'interception de shell
  • Absence de systĂšme d'empaquetage contextuel permettant de choisir parmi vingt candidats sous une limite de 4 Ko (conçu plus tard dans la feuille de route initiale, non implĂ©mentĂ©).
  • Aucune suite de tests PHPUnit n'est utilisĂ©e ; tokens:benchmark constitue la surface de validation.
  • Aucune affirmation selon laquelle les jetons estimĂ©s correspondent aux compteurs de facturation d'OpenAI/Anthropic

Le fait de les omettre fait partie de la mĂ©thode : Ă©valuer l’idĂ©e de rĂ©duction rĂ©versible avant d’y superposer des produits.

Suivant : divulgation progressive

La suite logique :

LEVEL 0  tiny overview
   ↓
LEVEL 1  selected section / #ref expansion
   ↓
LEVEL 2  raw original source

Exemple de croquis :

Application failed during checkout.
1 PaymentService error.
telemetry omitted.
#ref:ctx_payment

Si nĂ©cessaire : dĂ©velopper la rĂ©fĂ©rence. Uniquement si nĂ©cessaire : donnĂ©es brutes complĂštes. Le contexte est dĂ©sormais dĂ©terminĂ© par la demande plutĂŽt que par l’envoi systĂ©matique du journal complet.

C’est lĂ  que nolife-tokens cesse d’ĂȘtre seulement un compresseur et devient une expĂ©rience en matiĂšre d’architecture de contexte.

Schématiquement :

                    ┌─────────────────────┐
   raw tool dump ─â–ș │ classify + optimize │ ─â–ș visible context (+ #ref)
                    └──────────┬──────────┘
                               │ omissions
                               ▌
                        var/context/*.json
                               │
              expand / show-ref │ (on demand)
                               ▌
                         original bytes

Aujourd'hui, la flÚche vers le bas est manuelle. La divulgation progressive l'intÚgre à la boucle de l'agent : d'abord une vue d'ensemble, puis les extensions choisies, puis les données brutes uniquement lorsque les couches moins coûteuses échouent.

Conclusion

Les grandes fenĂȘtres de contexte incitent Ă  la facilité : tout envoyer. La question technique passe de « quelle quantitĂ© de donnĂ©es le modĂšle peut-il accepter ? » à :

Quel est le contexte minimal nécessaire à la prise de décision correcte, et à quel coût pouvons-nous récupérer le reste ?

Deux étapes importantes concernant les jetons nolife sont déjà visibles, avec des mesures :

  • Des rĂ©ductions dĂ©terministes importantes sont possibles pour les journaux bruitĂ©s et les fichiers JSON
  • la rĂ©tention du signal peut ĂȘtre testĂ©e comme un invariant de premiĂšre classe
  • les donnĂ©es omises peuvent ĂȘtre rĂ©cupĂ©rĂ©es octet par octet.
  • La granularitĂ© de rĂ©fĂ©rence elle-mĂȘme a un coĂ»t mesurable (une granularitĂ© grossiĂšre est prĂ©fĂ©rable Ă  une granularitĂ© fine sur notre configuration logarithmique).
  • Les types de contenu ont des limites de compression naturelles diffĂ©rentes (les diffĂ©rences Git sont d'environ 24 % ici).

Le problĂšme n'est pas rĂ©solu. Les questions de coĂ»t pour les prestataires, d'expansion pilotĂ©e par les agents et de divulgation progressive restent Ă  explorer. Le laboratoire est volontairement de petite taille : suffisamment petit pour que chaque mĂ©canisme demeure comprĂ©hensible, ce qui, pour les systĂšmes contextuels, est peut-ĂȘtre l'objectif principal.

Commandes utilisées dans ce travail

bin/console tokens:analyze fixtures/sample.log
bin/console tokens:analyze fixtures/sample.log --granularity=fine
bin/console tokens:analyze fixtures/sample.json
bin/console tokens:analyze fixtures/sample.diff
bin/console tokens:benchmark
bin/console tokens:show-ref ctx_31154f

Code source

DépÎt : https://github.com/matyo91/nolife-tokens
Slides: https://github.com/matyo91/slidewire

Connectez-vous pour réagir à cet article

🚀 1

Site

  • Plan du Site
  • Contact
  • Mentions lĂ©gales

Network

  • Hello
  • Blog
  • Apps
  • Photos

Social

Darkwood 2026, tous droits réservés