Skip to main content
This program redesigns a nanobody (VHH) against the PD-L1 target using a Germinal-style, three-stage pipeline. A fixed target segment carries the PD-L1 structure, and a designable binder segment is optimized through three stages that share the same construct: a gradient stage over continuous logits, a gradient stage through a softmax schedule, and a discrete semigreedy MCMC stage. Every stage scores candidates with AlphaFold2 binder objectives (interface pTM, pLDDT, contact, radius-of-gyration losses) and an AbLang antibody language-model term that keeps the sequence antibody-like. Because the three stages, the stitched AF2 template, and the CDR/framework layout are involved to assemble by hand, this walkthrough imports the program builder from the example script and runs it with a small configuration: one seed, one final candidate, and a few steps per stage. The full script sweeps many seeds and runs longer schedules to produce stronger binders. It requires a GPU and the AlphaFold2 and AbLang weights. Open as a runnable notebook View as a Python script
Runtime: this walkthrough runs real models on a GPU and takes several minutes to complete. The first run is slower because it builds the tool environment and downloads model weights.

Building the three-stage program

build_program resolves the PD-L1 target and nanobody template into language-layer segments, stitches the two-chain AF2 template, and wires the three optimizers with their AF2 and AbLang constraints. The fixed target segment is built from the template PDB chain; the designable binder segment is seeded from the scaffold sequence, and both are grouped into one Construct shared across all three stages. The first two stages are GradientOptimizer instances configured from germinal_logit_preset (the logit hallucination phase) and germinal_softmax_preset (the softmax refinement phase); the third is an MCMCOptimizer running semigreedy mutation. The arguments below scale every stage down. --logit-steps, --softmax-steps, and --mcmc-steps override each stage’s step count, --num-seeds 1 --num-results 1 produces a single trajectory and a single ranked candidate, --proposals-per-result 1 sets the MCMC proposals per trajectory per step, and --num-recycles 1 sets the AlphaFold2 recycle iterations used for multimer scoring. The printout reports the resolved binder and target lengths.
python
import sys
from pathlib import Path

# The PD-L1 pipeline composes three stages with stitched AF2 templates; reuse the script's builder.
sys.path.insert(0, str(Path.cwd().parents[1]))
from examples.scripts.germinal_pdl1_sampling import build_program, parse_args, summarize_candidates

sys.argv = [
    "germinal",
    "--num-seeds", "1",          # one design trajectory
    "--num-results", "1",        # keep the single best candidate
    "--logit-steps", "2",        # stage 1: gradient over logits
    "--softmax-steps", "1",      # stage 2: gradient through a softmax schedule
    "--mcmc-steps", "1",         # stage 3: discrete semigreedy MCMC
    "--proposals-per-result", "1",
    "--num-recycles", "1",       # AF2 recycles for multimer scoring
    "--seed", "0",
]
args = parse_args()
program, binder, target, binder_seed, template_pdb = build_program(args)

print(f"binder length: {binder.sequence_length} aa  |  target: PD-L1 ({target.sequence_length} aa)")

Running the stages

The three optimizers run in sequence on the shared construct, so each stage’s output becomes the next stage’s starting point. Stage one optimizes the per-position logits with gradient descent; stage two continues those logits through Germinal’s softmax annealing schedule, where the softmax temperature ramps from 1.0 toward 0.01; and stage three runs discrete Metropolis-Hastings, proposing single-point mutations with the SemigreedyMutationGenerator and accepting or rejecting them under simulated annealing. Every stage scores candidates with the AlphaFold2 binder objectives and the AbLang antibody-language-model term, which scores how natural the sequence is under an antibody language model. DeviceManager.get_instance().configure(allow_multiple_per_device=True) lets the AlphaFold2 and AbLang persistent workers coexist on the same GPU. program.run() executes all three stages and populates program.energy_scores with the final per-trajectory objective values.
python
from proto_tools.utils import DeviceManager

DeviceManager.get_instance().configure(allow_multiple_per_device=True)
program.run()

Inspect the result

summarize_candidates ranks the final designs by their combined objective (lower energy is better) and pulls the headline AlphaFold2 confidence metrics out of each result’s constraint metadata. The printout shows, per candidate: energy (the summed weighted constraint loss being minimized), avg_plddt (the predicted local-distance-difference-test confidence), and iptm (the predicted interface TM-score for the binder-target interface), followed by the designed binder sequence.
python
summary = summarize_candidates(binder, program.energy_scores)
for row in summary:
    print(f"rank {row['rank']}: energy={row['energy']:.3f} "
          f"avg_plddt={row['avg_plddt']} iptm={row['iptm']}")
    print(f"  designed binder: {row['sequence']}")
rank 1: energy=3.850 avg_plddt=0.7996058464050293 iptm=0.11053422838449478
  designed binder: QVQLVESGGGLVQPGGSLRLSCAASGDKGAQHQTTSLGWFRQAPGQGAEAVAAWQTKQRYGYYADSVKGRFTISRDNSKNTLYLQMNSLRAEDTAVYYCRSRVPRLARVYQGWAFEMWGQGTLVTVSSRGR

Next Steps

Binder Design

A single-stage binder design with RFdiffusion3 and ProteinMPNN.

Multi-Stage Optimization

How stages hand a shared construct forward.