Getting Started with Google Gemini: A Practical Guide for Developers
This guide walks through setting up a new Google Cloud project for Gemini, authenticating with ADC, configuring environment variables, and using the Gemini API for chat, structured output, and image analysis. It includes code examples and practical explanations of key configuration options like temperature and response schemas.
Getting started with Google's latest generative AI tools means understanding a few moving parts: authentication, environment configuration, and the right APIs. Here's how I set up a new project and some tips I wish I'd known up front.
Authenticating with Application Default Credentials (ADC)
First, I authenticate with Google Cloud using ADC. This lets my local tools and code access cloud resources as me.
gcloud auth application-default login
This opens a browser for login and sets up credentials that most Google Cloud SDKs can pick up automatically.
Setting Project Environment Variables
I always set project-level environment variables for clarity and to avoid accidental cross-project mistakes.
GOOGLE_CLOUD_LOCATION — Usually global for GenAI, but can be a region.
GOOGLE_GENAI_USE_ENTERPRISE — Enables enterprise features if you have access.
Using the GenAI Chat Client with a System Prompt
The chat client lets you set a "system prompt"—instructions that shape how the model responds. Here's how I set it up:
client = genai.Client(
vertexai=True
)
chat = client.chats.create(
model="gemini-3.5-flash",
config=types.GenerateContentConfig(
system_instruction="""
You are a technical teacher.
Teach backend developers about generative AI.
Rules:
- Explain why a concept exists before showing code.
- Use practical examples.
- Clearly distinguish concepts that are commonly confused.
- Do not assume advanced AI knowledge.
"""
)
)
This system prompt turns the model into a focused technical tutor for backend developers.
GenerateContentConfig: What Actually Matters
The GenerateContentConfig has a bunch of attributes. The ones I use most:
Attribute
What it does
temperature
Controls randomness/creativity. See below.
top_p, top_k
Nucleus and top-k sampling—how many options are considered at each step.
max_output_tokens
Limits response length.
stop_sequences
Where to stop generating.
seed
For reproducibility.
presence_penalty
Penalizes repeated topics.
frequency_penalty
Penalizes repeated phrases.
thinking/reasoning
Controls for more/less reasoning (where supported).
safety_settings
Filters for content safety.
On Temperature
A lot of guides say:
"Temperature controls creativity."
That's not wrong, but it's not the whole story.
Better mental model:
Temperature changes how strongly the model favors higher-probability tokens versus allowing more probability mass to influence sampling.
Lower temperature = more deterministic, higher = more diverse but less predictable.
Streaming Responses
For chat-like interactions, streaming lets you process output as it's generated:
for chunk in chat.send_message_stream(
"What is python"
):
print(chunk.text, end="")
This is great for user-facing apps where latency matters.
Structured Output: Getting JSON Back
Sometimes I want structured data, not just text. With the right config, the model can return JSON directly:
response = client.models.generate_content(
model="gemini-3.5-flash",
contents="""
Customer message:
My order was supposed to arrive three days ago,
but the tracking hasn't updated.
""",
config=types.GenerateContentConfig(
response_mime_type="application/json",
response_schema=CustomerIssue,
),
)
print(response.parsed)
response.text is the raw output.
response.parsed is the parsed object (assuming the schema matches).
Working with Content: Images and More
You can send images (or other files) as part of the prompt. Either upload bytes directly or reference a URI.
withopen("product.jpeg", "rb") as f:
image_bytes = f.read()
response = client.models.generate_content(
model="gemini-3.5-flash",
contents=[
"Analyze this product image and describe the product.",
# Part.from_bytes(# data=image_bytes,# mime_type="image/jpeg"# )
Part.from_uri(
file_uri="https://images.unsplash.com/photo-1606081430924-b6480765d470?fm=jpg&q=60&w=3000&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTJ8fHN3ZWF0c2hpcnR8ZW58MHx8MHx8fDA%3D",
mime_type="image/jpeg"
)
]
)
Use Part.from_bytes for local files.
Use Part.from_uri for files already hosted somewhere.
Gotchas and Learnings
Always double-check which project and location your environment is set to—I've wasted time debugging permissions that were just a wrong env var.
System prompts are powerful, but don't expect them to override everything. The model still has its own "personality."
For structured output, your schema must match what the model is likely to produce—be explicit and test with real examples.
That's my current setup for Google's GenAI stack. If you hit weird errors, check your credentials and project settings first—it's almost always that.
Join the discussion
Nothing here yet — be the first to weigh in.