Branching

Fork a working set to explore multiple continuations from a shared prefix.

ws.fork(pipe) creates a new working set that shares all frozen KV cache pages with the original. As shown below, each branch then decodes independently and pays only for the tokens it adds.

Write a short scene setin a cityin a forestat dawnat nightat dawnat night
The shared prompt is computed once. Each branch pays only for its own words.

Three branches from one prompt

main.py
import asyncio

from inferlet import chat, model
from inferlet.eta import ForwardPass, Pipeline, StateGeometry, WorkingSet, intrinsics, reduce_argmax
# generate() as in "Your first inferlet"


async def branch(ws, ending):
    pipe = Pipeline()
    words = [t async for t in generate(ws, pipe, model.encode(ending), max_tokens=24)]
    pipe.close()
    return ending + model.decode(words)


async def main(input: dict) -> dict:
    # 1. Prefill and freeze the shared prompt once.
    root, setup = WorkingSet(), Pipeline()
    fwd = ForwardPass()
    fwd.embed(chat.prefix() + model.encode("Write one sentence about a cat"))
    fwd.state([root], StateGeometry.folding())
    done = fwd.epilogue(lambda: reduce_argmax(intrinsics.output(0, "logits")))
    setup.submit(fwd)
    await done

    # 2. Fork three child working sets and run them concurrently.
    endings = [" at dawn:", " at night:", " in the rain:"]
    children = [root.fork(setup) for _ in endings]
    setup.close()
    texts = await asyncio.gather(*(branch(ws, e) for ws, e in zip(children, endings)))
    return {"branches": texts}

Rules of thumb

  • Freeze the prefix before forking. fork() shares frozen KV pages by reference and copies only the writable buffer. Passing StateGeometry.folding() on the prompt pass freezes the prompt so all branches share it.
  • Give each branch its own Pipeline. Passes on a single pipeline run sequentially. Giving each branch its own pipeline lets them run concurrently. Close the parent setup pipeline once you finish forking from it.
  • Branches batch together automatically. The runtime batches passes from concurrent branches into shared GPU launches, so ten branches take far less than ten times the latency of one.

Common branching patterns

PatternExample
Best-of-$N$ votingconsensus-decoding
Beam searchbeam-search-py
Shared prefix treesprefix-tree-kv-cache-py
Agent rolloutsFork before trying candidate tool plans and keep the one that succeeds.
Go deeperRun multiple branches in one pass →

Lanes let several branches share a single ForwardPass for algorithms that compare logits at every token.