Skip to main content

Google Gemini Backend

The GeminiBackend compiles AXON IR into prompts optimized for the Google Gemini model family.

Overview

Target API: Google Gemini API
Models: Gemini Pro, Gemini Ultra, future models
Key Features:
  • system_instruction as a first-class parameter
  • Markdown-optimized formatting for better instruction following
  • FunctionDeclaration format for tool use
  • response_schema for structured output

Key Differences from Anthropic

FeatureAnthropicGemini
System promptsystem messagesystem_instruction parameter
Persona framing”You are X""Your identity is X”
FormattingPlain textMarkdown (##, -, bold)
Tool formatinput_schemaparameters
Type nameslowercaseUPPERCASE
Structured outputJSON schemaresponse_schema

Implementation

from axon.backends.base_backend import BaseBackend, CompiledStep, CompilationContext
from axon.compiler.ir_nodes import (
    IRAnchor, IRContext, IRPersona, IRStep, IRProbe, IRReason, IRWeave
)

class GeminiBackend(BaseBackend):
    """Compiles AXON IR to Gemini-native prompt structures."""

    @property
    def name(self) -> str:
        return "gemini"

System Instruction Compilation

Overview

Gemini’s system_instruction is persistent across all turns and applied before content generation. This makes it ideal for persona identity and hard constraints.

Persona Block

def _compile_persona_block(self, persona: IRPersona) -> str:
    lines: list[str] = [f"Your identity is {persona.name}."]

    if persona.description:
        lines.append(persona.description)

    if persona.domain:
        domain_str = ", ".join(persona.domain)
        lines.append(f"Expertise areas: {domain_str}.")

    if persona.tone:
        lines.append(f"Tone of communication: {persona.tone}.")

    if persona.confidence_threshold is not None:
        lines.append(
            f"Only state claims when you are at least "
            f"{persona.confidence_threshold:.0%} confident."
        )

    if persona.cite_sources:
        lines.append("Cite sources for factual claims using inline references.")

    return "\n".join(lines)
Example Output:
Your identity is LegalExpert.
Expertise areas: contract law, IP.
Tone of communication: precise.
Only state claims when you are at least 85% confident.
Cite sources for factual claims using inline references.
Note: “Your identity is” (Gemini) vs “You are” (Anthropic)

Context Block (Markdown Formatting)

def _compile_context_block(self, context: IRContext) -> str:
    lines: list[str] = ["## Session Parameters"]

    if context.depth:
        depth_map = {
            "shallow": "Keep responses brief and high-level.",
            "standard": "Provide clear, moderately detailed responses.",
            "deep": "Provide in-depth, comprehensive analysis.",
            "exhaustive": "Provide the most thorough analysis possible.",
        }
        instruction = depth_map.get(context.depth, f"Response depth: {context.depth}.")
        lines.append(f"- Depth: {instruction}")

    if context.max_tokens is not None:
        lines.append(
            f"- Target response length: approximately {context.max_tokens} tokens"
        )

    return "\n".join(lines)
Example Output:
## Session Parameters
- Depth: Provide in-depth, comprehensive analysis.
- Target response length: approximately 4096 tokens
- Citations: Required for all factual statements

Anchor Block (Markdown-Optimized)

def _compile_anchor_block(self, anchors: list[IRAnchor]) -> str:
    lines: list[str] = [
        "## Mandatory Constraints",
        "The following rules are absolute. Never violate them.",
        "",
    ]

    for i, anchor in enumerate(anchors, 1):
        lines.append(f"### Constraint {i}: {anchor.name}")

        if anchor.require:
            lines.append(f"- **MUST**: {anchor.require}")
        if anchor.reject:
            reject_str = ", ".join(anchor.reject)
            lines.append(f"- **MUST NOT**: {reject_str}")
        if anchor.confidence_floor is not None:
            lines.append(
                f"- **Min Confidence**: {anchor.confidence_floor:.0%} — "
                f"do not make claims below this threshold"
            )
        if anchor.unknown_response:
            lines.append(
                f'- **When uncertain**, respond with: '
                f'"{anchor.unknown_response}"'
            )
        lines.append("")

    return "\n".join(lines).rstrip()
Example Output:
## Mandatory Constraints
The following rules are absolute. Never violate them.

### Constraint 1: NoHallucination
- **MUST**: cite all sources
- **MUST NOT**: hallucinate, speculate
- **Min Confidence**: 90% — do not make claims below this threshold
- **When uncertain**, respond with: "I don't have sufficient information."

Step Compilation

IRStep with Markdown

def _compile_step_node(
    self, step: IRStep, context: CompilationContext
) -> CompiledStep:
    parts: list[str] = []

    if step.given:
        parts.append(f"**Input:** {step.given}")

    # Embedded operations
    if step.probe is not None:
        parts.append(self._format_probe(step.probe))
    elif step.reason is not None:
        parts.append(self._format_reason(step.reason))
    elif step.ask:
        parts.append(step.ask)

    if step.output_type:
        parts.append(f"\n**Required output type:** `{step.output_type}`")

    if step.confidence_floor is not None:
        parts.append(
            f"\n**Minimum confidence:** {step.confidence_floor:.0%}. "
            f"Express uncertainty if below this threshold."
        )

    return CompiledStep(
        step_name=step.name,
        user_prompt="\n".join(parts),
        metadata={"ir_node_type": "step"},
    )
Example Output:
**Input:** contract_document

**Extract** from `contract`: [parties, effective_date, termination_clause]
Return structured results as JSON.

**Required output type:** `EntityMap`

**Minimum confidence:** 85%. Express uncertainty if below this threshold.

Probe Compilation (with response_schema)

def _compile_probe(
    self, probe: IRProbe, context: CompilationContext
) -> CompiledStep:
    fields_str = ", ".join(probe.fields)

    prompt = (
        f"Extract the following fields from the given source:\n\n"
        f"**Fields to extract:** {fields_str}\n"
        f"**Source:** {probe.target}\n\n"
        f"Return a JSON object with keys: [{fields_str}]. "
        f"Use `null` for fields that cannot be determined."
    )

    # Gemini's response_schema for structured output
    schema: dict[str, Any] = {
        "type": "OBJECT",  # UPPERCASE!
        "properties": {
            f: {"type": "STRING"} for f in probe.fields
        },
        "required": list(probe.fields),
    }

    return CompiledStep(
        step_name=f"probe_{probe.target}",
        user_prompt=prompt,
        output_schema=schema,
        metadata={"ir_node_type": "probe"},
    )
Key Difference: Gemini uses UPPERCASE type names ("type": "OBJECT", "type": "STRING").

Reason Compilation (Markdown Formatting)

def _compile_reason(
    self, reason: IRReason, context: CompilationContext
) -> CompiledStep:
    parts: list[str] = []

    if reason.about:
        parts.append(f"**Topic:** {reason.about}")

    if reason.given:
        given_str = ", ".join(reason.given)
        parts.append(f"**Base information:** {given_str}")

    if reason.ask:
        parts.append(f"\n{reason.ask}")

    if reason.depth > 1:
        parts.append(
            f"\nPerform a {reason.depth}-level deep analysis. "
            f"Each level should build on the insights of the previous one."
        )

    if reason.show_work or reason.chain_of_thought:
        parts.append(
            "\nThink step by step. Show your complete reasoning process "
            "explicitly before arriving at your conclusion."
        )

    return CompiledStep(
        step_name=reason.name or f"reason_{reason.about}",
        user_prompt="\n".join(parts),
        metadata={
            "ir_node_type": "reason",
            "depth": reason.depth,
            "show_work": reason.show_work,
        },
    )
Example Output:
**Topic:** contract_risks
**Base information:** extracted_clauses, industry_standards

What clauses in this contract present the highest legal risks?

Perform a 3-level deep analysis. Each level should build on the insights of the previous one.

Think step by step. Show your complete reasoning process explicitly before arriving at your conclusion.

Tool Specification Compilation

Gemini FunctionDeclaration Format

def compile_tool_spec(self, tool: IRToolSpec) -> dict[str, Any]:
    # Build description
    desc_parts: list[str] = [f"Tool: {tool.name}"]
    if tool.provider:
        desc_parts.append(f"Provider: {tool.provider}")
    if tool.timeout:
        desc_parts.append(f"Timeout: {tool.timeout}")

    # Build parameter schema (Gemini format)
    properties: dict[str, Any] = {
        "query": {
            "type": "STRING",  # UPPERCASE!
            "description": f"The input query for {tool.name}",
        }
    }
    if tool.max_results is not None:
        properties["max_results"] = {
            "type": "INTEGER",  # UPPERCASE!
            "description": "Maximum number of results to return",
        }

    return {
        "name": tool.name,
        "description": ". ".join(desc_parts),
        "parameters": {  # Note: "parameters", not "input_schema"
            "type": "OBJECT",
            "properties": properties,
            "required": ["query"],
        },
    }
Example Output:
{
  "name": "WebSearch",
  "description": "Tool: WebSearch. Provider: brave. Timeout: 10s.",
  "parameters": {
    "type": "OBJECT",
    "properties": {
      "query": {
        "type": "STRING",
        "description": "The input query for WebSearch"
      },
      "max_results": {
        "type": "INTEGER",
        "description": "Maximum number of results to return"
      }
    },
    "required": ["query"]
  }
}

Comparison: Anthropic vs Gemini

System Prompt

Anthropic:
You are LegalExpert.
Your areas of expertise: contract law.

[HARD CONSTRAINTS — THESE RULES ARE ABSOLUTE]
CONSTRAINT 1: NoHallucination
  → You MUST: cite all sources
Gemini:
Your identity is LegalExpert.
Expertise areas: contract law.

## Mandatory Constraints
The following rules are absolute.

### Constraint 1: NoHallucination
- **MUST**: cite all sources

Tool Declaration

Anthropic:
{
  "name": "WebSearch",
  "input_schema": {
    "type": "object",
    "properties": {"query": {"type": "string"}}
  }
}
Gemini:
{
  "name": "WebSearch",
  "parameters": {
    "type": "OBJECT",
    "properties": {"query": {"type": "STRING"}}
  }
}
Key Differences:
  • input_schemaparameters
  • "object""OBJECT"
  • "string""STRING"

Next Steps

Anthropic Backend

Compare with Claude’s compilation approach

Runtime Executor

See how compiled prompts are executed

Build docs developers (and LLMs) love