Lesson 154·M18 AI & LLM Foundations
The Google Gemini API
OpenLearning Objectives
By the end of this lesson you should be able to:
- Explain the Gemini API surface:
generateContent, content parts,responseSchema, tools - Build a request end to end: parts (text + image), generationConfig (temperature, responseSchema), tools (L144)
- Handle the response: candidates, parts, finish_reason, usageMetadata
- Explain the differences from the OpenAI baseline (L152) — and what maps 1:1
- Compare Gemini to OpenAI and Anthropic on the axes that matter (L156)
One-Line Definition
The Google Gemini API is the multimodal-native provider surface: a generateContent endpoint where a request is a list of content parts (text, image, audio, video), with generationConfig for sampling (L139) and structured output via responseSchema (L143) — the same concepts as the baseline (L152), designed around multimodal input from day one.
The one-sentence interview answer: "Gemini's API is the same concepts as the baseline (L152), designed multimodal-first: a request is generateContent with content parts — text and images together (L146) — and the response is a list of candidate parts. Structured output is responseSchema (L143), tools are declared with a function-declaration schema (L144), and finishReason plays finish_reason's role. The dialect is built around parts instead of a single string."
Mental Model
Think of Gemini as the same engine, with "parts" instead of strings — a request is a list of content parts, which is what makes it multimodal-native.
OpenAI baseline (L152) Gemini dialect (this lesson)
┌─────────────────────────┐ ┌─────────────────────────┐
│ messages: [ │ │ contents: [{ │
│ {system}, {user} │ │ parts: [ │
│ ] │ │ {text: "…"}, │
│ response_format: schema │ │ {inlineData: img} │ ← parts, not strings
│ tools: [ {function} ] │ │ ] │
│ │ │ }] │
│ response: content OR │ │ generationConfig: { │
│ tool_calls │ │ responseSchema } │ ← structured (L143)
└─────────────────────────┘ │ tools: [{functionDecl}] │
└─────────────────────────┘
same concepts ──── "parts" instead of strings ──── same concepts
The mental model for interviews: know the baseline (L152), and Gemini is "like that, except it's built around parts" — which is why multimodality (L146) is a first-class citizen instead of a bolt-on.
Visual Flow — The Gemini Request → Response
your code
┌──────────────────────────────────────────────────────┐
│ 1 · build: contents: [{ parts: [ │
│ {text}, {inlineData: image}, …] }] │
│ + generationConfig: { temperature (L139), │
│ responseSchema (L143), maxOutputTokens } │
│ + tools: [{ functionDecl }] (L144) │
└──────────────────┬───────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────┐
│ 2 · POST /v1beta/models/{model}:generateContent │
└──────────────────┬───────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────┐
│ 3 · response: candidates[0].content.parts │
│ [{text:"…"}, │
│ {functionCall: {name, args}}, │
│ …] │
└──────────────────┬───────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────┐
│ 4 · you: render text · execute functionCall (L144) │
│ · append functionResponse part · loop │
│ · read finishReason + usageMetadata (L149) │
└──────────────────────────────────────────────────────┘
The lifecycle is L152's — build → post → branch on parts → loop on functionCall → read finishReason + usageMetadata — with parts carrying the multimodality (L146) that the other dialects bolt on.
How It Works — The Gemini Dialect
generateContentis the endpoint; a request iscontentswithparts. Each part is a typed unit —text,inlineData(image/audio/video bytes),fileData(referenced files). Multimodal input (L146) is structural, not a special mode: you just add an image part.generationConfigholds the knobs:temperature(L139),maxOutputTokens(L149),topP, andresponseSchema— the structured-output mechanism (L143). It's the params object of the dialect.- Structured output is
responseSchema(withresponseMimeType: 'application/json'): the provider constrains generation to your schema — L143's guarantee, in Gemini's dialect. - The tool loop (L144) uses
functionDecldeclarations; the model responds with afunctionCallpart; you execute and return afunctionResponsepart (withnamematching), then call again. finishReasonplaysfinish_reason's role (L145):STOP(done),MAX_TOKENS(truncated),TOOL_CALLS(execute and loop),SAFETY(the safety filter stopped it — a Gemini-specific reason worth handling).usageMetadatais the token ledger (L149):promptTokenCountandcandidatesTokenCount, logged per call (L332).- The model family is multimodal-native (L146): the models are trained for text+image+audio+video together, and the API's parts structure reflects it.
Note
The honest delta. For text-only features, Gemini maps 1:1 onto the baseline (L152) behind the abstraction (L155). Its real differentiators: native multimodality (vision/audio/video as first-class parts, L146), long context, deep Google-ecosystem integration (Google Cloud, Vertex AI, L278-adjacent), and often aggressive pricing (L150). L156 turns this into a decision table.
Real Project Usage
- Multimodal-native products (L146). Vision, audio, video understanding where the media is the input — the parts structure is the natural fit.
- Google-ecosystem stacks. Vertex AI, Google Cloud (L261+), BigQuery — when the architecture is already on Google's cloud, Gemini is the integration path.
- Structured extraction (L143).
responseSchema+ JSON mime type is a clean structured-output dialect for extraction pipelines. - The third provider in a multi-provider stack (L155, L156). Routing by task, cost, or eval — the abstraction makes Gemini one of three interchangeable dialects.
- Long-context media analysis. Video + long documents together — a multimodal-long-context combination the other two handle less natively.
The through-line: Gemini is the "multimodal-native dialect" — the same grammar as L152, built around parts, and the choice when the input is media or the stack is Google's.
Interview Explanation
Say it in four moves:
- The frame. "Gemini's API is the same concepts as the baseline (L152), designed multimodal-first — a request is content parts, not strings."
- The dialect. "
generateContentwith parts (text, image, audio);generationConfigfor temperature (L139), maxOutputTokens (L149), andresponseSchemafor structured output (L143); tools via functionDecl (L144)." - The loop. "The model emits a
functionCallpart, I execute it, return afunctionResponsepart matching the name, and call again (L144)." - The choice. "Its differentiators are native multimodality (L146), long context, and Google-ecosystem integration — and L156 is where I'd actually choose between it and the other two."
Senior-Level Insights
- The parts structure is the multimodality (L146) made structural. Where OpenAI and Anthropic treat vision as a message-content type, Gemini is parts — the architecture of the API reflects the architecture of the model. Naming that is the senior read.
finishReason: SAFETYis a first-class flow. The safety filter is a real branch in production (L317): handle it as a designed path, not a mystery — "the model refused" is a UX state, not a bug.- Provider choice is a stack decision (L156). If the architecture is already on Google Cloud (L261+), Gemini's integration and pricing change the math. The abstraction (L155) keeps the option open either way.
- The abstraction normalises dialects, never prices (L150). Same concepts, different bills — Gemini's aggressive pricing (L150) is a reason to route there, measured, not assumed.
- Multimodal eval is a distinct axis (L343). When the input is media, the eval set is images/audio/video, not text — Gemini's native strength only matters if your eval confirms it.
Common Mistakes
- Building parts as one string. Text-only requests work, but the point of the dialect is parts — for media, add the
inlineData/fileDatapart, not a base64 blob in the text. - Forgetting
responseMimeType: 'application/json'withresponseSchema— the schema is inert without the JSON mime type (L143). - Not handling
finishReason: SAFETY. The safety filter stopping generation is a real production path (L317), not an error to ignore. - Mismatching the
functionResponsename. The tool loop (L144) breaks if the response part's name doesn't match thefunctionCall. - Treating
usageMetadataas optional. It's the token ledger (L149) — log it (L332), or the cost model (L150) is a guess. - Assuming "Google = Gemini" without the abstraction. The dialect still lives behind the interface (L155); the stack choice and the model choice are separate decisions.
Best Practices
- Use parts for media —
inlineDatafor bytes,fileDatafor references (L146). - Set
responseSchema+responseMimeType: 'application/json'together for structured output (L143). - Complete the tool loop exactly: execute, return
functionResponsewith the matchingname, call again (L144). - Handle
finishReason: SAFETYas a designed UX path (L317). - Log
usageMetadataper call (L332) — the cost ledger (L149). - Keep it behind the abstraction (L155) — the dialect stays at the adapter, and L156 decides the routing.
Interview Questions
Q: How does the Gemini API differ from OpenAI's (L152)?
A: Same concepts, a parts-based dialect. A request is
contentswith typed parts — text, image, audio — instead of strings;generationConfigholds temperature (L139) andresponseSchemafor structured output (L143); tools usefunctionDecl;finishReasonplaysfinish_reason's role. It's multimodal-first by construction (L146).
Q: How does tool calling work in Gemini?
A: Declare tools as
functionDecl. The model responds with afunctionCallpart; I execute it and return afunctionResponsepart with the matchingname, then call again so the model continues with the result (L144). Same loop, parts-shaped.
Q: How do you get structured output from Gemini?
A:
generationConfig.responseSchemaplusresponseMimeType: 'application/json'— the provider constrains generation to the schema (L143), the same guarantee as OpenAI'sresponse_format, in Gemini's dialect.
Q: When would you choose Gemini?
A: When the input is genuinely multimodal (L146) — vision, audio, video — or when the stack is on Google Cloud (L261+), where integration and pricing change the math. For text-only features it's interchangeable behind the abstraction (L155), and L156's table is where the routing decision lives.
Follow-Up Questions
- What does the parts structure say about the model's architecture (L146)?
- How does
finishReason: SAFETYchange your production design (L317)? - How does Gemini's pricing compare on the cost model (L150)?
- Where does Gemini fit in a multi-provider routing strategy (L155, L156)?
- How do you eval a multimodal model's real quality (L343)?
Comparison Table — Gemini vs the Baseline
| Concept | OpenAI (L152) | Anthropic (L153) | Gemini |
|---|---|---|---|
| Request | messages (strings) | system + messages | contents + parts |
| Multimodal | message content type | content type | structural parts (L146) |
| Structured output | response_format | input_schema tool | responseSchema (L143) |
| Tools | tools[].function | tools[].input_schema | functionDecl (L144) |
| Tool result | tool message | tool_result block | functionResponse part |
| Stop reason | finish_reason | stop_reason | finishReason (incl. SAFETY) |
| Usage | usage | usage | usageMetadata |
The senior read: the three columns map 1:1 at the concept level — which is precisely why the abstraction (L155) can present one interface, and why the comparison (L156) is a table of deltas, not a rewrite.
Code Example — The Gemini Dialect, End to End
// The Gemini dialect: parts, generationConfig, the tool loop (L144).
const { GoogleGenerativeAI } = require('@google/generative-ai');
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
async function askWithImage(question, imageBase64) {
const model = genAI.getGenerativeModel({
model: 'gemini-1.5-flash', // tier: config, not code (L155)
generationConfig: {
temperature: 0.3, // sampling knob (L139)
maxOutputTokens: 300, // the output budget (L149)
responseMimeType: 'application/json', // ← needed for the schema (L143)
responseSchema: { // structured output (L143)
type: 'OBJECT',
properties: {
answer: { type: 'STRING' },
confidence: { type: 'NUMBER' },
},
required: ['answer'],
},
},
tools: [{ // tool declarations (L144)
functionDeclarations: [{
name: 'get_stock',
description: 'Current price of a US ticker.',
parameters: {
type: 'OBJECT',
properties: { ticker: { type: 'STRING' } },
required: ['ticker'],
},
}],
}],
});
// Multimodal input as parts (L146) — text + image, structurally.
const result = await model.generateContent([
{ text: question },
{ inlineData: { mimeType: 'image/png', data: imageBase64 } },
]);
const parts = result.response.candidates[0].content.parts;
const call = parts.find((p) => p.functionCall);
if (call) {
const { ticker } = call.functionCall.args;
const price = await fetchPrice(ticker); // ← YOUR execution
// return a functionResponse part and loop (L144)
return model.generateContent([
{ text: question },
{ inlineData: { mimeType: 'image/png', data: imageBase64 } },
{ functionCall: call.functionCall },
{ functionResponse: { name: 'get_stock', response: { price } } },
]).then((r2) => r2.response.text());
}
return parts.find((p) => p.text)?.text;
}
What the reader must SEE — the dialect, named:
generateContent + parts → multimodal is structural (L146)
generationConfig → temperature + maxOutputTokens (L139, L149)
responseSchema + MIME json → structured output (L143)
functionDecl → functionCall → execute → functionResponse → loop (L144)
finishReason + usageMetadata → the "why" + the ledger (L145, L149)
Tip
The line that shows the dialect's soul is { inlineData: … } — media as a first-class part. That's multimodality (L146) as architecture, not bolt-on. Behind the abstraction (L155), the feature code just calls "generate", and this dialect lives at the adapter.
Performance Notes
- Multimodal input costs image tokens (L146, L150) — the parts structure doesn't make vision free; budget the media path (L149).
responseSchemaconstrained generation can add latency on complex schemas (L143, L151) — keep schemas flat.- Long context + media is the expensive combo (L138, L150) — video and huge documents together scale tokens fast; sample frames and retrieve tightly (L146, L189).
- Prompt caching (L171) applies to stable prefixes — a byte-stable system text part is the cache key, same as the other dialects.
Debugging Scenarios
| Symptom | Likely cause | First thing to check |
|---|---|---|
| Structured output ignored | responseMimeType missing next to responseSchema (L143) | Set the JSON mime type alongside the schema |
| Image not understood | Part added as text, not inlineData/fileData (L146) | Add the media as a proper part |
| Tool loop breaks | functionResponse name mismatch (L144) | Match the name exactly; return the response part |
| Generation stops unexpectedly | finishReason: SAFETY (L317) | Handle safety as a designed UX path |
| Cost higher than modeled | Multimodal tokens unaccounted (L146, L150) | Budget image/media tokens (L149); log usageMetadata (L332) |
Quick Revision Notes
- Gemini = the same concepts as L152, a parts-based, multimodal-native dialect.
generateContent+ parts (text, image, audio) — media is structural (L146).generationConfig: temperature (L139), maxOutputTokens (L149),responseSchema(L143).- The tool loop:
functionDecl→functionCall→ execute →functionResponse→ loop (L144). finishReasonincludesSAFETY— a designed path, not a bug (L317).- Provider choice is a stack + task decision (L156), behind the abstraction (L155).
Cheat Sheet
GEMINI API = the baseline (L152), parts-based and multimodal-native
DIALECT
generateContent the endpoint
contents + parts text | inlineData | fileData (L146)
generationConfig temperature (L139) · maxOutputTokens (L149)
responseMimeType + responseSchema (L143)
tools functionDeclarations (L144)
THE TOOL LOOP (L144)
model → functionCall {name, args}
you → execute
you → functionResponse {name, response}
call again → model continues
FINISH REASONS (L145)
STOP · MAX_TOKENS · TOOL_CALLS · SAFETY (handle it, L317)
USAGE (L149, L332)
usageMetadata → promptTokenCount + candidatesTokenCount → the ledger
DIFFERENTIATORS
native multimodality (L146) · long context · Google-ecosystem
aggressive pricing — measured, not assumed (L150)
RULES
parts for media, always
schema + JSON mime type together (L143)
handle SAFETY as a UX path (L317)
behind the abstraction (L155) — L156 decides routing
INTERVIEW, 4 MOVES
1 frame "same concepts, parts-based dialect"
2 dialect "contents + parts, generationConfig, responseSchema"
3 loop "functionDecl → execute → functionResponse → continue"
4 choice "multimodal + Google stack → L156 decides"Key Takeaways
Recap
- The Gemini API is the same concepts as the baseline (L152) in a parts-based, multimodal-native dialect — a request is content parts, not strings (L146)
generationConfigholds the knobs: temperature (L139),maxOutputTokens(L149), andresponseSchemafor structured output (L143)- The tool loop is
functionDecl→functionCall→ execute →functionResponse→ continue (L144) finishReasonincludesSAFETY— a first-class production path, not a mystery (L317), andusageMetadatais the token ledger (L149)- Its differentiators: native multimodality (L146), long context, and Google-ecosystem integration — and pricing worth measuring, not assuming (L150)
- The three dialects map 1:1 at the concept level — which is exactly what L155's abstraction normalises and L156's table compares
Check your understanding
Answer each one out loud. Then rate yourself honestly.
0/8What makes Gemini's dialect "parts-based", and why does it matter (L146)?
How do you request structured output from Gemini (L143)?
Walk the Gemini tool loop, part by part (L144).
Why is finishReason: SAFETY a designed path, not a bug?
What is usageMetadata, and why log it (L149, L332)?
When would Gemini be the right provider choice (L156)?
How do the three providers map onto one abstraction (L155)?
Why is pricing "measured, not assumed" for Gemini (L150)?
A Closing Note — The Third Dialect, the Complete Map
You now speak all three dialects of the frontier: the baseline (L152), Anthropic's (L153), and Gemini's (this lesson). Hold the concept map — messages/parts, tools, structured output, stop reasons, usage — and the three are variations on one grammar. That map is exactly what the next lesson formalises: the abstraction (L155) that lets your code speak one interface and route across all three — and the comparison (L156) that turns the map into a decision table.