IgG antibodies use six complementarity-determining region (CDR) loops — three on the heavy chain (H1, H2, H3) and three on the light chain (L1, L2, L3) — to bind antigen. CDR-H3 is the most variable and typically contributes most to binding specificity and affinity. Antibody language models pre-trained on millions of antibody sequences (OAS database) capture natural CDR sequence distributions and can score the fitness of candidate sequences without experimental measurement.
Antibody Sequence Feature Encoding
import numpy as np
from typing import Optional
IMGT_CDR_POSITIONS = {
"CDRH1": (26, 35, "heavy"),
"CDRH2": (51, 57, "heavy"),
"CDRH3": (93, 102, "heavy"),
"CDRL1": (27, 32, "light"),
"CDRL2": (50, 52, "light"),
"CDRL3": (89, 97, "light"),
}
AA_VOCAB = list("ACDEFGHIKLMNPQRSTVWY")
AA_TO_IDX = {aa: i for i, aa in enumerate(AA_VOCAB)}
def encode_cdr_sequences(
heavy_seq: str,
light_seq: str,
scheme: str = "IMGT",
include_framework: bool = False,
) -> dict[str, np.ndarray]:
"""
One-hot encode CDR sequences from a numbered antibody sequence pair.
Args:
heavy_seq: Full variable domain sequence (heavy chain), IMGT-numbered
light_seq: Full variable domain sequence (light chain), IMGT-numbered
scheme: Numbering scheme ('IMGT', 'Chothia', 'Kabat')
include_framework: If True, also encode framework regions FW1–FW4
Returns:
Dict mapping CDR/FW loop name → one-hot encoded matrix (L × 20).
"""
encodings = {}
for loop_name, (start, end, chain) in IMGT_CDR_POSITIONS.items():
seq = heavy_seq if chain == "heavy" else light_seq
segment = seq[start:end + 1] if len(seq) > end else seq[start:]
onehot = np.zeros((len(segment), 20), dtype=np.float32)
for i, aa in enumerate(segment):
j = AA_TO_IDX.get(aa, -1)
if j >= 0:
onehot[i, j] = 1.0
encodings[loop_name] = onehot
return encodings
def compute_cdr_physicochemical(cdr_sequence: str) -> dict[str, float]:
"""
Compute physicochemical properties of a CDR sequence for developability scoring.
Properties known to correlate with developability liabilities:
- Net charge at pH 7.4
- Hydrophobicity (GRAVY index)
- Aromatic content (W/Y/F fraction)
- CDR length (absolute and vs. germline mean)
"""
pKa_residues = {"D": -1, "E": -1, "K": 1, "R": 1, "H": 0.1}
hydrophobicity = {"A":1.8,"C":2.5,"D":-3.5,"E":-3.5,"F":2.8,"G":-0.4,"H":-3.2,
"I":4.5,"K":-3.9,"L":3.8,"M":1.9,"N":-3.5,"P":-1.6,"Q":-3.5,
"R":-4.5,"S":-0.8,"T":-0.7,"V":4.2,"W":-0.9,"Y":-1.3}
aromatics = {"W", "Y", "F"}
seq = cdr_sequence.upper()
net_charge = sum(pKa_residues.get(aa, 0) for aa in seq)
gravy = sum(hydrophobicity.get(aa, 0) for aa in seq) / max(len(seq), 1)
frac_aromatic = sum(1 for aa in seq if aa in aromatics) / max(len(seq), 1)
return {
"net_charge": round(net_charge, 2),
"gravy": round(gravy, 3),
"frac_aromatic": round(frac_aromatic, 3),
"length": len(seq),
}
Developability Prediction
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
DEVELOPABILITY_LIABILITIES = {
"aggregation": "Hydrophobic patches in CDR-H3, CDRH1 + CDRL1 proximity",
"high_viscosity": "High net positive charge at pH 7.4 (net_charge_VH+VL > +5)",
"immunogenicity": "Non-germline residues in frameworks, PTM-prone motifs",
"thermal_instability": "Unpaired cysteines, buried charged residues",
"polyreactivity": "High CDR-H3 hydrophobicity and length > 20 residues",
}
def predict_developability_risk(
heavy_seq: str,
light_seq: str,
) -> dict[str, str]:
"""
Rule-based developability liability screen using biophysical heuristics.
Based on Jain et al. (2017), Raybould et al. (2019) TAP guidelines,
and Rabia et al. (2018) viscosity predictors.
Returns:
Dict of liability → risk level (low/medium/high) with rationale.
"""
from typing import Any
risks: dict[str, Any] = {}
# Aggregation: high CDR-H3 hydrophobicity
h3_start, h3_end = 93, 102
cdrh3 = heavy_seq[h3_start:h3_end + 1] if len(heavy_seq) > h3_end else ""
if cdrh3:
h3_phys = compute_cdr_physicochemical(cdrh3)
if h3_phys["gravy"] > 1.5:
risks["aggregation"] = "high — CDRH3 GRAVY > 1.5"
elif h3_phys["gravy"] > 0.5:
risks["aggregation"] = "medium — CDRH3 GRAVY > 0.5"
else:
risks["aggregation"] = "low"
risks["polyreactivity"] = (
"high" if h3_phys["gravy"] > 1.0 and h3_phys["length"] > 15
else "medium" if h3_phys["gravy"] > 0.5
else "low"
)
# High viscosity: net positive charge in variable domains
vh_charge = compute_cdr_physicochemical(heavy_seq)["net_charge"]
vl_charge = compute_cdr_physicochemical(light_seq)["net_charge"]
total_charge = vh_charge + vl_charge
risks["high_viscosity"] = (
"high" if total_charge > 5
else "medium" if total_charge > 2
else "low"
)
# PTM risk: motifs NxS/T (deamidation), DG (isomerisation), MW/WM oxidation
PTM_MOTIFS = {"NG": "deamidation", "NS": "deamidation",
"DG": "isomerisation", "DS": "isomerisation",
"MW": "oxidation", "WM": "oxidation"}
found_ptm = []
for chain in (heavy_seq, light_seq):
for i in range(len(chain) - 1):
motif = chain[i:i+2]
if motif in PTM_MOTIFS:
found_ptm.append(PTM_MOTIFS[motif])
risks["ptm_liability"] = "high" if found_ptm else "low"
risks["ptm_motifs_found"] = list(set(found_ptm))
return risks
Antibody ML Tool Landscape
| Tool / Model | Task | Architecture | Training Data | Access |
|---|---|---|---|---|
| AbLang-2 | CDR sequence scoring, filling | RoBERTa (antibody) | OAS (2B sequences) | Open source |
| AntiBERTy | Sequence embedding | BERT | OAS paired sequences | Open source |
| ProteinMPNN-AbDesign | CDR design given backbone | Message passing NN | PDB antibody structures | Open source |
| IgFold | Antibody structure prediction | Transformer + IPA | OAS + PDB | Open source |
| TAP (Therapeutic Ab Profiler) | Developability scoring | Biophysical rules | Approved Ab database | Web server |
Key Takeaways
- Antibody language models (AbLang-2, AntiBERTy) trained on the Observed Antibody Space (OAS) database capture natural CDR sequence distributions and can score the naturalness/fitness of candidate sequences as pseudo-log-likelihoods — a powerful signal for affinity maturation campaigns.
- Developability assessment must be done in parallel with affinity optimisation, not after. The five key liabilities (aggregation, high viscosity, immunogenicity, thermal instability, and polyreactivity) frequently increase when CDR sequences are optimised only for affinity without diversity constraints.
- CDR-H3 is the primary determinant of specificity and affinity. ML-guided CDR-H3 design using structure-conditioned models (ProteinMPNN, RFdiffusion) generates diverse high-quality candidates while respecting backbone geometry constraints from the target complex.
- Unlike small molecules, antibody ML models require careful handling of the heavy-light pairing: concatenated VH-VL embeddings retain cross-chain interaction information crucial for accurate affinity and stability predictions.
Try it live
Explore a related model hands-on: open Antibody Engineering Simulator and change its parameters while it runs. Everything stays in your browser.
▶ Open Antibody Engineering Simulator simulation