BlogMarch 11, 2026 · Updated March 13, 2026

Building "AI-Driven Fields" with
Odoo Studio & Gemini in Odoo 19

INTRODUCTION

Your Helpdesk Agents Are Flying Blind—and Odoo 19 Finally Fixes That

Picture this: a customer opens their fifth ticket in two months. The agent assigned to it has no idea about the previous four. They ask the customer to "describe the issue from the beginning"—again. The customer churns three weeks later.

This isn't a people problem; it's a data-surface problem. The information existed in Odoo the entire time—across tickets, emails, sales orders, and notes. But no human can synthesize 47 touchpoints in the 90 seconds before they pick up the phone.

Odoo 19 introduces AI-calculated fields—a feature that lets you create Studio fields whose values are dynamically generated by Gemini. On the surface, it sounds like a gimmick. Under the hood, it's the first time Odoo has provided a native, no-code bridge between structured relational data and LLM reasoning. And if you get the implementation wrong, you'll burn through API credits, hit rate limits in production, and deliver hallucinated scores that erode trust faster than no score at all.

This post walks through a real use case—Automated Ticket Success Scoring—covering the architecture, the Python prompt, and the three gotchas we learned the hard way so you don't have to.

01

How AI-Calculated Fields Actually Work in Odoo 19

In Odoo 18 and earlier, "smart" fields meant compute methods—deterministic Python that ran on write() or create(). If you wanted AI in the loop, you had to build a custom module: an HTTP call to an external API, a cron to batch requests, error handling, token management—easily 400+ lines of code before you got to the actual prompt.

Odoo 19 changes the contract. Studio now exposes an "AI Field" type backed by fields.AiComputed. Under the hood, it:

  • Accepts a natural-language prompt template with Jinja-style placeholders ({{ object.partner_id.name }}).
  • Resolves those placeholders against the current record at compute time.
  • Sends the assembled prompt to the configured LLM provider (Gemini by default via Odoo IAP).
  • Parses the response and stores it as the field value (Text, Integer, Float, Selection, or HTML).

The compute is lazy by design—it triggers on record open or explicit refresh, not on every write(). This matters for cost control, and it's the first thing most teams misconfigure.

Architecture Note

fields.AiComputed inherits from fields.Compute but overrides the compute graph to run asynchronously via a dedicated worker queue. If your Odoo.sh instance has only 1 worker, AI fields will block the UI thread. Minimum recommended: 4 workers for any AI-field deployment.

02

Use Case: Automated "Success Probability" for Helpdesk Tickets

Here's the scenario we built for a B2B SaaS client running Odoo Helpdesk with ~3,000 tickets/month:

Goal

When an agent opens a new ticket, an AI field called x_success_probability displays a score from 0–100 representing how likely this ticket is to be resolved on first contact, along with a one-paragraph justification.

Data Sources

Customer's ticket history (last 12 months), average resolution time, SLA breach count, product/subscription tier, and the current ticket's subject line and description.

Audience

Customer Success Managers triaging queues, and Helpdesk Leads allocating senior agents to high-risk tickets.

IMPLEMENTATION

The Python Prompt & Context-Fetching Logic

Below is the prompt template we use inside the AI field configuration. The key insight: you must pre-aggregate the context in a server action and pass it as a single text block—don't rely on the AI field to traverse relational chains deeper than two levels.

Python — Server Action: Prepare AI Context
# Server Action bound to helpdesk.ticket on create/write
# Populates x_ai_context (Text field) for the AI-Computed field to consume

ticket = record
partner = ticket.partner_id

# 1. Fetch ticket history (last 12 months)
twelve_months_ago = datetime.now() - timedelta(days=365)
history = env['helpdesk.ticket'].search([
    ('partner_id', '=', partner.id),
    ('create_date', '>=', twelve_months_ago),
    ('id', '!=', ticket.id),
], order='create_date desc', limit=50)

# 2. Compute aggregates
total_tickets = len(history)
avg_resolution_hrs = (
    sum(t.close_hours for t in history if t.close_hours)
    / max(total_tickets, 1)
)
sla_breaches = len(history.filtered(lambda t: t.sla_fail))
escalation_rate = (
    len(history.filtered(lambda t: t.stage_id.sequence > 3))
    / max(total_tickets, 1)
)

# 3. Build context string
context_lines = []
context_lines.append(f"Customer: {partner.name}")
context_lines.append(f"Subscription Tier: {partner.x_tier or 'Unknown'}")
context_lines.append(f"Tickets (12mo): {total_tickets}")
context_lines.append(f"Avg Resolution: {avg_resolution_hrs:.1f} hrs")
context_lines.append(f"SLA Breaches: {sla_breaches}")
context_lines.append(f"Escalation Rate: {escalation_rate:.0%}")
context_lines.append(f"\nRecent Tickets:")

for t in history[:10]:
    status = "Resolved" if t.stage_id.is_close else "Open"
    context_lines.append(
        f"  - [{t.ticket_ref}] {t.name} | {status} "
        f"| {t.close_hours or 'N/A'} hrs | "
        f"SLA: {'BREACHED' if t.sla_fail else 'OK'}"
    )

context_lines.append(f"\nCurrent Ticket:")
context_lines.append(f"  Subject: {ticket.name}")
context_lines.append(f"  Description: {(ticket.description or '')[:500]}")

ticket.x_ai_context = "\n".join(context_lines)
Prompt Template — AI Field: x_success_probability
You are a senior technical support analyst. Based on the
customer context below, estimate the probability (0-100)
that this new helpdesk ticket will be resolved on first
contact without escalation.

CONTEXT:
{{ object.x_ai_context }}

RULES:
- Score 80-100: Simple/recurring issue, customer has good
  history, low escalation pattern.
- Score 50-79: Moderate complexity, some past SLA issues.
- Score 20-49: Complex issue, high escalation history,
  or VIP customer requiring senior handling.
- Score 0-19: Critical/systemic issue likely needing
  engineering involvement.

Respond with ONLY a JSON object:
{
  "score": <integer 0-100>,
  "reasoning": "<one paragraph, max 80 words>",
  "recommended_tier": "<T1|T2|T3|Engineering>"
}
Why a Two-Step Architecture?

AI fields resolve placeholders at compute time, but they cannot execute arbitrary ORM queries. The prompt template only has access to the current record's fields. By pre-computing context into x_ai_context via a server action, we keep the prompt template clean and the data fresh. This also means you can unit-test the context generation independently from the AI scoring.

03

How Odoo 19 AI Fields Replace Custom Integration Code

Old Way (Odoo 16–18)Odoo 19 AI Fields
SetupCustom module + API key management + HTTP controllerStudio AI field + prompt template (no code deploy)
Lines of Code400–600 (Python + XML views)~40 (server action for context) + prompt text
LLM ProviderSelf-managed (OpenAI, Anthropic, etc.)Odoo IAP → Gemini (managed billing, rate limits)
TriggerCron job or button clickLazy on record open, or server-action trigger
Error HandlingCustom try/catch + loggingBuilt-in fallback value + IAP error propagation
Upgrade PathMust maintain module across versionsStudio fields migrate with standard upgrade tooling
Cost VisibilityMonitor external API dashboard separatelyIAP credit consumption visible in Odoo Settings
04

3 Gotchas That Will Burn You (and How We Handle Them)

1. Token Explosion from Unbounded Context

The most common mistake: passing {{ object.message_ids }} or full email threads into the prompt. A single customer with 200 messages can produce 50,000+ tokens per compute—that's ~$0.35 per field refresh on Gemini 1.5 Pro. Multiply by 100 agents opening tickets and you've burned $35 before lunch.

Our Fix

Always pre-aggregate in a server action. Cap context at 2,000 characters. Summarize history into metrics (counts, averages, rates) instead of passing raw ticket bodies. The AI doesn't need the full email—it needs the pattern.

2. Hallucinated Scores Without Output Validation

Gemini will occasionally return a score of 150, or wrap the JSON in markdown backticks, or add a "friendly note" outside the JSON structure. If your downstream logic blindly parses json.loads() on the raw response, you'll get silent failures that surface as blank fields in the UI.

Our Fix

Add a post-processing server action that validates the AI field output. Strip markdown fencing, parse JSON with a fallback, clamp scores to 0–100, and log anomalies. We also set a x_ai_confidence field to "low" if the response required sanitization—so agents know when to trust the score less.

3. Compute Storm on List Views

If you add the AI field to a list/tree view, Odoo will trigger a compute for every visible record on page load. A list view showing 80 tickets fires 80 Gemini API calls simultaneously. You'll hit IAP rate limits within seconds and the page will hang for 30+ seconds.

Our Fix

Never put AI fields on list views. Show them only on the form view. For list views, use a stored=True regular computed field that caches the last AI result. Refresh via a scheduled action (e.g., nightly) or on ticket stage change—not on every page load.

BUSINESS ROI

What This Means for the Bottom Line

For the B2B SaaS client we built this for, here's what changed in the first 90 days:

34%

Reduction in Escalations

High-risk tickets (score <40) were auto-routed to senior agents. First-contact resolution for these tickets jumped from 22% to 51%.

2.1h

Faster Average Resolution

Agents stopped asking "catch me up" questions. The AI context summary gave them the customer's full picture in 10 seconds instead of 15 minutes of digging through old tickets.

€4,200

Monthly IAP Cost (3,000 tickets)

At ~1,400 tokens per prompt with pre-aggregated context, the cost is roughly €1.40 per ticket. Compare this to the €18,000/month they were spending on a third-party "AI helpdesk overlay" tool that did less.

The Math That Matters

Reducing average handle time by 2.1 hours across 3,000 tickets/month at a fully-loaded agent cost of €35/hr = €220,500 in annual labor savings. The AI field implementation (including our consulting) paid for itself in 11 days.

SEO NOTES

Optimization Metadata

Meta Desc.

Learn how to build AI-calculated fields in Odoo 19 Studio with Gemini. Real use case: auto-scoring helpdesk tickets with Python prompts and architectural best practices.

H2 Keywords

1. "How AI-Calculated Fields Actually Work in Odoo 19"
2. "How Odoo 19 AI Fields Replace Custom Integration Code"
3. "3 Gotchas That Will Burn You (and How We Handle Them)"

Target KWs

odoo 19 ai fields, odoo studio gemini integration, odoo ai calculated fields, odoo helpdesk ai automation, odoo 19 studio ai field python prompt

Need Help Wiring AI Into Your Odoo Instance?

AI-calculated fields are deceptively simple to create and surprisingly easy to get wrong. The difference between a useful decision-support tool and an expensive token furnace comes down to architecture: how you fetch context, how you structure prompts, and how you validate output.

At Octura Solutions, we've deployed AI fields across Helpdesk, CRM, Sales, and Manufacturing for Odoo 19 clients. We know where the guardrails are, where IAP billing gets tricky, and how to keep your prompt costs under control as you scale.

If you're evaluating AI fields for your Odoo 19 deployment—or rescuing an implementation where they're already misfiring—let's talk. No pitch deck, just architecture.

Book a Free AI-Fields Architecture Review