GEMINI LABJP
SUNSET — Six days until the image generation models shut down: the imagen-4.0 family and Gemini 3 Image models stop on August 17MIGRATE — gemini-3.1-flash-image is the recommended replacement, and it means rewriting generate_images calls as generate_contentCHECK — The same prompt will not necessarily produce the same picture after migrating, so secure any images you still need before the cutoffCLASSROOM — August 17 is also the day Gemini in Classroom arrives on mobile; the web rollout to students of all ages began on August 10DEPRECATION — The Grok 4.1 family shuts down on August 20, and gemini-robotics-er-1.6-preview on August 31, succeeded by the er-2 modelsCHANGELOG — The Gemini API changelog still ends at July 30. The most recent major change remains the GA of Gemini 3.6 Flash and 3.5 Flash-LiteSUNSET — Six days until the image generation models shut down: the imagen-4.0 family and Gemini 3 Image models stop on August 17MIGRATE — gemini-3.1-flash-image is the recommended replacement, and it means rewriting generate_images calls as generate_contentCHECK — The same prompt will not necessarily produce the same picture after migrating, so secure any images you still need before the cutoffCLASSROOM — August 17 is also the day Gemini in Classroom arrives on mobile; the web rollout to students of all ages began on August 10DEPRECATION — The Grok 4.1 family shuts down on August 20, and gemini-robotics-er-1.6-preview on August 31, succeeded by the er-2 modelsCHANGELOG — The Gemini API changelog still ends at July 30. The most recent major change remains the GA of Gemini 3.6 Flash and 3.5 Flash-Lite
Articles/Advanced
Advanced/2026-07-31Advanced

After the Vertex AI Rename, I Measured My Search Stack. Ranking Held. Aggregation Did Not.

When Vertex AI became Gemini Enterprise Agent Platform, I benchmarked my own docs search. Ranking barely moved. The exact-match layer quietly lost most of its results without raising a single error.

Gemini Enterprise Agent PlatformVertex AI12search designaliasingoperations12

Premium Article

I found the line in the release notes late on July 30th: Vertex AI is now Gemini Enterprise Agent Platform.

My first thought went to my runbooks. Running six apps solo means my personal notes and my in-app help index have slowly turned into a small knowledge base. Every "Vertex AI" in there now points at a name that no longer exists.

Tomorrow, when someone searches with the new name, would anything come back at all?

So the next morning I measured it. The answer was the opposite of what I expected. Ranking held up fine. Something else had gone quietly missing.

What I Measured

I rebuilt my situation as the smallest thing that still reproduces it — no external services, so anyone can get the same numbers.

  • Corpus: 30 runbook fragments. Twelve of them describe platform-side concerns (deployment, quota, IAM, billing). Ten of those use the legacy name, two use the new one.
  • Retriever: BM25 (k1=1.5, b=0.75). Japanese text tokenized as 2-grams, ASCII as whole words.
  • Queries: three families of five.
    • Topical — "how do I handle a quota overage" — the query carries signal beyond the product name.
    • Name-only — "what is X", "X settings" — the name is the only handle.
    • Unrelated — cache TTL, AdMob — a control group.

Three responses, compared head to head:

ConditionActionReindex needed?
A: do nothingLeave the legacy name in placeNo
B: bulk rewriteReplace the old name inside every chunk, reindexYes
C: query-side expansionLeave the index alone, expand queries in both directionsNo

B looks obviously right. It brings your data in line with reality. That was my assumption going in.

The Benchmark Code

No dependencies. Swap in your own corpus and you can run exactly this.

# -*- coding: utf-8 -*-
"""Measuring how a product rename affects lexical retrieval. No external deps."""
import math, re
from collections import Counter
 
OLD = "vertex ai"
NEW = "gemini enterprise agent platform"
 
def tok(s: str):
    """2-grams for CJK, whole words for ASCII. Keeps the BM25 vocabulary consistent."""
    s = s.lower()
    s = re.sub(r"[、。()()「」・,.]", " ", s)
    parts = []
    for w in s.split():
        if re.fullmatch(r"[a-z0-9_\-\.]+", w):
            parts.append(w)               # ASCII stays a single token
        else:
            for i in range(len(w) - 1):
                parts.append(w[i:i + 2])  # CJK becomes 2-grams
            if len(w) == 1:
                parts.append(w)           # don't drop single-character tokens
    return parts
 
class BM25:
    def __init__(self, docs, k1=1.5, b=0.75):
        self.ids = [d[0] for d in docs]
        self.toks = [tok(d[1]) for d in docs]
        self.k1, self.b = k1, b
        self.N = len(docs)
        self.avgdl = sum(len(t) for t in self.toks) / self.N
        self.df = Counter()
        for t in self.toks:
            self.df.update(set(t))        # document frequency counts sets, not totals
        self.tf = [Counter(t) for t in self.toks]
 
    def search(self, q: str, topk=5):
        qt = tok(q)
        scores = []
        for i in range(self.N):
            s, dl = 0.0, len(self.toks[i])
            for w in qt:
                f = self.tf[i].get(w, 0)
                if not f:
                    continue
                idf = math.log(1 + (self.N - self.df[w] + 0.5) / (self.df[w] + 0.5))
                s += idf * (f * (self.k1 + 1)) / (
                    f + self.k1 * (1 - self.b + self.b * dl / self.avgdl))
            scores.append((s, self.ids[i]))
        # Without a deterministic tiebreak your measurements drift between runs
        scores.sort(key=lambda x: (-x[0], x[1]))
        return [i for s, i in scores[:topk] if s > 0]
 
def expand_bidirectional(q: str) -> str:
    """Condition C. Old to new AND new to old. One direction only saves half your users."""
    ql = q.lower()
    if OLD in ql:
        return q + " " + NEW
    if NEW in ql:
        return q + " " + OLD
    return q
 
def precision_at_k(idx: BM25, queries, gold: set, k=5, expand=None):
    total = 0.0
    for q in queries:
        got = idx.search(expand(q) if expand else q, k)
        if not got:
            continue
        total += sum(1 for d in got if d in gold) / k
    return round(total / len(queries), 3)

I wrote expand_bidirectional one-way first — legacy queries rewritten toward the new name. That version dropped every reader who had already adopted the new terminology. Expansion has to run both ways or it is not worth shipping.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
A reproducible BM25 benchmark of retrieval quality immediately after a vendor product rename
Why bulk-rewriting your chunks is a net loss (P@5 drops from 0.92 to 0.08 for legacy-name queries)
The layer that actually breaks is exact-match routing and aggregation, plus where to put the alias resolver instead
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Advanced2026-08-06
The Day the Knowledge Cutoff Moved Forward, the Stale Part Was My System Instruction
When a model's knowledge cutoff advances, the thing that goes stale is not the model — it is the dated assertions in your system instruction. Here is why only the lines written between the two cutoffs flip from helpful to contradictory, plus a working audit script and its measured results.
Advanced2026-07-03
Your Night Batch Is Causing the Morning 429s — Priority Admission Control for a Shared Gemini Quota
When bulk jobs and interactive features share one project's RPM/TPM, the bulk lane wins by default. A priority token bucket design with measurements: 429 rate 3.2% down to 0.03%.
Advanced2026-07-02
When the Gemini Review Bot in Your CI Quietly Stops Earning Its Keep — Rebuilding Trust with Coverage and Actioned-Rate Metrics
A Gemini-powered PR review bot in GitHub Actions degrades without ever throwing an error. Field notes on catching diff truncation, model alias drift, and swallowed parse failures with one-line JSON logs and an actioned-rate metric.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →