✅ BenefitsProduct ManagementIntermediate✨ AI-assisted

Benefits of Gemini 3.8 Flash for Customer Feedback Analysis

WittyTech Daily··5 min read
#gemini#batch-api#structured-output#feedback-analysis

Your support inbox has a roadmap in it, and nobody has read it. Thousands of tickets, app reviews and survey answers pile up, and the roadmap meeting runs on the five complaints someone remembers. This post covers Gemini 3.8 Flash feedback analysis: what it gives a product manager, what it costs, and when to skip it.

Gemini 3.8 Flash feedback analysis costs cents per week

Take 10,000 feedback items a week. My assumptions: each request is about 500 input tokens (instructions, schema and one ticket) and returns about 150 output tokens. That is 5M input and 1.5M output tokens a week.

The pricing page lists gemini-3.8-flash at $0.75 input and $3.75 output per 1M tokens on Standard, with Batch at half that. Both double on January 1, 2027.

| Weekly cost for 10,000 tickets | Until Dec 31, 2026 | From Jan 1, 2027 | | --- | --- | --- | | Standard | $9.38 | $18.75 | | Batch | $4.69 | $9.38 |

At today's Batch rate that is about 0.05 cents a ticket. In January, Batch costs what Standard costs today.

Thinking tokens bill as output. The model page lists thinking levels low, medium and high (minimal returns an error), so pick the lowest level that tags your sample correctly. Then run 100 real tickets and compare billed tokens against my guesses before you trust the table.

Five benefits for a weekly roadmap review

1. Every ticket gets read, not a sample. Sampling 200 tickets and calling it a trend is how a loud minority steers a quarter. At roughly $4.69 a week, tagging all 10,000 costs less than the team lunch the meeting orders.

2. Structured output turns opinions into rows. You define a schema and the model fills it. Enum fields (Literal in Pydantic) keep your theme list identical week to week, so charts compare like with like. The structured output docs say minLength and maxLength are not enforced, so check lengths in your own code.

from typing import Literal
from pydantic import BaseModel, Field

class FeedbackTag(BaseModel):
    ticket_id: str
    theme: Literal['billing', 'onboarding', 'performance', 'missing-feature', 'bug', 'docs', 'other']
    sentiment: Literal['positive', 'neutral', 'negative']
    severity: Literal['low', 'medium', 'high']
    summary: str = Field(description='One sentence, 20 words max')

The other bucket is your taxonomy's smoke alarm. When it grows past a tenth of the volume, read a sample and add a theme.

3. The Batch tier fits a weekly rhythm. The Batch API docs give a target turnaround of 24 hours, expire jobs after 48, and keep results for 6 weeks. Submit Friday afternoon, read Monday morning.

Inline requests must stay under 20MB in total. Beyond that, upload a JSONL file (2GB max), where each line carries a key that comes back with its result.

import time
from google import genai
from pydantic import ValidationError

SYSTEM = 'You tag customer feedback for a product team. Echo the ticket_id exactly. Pick the single best theme and use other only when none fit.'

config = {
    'system_instruction': {'parts': [{'text': SYSTEM}]},
    'response_mime_type': 'application/json',
    'response_schema': FeedbackTag,
}

def to_request(ticket_id: str, text: str) -> dict:
    return {
        'contents': [{'parts': [{'text': f'ticket_id: {ticket_id}\n\n{text}'}], 'role': 'user'}],
        'config': config,
    }

client = genai.Client()
tickets = {'T-1042': 'Invoice shows two charges for March', 'T-1043': 'Love the new export button'}  # id -> text, redact PII first

job = client.batches.create(
    model='gemini-3.8-flash',
    src=[to_request(i, t) for i, t in tickets.items()],
    config={'display_name': 'feedback-week-43'},
)
print(job.name)  # save this; creating the job twice bills twice

DONE = {'JOB_STATE_SUCCEEDED', 'JOB_STATE_FAILED', 'JOB_STATE_CANCELLED', 'JOB_STATE_EXPIRED'}
job = client.batches.get(name=job.name)
while job.state.name not in DONE:
    time.sleep(300)
    job = client.batches.get(name=job.name)

tags, bad = [], 0
if job.state.name == 'JOB_STATE_SUCCEEDED':
    for item in job.dest.inlined_responses:
        if item.error or not item.response:
            bad += 1
            continue
        try:
            tag = FeedbackTag.model_validate_json(item.response.text)
        except ValidationError:
            bad += 1
            continue
        if tag.ticket_id in tickets:
            tags.append(tag)
print(f'{len(tags)} tagged, {bad} failed')

The docs don't promise inline results come back in request order, so the schema asks the model to echo ticket_id and the parser drops any ID you never sent.

4. One long-context call writes the summary. The model page lists a 1,048,576-token input limit, so a week of tags fits in one prompt with room to spare. Boil it down to counts plus the high-severity summaries per theme, then ask for the brief.

from collections import Counter

counts = Counter(t.theme for t in tags)
digest = []
for theme, n in counts.most_common():
    urgent = [t.summary for t in tags if t.theme == theme and t.severity == 'high'][:15]
    digest.append(f'{theme} ({n} items). High severity: ' + ' | '.join(urgent))

response = client.models.generate_content(
    model='gemini-3.8-flash',
    contents='Write a one-page brief for a roadmap review. Rank themes by volume and severity, '
             'quote the summaries that support each claim, and flag anything that looks new.\n\n'
             + '\n'.join(digest),
)
print(response.text)

The counts come from your code, not the model, so the ranking in the brief is checkable against the table you already have.

5. Screenshots and recordings can ride along. The model page lists text, images, video, audio and PDFs as inputs. A bug ticket with a screenshot, or a call recording from an account that churned, can go through the same schema. Check a sample by eye before you trust either.

When it's not worth it

Under a few hundred items a week, the savings are cents and a person can read the lot in an hour. The schema, the pipeline and the review of the other bucket cost more than the reading.

Interviews are the other miss. A tag flattens sarcasm, hesitation and the story behind the complaint, which is what a discovery call exists to catch. Read those yourself.

Before you point this at real customers: the pricing page says free-tier content may be used to improve Google's products, so use a paid project and redact names and emails.

For anyone handing this to a customer's product team, a schema-checked, batch-run pipeline that costs under a fiver a week is something they can afford to keep running after you leave.

← More in Product Management