Retrieval-Augmented Training: RETRO Architecture

Michael BrenndoerferMarch 11, 202640 min read

Part of Language AI Handbook

How RETRO trains language models with retrieval from scratch, using chunked cross-attention to integrate a 2T-token database and cut parameter needs 25x.

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Retrieval-Augmented Training

Language models face a fundamental tension: the knowledge they contain is frozen at training time. No matter how large the model or how extensive its pretraining corpus, it cannot know about events that happened after the data cutoff, cannot access information that was never included in its training set, and must compress everything it has learned into billions of static parameters. This creates both a knowledge staleness problem and a storage efficiency problem. Every fact the model needs to recall must somehow be encoded in its weights, competing for capacity with the syntactic patterns, reasoning strategies, and linguistic regularities it also needs to internalize.

Retrieval-augmented generation (RAG), which you saw in earlier chapters on inference-time techniques, addresses this by supplying retrieved context to the model at inference time. The model reads relevant passages alongside the query and generates its response by conditioning on both. This works remarkably well, but it treats retrieval as an afterthought: the model was trained without any exposure to the retrieval interface, so it must cope with injected context through in-context learning rather than through internalized patterns for processing retrieved material.

Retrieval-augmented training takes a different approach. Instead of bolting retrieval onto a frozen model at inference time, the model is trained from the ground up with retrieval as an integral part of the forward pass. The model learns to read and use retrieved neighbors as part of its core computation, not as an incidental prompt prefix. The result is a model architecture and training regime where the boundary between "memory in weights" and "memory in retrieval database" is deliberately and efficiently managed.

The most influential architecture in this space is RETRO (Retrieval-Enhanced Transformer), introduced by Borgeaud et al. at DeepMind in 2021. RETRO showed that models with roughly 7 billion parameters could match the perplexity of GPT-3-scale models (175 billion parameters) when given access to a 2 trillion token retrieval database. The implication was provocative: a 25-fold reduction in parameter count with no quality loss, achieved by offloading factual storage to an external database rather than into model weights. This chapter unpacks how RETRO achieves this, why retrieval during training matters, and what the architecture teaches us about the separation of compute and memory in language modeling.

The Case for Retrieval During Training

To understand why training with retrieval is qualitatively different from inference-time RAG, consider what a model must learn in each setting.

In standard pretraining, the model is exposed to text tokens and must predict each next token. Over trillions of tokens, it learns to encode factual associations in its weights: that Paris is the capital of France, that Einstein developed the theory of relativity, that the boiling point of water at sea level is 100 degrees Celsius. These facts become distributed representations entangled with all the other knowledge in the network. Recalling a specific fact requires routing computation through the right layers and attention heads, with no guarantee that rarely-seen facts are reliably stored or that common facts have not been overwritten by more frequent patterns.

In inference-time RAG, a frozen model receives retrieved text prepended to its context. The model must figure out how to use this external context purely through in-context learning. It was never explicitly trained to extract and integrate retrieved information, so the integration quality depends on how well the retrieved text resembles the kind of context the model saw during pretraining. If the model has never been shown a pattern like "Here is a retrieved passage: [passage]. Now answer: [question]," it must generalize from loosely related training examples.

Training with retrieval changes this entirely. The model sees retrieved neighbors during every training step and learns to compute loss conditioned on both the local context and the retrieved material. It develops specialized architectural mechanisms for reading retrieved text and integrating it into its representations. The training objective directly rewards the model for using retrieved context well. By the time the model is deployed, it has internalized a general strategy for using retrieval rather than trying to adapt a strategy developed for a different setting.

There is also a compression argument. When a model must store facts in its weights, those parameters must simultaneously encode the facts and participate in general language understanding and reasoning. These roles may not be perfectly compatible. A parameter that stores "the capital of France" cannot simultaneously be optimal for representing syntactic agreement patterns. Retrieval-augmented training lets the model specialize its parameters more heavily toward language understanding and reasoning, while delegating factual storage to the retrieval database where it can be stored verbatim and accessed precisely.

The RETRO Architecture

RETRO introduces a specific architectural pattern for integrating retrieved sequences into the forward pass of a transformer language model. Understanding it requires first understanding how the retrieval interface is structured.

Chunked Cross-Attention

The core insight in RETRO is that a long sequence can be processed in fixed-length chunks, and each chunk can be enriched with retrieved material that is relevant to the local context up to that point. Rather than trying to process the entire sequence against a global retrieved set, RETRO maintains alignment between local sequence segments and their retrieved neighbors.

Formally, given an input sequence of tokens x1,x2,…,xnx_1, x_2, \ldots, x_n, RETRO splits it into non-overlapping chunks of size ll (typically 64 tokens):

Cu=(x(u−1)l+1,…,xul)C_u = (x_{(u-1)l + 1}, \ldots, x_{ul})

where:

  • CuC_u is the uu-th chunk
  • ll is the chunk length (64 tokens in the original paper)
  • uu ranges from 1 to n/ln / l

For each chunk CuC_u, RETRO retrieves kk neighbor sequences from the database using the chunk as a query. Each neighbor NujN_u^j consists of two parts: the retrieved passage itself (the "neighbor") plus a continuation (the "neighbor-plus") which is the text that follows the neighbor in the original document. This continuation provides additional context that is informative but was not the direct retrieval target.

During training, the model processes chunks sequentially, but the retrieval for chunk CuC_u is based on all tokens seen up to and including chunk Cu−1C_{u-1}. This is a causal constraint: you cannot use chunk CuC_u itself to retrieve its neighbors, because at inference time you would be retrieving before you have generated those tokens. The retrieval query for chunk CuC_u is formed from the prefix C1,…,Cu−1C_1, \ldots, C_{u-1}.

The chunked cross-attention (CCA) mechanism is the architectural innovation that implements this integration. At specific layers in the transformer stack, the representation of each token in chunk CuC_u attends to the encoded representations of the retrieved neighbors Nu1,…,NukN_u^1, \ldots, N_u^k. This is different from standard self-attention in several ways:

  • The keys and values come from a separate encoder that processes the retrieved sequences
  • Only tokens within the same chunk attend to the same retrieved set
  • The cross-attention is causally masked: tokens in chunk CuC_u can only attend to retrieved neighbors computed from the prefix C1,…,Cu−1C_1, \ldots, C_{u-1}

The CCA operation for a token at position ii within chunk CuC_u computes:

CCA(qi,Ku,Vu)=softmax(qiKuTdk)Vu\text{CCA}(q_i, K_u, V_u) = \text{softmax}\left(\frac{q_i K_u^T}{\sqrt{d_k}}\right) V_u

where:

  • qiq_i is the query vector for token ii derived from its hidden state
  • KuK_u and VuV_u are the key and value matrices derived from the encoded neighbor sequences for chunk uu
  • dkd_k is the key dimension

The encoder that produces KuK_u and VuV_u is a bidirectional transformer (since the neighbors are fully observed and do not need causal masking). It processes each retrieved neighbor independently and produces a sequence of hidden states that the main model can attend to through CCA.

The RETRO Architecture Stack

The full RETRO model interleaves two types of transformer layers.

A standard transformer layer applies multi-head self-attention followed by a feed-forward network in the usual way. No retrieved context is used in these layers.

A RETRO layer contains three sub-components applied in sequence. First, standard self-attention over the input sequence. Second, chunked cross-attention over the encoded neighbors. Third, a feed-forward network. The CCA step is inserted between self-attention and the feed-forward network, after the self-attention has already contextualized the token representations within the sequence.

Not every layer is a RETRO layer. Typically, CCA is only applied in every third or fourth layer, allowing the model to first build up contextualized representations through self-attention before integrating the retrieved material. This design reflects the intuition that retrieval integration is most effective when the model already has a rich understanding of the local context.

The encoder used to process neighbors is significantly smaller than the main model. In the original RETRO paper, the main model has up to 7 billion parameters while the encoder uses approximately the same architecture as a standard 600 million parameter transformer. The encoder is frozen during much of the training process in some configurations, though the original paper trains the full system end-to-end.

The Retrieval Database

The retrieval component is a massive key-value store. In the original RETRO experiments, this database contains 2 trillion tokens drawn from MassiveText, which is the same corpus used to train Gopher and other DeepMind models. The database is split into 64-token chunks, and each chunk is associated with a dense embedding vector computed by a frozen sentence encoder (BERT-based in the original paper).

At retrieval time, the query embedding is computed from the prefix tokens and compared to all chunk embeddings using approximate nearest-neighbor search (specifically, SCaNN in the original implementation). The top-kk neighbors by embedding similarity are retrieved, along with their continuations.

The choice to use frozen embeddings for retrieval rather than training the retrieval system end-to-end with the model is a practical compromise. Training a retrieval system that indexes trillions of tokens requires recomputing and reindexing embeddings periodically as the encoder changes, which is computationally expensive. Using a frozen retriever eliminates this cost at the expense of some potential quality.

Why the Scaling Results Are Surprising

The headline result from the RETRO paper is that a 7.5 billion parameter RETRO model achieves lower perplexity on language modeling benchmarks than a 175 billion parameter GPT-3. This is roughly a 25x parameter reduction, which requires some unpacking because raw parameter counts can be misleading.

The RETRO model, while small in parameter count, is supplemented by the 2 trillion token retrieval database. If we ask how much "information capacity" the full RETRO system has, we need to account for both the model weights and the retrieval database. The database itself is large: 2 trillion tokens at roughly 2 bytes per token is about 4 terabytes of raw text. In that sense, RETRO is better described as differently organized than simply more efficient.

The performance advantage also the performance advantage holds even at high numbers of retrieved tokens. The perplexity curves for RETRO as a function of database size and model size show a consistent pattern: doubling the database size improves perplexity more cheaply (in compute) than doubling model parameters. This suggests that much of what large language models store in their weights is effectively a compressed lookup table for world knowledge, and that externalizing this lookup table into a database is more efficient than encoding it in weights.

The comparison also reveals something about the nature of perplexity as a metric. Perplexity on the Pile and similar benchmarks is strongly influenced by the model's ability to predict rare and specific facts: proper nouns, technical terminology, numerical quantities. These are exactly the kinds of tokens where retrieval provides the most benefit, because they are hard to memorize in weights but easy to find in a database. Reasoning and syntax, by contrast, are less directly aided by retrieval because they require computation rather than lookup.

Out[3]:
Visualization
Log-scale line plot of model parameters from 0.17 to 175 billion. Dense-model perplexity falls from about 23.7 to 12.2; the stylized RETRO curve spans 0.17 to 7.5 billion parameters and falls from about 17.4 to 12.2.
Stylized power-law perplexity curves as a function of model parameter count. The RETRO curve applies a fixed 25-fold effective parameter multiplier to illustrate the original paper's reported parameter-efficiency result; it is an explanatory approximation rather than digitized benchmark data.
Log-scale line plot of database size from 4 billion to 2 trillion tokens. Stylized RETRO perplexity falls from 9.8 to 7.5, while a dashed dense 7B baseline remains at 9.8.
Stylized perplexity as a function of retrieval database size for a fixed 7B RETRO model. The assumed log-linear relationship lowers perplexity from 9.8 with 4 billion database tokens to 7.5 with 2 trillion tokens. This is an illustrative scaling model, not a reported measurement series.

Training Dynamics with Retrieval

Training RETRO from scratch involves several considerations that differ from standard pretraining.

Retrieval During Training

Every training step requires actual retrieval operations. For each training batch, the input sequences must be split into chunks, each chunk must be encoded into a query vector, and the kk nearest neighbors must be retrieved from the database. This adds a non-trivial overhead to each training step compared to a standard dense transformer.

In practice, RETRO mitigates this overhead by pre-computing retrievals offline before training begins. A retrieval index is built once from the training corpus, and for each training sequence, the neighbors are retrieved and cached alongside the training examples. During the actual training forward pass, the retrieved neighbors are simply looked up from this cache rather than computed dynamically. This converts the online retrieval problem into a storage problem: you need to store the cached neighbors for all training sequences, which is significant but manageable.

This pre-computation has an interesting implication: the retrievals are static during training. As the main model's parameters change, the optimal neighbors for each query might change, but the cached neighbors do not update. In the original RETRO paper, the retrievals are computed once and held fixed throughout training. This is a further trade-off that likely reduces quality somewhat but is necessary for practical training.

The Training Objective

The RETRO training objective is standard autoregressive language modeling loss. The model is trained to predict the next token given all previous tokens, conditioned on the retrieved neighbors for the relevant chunk. Formally:

L=−∑i=1nlog⁡pθ(xi∣x<i,RET(C⌊i/l⌋−1))\mathcal{L} = -\sum_{i=1}^{n} \log p_\theta\left(x_i \mid x_{<i}, \text{RET}(C_{\lfloor i/l \rfloor - 1})\right)

where:

  • x<ix_{<i} denotes all tokens preceding position ii
  • RET(Cu−1)\text{RET}(C_{u-1}) denotes the retrieved neighbors computed from the prefix up to chunk u−1u-1
  • ll is the chunk length
  • θ\theta represents all model parameters

The key point is that for tokens in the first chunk (u=1u = 1), there are no previous chunks to use as a retrieval query, so the model must predict those tokens without any retrieved context. The retrieval benefit only kicks in starting from the second chunk. This is analogous to how inference-time RAG typically requires a full query before retrieval can occur.

Training from Scratch vs. RETROfit

The original RETRO paper trains the full architecture from scratch with retrieval. However, a subsequent line of work has explored "retrofitting" a standard pretrained model to use the RETRO architecture, a process called RETROfit. In this approach, a standard GPT-style model is extended with the CCA layers and encoder, and these new components are trained while the original model weights are frozen or lightly fine-tuned.

RETROfit is appealing because it avoids the enormous cost of pretraining from scratch. A 7 billion parameter model trained from scratch with RETRO requires the same compute as pretraining a 7 billion parameter GPT model, plus the overhead of retrieval during training. RETROfit allows reuse of existing pretrained weights.

The trade-off is quality. When trained from scratch, the model can develop retrieval-aware representations in its self-attention layers from the very beginning, integrating retrieval knowledge throughout the network. In RETROfit, the existing self-attention weights were optimized without any retrieval signal, so they may not be ideal for the CCA integration. Empirically, RETROfit achieves most but not all of the quality benefit of full RETRO training, with substantially lower training cost.

Integrating Retrieved Context: The Mechanics

Understanding how retrieved text is used in the forward pass requires working through the architecture in detail.

Encoding Neighbors

The neighbor encoder is a bidirectional transformer that processes each retrieved sequence independently. Given a retrieved neighbor NujN_u^j of length mm tokens (typically 128 tokens: 64 for the neighbor plus 64 for the continuation), the encoder produces a sequence of hidden states:

Huj=Encoder(Nuj)∈Rm×dencH_u^j = \text{Encoder}(N_u^j) \in \mathbb{R}^{m \times d_{\text{enc}}}

where dencd_{\text{enc}} is the encoder hidden dimension. These hidden states are the keys and values that the main model attends to through CCA.

Because the encoder is bidirectional, each token in the neighbor sequence attends to all other tokens, including those that come after it. This is appropriate because the neighbor is fully observed at inference time. The model is not generating the neighbor; it is reading it.

The encoder processes all kk neighbors in parallel. Their outputs are concatenated along the sequence dimension to form the full key-value matrix that the main model attends to for a given chunk.

Cross-Attention Integration

When the main model reaches a CCA layer, it performs cross-attention from the token representations in chunk CuC_u to the encoded neighbor representations. Each token in CuC_u can attend to all tokens across all kk encoded neighbors.

The cross-attention mechanism computes:

Qu=HumainWQKu=HuencWKVu=HuencWVCCA(Cu)=softmax(QuKuTdk)Vu\begin{aligned} Q_u &= H_u^{\text{main}} W_Q \\ K_u &= H_u^{\text{enc}} W_K \\ V_u &= H_u^{\text{enc}} W_V \\ \text{CCA}(C_u) &= \text{softmax}\left(\frac{Q_u K_u^T}{\sqrt{d_k}}\right) V_u \end{aligned}

where:

  • HumainH_u^{\text{main}} is the main model's hidden state for tokens in chunk CuC_u
  • HuencH_u^{\text{enc}} is the concatenated encoded representation of all kk neighbors for chunk uu
  • WQ,WK,WVW_Q, W_K, W_V are learned projection matrices
  • dkd_k is the key dimension

The output of CCA is combined with the main model's self-attention output through a residual connection and layer normalization, before being passed to the feed-forward sublayer.

This design has a natural interpretation. The self-attention over CuC_u allows tokens to contextualize themselves relative to the current local and global sequence context. The cross-attention to neighbors then allows those contextualized representations to be enriched with retrieved information. The feed-forward network integrates these two sources of information into the final token representations.

Causal Constraints and the Retrieval Lag

The causal constraint in RETRO creates a one-chunk lag in retrieval. When predicting tokens in chunk CuC_u, the model uses retrieved neighbors queried from the prefix ending at chunk Cu−1C_{u-1}. This means the model never retrieves information that is directly relevant to the tokens it is currently predicting based on those same tokens, which preserves autoregressive causality.

In practice, this lag is small (64 tokens) and the retrieved neighbors are typically relevant because they were retrieved using the preceding context, which is closely related to the current context in most natural text. A text that discusses the French Revolution in one chunk will almost certainly continue to discuss it in the next chunk, so neighbors retrieved for the preceding context remain relevant.

The lag does create a theoretical gap at sequence boundaries, where the very beginning of a new topic might not have optimal retrievals because the preceding context established a different topic. This is a known limitation of the chunked approach.

A Worked Example: Chunk-by-Chunk Retrieval

To make the chunked retrieval process concrete, walk through how RETRO processes a passage about climate science.

Suppose the model is processing the following 256-token passage (represented schematically as four 64-token chunks):

  • Chunk 1: "The Earth's average surface temperature has risen approximately 1.1 degrees Celsius since the late 19th century. This warming is primarily driven by increased atmospheric concentrations of greenhouse gases such as carbon dioxide and methane..."
  • Chunk 2: "Carbon dioxide levels have increased from 280 parts per million in pre-industrial times to over 420 parts per million today. This increase is primarily attributable to the burning of fossil fuels, deforestation, and industrial processes..."
  • Chunk 3: "The consequences of this warming include rising sea levels, more frequent extreme weather events, and disruptions to agricultural systems. Arctic sea ice extent has declined significantly, and permafrost regions are beginning to thaw..."
  • Chunk 4: "International agreements such as the Paris Agreement aim to limit warming to 1.5 degrees Celsius above pre-industrial levels. Achieving this target requires substantial reductions in global greenhouse gas emissions by 2030..."

At the start of processing, the model has seen no context, so Chunk 1 is processed without any retrieved neighbors. This is unavoidable: there is no prefix to query against.

When the model begins processing Chunk 2, it encodes Chunk 1 as a retrieval query. The query embedding is a dense vector representation computed from the tokens in Chunk 1. The nearest-neighbor search finds database chunks that discuss similar material: passages about temperature measurements, greenhouse gas warming, historical climate records. These retrieved chunks, along with their continuations, become the CCA input for Chunk 2. The model can now predict tokens in Chunk 2 with access to related facts from elsewhere in the training corpus, for example data tables of historical temperature records or scientific explanations of the greenhouse effect that may not appear verbatim in the current passage.

When processing Chunk 3, the query is formed from the full prefix up to the end of Chunk 2. Now the model has more context to work with: the passage is clearly about climate science, specifically focusing on CO2 concentrations and their sources. The retrieved neighbors are likely to be even more relevant, potentially including passages about sea level rise data, extreme weather attribution studies, or Arctic observation reports.

This chunk-by-chunk retrieval rhythm means the model gets progressively better retrievals as the sequence unfolds and the topic becomes clearer. The first chunk is the weakest point, but for any passage of reasonable length, the majority of tokens are predicted with high-quality retrieved context.

The worked example also illustrates why the neighbor continuation matters. If the retrieval database contains a chunk beginning with "Arctic sea ice extent reached a record minimum in..." and the query from Chunk 2 matches this chunk, the model receives that chunk and the following text: "...2012, covering only 3.41 million square kilometers, roughly half the average from 1979-2000." This continuation, which extends beyond what was directly retrieved, gives the model access to specific quantitative facts that would be relevant for predicting tokens in Chunk 3 about Arctic conditions. Without the continuation, the model gets the beginning of a fact but not its resolution.

Semi-Parametric Models

RETRO belongs to a family of architectures called semi-parametric models. A purely parametric model (like a standard GPT) stores all knowledge in its weights, which are fixed after training. A purely non-parametric model (like a k-nearest-neighbor classifier) stores all knowledge in a database and has no learned parameters at all. Semi-parametric models combine both: a neural network with learned weights handles computation and pattern recognition, while a database handles factual storage and retrieval. The key design question is how to allocate responsibility between the two components, which is exactly what RETRO's chunked cross-attention architecture addresses.

Code Implementation

Let us build a simplified but complete implementation of the RETRO components to develop concrete intuition for the architecture. We will implement the core building blocks: the chunked cross-attention mechanism, a toy retrieval system, and a miniature RETRO-style transformer.

Setting Up: Imports and Utilities

In[4]:
Code
import numpy as np
import torch

# Set reproducibility
torch.manual_seed(42)
np.random.seed(42)

Building a Toy Retrieval Database

We will create a simple retrieval system using cosine similarity over dense embeddings. In a full RETRO implementation, this would be approximate nearest-neighbor search over trillions of chunks, but the interface is identical.

In[5]:
Code
import torch.nn.functional as F


class ToyRetrievalDatabase:
    """Simple retrieval database using cosine similarity over embeddings."""

    def __init__(
        self, n_chunks: int = 200, embed_dim: int = 64, vocab_size: int = 100
    ):
        self.n_chunks = n_chunks
        self.embed_dim = embed_dim
        self.vocab_size = vocab_size
        # Simulate chunk embeddings (in practice, computed by a frozen encoder)
        self.embeddings = F.normalize(torch.randn(n_chunks, embed_dim), dim=-1)

    def retrieve(self, query_embedding: torch.Tensor, k: int = 2) -> list:
        """Retrieve k nearest neighbors by cosine similarity."""
        query_norm = F.normalize(query_embedding.unsqueeze(0), dim=-1)
        similarities = torch.matmul(query_norm, self.embeddings.T).squeeze(0)
        top_k_indices = torch.topk(similarities, k=k).indices.tolist()
        return top_k_indices

    def get_chunk_tokens(self, idx: int, chunk_len: int = 8) -> torch.Tensor:
        """Return a token tensor for the chunk at index idx."""
        # In practice, these would be the actual tokenized chunks
        gen = torch.Generator()
        gen.manual_seed(idx)
        return torch.randint(0, self.vocab_size, (chunk_len,), generator=gen)

Chunked Cross-Attention

The core RETRO mechanism is chunked cross-attention. This module computes attention from main-sequence tokens to encoded neighbor tokens:

In[6]:
Code
import math

import torch.nn as nn
import torch.nn.functional as F


class ChunkedCrossAttention(nn.Module):
    """Chunked cross-attention as in RETRO."""

    def __init__(self, d_model: int, n_heads: int):
        super().__init__()
        self.d_model = d_model
        self.n_heads = n_heads
        self.d_k = d_model // n_heads

        self.q_proj = nn.Linear(d_model, d_model, bias=False)
        self.k_proj = nn.Linear(d_model, d_model, bias=False)
        self.v_proj = nn.Linear(d_model, d_model, bias=False)
        self.out_proj = nn.Linear(d_model, d_model, bias=False)

    def forward(
        self,
        chunk_hidden: torch.Tensor,  # (batch, chunk_len, d_model)
        neighbor_hidden: torch.Tensor,  # (batch, k * neighbor_len, d_model)
    ) -> torch.Tensor:
        B, L, _ = chunk_hidden.shape
        M = neighbor_hidden.shape[1]

        Q = (
            self.q_proj(chunk_hidden)
            .view(B, L, self.n_heads, self.d_k)
            .transpose(1, 2)
        )
        K = (
            self.k_proj(neighbor_hidden)
            .view(B, M, self.n_heads, self.d_k)
            .transpose(1, 2)
        )
        V = (
            self.v_proj(neighbor_hidden)
            .view(B, M, self.n_heads, self.d_k)
            .transpose(1, 2)
        )

        scale = math.sqrt(self.d_k)
        attn_weights = torch.matmul(Q, K.transpose(-2, -1)) / scale
        attn_probs = F.softmax(attn_weights, dim=-1)
        attended = torch.matmul(attn_probs, V)

        attended = attended.transpose(1, 2).contiguous().view(B, L, -1)
        return self.out_proj(attended)

The Neighbor Encoder

The encoder processes retrieved neighbors bidirectionally. In RETRO, this is a smaller transformer that produces hidden states for the retrieved text:

In[7]:
Code
class NeighborEncoder(nn.Module):
    """Bidirectional transformer encoder for retrieved neighbors."""

    def __init__(
        self, vocab_size: int, d_model: int, n_heads: int, n_layers: int
    ):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, d_model)
        encoder_layer = nn.TransformerEncoderLayer(
            d_model=d_model,
            nhead=n_heads,
            dim_feedforward=d_model * 4,
            batch_first=True,
            norm_first=True,
        )
        self.transformer = nn.TransformerEncoder(
            encoder_layer, num_layers=n_layers
        )
        self.d_model = d_model

    def forward(self, neighbor_tokens: torch.Tensor) -> torch.Tensor:
        """
        neighbor_tokens: (batch, k, neighbor_len)
        Returns: (batch, k * neighbor_len, d_model)
        """
        B, k, L = neighbor_tokens.shape
        flat_tokens = neighbor_tokens.reshape(B * k, L)
        embeds = self.embedding(flat_tokens) * math.sqrt(self.d_model)
        encoded = self.transformer(embeds)
        return encoded.reshape(B, k * L, self.d_model)

A Minimal RETRO Layer

Now we put it together: a RETRO transformer layer that combines self-attention with chunked cross-attention:

In[8]:
Code
class RETROLayer(nn.Module):
    """A single RETRO transformer layer: self-attention + CCA + FFN."""

    def __init__(self, d_model: int, n_heads: int, is_retro_layer: bool = True):
        super().__init__()
        self.is_retro_layer = is_retro_layer
        self.d_model = d_model

        self.self_attn = nn.MultiheadAttention(
            d_model, n_heads, batch_first=True
        )
        self.norm1 = nn.LayerNorm(d_model)

        if is_retro_layer:
            self.cca = ChunkedCrossAttention(d_model, n_heads)
            self.norm_cca = nn.LayerNorm(d_model)

        self.ffn = nn.Sequential(
            nn.Linear(d_model, d_model * 4),
            nn.GELU(),
            nn.Linear(d_model * 4, d_model),
        )
        self.norm2 = nn.LayerNorm(d_model)

    def forward(
        self,
        x: torch.Tensor,
        attn_mask: torch.Tensor,
        neighbor_hidden: torch.Tensor,
        chunk_size: int,
    ) -> torch.Tensor:
        B, S, D = x.shape

        # 1. Self-attention
        x_normed = self.norm1(x)
        sa_out, _ = self.self_attn(
            x_normed,
            x_normed,
            x_normed,
            attn_mask=attn_mask,
            need_weights=False,
        )
        x = x + sa_out

        # 2. Chunked cross-attention (only in RETRO layers)
        if self.is_retro_layer and neighbor_hidden is not None:
            n_chunks = S // chunk_size
            cca_outputs = []
            for u in range(n_chunks):
                start = u * chunk_size
                end = start + chunk_size
                chunk_normed = self.norm_cca(x[:, start:end, :])
                cca_out = self.cca(chunk_normed, neighbor_hidden)
                cca_outputs.append(cca_out)
            x = x + torch.cat(cca_outputs, dim=1)

        # 3. Feed-forward
        x = x + self.ffn(self.norm2(x))
        return x

A Mini RETRO Model

In[9]:
Code
class MiniRETRO(nn.Module):
    """A small RETRO-style language model. Every other layer includes CCA."""

    def __init__(
        self,
        vocab_size: int = 100,
        d_model: int = 64,
        n_heads: int = 4,
        n_layers: int = 4,
        chunk_size: int = 8,
        k: int = 2,
        neighbor_len: int = 8,
    ):
        super().__init__()
        self.vocab_size = vocab_size
        self.d_model = d_model
        self.chunk_size = chunk_size
        self.k = k
        self.neighbor_len = neighbor_len

        self.token_emb = nn.Embedding(vocab_size, d_model)
        self.pos_emb = nn.Embedding(512, d_model)

        # Neighbor encoder: smaller than main model
        self.encoder = NeighborEncoder(
            vocab_size, d_model // 2, n_heads // 2, n_layers=1
        )
        self.enc_proj = nn.Linear(d_model // 2, d_model)

        # Alternate standard and RETRO layers
        self.layers = nn.ModuleList(
            [
                RETROLayer(d_model, n_heads, is_retro_layer=(i % 2 == 1))
                for i in range(n_layers)
            ]
        )

        self.norm_final = nn.LayerNorm(d_model)
        self.lm_head = nn.Linear(d_model, vocab_size, bias=False)

    def forward(
        self,
        input_ids: torch.Tensor,  # (batch, seq_len)
        neighbor_ids: torch.Tensor,  # (batch, n_chunks, k, neighbor_len)
    ) -> torch.Tensor:
        B, S = input_ids.shape
        device = input_ids.device

        positions = torch.arange(S, device=device).unsqueeze(0)
        x = self.token_emb(input_ids) + self.pos_emb(positions)

        causal_mask = torch.triu(
            torch.full((S, S), float("-inf"), device=device), diagonal=1
        )

        # Encode neighbors for the first chunk (demo simplification)
        chunk_neighbors = neighbor_ids[:, 0, :, :]  # (B, k, neighbor_len)
        enc_out = self.encoder(chunk_neighbors)  # (B, k * neighbor_len, d//2)
        neighbor_h = self.enc_proj(enc_out)  # (B, k * neighbor_len, d)

        for layer in self.layers:
            if layer.is_retro_layer:
                x = layer(x, causal_mask, neighbor_h, self.chunk_size)
            else:
                x = layer(x, causal_mask, None, self.chunk_size)

        return self.lm_head(self.norm_final(x))

Training a Mini RETRO Model

Let us train this model on a simple synthetic language modeling task and compare it against a standard transformer baseline:

In[10]:
Code
def make_causal_lm_data(
    vocab_size: int = 100,
    n_samples: int = 500,
    seq_len: int = 32,
    chunk_size: int = 8,
    k: int = 2,
    neighbor_len: int = 8,
):
    input_ids = torch.randint(0, vocab_size, (n_samples, seq_len))
    n_chunks = seq_len // chunk_size
    neighbor_ids = torch.randint(
        0, vocab_size, (n_samples, n_chunks, k, neighbor_len)
    )
    labels = torch.cat(
        [input_ids[:, 1:], torch.zeros(n_samples, 1, dtype=torch.long)], dim=1
    )
    return input_ids, neighbor_ids, labels


class StandardLM(nn.Module):
    """Standard GPT-like transformer for comparison."""

    def __init__(
        self,
        vocab_size: int = 100,
        d_model: int = 64,
        n_heads: int = 4,
        n_layers: int = 4,
    ):
        super().__init__()
        self.token_emb = nn.Embedding(vocab_size, d_model)
        self.pos_emb = nn.Embedding(512, d_model)
        layer = nn.TransformerEncoderLayer(
            d_model=d_model,
            nhead=n_heads,
            dim_feedforward=d_model * 4,
            batch_first=True,
            norm_first=True,
        )
        self.transformer = nn.TransformerEncoder(layer, num_layers=n_layers)
        self.norm = nn.LayerNorm(d_model)
        self.lm_head = nn.Linear(d_model, vocab_size, bias=False)

    def forward(self, input_ids: torch.Tensor) -> torch.Tensor:
        B, S = input_ids.shape
        pos = torch.arange(S, device=input_ids.device).unsqueeze(0)
        x = self.token_emb(input_ids) + self.pos_emb(pos)
        mask = torch.triu(
            torch.full((S, S), float("-inf"), device=input_ids.device),
            diagonal=1,
        )
        x = self.transformer(x, mask=mask, is_causal=True)
        return self.lm_head(self.norm(x))


VOCAB_SIZE = 100
SEQ_LEN = 32
CHUNK_SIZE = 8
K = 2
NEIGHBOR_LEN = 8
BATCH_SIZE = 32
N_EPOCHS = 40

input_ids, neighbor_ids, labels = make_causal_lm_data(
    vocab_size=VOCAB_SIZE,
    n_samples=500,
    seq_len=SEQ_LEN,
    chunk_size=CHUNK_SIZE,
    k=K,
    neighbor_len=NEIGHBOR_LEN,
)

retro_model = MiniRETRO(
    vocab_size=VOCAB_SIZE,
    d_model=64,
    n_heads=4,
    n_layers=4,
    chunk_size=CHUNK_SIZE,
    k=K,
    neighbor_len=NEIGHBOR_LEN,
)
standard_model = StandardLM(VOCAB_SIZE)

retro_opt = torch.optim.Adam(retro_model.parameters(), lr=3e-3)
standard_opt = torch.optim.Adam(standard_model.parameters(), lr=3e-3)

retro_losses = []
standard_losses = []

n_batches = len(input_ids) // BATCH_SIZE

for epoch in range(N_EPOCHS):
    perm = torch.randperm(len(input_ids))
    epoch_retro_loss = 0.0
    epoch_standard_loss = 0.0

    for b in range(n_batches):
        idx = perm[b * BATCH_SIZE : (b + 1) * BATCH_SIZE]
        x_batch = input_ids[idx]
        n_batch = neighbor_ids[idx]
        y_batch = labels[idx]

        retro_opt.zero_grad()
        retro_logits = retro_model(x_batch, n_batch)
        retro_loss = F.cross_entropy(
            retro_logits.view(-1, VOCAB_SIZE), y_batch.view(-1)
        )
        retro_loss.backward()
        retro_opt.step()
        epoch_retro_loss += retro_loss.item()

        standard_opt.zero_grad()
        std_logits = standard_model(x_batch)
        std_loss = F.cross_entropy(
            std_logits.view(-1, VOCAB_SIZE), y_batch.view(-1)
        )
        std_loss.backward()
        standard_opt.step()
        epoch_standard_loss += std_loss.item()

    retro_losses.append(epoch_retro_loss / n_batches)
    standard_losses.append(epoch_standard_loss / n_batches)

final_retro_loss = retro_losses[-1]
final_standard_loss = standard_losses[-1]
Out[11]:
Console
Final training loss (RETRO):    0.0034
Final training loss (Standard): 1.9122
RETRO parameter count:    296,672
Standard parameter count: 245,632

On this synthetic task with random neighbors, both models learn to reduce training loss, but they do not form a controlled quality comparison. The RETRO model has 296,672 parameters versus 245,632 for the standard model, and its training loss falls much faster. Because the neighbors carry no semantic signal and the chart shows training rather than held-out loss, that gap should be read as extra capacity fitting the synthetic examples, not as evidence that retrieval improves generalization. The demo captures the architectural mechanics but not RETRO's representational benefit on meaningful retrievals.

Out[12]:
Visualization
Line plot of synthetic training loss over 40 epochs. RETRO drops steeply from about 4.6 to 0.003; the standard transformer decreases more gradually to 1.912. The neighbors are random, so the gap is not evidence of retrieval generalization.
Training loss over 40 epochs for the synthetic RETRO demonstration with random neighbors. RETRO falls from about 4.6 to 0.003, while the standard transformer falls from about 4.6 to 1.912. RETRO also has more parameters (296,672 versus 245,632), and the plot contains no held-out evaluation, so the lower training loss demonstrates fitting capacity rather than a retrieval-quality advantage.

Visualizing Attention Patterns in CCA

One of the most instructive things we can examine is what the chunked cross-attention attends to. If the cross-attention is working correctly, tokens in a chunk should develop non-uniform attention patterns over neighbor tokens:

In[13]:
Code
def get_cca_attention_weights(model, input_ids, neighbor_ids):
    """Extract CCA attention weights from the first RETRO layer."""
    model.eval()
    with torch.no_grad():
        B, S = input_ids.shape
        positions = torch.arange(S).unsqueeze(0)
        x = model.token_emb(input_ids) + model.pos_emb(positions)

        chunk_neighbors = neighbor_ids[:, 0, :, :]
        enc_out = model.encoder(chunk_neighbors)
        neighbor_h = model.enc_proj(enc_out)

        causal_mask = torch.triu(torch.full((S, S), float("-inf")), diagonal=1)

        # Forward through standard layer first (layer 0)
        x = model.layers[0](x, causal_mask, None, model.chunk_size)

        # Manually extract CCA weights from layer 1 (first RETRO layer)
        retro_layer = model.layers[1]
        x_normed = retro_layer.norm1(x)
        sa_out, _ = retro_layer.self_attn(
            x_normed,
            x_normed,
            x_normed,
            attn_mask=causal_mask,
            need_weights=False,
        )
        x = x + sa_out

        chunk_h = x[:, : model.chunk_size, :]
        chunk_normed = retro_layer.norm_cca(chunk_h)

        cca = retro_layer.cca
        chunk_len = chunk_h.shape[1]
        neighbor_len = neighbor_h.shape[1]
        Q = (
            cca.q_proj(chunk_normed)
            .view(B, chunk_len, cca.n_heads, cca.d_k)
            .transpose(1, 2)
        )
        K = (
            cca.k_proj(neighbor_h)
            .view(B, neighbor_len, cca.n_heads, cca.d_k)
            .transpose(1, 2)
        )

        scale = math.sqrt(cca.d_k)
        attn = F.softmax(torch.matmul(Q, K.transpose(-2, -1)) / scale, dim=-1)
        attn_weights = attn.mean(dim=(0, 1)).cpu().numpy()

    return attn_weights


sample_input = input_ids[:1]
sample_neighbors = neighbor_ids[:1]
attn_weights = get_cca_attention_weights(
    retro_model, sample_input, sample_neighbors
)
Out[14]:
Console
CCA attention weight matrix shape: (8, 16)
  rows = chunk tokens (8)
  cols = neighbor tokens (16): 2 neighbors x 8 tokens each
Attention weight statistics:
  Mean: 0.0625  (uniform baseline = 0.0625)
  Max:  0.3121
  Std:  0.0725
  Attention entropy (mean): 2.2222 / max 2.7726
  Entropy ratio: 0.801 (1.0 = fully uniform, lower = more focused)

The attention entropy ratio tells us how selective the CCA is. A ratio near 1.0 means the model attends roughly equally to all neighbor tokens. Here the ratio is about 0.80, so the learned attention is clearly non-uniform. Because this demonstration uses random neighbors and measures training behavior only, however, individual bright cells cannot be interpreted as semantically relevant retrievals; they show that the CCA mechanism can form selective patterns on the synthetic task.

Out[15]:
Visualization
Heatmap with 8 query-token rows and 16 neighbor-token columns, divided into N1 and N2 blocks of 8. Weights range from near 0 to 0.312; the strongest cell is around query token Q7 and neighbor token N1-2.
Chunked cross-attention weights from the first RETRO layer in the synthetic demonstration. Rows are 8 query-chunk tokens and columns are 16 retrieved tokens, split into two 8-token neighbors by the dashed divider. Each row sums to 1; the maximum weight is 0.312 and the mean entropy ratio is 0.801. The non-uniform pattern shows selectivity, but random neighbors mean it should not be interpreted as semantic retrieval relevance.

Limitations and Practical Challenges

Retrieval-augmented training is a powerful paradigm but carries substantial engineering and conceptual challenges.

Engineering Complexity

The training pipeline for RETRO is significantly more complex than standard transformer pretraining. Building and maintaining a 2 trillion token retrieval index requires specialized infrastructure. Pre-computing retrievals for all training sequences requires storing the retrieved neighbors alongside the training data, multiplying storage requirements. The encoder adds compute to each forward pass. Reindexing the retrieval database as the model evolves requires repeated embedding computation over the entire database.

In practice, few organizations outside of large research labs have deployed full-scale retrieval-augmented training. The infrastructure requirements are substantial: approximate nearest-neighbor indices over trillions of embeddings are nontrivial to build, query, and maintain.

Retrieval Quality Bottleneck

The quality of the learned model is bounded by the quality of retrieval. If the nearest-neighbor search returns irrelevant neighbors, the CCA mechanism must learn to ignore them or, worse, may propagate irrelevant information through the network. In the original RETRO paper, using a fixed BERT-based retriever that was not updated during training means the retrieval quality may not be optimal for the task at hand.

The retrieval quality problem is especially acute for rare topics. Well-represented topics in the retrieval database yield good neighbors; obscure or specialized topics may not have relevant entries, leaving the model to fall back on its parametric knowledge for those queries.

Static Retrieval During Training

Pre-computing retrievals and caching them throughout training creates a subtle mismatch: the cached retrievals were computed by a retriever that does not co-evolve with the main model. As the main model's representations change, the optimal retrieved neighbors might change, but the cached neighbors remain fixed. This is analogous to using stale gradients in asynchronous distributed training: it works in practice but introduces noise relative to the ideal.

Joint training of the retriever and main model is theoretically superior but requires periodic reindexing of the retrieval database, which is expensive. Some follow-up work has explored online retrieval with periodic index refreshes, but this remains an active research area.

Inference Latency

At inference time, RETRO requires a retrieval step for each chunk of the generated sequence. This adds latency that standard dense models do not have. For conversational applications where low latency is important, the retrieval overhead can be significant, requiring careful optimization of the nearest-neighbor search pipeline. Batched inference with retrieval caching can mitigate this, but it adds engineering complexity.

Knowledge Freshness

While retrieval-augmented training solves the knowledge staleness problem at inference time (by allowing the database to be updated), the model's ability to use the retrieved information is still governed by its training-time distribution. If a new type of knowledge structure appears in the database that was not represented during training, the model may not know how to integrate it optimally.

The Database Maintenance Problem

A retrieval database used in production must be continuously maintained: new documents added, stale or incorrect documents removed, embeddings recomputed for changed documents. For a 2 trillion token database, this is a substantial ongoing engineering effort. The operational cost of maintaining a retrieval database is often underestimated in research settings.

RETRO and retrieval-augmented training represent a broader shift in how the field thinks about the relationship between model parameters and external memory.

The traditional view of a language model was a self-contained system: all knowledge in weights, all computation in the forward pass. RETRO demonstrated that this is not optimal. Some knowledge, particularly factual and encyclopedic knowledge, is more efficiently stored in databases than in weights. Model parameters can be specialized toward the kinds of computation that are difficult to offload: reasoning, syntactic understanding, stylistic generation.

To appreciate why this matters, consider what happens when a model must store a fact like "the 2019 Nobel Prize in Physics was awarded for theoretical discoveries in physical cosmology." This fact appears infrequently in text, so the gradient signal pushing the model to remember it is weak. The memory will compete with millions of other rare facts for weight capacity. The fact may be partially encoded in several attention heads, none of which has it with high fidelity. When the model is asked to recall it, the retrieval succeeds sometimes and fails others. Contrast this with a retrieval database: the fact is stored verbatim in a Wikipedia article, searchable by any query about Nobel Prizes, cosmology, or 2019 physics achievements. Retrieval is deterministic and exact.

This comparison highlights that "storing facts in weights" is a fundamentally lossy and unreliable process. Weights encode probability distributions over tokens, not discrete facts. Facts that are rarely co-occurring with queries lose fidelity over training. RETRO's insight is that this lossy encoding is not necessary for factual knowledge, which can be stored losslessly in a database.

This connects to a broader research program on semi-parametric models: systems that combine a parametric component (the neural network) with a non-parametric component (a database, a retrieval system, or an external tool). Inference-time RAG, explored in previous chapters, is the most widely deployed instance of this paradigm. RETRO shows that the integration can be made much tighter by training with retrieval from the start.

The ideas in RETRO have influenced subsequent work in several directions. Atlas (Izacard et al., 2022) showed that jointly fine-tuning the retriever and the reader for specific tasks could substantially outperform RETRO on knowledge-intensive benchmarks. The key innovation in Atlas was allowing gradients to flow through the retrieval system during fine-tuning, so the model could learn to retrieve the specific kinds of information it needed for a given task. Toolformer (Schick et al., 2023) extended the idea of training with external tools beyond retrieval to calculators, search engines, and translation systems, with the model learning to call these tools through its own generation. Internet-augmented language models explore querying live web search during inference, generalizing the static database to the entire indexed web.

A related but distinct development is the use of retrieval during fine-tuning for knowledge-intensive tasks. Rather than training with retrieval from scratch (as in RETRO) or adapting frozen models to use retrieval at inference time (as in standard RAG), intermediate approaches train a base model normally and then fine-tune it with retrieval using task-specific supervision. This "retrieval-augmented fine-tuning" has shown strong results on tasks like open-domain question answering, where the model must retrieve relevant passages before generating an answer.

The long-term trajectory of this research direction points toward models that are deliberately designed for open-world operation: models that know how to use external information sources, that can identify when their parametric knowledge is insufficient and defer to retrieval, and that can integrate retrieved content with their own learned representations consistently. RETRO provides the foundational architectural blueprint for this kind of system.

Looking ahead to topics we will cover in the following chapters on long-form generation, the lessons from retrieval-augmented training inform how we think about maintaining coherence when producing extended text: retrieval can ground each section in relevant content from earlier parts of the document or from external sources. The decomposition between computation and memory that RETRO exemplifies is increasingly central to efficient language model design.

Key Parameters

The key parameters for RETRO-style retrieval-augmented training are:

  • chunk_size: The number of tokens per chunk, controlling the granularity of retrieval alignment. RETRO uses 64 tokens. Smaller chunks mean more frequent retrieval and finer alignment, at higher computational cost.
  • k: The number of retrieved neighbors per chunk. RETRO retrieves 2 neighbors. More neighbors provide more context but increase the cross-attention cost and may introduce noise.
  • neighbor_len: The length of each retrieved neighbor sequence, including the continuation. RETRO uses 128 tokens (64 neighbor + 64 continuation).
  • retro_layer_frequency: How frequently CCA layers appear in the stack. More RETRO layers provide more integration opportunities but increase computation.
  • database_size: The total number of tokens in the retrieval database. RETRO demonstrates that doubling database size consistently improves perplexity, suggesting diminishing but meaningful returns.

Summary

Retrieval-augmented training integrates external memory into the model at training time rather than as an inference-time add-on. The key insight is that language models trained with retrieval develop specialized mechanisms for reading and integrating retrieved content, making them more effective at using external knowledge than models trained without retrieval that are given retrieved context at inference time.

The RETRO architecture achieves this through chunked cross-attention: splitting input sequences into fixed-length chunks, retrieving relevant neighbors for each chunk from a massive database, and attending to those neighbors through dedicated cross-attention layers interspersed with standard self-attention. The 25x parameter reduction demonstrated by RETRO, relative to GPT-3 at matched perplexity, suggests that much of what large models store in their weights is effectively a compressed fact database that can be more efficiently stored externally.

The paradigm raises important engineering challenges: maintaining large retrieval databases, pre-computing and caching retrievals for training, managing the mismatch between static cached retrievals and evolving model representations, and handling inference latency. These challenges explain why retrieval-augmented training remains primarily a research direction rather than a widely deployed production technique, though inference-time RAG has seen broad adoption.

The broader lesson is architectural: model parameters and external databases have different strengths. Parameters excel at encoding procedural knowledge, reasoning patterns, and linguistic structure. Databases excel at storing and precisely retrieving factual content. Designing systems that allocate each type of knowledge to its most efficient storage medium is a productive direction for continued research.

Quiz

Ready to test your understanding? Take this quick quiz to reinforce what you've learned about retrieval-augmented training and the RETRO architecture.

Retrieval-Augmented Training Quiz

Question 1 of 80 of 8 completed
What is the primary advantage of training a model with retrieval from scratch (as in RETRO) compared to inference-time RAG with a frozen model?

Comments

No comments yet. Be the first to share your thoughts!

Reference

Citation details

Cite or share this article.

BIBTEXAcademic
@misc{brenndoerfer2026retrievalaugmented, author = {Michael Brenndoerfer}, title = {Retrieval-Augmented Training: RETRO Architecture}, year = {2026}, url = {https://mbrenndoerfer.com/writing/retrieval-augmented-training-retro-architecture-context-integration}, organization = {mbrenndoerfer.com}, note = {Accessed: 2026-10-15} }
APAAcademic
Michael Brenndoerfer (2026). Retrieval-Augmented Training: RETRO Architecture. Retrieved from https://mbrenndoerfer.com/writing/retrieval-augmented-training-retro-architecture-context-integration
MLAAcademic
Michael Brenndoerfer. "Retrieval-Augmented Training: RETRO Architecture." 2026. Web. October 15, 2026. <https://mbrenndoerfer.com/writing/retrieval-augmented-training-retro-architecture-context-integration>.
CHICAGOAcademic
Michael Brenndoerfer. "Retrieval-Augmented Training: RETRO Architecture." Accessed October 15, 2026. https://mbrenndoerfer.com/writing/retrieval-augmented-training-retro-architecture-context-integration.
HARVARDAcademic
Michael Brenndoerfer (2026) 'Retrieval-Augmented Training: RETRO Architecture'. Available at: https://mbrenndoerfer.com/writing/retrieval-augmented-training-retro-architecture-context-integration (Accessed: October 15, 2026).
SimpleBasic
Michael Brenndoerfer (2026). Retrieval-Augmented Training: RETRO Architecture. https://mbrenndoerfer.com/writing/retrieval-augmented-training-retro-architecture-context-integration

About the author

Continue with the full handbook

This chapter is part of Language AI Handbook. Use the handbook page to browse the complete table of contents and continue reading in sequence.

Explore Language AI Handbook
Newsletter

Stay up to date

Get articles, book updates, and news delivered to your inbox.

No spam, unsubscribe anytime.

or

Join the community

Sign in to remove popups, track your reading progress, and join the discussion.