What’s new in Gemini-1.5-pro-002 and Gemini-1.5-flash-002

This notebook explores the new options added with the 002 versions of the 1.5 series models:

Setup

Install the Google GenAI SDK

Install the Google GenAI SDK from npm.

$ npm install @google/genai

Setup your API key

You can create your API key using Google AI Studio with a single click.

Remember to treat your API key like a password. Don’t accidentally save it in a notebook or source file you later commit to GitHub. In this notebook we will be storing the API key in a .env file. You can also set it as an environment variable or use a secret manager.

Here’s how to set it up in a .env file:

$ touch .env
$ echo "GEMINI_API_KEY=<YOUR_API_KEY>" >> .env
Tip

Another option is to set the API key as an environment variable. You can do this in your terminal with the following command:

$ export GEMINI_API_KEY="<YOUR_API_KEY>"

Load the API key

To load the API key from the .env file, we will use the dotenv package. This package loads environment variables from a .env file into process.env.

$ npm install dotenv

Then, we can load the API key in our code:

const dotenv = require("dotenv") as typeof import("dotenv");

dotenv.config({
  path: "../.env",
});

const GEMINI_API_KEY = process.env.GEMINI_API_KEY ?? "";
if (!GEMINI_API_KEY) {
  throw new Error("GEMINI_API_KEY is not set in the environment variables");
}
console.log("GEMINI_API_KEY is set in the environment variables");
GEMINI_API_KEY is set in the environment variables
Note

In our particular case the .env is is one directory up from the notebook, hence we need to use ../ to go up one directory. If the .env file is in the same directory as the notebook, you can omit it altogether.

│
├── .env
└── quickstarts
    └── New_in_002.ipynb

Initialize SDK Client

With the new SDK, now you only need to initialize a client with you API key (or OAuth if using Vertex AI). The model is now set in each call.

const google = require("@google/genai") as typeof import("@google/genai");

const ai = new google.GoogleGenAI({ apiKey: GEMINI_API_KEY });

Select a model

Check available 002 models

const models = await ai.models.list();
let { page } = models;
while (page.length > 0) {
  for (const model of page) {
    if (model.name.includes("002")) {
      console.log(model.name);
    }
  }
  page = models.hasNextPage() ? await models.nextPage() : [];
}
models/gemini-1.5-pro-002
models/gemini-1.5-flash-002
models/imagen-3.0-generate-002
const tslab = require("tslab") as typeof import("tslab");

const MODEL_ID = "gemini-1.5-flash-002";

Quick refresher on GenerationConfig [Optional]

const response = await ai.models.generateContent({
  model: MODEL_ID,
  contents: "Why don't people have tails",
  config: {
    temperature: 1.0,
    maxOutputTokens: 5,
  },
});
console.log(response.text);
Humans don't have
  • Each generateContent request is sent with a GenerationConfig (chat.sendMessage uses generateContent).
  • You can set the GenerationConfig by passing it in the arguments to generateContent (or chat.sendMessage).
  • If you’re ever unsure about the parameters of GenerationConfig check types.GenerationConfig.

Candidate count

With 002 models you can now use candidateCount > 1.

const responses = await ai.models.generateContent({
  model: MODEL_ID,
  contents: "Why don't people have tails",
  config: {
    candidateCount: 2,
  },
});
Note

Note that the .text quick-accessor only works for the simple 1-candidate case, and the sdk will log a console.warn stating that it’s only returning the first candidate. If you want to access all candidates, use the .candidates property instead.

tslab.display.markdown(responses.text ?? "");
there are multiple candidates in the response, returning text from the first one.

Humans don’t have tails because of evolutionary changes over millions of years. Our ancestors did have tails, but as humans evolved and adapted to walking upright (bipedalism), the tail became less necessary and advantageous. The genes that controlled tail development were gradually switched off or modified through a process called natural selection.

Specifically:

  • Loss of function mutations: Random genetic mutations occurred that affected the genes responsible for tail development. If these mutations didn’t have a significant negative impact on survival and reproduction, they could be passed on to future generations. Over time, accumulating mutations progressively reduced tail size until it became vestigial (the coccyx, or tailbone, is what remains).

  • Bipedalism and its consequences: Walking upright changed the way our bodies functioned and the pressures of natural selection. A tail, which is useful for balance and climbing in arboreal (tree-dwelling) animals, became less important for bipedal locomotion. The energy spent developing and maintaining a tail was likely better spent on other adaptations crucial for survival on the ground.

  • Developmental changes: The changes in our embryonic development also contributed to the reduction of the tail. Human embryos do initially have a tail-like structure during development, but it regresses and is largely absorbed before birth, leaving only the coccyx.

In short, the lack of a tail in humans is the result of a complex interplay of genetic mutations, evolutionary pressures related to bipedalism, and changes in embryonic development. It’s an example of how natural selection can lead to the loss of features that are no longer advantageous.

With multiple candidates you have to handle the list of candidates yourself:

for (const response of responses.candidates ?? []) {
  tslab.display.markdown(response.content?.parts?.[0].text ?? "");
  tslab.display.markdown("\n---\n");
}

Humans don’t have tails because of evolutionary changes over millions of years. Our ancestors had tails, but as humans evolved, the genes that controlled tail development were suppressed. This wasn’t a sudden change, but a gradual process driven by natural selection. Several theories attempt to explain why this happened:

  • Loss of function: The tail’s original functions (balance, climbing, etc.) became less crucial as our ancestors adopted bipedalism (walking upright). The energy and resources used to maintain a tail were no longer offset by its benefits, leading to a neutral, or even slightly negative, selective pressure on genes controlling tail development. Mutations that reduced or eliminated tail growth were not disadvantageous and were therefore passed on.

  • Developmental changes: The changes might also have resulted from shifts in embryonic development. Genes regulating the development of the tail and the coccyx (the small bone at the base of our spine, which is a vestigial tail) may have interacted in ways that ultimately favored shorter and eventually, non-existent external tails.

  • Sexual selection: It’s possible that, at some point, taillessness or shorter tails became a desirable trait from a sexual selection perspective. This is purely speculative and difficult to prove.

It’s important to note that we still have a vestigial tail – the coccyx. This remnant of our tailed ancestry is a testament to our evolutionary history. While a functional tail is absent, the genetic mechanisms for tail development are still present, albeit largely inactive, as evidenced by rare cases of human babies born with tails (which are usually surgically removed). These are usually malformations rather than a “re-emergence” of a functional tail, but they highlight the fact that the genetic information for a tail isn’t entirely lost.


Humans don’t have tails because of evolution. Our ancestors, like apes, did have tails, but over millions of years, the genes responsible for tail development were switched off or mutated in ways that resulted in the loss of the tail. This wasn’t a conscious decision, but rather a consequence of natural selection.

Several theories propose why this might have been advantageous:

  • Improved balance and bipedalism: As humans evolved to walk upright, a tail might have become more of a hindrance than a help. A tail could interfere with balance and efficient movement on two legs.

  • Reduced energy consumption: Maintaining a tail requires energy. Losing the tail could have freed up resources for other developmental needs.

  • Social signaling: In some primates, tails are used for communication. However, humans developed other, more complex communication methods, making a tail less necessary.

  • Sexual selection: The lack of a tail might have become a desirable trait in mate selection, leading to its elimination through sexual selection.

It’s important to note that this is a complex evolutionary process, and the exact reasons are still being researched. It’s likely a combination of these factors, and perhaps others we haven’t yet identified, that contributed to the loss of the tail in humans. The occasional birth of a human baby with a vestigial tail (a small, rudimentary tail) demonstrates that the genes for tail development haven’t completely disappeared from the human genome, they’re just usually inactive.


The response contains multiple full Candidate objects.

console.log(JSON.stringify(responses, null, 2));
{
  "candidates": [
    {
      "content": {
        "parts": [
          {
            "text": "Humans don't have tails because of evolutionary changes over millions of years.  Our ancestors did have tails, but as humans evolved and adapted to walking upright (bipedalism), the tail became less necessary and advantageous.  The genes that controlled tail development were gradually switched off or modified through a process called natural selection.  \n\nSpecifically:\n\n* **Loss of function mutations:**  Random genetic mutations occurred that affected the genes responsible for tail development.  If these mutations didn't have a significant negative impact on survival and reproduction, they could be passed on to future generations.  Over time, accumulating mutations progressively reduced tail size until it became vestigial (the coccyx, or tailbone, is what remains).\n\n* **Bipedalism and its consequences:**  Walking upright changed the way our bodies functioned and the pressures of natural selection.  A tail, which is useful for balance and climbing in arboreal (tree-dwelling) animals, became less important for bipedal locomotion. The energy spent developing and maintaining a tail was likely better spent on other adaptations crucial for survival on the ground.\n\n* **Developmental changes:**  The changes in our embryonic development also contributed to the reduction of the tail.  Human embryos do initially have a tail-like structure during development, but it regresses and is largely absorbed before birth, leaving only the coccyx.\n\nIn short, the lack of a tail in humans is the result of a complex interplay of genetic mutations, evolutionary pressures related to bipedalism, and changes in embryonic development.  It's an example of how natural selection can lead to the loss of features that are no longer advantageous.\n"
          }
        ],
        "role": "model"
      },
      "finishReason": "STOP",
      "avgLogprobs": -0.3816025597708566
    },
    {
      "content": {
        "parts": [
          {
            "text": "Humans don't have tails primarily because of **evolutionary changes**.  Over millions of years, our primate ancestors gradually lost their tails through a process of natural selection.  While the exact reasons are complex and not fully understood, several contributing factors are likely:\n\n* **Bipedalism:**  As our ancestors transitioned to walking upright on two legs, a tail became less advantageous.  Tails are helpful for balance and locomotion in quadrupedal (four-legged) animals, but they would have been less useful and potentially even hindering for bipedal locomotion.  The energy expended maintaining a tail might have been better allocated to other adaptations.\n\n* **Changes in Genes:**  Specific genetic mutations likely played a crucial role.  These mutations affected the genes controlling tail development during embryonic growth, leading to shorter and eventually absent tails in our lineage.\n\n* **Selection Pressures:**  Natural selection favored individuals with shorter tails or no tails at all.  Those without tails might have had advantages in terms of energy efficiency, agility, or even reduced predation risk, depending on the specific environmental pressures.\n\nIt's important to note that the loss of the tail wasn't a sudden event.  It occurred gradually over a long period, with intermediate forms showing progressively shorter tails.  The vestigial tailbone (coccyx) we have today is a remnant of this evolutionary process.  It's a small, fused collection of bones at the base of our spine, reflecting our tailed ancestry.\n"
          }
        ],
        "role": "model"
      },
      "finishReason": "STOP",
      "avgLogprobs": -0.302224858601888,
      "index": 1
    }
  ],
  "modelVersion": "gemini-1.5-flash-002",
  "usageMetadata": {
    "promptTokenCount": 7,
    "candidatesTokenCount": 636,
    "totalTokenCount": 643,
    "promptTokensDetails": [
      {
        "modality": "TEXT",
        "tokenCount": 7
      }
    ],
    "candidatesTokensDetails": [
      {
        "modality": "TEXT",
        "tokenCount": 636
      }
    ]
  }
}

Penalties

The 002 models expose penalty arguments that let you affect the statistics of output tokens.

Presence penalty

The presencePenalty penalizes tokens that have already been used in the output, so it induces variety in the model’s output. This is detectible if you count the unique words in the output.

Here’s a function to run a prompt a few times and report the fraction of unique words (words don’t map perfectly to tokens but it’s a simple way to see the effect).

const PROMPT = "Tell me a story";

async function uniqueWords(penalty?: number, N = 10): Promise<number[]> {
  const fractions: number[] = [];
  for (let i = 0; i < N; i++) {
    const response = await ai.models.generateContent({
      model: MODEL_ID,
      contents: PROMPT,
      config: {
        ...(penalty ? { presencePenalty: penalty } : {}),
      },
    });
    const words = (response.text ?? "").toLowerCase().split(/\s+/);
    fractions.push(new Set(words).size / words.length);
  }
  return fractions;
}

function mean(arr: number[]): number {
  return arr.reduce((a, b) => a + b, 0) / arr.length;
}
const v1 = await uniqueWords();
console.log(JSON.stringify(v1, null, 2));
[
  0.565121412803532,
  0.5858585858585859,
  0.6172839506172839,
  0.6188235294117647,
  0.6035634743875279,
  0.5790754257907542,
  0.6004901960784313,
  0.5717821782178217,
  0.5853658536585366,
  0.5574837310195228
]
// baseline
console.log("Mean unique words:", mean(v1).toFixed(2));
Mean unique words: 0.59
// the penalty encourages diversity in the oputput tokens.
const v2 = await uniqueWords(1.999);
console.log(JSON.stringify(v2, null, 2));
[
  0.5771971496437055,
  0.5931818181818181,
  0.5955555555555555,
  0.6108247422680413,
  0.5742092457420924,
  0.59,
  0.6296296296296297,
  0.6077097505668935,
  0.6077981651376146,
  0.6103896103896104
]
console.log("Mean unique words with penalty:", mean(v2).toFixed(2));
Mean unique words with penalty: 0.60
// a negative penalty discourages diversity in the output tokens.
const v3 = await uniqueWords(-1.999);
console.log(JSON.stringify(v3, null, 2));
[
  0.5708061002178649,
  0.5588235294117647,
  0.5515695067264574,
  0.5736263736263736,
  0.5495867768595041,
  0.6142506142506142,
  0.6072289156626506,
  0.5573770491803278,
  0.5839080459770115,
  0.6190476190476191
]
console.log("Mean unique words with negative penalty:", mean(v3).toFixed(2));
Mean unique words with negative penalty: 0.58

The presencePenalty has a small effect on the vocabulary statistics.

Frequency Penalty

Frequency penalty is similar to the presencePenalty but the penalty is multiplied by the number of times a token is used. This effect is much stronger than the presencePenalty.

The easiest way to see that it works is to ask the model to do something repetitive. The model has to get creative while trying to complete the task.

const frequency_response = await ai.models.generateContent({
  model: MODEL_ID,
  contents: `please repeat "Cat" 50 times, 10 per line`,
  config: {
    frequencyPenalty: 1.999,
  },
});
console.log(frequency_response.text ?? "");
Cat Cat Cat Cat Cat Cat Cat Cat Cat Cat
Cat Cat Cat Cat Cat Cat Cat Cat Ca tCat
Cat Cat Cat Cat Cat Cat Cat Cat Cat
Cat Cat Cat Cat Ca tCat Cat Cat Cat
Cat Cat Cat Cat Cat Cat Cat Cat Ca tCat
Cat Cat Cat Cat Ca tCat Cat Cata t

Since the frequency penalty accumulates with usage, it can have a much stronger effect on the output compared to the presence penalty.

Important

Be careful with negative frequency penalties: A negative penalty makes a token more likely the more it’s used. This positive feedback quickly leads the model to just repeat a common token until it hits the maxOutputTokens limit (once it starts the model can’t produce the token).

const negative_frequency_response = await ai.models.generateContent({
  model: MODEL_ID,
  contents: PROMPT,
  config: {
    frequencyPenalty: -2.0,
    maxOutputTokens: 400,
  },
});
tslab.display.markdown(negative_frequency_response.text ?? "");

Elara, a wisp of a girl with eyes the colour of a stormy sea, lived in a lighthouse perched precariously on the edge of the Whispering Cliffs. Her only companion was her grandfather, a grizzled man whose weathered face held the map of a thousand storms. He taught her the language of the sea – the mournful cry of gulls, the rhythmic crash of waves, the subtle shift in the wind that foretold a tempest.

One day, a storm unlike any Elara had ever seen descended upon the coast. The wind howled like a banshee, tearing at the lighthouse, and the waves, monstrous and frothing, crashed against the rocks below with terrifying force. Grandpa, usually unflappable, felt a tremor of unease. He’d seen many storms, but this one felt… different.

Midst the fury, a faint, rhythmic glow pulsed through the swirling mist. Intrigued, and despite Grandpa’s warnings, Elara climbed to the lantern room. Through the driving rain, she saw it: a small, glowing boat, battling the waves with impossible grace. It was crafted from what looked like polished sea glass, and its sail, a shimmering, opalescent membrane, billowed, defying the wind.

As the boat neared, a figure, shimmering, like the boat, emerged, a woman, her,, hair like spun moonlight, her eyes like twin stars. The woman smiled, a serene, otherworldly smile, and extended a hand, a hand that, as Elara touched it, sent a jolt of warmth through her, a feeling of profound peace.

The woman spoke, her voice a whisper of the sea, “The storm, child, is not of this world. It is a tear from a fallen star. We, the children of the tide, must mend it.”

Elara, without hesitation, stepped onto the luminous boat.

console.log(negative_frequency_response.candidates?.[0]?.finishReason);
MAX_TOKENS

Next steps

Check out the latest models and their capabilities.