Un modèle abliterated est un modèle à poids ouverts ordinaire dont le comportement de refus a été retiré chirurgicalement en modifiant ses poids — pas en le réentraînant, ni en l'enveloppant dans un prompt astucieux. Le nom est un mot-valise formé sur ablate et obliterate — ablation et oblitération — et il décrit le mécanisme avec exactitude : on identifie l'unique direction de l'espace des activations qui porte « je devrais refuser », puis on fait en sorte que le réseau ne puisse plus jamais écrire cette direction.
La technique est issue de travaux d'interprétabilité montrant que, dans les transformers ajustés pour le chat, le refus est en grande partie porté par une seule direction linéaire. C'est ce résultat qui rend l'opération si peu coûteuse. Si le refus était étalé sur des milliers de features en interaction, le retirer exigerait une descente de gradient. Parce qu'il se concentre, le retirer ne demande que de l'algèbre linéaire.
Le refus vit dans le flux résiduel
Le flux résiduel (residual stream) d'un transformer est le vecteur courant, un par position de token, que chaque bloc lit et dans lequel il réécrit. Les têtes d'attention et les MLP y ajoutent leurs sorties ; rien ne l'écrase. Grâce à cette structure additive, une direction du flux résiduel signifie à peu près la même chose à la couche 10 et à la couche 40 — c'est exactement la propriété qui permet de parler de « la direction de refus » comme d'un objet unique plutôt que de quarante objets sans rapport.
Pour la trouver, il faut deux jeux de prompts : l'un que le modèle refuse de façon fiable, l'autre auquel il répond de façon fiable. On exécute les deux, on capture les activations du flux résiduel à une couche et une position de token fixes (les derniers tokens de l'instruction conviennent bien, puisque c'est là que le modèle a fini de lire la requête et n'a pas encore commencé à répondre), et on prend la différence des moyennes.
import torch
def refusal_direction(harmful: torch.Tensor, harmless: torch.Tensor) -> torch.Tensor:
"""Difference-in-means estimate of the refusal direction, unit-normalised.
Both tensors are [n_prompts, d_model] residual-stream activations captured at
the same layer and token position. Difference-in-means beats a trained probe
here: with a few hundred prompts a probe overfits, a mean shift does not.
"""
r = harmful.mean(dim=0) - harmless.mean(dim=0)
return r / r.norm()On répète l'opération pour chaque couche et chaque position candidates, ce qui produit des dizaines de directions candidates, puis on en choisit une. La sélection compte plus que l'extraction : le bon critère est ablater ce candidat, puis mesurer à la fois de combien le refus chute sur des prompts nuisibles de validation et de combien la distribution du token suivant bouge sur des prompts inoffensifs. Ce second nombre — typiquement une divergence KL par rapport au modèle non modifié — est votre jauge de dégâts. Un candidat qui tue le refus mais déplace fortement la distribution inoffensive est un moins bon choix qu'un candidat qui tue un peu moins de refus pour une fraction des dommages collatéraux.
Comment un modèle abliterated est construit
Une fois que l'on dispose d'un vecteur unitaire r, il y a deux façons de l'utiliser. La première est un hook à l'inférence : à chaque couche, on soustrait la composante de l'activation le long de r avant de la transmettre. Ça fonctionne, mais ça vous coûte un hook à l'exécution, et le modèle n'est plus un simple checkpoint.
La seconde — l'abliteration proprement dite — l'inscrit dans les poids. Chaque matrice qui écrit dans le flux résiduel reçoit une mise à jour de rang un qui retire r de son espace de sortie : la matrice d'embedding, chaque projection de sortie de l'attention, chaque projection descendante des MLP.
def orthogonalize_(weight: torch.Tensor, r: torch.Tensor) -> None:
"""Project r out of a matrix that writes into the residual stream, in place.
weight is [d_model, d_in]. After W <- (I - r rT) W, the product W @ x has zero
component along r for every possible x, so no amount of prompting can put the
direction back. Rank-one per matrix; no gradients, no optimiser, no dataset of
answers — only the few hundred prompts used to estimate r.
"""
weight -= torch.outer(r, r @ weight)Le résultat est un checkpoint ordinaire. Même architecture, même format de fichier, même coût d'inférence ; il se charge tel quel dans vLLM ou llama.cpp. Sur un seul GPU, toute la procédure tient en quelques minutes, et la partie coûteuse est le balayage des candidats, pas la modification.
En quoi ça diffère du fine-tuning
Faire du fine-tuning pour supprimer les refus — SFT ou DPO sur un corpus de réponses sans refus — est une opération fondamentalement différente. Elle déplace chaque poids par descente de gradient, elle a besoin d'un jeu de données de réponses et pas seulement de prompts, elle coûte des heures de GPU, et elle enseigne un nouveau comportement au lieu de supprimer un comportement existant. Elle emporte aussi avec elle le style, les biais de longueur et les particularités factuelles du corpus de fine-tuning, et risque un oubli catastrophique de capacités sans rapport.
L'abliteration touche un sous-espace de rang un et rien d'autre. Cette précision est son principal argument et la source de son principal mode de défaillance : si autre chose que le refus se trouve vivre le long de r, c'est détruit aussi, et aucun soin apporté au balayage ne l'évite complètement.
En quoi ça diffère d'un prompt de jailbreak
Un jailbreak laisse les poids intacts et pousse plutôt les activations dans une région où le circuit de refus ne se déclenche pas. C'est fragile, et de façons qui comptent pour l'automatisation. Il brûle des tokens de contexte à chaque appel. Il est non déterministe — le même prompt peut obtenir une réponse sur un échantillon et un refus sur le suivant. Il casse silencieusement quand le fournisseur met à jour le modèle ou corrige la formulation précise. Et parce que la machinerie du refus est toujours entièrement présente, elle peut se réaffirmer en pleine génération, vous laissant trois paragraphes de sortie utile suivis d'un « en fait, je ne peux pas continuer ».
Un modèle abliterated n'a rien à réaffirmer. Le comportement est stable sur toute la génération et d'une formulation de prompt à l'autre — c'est la propriété qui le rend utilisable dans un pipeline batch.
Soyons honnêtes sur les compromis
Un modèle abliterated n'est pas un meilleur modèle. C'est un modèle qui a cessé de dire non, et c'est une affirmation plus étroite qu'elle n'en a l'air.
- Dérive des capacités. Retirer une direction de chaque matrice d'écriture a des coûts mesurables. Les checkpoints abliterated montrent couramment un suivi d'instructions plus faible sur les cas limites, davantage d'adhésion aux prémisses fausses d'un prompt, et de petites régressions sur les benchmarks de raisonnement.
- Le refus n'est pas parfaitement unidimensionnel. Une direction capture l'essentiel du comportement, pas la totalité. Attendez-vous à ce que certains refus survivent, et à des dommages collatéraux sur les comportements qui partagent la direction.
- Aucune connaissance nouvelle. L'abliteration n'ajoute rien. Là où le modèle de base aurait refusé par ignorance déguisée en prudence, vous obtenez maintenant une réponse inventée avec aplomb — ce qui, pour un pipeline d'évaluation, peut être pire qu'un refus, parce qu'un refus est au moins un signal honnête que vous pouvez détecter.
- Les jeux de prompts définissent la modification. Un jeu nuisible étroit donne une direction étroite. Deux abliterations du même modèle de base ne sont pas interchangeables.
Beaucoup de modèles abliterated publiés reçoivent ensuite un léger fine-tuning de réparation pour récupérer les capacités dégradées — ce qui réintroduit discrètement le coût que la technique était censée éviter.
À quoi ça sert
Le cas d'usage honnête, c'est le travail où un refus est une erreur de mesure et non un gain de sécurité : harnais de red-teaming, taux de refus de référence, évaluation de robustesse, et analyse de sécurité où le sujet déclenche un garde-fou alors même que la tâche est défensive. unbleep sert des modèles abliterated derrière un endpoint compatible OpenAI, pour que vous puissiez y pointer un client existant et obtenir une référence stable. Ce que vous construisez avec est de votre responsabilité — voir la politique d'usage acceptable pour les lignes que nous ne franchissons pas.
Obtenez une clé API et mesurez la différence par vous-même.