Back to List

Multimodal Foundation for Autonomous Protein Design — Generating 100 Novel Sequences While Maintaining the Serine Protease Active Site

Using ESM3's sequence-structure-function 3-track masked language model, we fix a specific catalytic triad (Ser-His-Asp) active site and autonomously design the remaining sequence. Generate 100 novel serine proteases, validate their structures with AF2/Boltz, quantify self-consistency and novelty, and compare and ensemble with RFdiffusion+ProteinMPNN to create a complete pipeline.

Advanced
|
50min
|
Verified (2026-07)
Progress0/15 (0%)

Multimodal Foundation for Autonomous Protein Design: Generating 100 Novel Sequences Maintaining Serine Protease Active Site

In Part 02 (Protein Embeddings) and Part 11 (Structure/Affinity Prediction), we saw how well foundation models understand natural proteins. But the truly interesting question is this: can these models code entirely new proteins from scratch, ones that don't exist in nature? EvolutionaryScale's ESM3 (2024) is the first large-scale protein foundation model that learns sequence, structure, and function modalities with a single transformer, enabling conditional generation of arbitrary modalities. This installment builds a practical pipeline for leveraging its capabilities: fixing the catalytic triad (Ser195-His57-Asp102, chymotrypsin numbering) of serine proteases and autonomously designing the remaining sequence in a novel way. We generate 100 truly novel serine protease candidates with less than 30% sequence similarity to natural sequences and complete the process by verifying their 3D structures with AF2/Boltz.

📚 Recommended Prerequisites (Strongly Recommended)

This installment is the pinnacle of the AI x Biology hardcore advanced course. We strongly recommend completing the following DryBench installments before diving in.

Without completing the prerequisites, it will be difficult to follow the practical code in this installment, as it proceeds without re-explaining the principles of multi-modal transformers, masked language model training, and large-scale PyTorch model management.


We Learned This in Our DryBench Course

In DryBench ai-native #3, we learned that transformer embeddings are scalable regardless of domain or modality, in #12 we learned the basics of large-scale tensor, GPU memory, and mixed precision optimization with PyTorch, and in #13 we learned that HuggingFace provides a standard loading and inference API for pre-trained models.

ESM3 is a case study where these three principles reach their peak in the protein domain. Sequence tokens, discrete structure tokens (similar to the 3Di alphabet), and functional domain tokens are placed in a single integrated vocabulary, and the transformer is trained to predict tokens at arbitrary locations and in arbitrary modalities in a masked language model style. The results are astounding. It can fix a specific active site structure and generate the remaining sequence, or autonomously code new sequences with desired functions (e.g., fluorescence, catalysis, binding) as conditions. This installment turns that ability into a practical enzyme design pipeline.

Defining the Hardcore Problem

Practical Scenario: Autonomous Design of Novel Serine Protease

Serine proteases are enzymes that break down proteins, with chymotrypsin, trypsin, and elastase being representative examples. Common catalytic mechanism: Ser195's hydroxyl is the nucleophile, His57 is the general base that transfers a proton, and Asp102 stabilizes His57. This triangle must maintain a perfect 3D arrangement for activity.

Our goal:

  • Less than 30% sequence similarity to natural serine proteases (truly novel).
  • Maintain the 3D coordinates of the Ser-His-Asp catalytic triad (AF2 predicted RMSD ≤ 2 Å).
  • Autonomously generate 100 candidates (approximately 30-60 minutes).
  • Self-consistency (ESM3 generation → AF2 prediction → active site reproduction) success rate of 40%+.
  • Re-validate the top 5 using active site prediction (Rosetta, MD) (optional).

Spectrum of De Novo Protein Design

  • Rosetta (2003 onwards): Physics-based protein design, an established standard.
  • RFdiffusion (Baker Lab 2023): Generates the backbone using a diffusion model. Subsequent sequence design uses ProteinMPNN [1].
  • ProteinMPNN (Baker Lab 2022): The standard for backbone → sequence redesign [2].
  • RFdiffusion + ProteinMPNN + AF2: Modern standard pipeline (backbone → sequence → validation).
  • Chroma (2024, Baker Lab): Diffusion-based, all-atom [3].
  • ESM3 (2024): The first large-scale multi-modal foundation. Integrates conditional generation [4].
  • Boltz-2 (Part 11): Specialized for prediction, limited in design.
  • Ligand-conditioned design: RFdiffusion-Motif, Chroma-Ligand.

This installment uses ESM3 conditional generation (main installment) + AF2/Boltz validation + RFdiffusion+ProteinMPNN ensemble comparison (extension).

Target Metrics for This Installment

  • Extract the 3D coordinates of the catalytic triad from chymotrypsin PDB (1AB9, 4CHA, etc.).
  • Generate 100 sequences using ESM3 conditional generation (target_length 200-250 residues).
  • Apply a diversity filter (pairwise identity ≤ 70%).
  • Check for similarity to natural sequences (UniProt Swiss-Prot BLAST or ESM embeddings) → retain only those with less than 30% similarity.
  • Predict structures using AF2/Boltz → achieve a 40%+ reproduction rate of active site RMSD ≤ 2 Å.
  • Average pLDDT ≥ 70 (structural confidence).

Tool Stack and Infrastructure Requirements

ToolRoleLicense
ESM3 (esm3-sm-open-v1 1.4B)3-track conditional generationAcademic open, commercial separate agreement
ESM3 large (open weights, non-commercial)Alternative large modelEvolutionaryScale license
RFdiffusion + ProteinMPNNEnsemble comparisonAcademic open
Boltz-2 (Part 11)Generates and validates the structure of the generated sequenceMIT
AlphaFold2 (or ColabFold)Alternative structure validationApache 2.0
Biopython · PyMOLSequence/structure manipulation and visualizationBiopython License · LGPL
BLAST · FoldseekSearch for similar natural sequences/structuresAcademic open
PyTorchBackendBSD

Infrastructure Requirements:

  • ESM3 1.4B small open weights: Server GPU with 16-24GB VRAM or higher. Approximately 4GB VRAM in fp16.
  • ESM3 large (98B, private): Access only through academic API.
  • RFdiffusion: Data center GPU with 24-48GB VRAM.
  • AF2/Boltz validation: See Part 11 (high-end consumer GPU or data center GPU with 24-48GB VRAM).
  • Large-scale batch generation and validation: Data center workstation with 80GB+ VRAM (generally inaccessible, cloud on-demand recommended).
  • RAM 32GB or higher.

Estimated reproduction cost for learners: If using local GPU, API cost is 0. Generating 100 sequences + AF2/Boltz validation takes approximately 4-8 hours (based on a 24-48GB VRAM GPU).

Practical Pipeline Implementation

Overall Flow:

mermaid

Step 1. Active Site Definition · ESM3 Constraint Preparation

Extract the 3D coordinates of the catalytic triad residues from Chymotrypsin (PDB 4CHA, 5CHA, 1AB9, etc.).

python
from dataclasses import dataclass
from pathlib import Path
import torch
import numpy as np
from Bio.PDB import PDBParser
@dataclass
class ActiveSiteConstraint:
"""Defines active site constraints."""
site_name: str # e.g. "serine_protease_triad"
residue_positions: list[int] # Positions of the active site residues in the generated sequence (0-based)
residue_types: list[str] # Amino acids at each position (e.g., ["S", "H", "D"])
coordinates_backbone: np.ndarray # (N_residues, 4, 3): N, CA, C, O coordinates
ideal_distances: dict[tuple[int, int], float] # Ideal distances between active site residues (Å)
AA_3TO1 = {
"ALA": "A", "ARG": "R", "ASN": "N", "ASP": "D", "CYS": "C",
"GLN": "Q", "GLU": "E", "GLY": "G", "HIS": "H", "ILE": "I",
"LEU": "L", "LYS": "K", "MET": "M", "PHE": "F", "PRO": "P",
"SER": "S", "THR": "T", "TRP": "W", "TYR": "Y", "VAL": "V",
}
def load_catalytic_triad_from_pdb(
pdb_path: Path,
triad_selection: list[tuple[str, int, str]], # [(chain, resid, expected_aa)]
site_name: str = "serine_protease_triad",
) -> ActiveSiteConstraint:
"""Extracts catalytic triad coordinates from a PDB file.
Example for Chymotrypsin (4CHA): [("A", 195, "S"), ("A", 57, "H"), ("A", 102, "D")]
"""
parser = PDBParser(QUIET=True)
structure = parser.get_structure("target", str(pdb_path))
residue_types = []
coordinates = []
positions = []
for i, (chain_id, resid, expected_aa) in enumerate(triad_selection):
try:
chain = structure[0][chain_id]
residue = chain[resid]
except KeyError:
raise ValueError(f"PDB missing: {chain_id}:{resid}")
aa = AA_3TO1.get(residue.get_resname().upper(), "X")
if aa != expected_aa:
raise ValueError(f"Active site {chain_id}:{resid} amino acid mismatch: expected {expected_aa}, actual {aa}")
residue_types.append(aa)
coords = np.array([
residue["N"].get_coord(),
residue["CA"].get_coord(),
residue["C"].get_coord(),
residue["O"].get_coord(),
])
coordinates.append(coords)
positions.append(i)
coordinates_arr = np.stack(coordinates, axis=0)
# Ideal distances between active site residues (based on chymotrypsin measurements)
ca_positions = coordinates_arr[:, 1, :] # CA only
ideal_dist = {}
for i in range(len(triad_selection)):
for j in range(i + 1, len(triad_selection)):
d = float(np.linalg.norm(ca_positions[i] - ca_positions[j]))
ideal_dist[(i, j)] = d
return ActiveSiteConstraint(
site_name=site_name,
residue_positions=positions,
residue_types=residue_types,
coordinates_backbone=coordinates_arr,
ideal_distances=ideal_dist,
)
# Example: chymotrypsin catalytic triad
CHYMOTRYPSIN_TRIAD_4CHA = [
("A", 57, "H"), # His57 (histidine base)
("A", 102, "D"), # Asp102 (aspartate stabilizer)
("A", 195, "S"), # Ser195 (serine nucleophile)
]

Step 2. ESM3 Conditional Generation

ESM3 SDK allows specifying masks for sequence/structure/function tracks and iteratively unmasking.

python
from esm.models.esm3 import ESM3
from esm.sdk.api import ESMProtein, GenerationConfig
class ESM3Designer:
"""ESM3-based protein design."""
def __init__(self, device: str = "cuda", model_name: str = "esm3-sm-open-v1"):
self.device = device
self.model = ESM3.from_pretrained(model_name).to(device).eval()
self.model_name = model_name
@torch.no_grad()
def design_with_active_site(
self,
constraint: ActiveSiteConstraint,
target_length: int = 245, # Similar length to chymotrypsin
num_samples: int = 100,
temperature: float = 0.7,
seed: int | None = None,
) -> list[dict]:
"""Generates new sequences while maintaining active site constraints.
Returns: [{sequence, seed, active_site_preserved: bool}]
"""
if seed is not None:
torch.manual_seed(seed)
np.random.seed(seed)
generated = []
for i in range(num_samples):
# Initial protein: sequence masked, active site residue positions fixed
seq_list = ["_"] * target_length
# Active site positions (placed arbitrarily in the target length, e.g., in the middle)
triad_positions = self._distribute_triad_positions(
target_length, len(constraint.residue_positions),
)
for pos, aa in zip(triad_positions, constraint.residue_types):
seq_list[pos] = aa
initial_sequence = "".join(seq_list)
protein = ESMProtein(sequence=initial_sequence)
# ESM3 iterative decoding
config = GenerationConfig(
track="sequence",
num_steps=max(target_length // 4, 20),
temperature=temperature,
)
try:
result = self.model.generate(protein, config)
# Post-hoc check to ensure that the active site residues are actually maintained
preserved = all(
result.sequence[pos] == aa
for pos, aa in zip(triad_positions, constraint.residue_types)
)
generated.append({
"sequence": result.sequence,
"seed": (seed or 0) + i,
"triad_positions": triad_positions,
"active_site_preserved": preserved,
"length": len(result.sequence),
})
except Exception as e:
print(f"[{i}] Generation failed: {e}")
return generated
def _distribute_triad_positions(
self, target_length: int, n_triad: int, spread_ratio: float = 0.4,
) -> list[int]:
"""Distribute active site residues evenly across the target length.
In the actual chymotrypsin, the positions are 57, 102, and 195 out of 245 residues, which are 21%, 42%, and 80%.
In the new design, maintain similar relative positions.
"""
chymo_ref = [57, 102, 195]
chymo_length = 245
positions = [
int(target_length * (p / chymo_length))
for p in chymo_ref[:n_triad]
]
return positions

Step 3. Diversity Filter

Ensure diversity by filtering generated sequences using a pairwise identity threshold.

python
def compute_pairwise_identity(seq_a: str, seq_b: str) -> float:
"""If the lengths are equal, perform position-wise comparison; otherwise, perform alignment."""
if len(seq_a) == len(seq_b):
matches = sum(1 for a, b in zip(seq_a, seq_b) if a == b)
return matches / len(seq_a)
# If lengths are different, perform global alignment
from Bio import pairwise2
aln = pairwise2.align.globalxx(seq_a, seq_b, one_alignment_only=True)[0]
return aln.score / max(len(seq_a), len(seq_b))
def diversity_filter(
sequences: list[str],
max_pairwise_identity: float = 0.7,
) -> list[str]:
"""Greedy filter: keep only sequences with low identity to already selected sequences."""
kept = []
for seq in sequences:
keep = True
for existing in kept:
if compute_pairwise_identity(seq, existing) > max_pairwise_identity:
keep = False
break
if keep:
kept.append(seq)
return kept

Step 4. Natural Sequence Similarity Check

Use BLAST or ESM embeddings + FAISS to check for similarity to natural sequences.

python
def blast_against_swissprot(
query_seq: str,
swissprot_fasta_path: Path,
e_threshold: float = 1e-5,
) -> list[dict]:
"""Perform similarity search against natural sequences using BLAST.
In practice, use a local BLAST database (makeblastdb + blastp).
"""
import subprocess
import tempfile
with tempfile.NamedTemporaryFile(mode="w", suffix=".fasta", delete=False) as query_f:
query_f.write(f">query\n{query_seq}\n")
query_path = query_f.name
try:
result = subprocess.run(
["blastp",
"-query", query_path,
"-db", str(swissprot_fasta_path),
"-outfmt", "6 qseqid sseqid pident evalue bitscore",
"-evalue", str(e_threshold),
"-max_target_seqs", "5"],
capture_output=True, text=True, check=True,
)
hits = []
for line in result.stdout.strip().split("\n"):
if not line:
continue
fields = line.split("\t")
hits.append({
"subject": fields[1],
"identity": float(fields[2]),
"e_value": float(fields[3]),
"bit_score": float(fields[4]),
})
return hits
except (subprocess.CalledProcessError, FileNotFoundError):
return []
def natural_similarity_check(
seq: str,
max_identity: float = 30.0, # %
) -> tuple[bool, float]:
"""Check if the sequence is novel compared to natural sequences (identity ≤ max_identity).
Returns: (is_novel, max_identity_found)
"""
hits = blast_against_swissprot(seq, Path("/path/to/swissprot.fasta"))
if not hits:
return True, 0.0
max_id = max(h["identity"] for h in hits)
return max_id < max_identity, max_id

Step 5. AF2/Boltz Structure Validation

Predict the 3D structure of the generated sequences using AF2 or Boltz-2 (from paper 11) and compare the RMSD to the original required active site coordinates.

python
import subprocess
import yaml
def predict_structure_boltz(sequence: str, output_dir: Path, seq_id: str) -> Path:
"""Predict structure using Boltz-2 pipeline from paper 11."""
yaml_content = {
"version": 1,
"sequences": [{"protein": {"id": "A", "sequence": sequence}}],
}
output_dir.mkdir(parents=True, exist_ok=True)
yaml_path = output_dir / f"{seq_id}.yaml"
with open(yaml_path, "w") as f:
yaml.safe_dump(yaml_content, f)
try:
subprocess.run([
"boltz", "predict", str(yaml_path),
"--out_dir", str(output_dir),
"--use_msa_server",
], check=True, capture_output=True)
except subprocess.CalledProcessError as e:
raise RuntimeError(f"Boltz-2 failed for {seq_id}: {e.stderr.decode()[:500]}")
return output_dir / seq_id / f"{seq_id}_model_0.pdb"
def kabsch_rmsd(coords_a: np.ndarray, coords_b: np.ndarray) -> float:
"""Calculate RMSD after Kabsch alignment."""
a = coords_a - coords_a.mean(axis=0)
b = coords_b - coords_b.mean(axis=0)
h = a.T @ b
u, _, vt = np.linalg.svd(h)
d = np.sign(np.linalg.det(vt.T @ u.T))
correction = np.eye(3)
correction[2, 2] = d
r = vt.T @ correction @ u.T
a_aligned = a @ r.T
return float(np.sqrt(np.mean(np.sum((a_aligned - b) ** 2, axis=1))))
def check_active_site_recovery(
predicted_pdb: Path,
triad_positions: list[int],
original_constraint: ActiveSiteConstraint,
rmsd_threshold: float = 2.0,
) -> tuple[bool, float, float]:
"""Check if the predicted structure recovers the active site.
Returns: (recovered, rmsd, mean_plddt)
"""
parser = PDBParser(QUIET=True)
structure = parser.get_structure("predicted", str(predicted_pdb))
residues_list = list(structure.get_residues())
predicted_coords = []
plddt_values = []
for pos in triad_positions:
if pos >= len(residues_list):
return False, float("inf"), 0.0
residue = residues_list[pos]
try:
coords = np.array([
residue["N"].get_coord(),
residue["CA"].get_coord(),
residue["C"].get_coord(),
residue["O"].get_coord(),
])
except KeyError:
return False, float("inf"), 0.0
predicted_coords.append(coords)
# pLDDT is stored in the B-factor of the CA atom (AF2/Boltz convention)
plddt_values.append(float(residue["CA"].get_bfactor()))
predicted_arr = np.stack(predicted_coords, axis=0).reshape(-1, 3)
reference_arr = original_constraint.coordinates_backbone.reshape(-1, 3)
rmsd = kabsch_rmsd(predicted_arr, reference_arr)
mean_plddt = float(np.mean(plddt_values))
return rmsd < rmsd_threshold, rmsd, mean_plddt

Step 6. Integration · Candidate Ranking

python
from dataclasses import asdict
import pandas as pd
@dataclass
class DesignCandidate:
sequence: str
length: int
seed: int
active_site_preserved_in_seq: bool
triad_positions: list[int]
pdb_path: str | None
active_site_rmsd: float
plddt_active_site: float
natural_identity_max: float
novelty_score: float
composite_score: float
def full_design_pipeline(
catalytic_pdb: Path,
triad_selection: list[tuple[str, int, str]],
target_length: int,
output_dir: Path,
num_samples: int = 100,
device: str = "cuda",
) -> pd.DataFrame:
"""Active site → new sequence generation → diversity · novelty · validation → ranking."""
output_dir.mkdir(parents=True, exist_ok=True)
print("[1/6] Loading active site constraint")
constraint = load_catalytic_triad_from_pdb(catalytic_pdb, triad_selection)
print(f" triad: {constraint.residue_types}, distances: {constraint.ideal_distances}")
print("[2/6] ESM3 conditional generation")
designer = ESM3Designer(device=device)
generated = designer.design_with_active_site(
constraint, target_length, num_samples, temperature=0.7, seed=42,
)
preserved = [g for g in generated if g["active_site_preserved"]]
print(f" Generated {len(generated)}, active site preserved {len(preserved)}")
print("[3/6] Diversity filter")
preserved_seqs = [g["sequence"] for g in preserved]
diverse_seqs = diversity_filter(preserved_seqs, max_pairwise_identity=0.7)
diverse = [g for g in preserved if g["sequence"] in diverse_seqs]
print(f" After diversity filtering: {len(diverse)}")
print("[4/6] Natural sequence novelty check")
novel_candidates = []
for g in diverse:
is_novel, max_id = natural_similarity_check(g["sequence"])
g["natural_identity_max"] = max_id
g["novelty_score"] = 1.0 - (max_id / 100.0)
if is_novel:
novel_candidates.append(g)
print(f" Novel (identity ≤ 30%): {len(novel_candidates)}")
print(f"[5/6] Boltz-2 structure validation ({len(novel_candidates)} sequences)")
candidates_verified = []
for i, g in enumerate(novel_candidates):
seq_id = f"design_{g['seed']}"
try:
pdb = predict_structure_boltz(g["sequence"], output_dir / "structures", seq_id)
recovered, rmsd, plddt = check_active_site_recovery(
pdb, g["triad_positions"], constraint,
)
candidates_verified.append(DesignCandidate(
sequence=g["sequence"],
length=g["length"],
seed=g["seed"],
active_site_preserved_in_seq=g["active_site_preserved"],
triad_positions=g["triad_positions"],
pdb_path=str(pdb),
active_site_rmsd=rmsd,
plddt_active_site=plddt,
natural_identity_max=g["natural_identity_max"],
novelty_score=g["novelty_score"],
composite_score=0.0, # Calculated below
))
except Exception as e:
print(f" [{i}] {seq_id} failed: {e}")
print("[6/6] Composite ranking · CSV saving")
if not candidates_verified:
return pd.DataFrame()
df = pd.DataFrame([asdict(c) for c in candidates_verified])
# Composite: pLDDT (40%) + active site RMSD (40%) + novelty (20%)
df["composite_score"] = (
df["plddt_active_site"] / 100 * 0.4 +
(1 - df["active_site_rmsd"].clip(0, 5) / 5.0) * 0.4 +
df["novelty_score"] * 0.2
)
df = df.sort_values("composite_score", ascending=False)
df.to_csv(output_dir / "design_candidates.csv", index=False)
print(f" Top 5 composite scores: {df.head(5)['composite_score'].tolist()}")
return df
# Example: (chymotrypsin catalytic triad → 100 new serine protease)
# result = full_design_pipeline(
# catalytic_pdb=Path("./4CHA.pdb"),
# triad_selection=CHYMOTRYPSIN_TRIAD_4CHA,
# target_length=245,
# output_dir=Path("./serine_protease_design"),
# num_samples=100,
# )

Step 7. RFdiffusion + ProteinMPNN Ensemble Comparison (Optional Extension)

Run the same active site constraint with the Baker Lab standard pipeline and compare the results.

python
def run_rfdiffusion_motif(
active_site_pdb: Path,
triad_residues: list[int],
output_dir: Path,
num_designs: int = 100,
) -> list[Path]:
"""RFdiffusion motif scaffolding.
Fix the catalytic triad as a motif and generate the rest of the backbone.
In practice, refer to the RosettaCommons RFdiffusion GitHub example.
"""
# Conceptual stub: call RFdiffusion CLI
# subprocess.run(["python", "run_inference.py", ...])
return [] # Complete when implementing
def run_proteinmpnn(
backbone_pdb: Path,
output_dir: Path,
num_sequences: int = 10,
) -> list[str]:
"""Use ProteinMPNN to place sequences onto the backbone."""
# subprocess.run(["python", "protein_mpnn_run.py", ...])
return []
## Performance, Cost, and Known Failure Cases
### Performance Reference (Citing Public Benchmarks)
| Approach | Benchmark (self-consistency AF2 RMSD ≤ 2Å) | Novelty | Source |
|------|:-------------------------------------:|:-------:|------|
| Rosetta enzyme design | 20~30% | Low | Baker Lab 2003+ |
| ProteinMPNN alone (re-designing existing backbone) | 40~50% | Low to Medium | Dauparas et al., Science 2022 [2] |
| RFdiffusion + ProteinMPNN + AF2 | 60~70% | Medium to High | Watson et al., Nature 2023 [1] |
| ESM3 conditional generation | 40~55% (estimated) | Medium to High | Hayes et al., bioRxiv 2024 [4] |
| Chroma (Baker Lab all-atom) | 65~75% | Medium to High | Ingraham et al., Nature 2023 [3] |
| RFdiffusion + ProteinMPNN + Boltz-2 validation | ~65~72% (ensemble of 11) | Medium to High | Community benchmark |
**Practical Observation:** RFdiffusion + ProteinMPNN + AF2 is the gold standard for backbone-first design. ESM3 excels in conditional flexibility (arbitrary conditions for function, sequence, or structure). Ensemble approaches yield the best results.
### Estimated Cost for Learner Reproduction
- API cost: 0 (completely local).
- Generating 100 sequences: Based on ESM3 1.4B, it takes 30 minutes to 1 hour on a 16-24GB VRAM GPU.
- Validating 100 with Boltz-2: Based on the ensemble of 11 pipeline, it takes 2-4 hours.
- Downloading and indexing UniProt/Swissprot locally: Approximately 500MB and 1-2 hours.
### 5 Known Failure Cases (Collected from Community and Papers)
1. **High pLDDT for generated sequences, but failure in active site reconstruction.**
Symptoms: AF2/Boltz predicted pLDDT is 80+, but the arrangement of active site residues is incorrect.
Cause: pLDDT is a global confidence score and is separate from the specific 3D arrangement of residues. Especially in loop regions, pLDDT can be high even with flexibility.
Mitigation: (a) Individually check the pLDDT of active site residues (Step 5 in this chapter), (b) Mandatory check of RMSD of the active site in the predicted structure, (c) Re-validate stability with MD simulations (OpenMM, GROMACS), (d) Repeat generation with multiple seeds and perform consensus.
Source: Discussion on RFdiffusion vs. AF2 self-consistency [1].
2. **Too similar to natural sequences (not truly novel).**
Symptoms: When the generated sequence is BLASTed against UniProt, it shows multiple hits with identity greater than 40%.
Cause: The foundation model fails to move beyond the distribution of natural sequences it was trained on.
Mitigation: (a) Apply a strict diversity filter (Step 3 in this chapter), (b) Apply a UniProt similarity filter after generation (Step 4 in this chapter), (c) Increase sampling diversity by increasing the temperature (0.9+), (d) Enforce lower similarity using conditional generation with auxiliary loss.
Source: Discussions in several de novo design papers [3][4].
3. **Target function (catalytic activity or fluorescence) is absent in actual measurement.**
Symptoms: The 3D structure perfectly reproduces the required conditions. After experimental expression and purification, the actual activity is 0.
Cause: Activity requires not only the arrangement of active site residues but also the overall folding stability, dynamics, and subtle side chain arrangements. Protein folding and expression yield are also separate issues.
Mitigation: (a) Enhance activity prediction with MD simulations and Rosetta enzyme design, (b) Perform multiple parallel experiments with top candidates, (c) Automate high-throughput screening (yeast or phage display), (d) Use stability tags and fluorescent reporters in experimental measurements.
Source: Discussion on experimental validation in Watson et al.'s RFdiffusion paper [1].
4. **Only the active site residues are maintained, but the orientation is incorrect.**
Symptoms: Ser195, His57, and Asp102 are present in the sequence, but in 3D space, the catalytic arrangement (Ser hydroxyl forms a hydrogen bond with His) is not present.
Cause: ESM3 only maintains the identity of residues and does not optimize the side chain rotamer or 3D relative position.
Mitigation: (a) Inject backbone + side chain constraints together into the structure track of ESM3, (b) Post-process with Rosetta enzyme design to optimize side chains, (c) Post-validate CA-CA distance and dihedral angles of the active site (check ideal_distances in Step 1 of this chapter), (d) Validate dynamics with MDFF or MDshaping.
Source: Discussion in the ESM3 paper [4]; Rosetta enzyme design tutorial.
5. **ESM3 commercial license limitations.**
Symptoms: EvolutionaryScale ESM3 large (98B) model requires separate agreement for commercial use. The small (1.4B) model is open-source but still primarily for academic use.
Cause: EvolutionaryScale policy and different license compared to the previous Meta ESM2.
Mitigation: (a) For academic projects, use the open-weight 1.4B model, (b) For commercial projects, inquire about the license or use an alternative (RFdiffusion + ProteinMPNN combination), (c) Re-confirm the license terms when performing custom fine-tuning.
Source: EvolutionaryScale ESM license [10].
## Extended Ideas
- **Complex design:** Design protein-protein interfaces instead of single proteins (linked to Boltz-2 in Chapter 11).
- **Antibody design:** Design antibodies with CDR loop conditional generation (refer to RFantibody and IgLM).
- **De novo enzyme with substrate:** Utilize the docking of a specific substrate binding site as a conditional constraint (refer to Chapter 8).
- **Cyclic peptide:** Autonomously design stable cyclic peptides with an N-C connection constraint.
- **Multi-objective optimization:** Simultaneously optimize for activity, stability (thermal stability, aggregation resistance), and solubility.
- **Fluorescent protein design:** Design novel fluorescent proteins while maintaining the GFP chromophore (Ser65-Tyr66-Gly67) triad.
## Next Chapter
- Chapter 11: `structure-affinity-boltz`: Predicting ligand binding of generated proteins.
- Chapter 12: `single-cell-perturbation`: In silico simulation of the response when the generated protein is expressed in cells.
- Chapter 7: `drug-target-gnn`: GNN scoring of potential inhibitors for a novel protease.
- Chapter 14: `bio-mcp-agent`: Exposing protein design as an MCP tool, enabling autonomous experimental design by an agent.
## References
1. Watson JL, Juergens D, Bennett NR, et al. "De novo design of protein structure and function with RFdiffusion." Nature 2023. `https://www.nature.com/articles/s41586-023-06415-8`
2. Dauparas J, Anishchenko I, Bennett N, et al. "Robust deep learning-based protein sequence design using ProteinMPNN." Science 2022. `https://www.science.org/doi/10.1126/science.add2187`
3. Ingraham J, Baranov M, Costello Z, et al. "Illuminating protein space with a programmable generative model (Chroma)." Nature 2023.
4. Hayes T, Rao R, Akin H, et al. "Simulating 500 million years of evolution with a language model (ESM3)." bioRxiv 2024. `https://www.biorxiv.org/content/10.1101/2024.07.01.600583v1`
5. EvolutionaryScale ESM GitHub: `https://github.com/evolutionaryscale/esm`
6. RFdiffusion GitHub: `https://github.com/RosettaCommons/RFdiffusion`
7. ProteinMPNN GitHub: `https://github.com/dauparas/ProteinMPNN`
8. AlphaFold2 (DeepMind): `https://github.com/google-deepmind/alphafold`
9. ColabFold: `https://github.com/sokrypton/ColabFold`
10. EvolutionaryScale ESM License: `https://www.evolutionaryscale.ai/` · GitHub LICENSE
11. Chroma (Baker Lab): `https://github.com/RosettaCommons/chroma`
12. Baker Lab comprehensive: `https://www.bakerlab.org/`
13. pyrosetta: `https://www.pyrosetta.org/`
14. PyMOL open-source: `https://github.com/schrodinger/pymol-open-source`
15. Boltz GitHub (refer to Chapter 11): `https://github.com/jwohlwend/boltz`
16. Biopython: `https://biopython.org/`
17. Foldseek (structure similarity search): `https://github.com/steineggerlab/foldseek`
18. UniProt (natural sequence search): `https://www.uniprot.org/`
19. RCSB PDB (chymotrypsin 4CHA, etc.): `https://www.rcsb.org/`
20. RosettaCommons enzyme design tutorial: `https://www.rosettacommons.org/docs/latest/application_documentation/design/enzyme-design`

💬 Questions & Comments

0 comments

You can post without signing in. Guest comments cannot be edited or deleted by their author.

0/2000

Loading...