Ir al contenido principal

Tutorial de Gemma 4: crea un agente de IA local para programar con Gradio y Ollama

Aprende a crear un asistente de programación local y multimodal con Gemma 4 vía Ollama, con herramientas de agente integradas en una UI de Gradio.
Actualizado 17 sept 2026  · 12 min leer

Explora con IA

ChatGPTClaudePerplexity

Los LLM locales han llegado a un punto de inflexión. Con la Gemma 4, su amplio contexto, el soporte multimodal nativo y la accesibilidad de Ollama, ahora es práctico ejecutar en tu propio equipo un asistente de código con capacidades de agente.

En este tutorial, te muestro cómo crear un asistente de programación usando Gemma 4 vía Ollama, con una interfaz en Gradio. La app tiene un diseño de panel dividido con un editor de código en vivo a la izquierda y un chat con capacidades de agente a la derecha. Puedes subir imágenes o archivos de código como contexto, activar el uso de herramientas para que el modelo ejecute y valide código, y habilitar un modo de "pensamiento" para problemas más complejos.

Al final, tendrás una app local que puede:

  • Escribir, explicar y depurar código en más de 15 lenguajes
  • Ejecutar código Python en un subproceso aislado y devolver resultados
  • Aceptar imágenes y archivos de texto como contexto multimodal
  • Transmitir respuestas en tiempo real desde un modelo Gemma 4 en local
  • Funcionar como un bucle agente, llamando a herramientas y haciendo seguimiento según resultados

El código completo de este tutorial está disponible aquí.

¿Qué es Gemma 4?

Gemma 4 es la familia de modelos de pesos abiertos de Google DeepMind, diseñada para despliegues locales e investigación. Mejora la línea Gemma con mejor seguimiento de instrucciones, ventanas de contexto más largas y entrada multimodal nativa, y se construye sobre la misma infraestructura de investigación que Gemini 3.

Model performance vs Size

Figura: rendimiento del modelo vs tamaño (fuente: blog de Gemma 4)

Modelos como Gemma-4-26B(MOE) y Gemma-4-31B logran puntuaciones Elo comparables a modelos mucho más grandes, lo que indica un gran rendimiento por parámetro. El modelo 31B figura actualmente como el 3.º modelo abierto del mundo en la clasificación de Arena AI para texto, y el 26B ocupa el 6.º lugar. Esto hace que Gemma 4 sea especialmente adecuada para despliegues locales y con recursos limitados sin sacrificar capacidad.

La familia de modelos Gemma 4

Gemma 4 se publica en cuatro tamaños versátiles: Effective 2B (E2B), Effective 4B (E4B), 26B Mixture of Experts (MoE) y 31B Dense. La familia se divide en dos niveles distintos según el objetivo de despliegue:

Modelo

Arquitectura

Parámetros totales

Parámetros activos/efectivos

Longitud de contexto

Modalidades

Gemma-4-31B

Transformer denso

31B

31B

256K tokens

Texto, visión, vídeo

Gemma-4-26B-A4B

MoE (128 expertos)

26B

3,8B activos

256K tokens

Texto, visión, vídeo

Gemma-4-E4B

Transformer denso

7,9B (con embeddings)

4,5B efectivos

128K tokens

Texto, audio, visión, vídeo

Gemma-4-E2B

Transformer denso

5,1B (con embeddings)

2,3B efectivos

128K tokens

Texto, audio, visión, vídeo

Profundicemos en cada variante:

Visual Guide to Gemma 4

Figura: guía visual de Gemma 4 (fuente)

  • 31B Dense es el modelo insignia optimizado para despliegue en centros de datos y cargas de trabajo de razonamiento complejo. Admite una ventana de 256K tokens con una ventana deslizante de 1024 tokens para procesamiento eficiente de contexto largo.
  • 26B-A4B (MoE) es el primer modelo MoE de Gemma que enruta tokens por 128 expertos manteniendo solo 3,8B parámetros activos por pasada. Ofrece calidad cercana a 31B con una fracción del coste computacional por token, ideal para servicios de alto rendimiento.
  • E4B y E2B son la gama para dispositivo y móvil. A diferencia de las variantes mayores, incluyen entrada de audio nativa para reconocimiento de voz junto con visión y vídeo, lo que las convierte en las más capaces a nivel multimodal para despliegue en el edge.

Los cuatro modelos están disponibles bajo licencia Apache 2.0 y pueden desplegarse en local mediante Ollama, vLLM, llama.cpp o Unsloth.

Para tareas de código, Gemma 4 destaca en:

  • Escritura de código completo y estructurado con explicaciones
  • Razonamiento sobre bases de código existentes cuando se proporcionan como contexto
  • Uso de herramientas y flujos de trabajo con agentes cuando se combina con una capa de orquestación
  • Gestión de imágenes junto con código (p. ej., leer una captura de una UI y generar HTML a juego)

En este tutorial usamos la variante gemma4:e4b (9,6 GB) vía Ollama, una versión cuantizada ideal para inferencia local en hardware de consumo.

Ejecutar Gemma 4 con Ollama

Ollama gestiona la descarga, cuantización y servicio del modelo, y ofrece una API HTTP compatible con OpenAI. En este tutorial, Ollama actúa como backend de inferencia y nuestra app se comunica con él a través de localhost:11434.

Para descargar y ejecutar el modelo:

curl -fsSL https://ollama.com/install.sh | sh
ollama pull gemma4:e4b 
ollama serve

Estos comandos instalan Ollama en local usando el script oficial. Después descargamos la variante gemma 4:e4b para inferencia en el dispositivo. Por último, ollama serve inicia el servidor de Ollama, permitiendo que nuestra app envíe peticiones al modelo.

Una vez el servidor esté activo, la app de Gradio se conecta automáticamente.

Demo de Gemma 4: crea un asistente de código con Ollama

En esta sección construiremos el asistente paso a paso. A alto nivel, la app hace lo siguiente:

  • Acepta un mensaje en lenguaje natural en el panel de chat, con posibilidad de adjuntar imagen o archivo

  • Inyecta el código actual del editor como contexto para el modelo

  • Envía una solicitud en streaming a Gemma 4 vía el endpoint /api/chat de Ollama

  • Opcionalmente llama a herramientas (ejecución de código, evaluación matemática) en un bucle de agente

  • Inserta en el editor los bloques de código extraídos de la respuesta

Vamos a construirlo paso a paso.

Final demo

Paso 1: instalar dependencias

La app requiere pocas librerías para la UI, gestión de imágenes y comunicación HTTP. Como el modelo corre en local con Ollama, no hay SDKs en la nube.

pip install gradio requests pillow

En este proyecto usaremos:

  • gradio para el editor de panel dividido y la UI de chat

  • requests para comunicar con la API HTTP de Ollama

  • pillow para el manejo de imágenes en la UI

Esto mantiene el entorno ligero y funciona en cualquier máquina con Ollama: macOS con Apple Silicon, Linux y Windows vía WSL.

Paso 2: configuración y constantes

Antes de escribir la lógica, definimos los imports, el nombre del modelo, la URL base de Ollama, los lenguajes compatibles y un system prompt por defecto. Estas constantes controlan el comportamiento de toda la app.

import base64
import json
import math
import os
import re
import subprocess
import tempfile
from pathlib import Path
import gradio as gr
import requests

OLLAMA_BASE = "http://localhost:11434"
MODEL       = "gemma4:e4b"
LANGUAGES = [
    "python", "javascript", "typescript", "bash", "sql",
    "rust", "go", "java", "c", "cpp", "html", "css",
    "json", "yaml", "markdown", "plaintext",
]
TEXT_EXTS = {
    ".py", ".js", ".ts", ".jsx", ".tsx", ".html", ".css",
    ".json", ".yaml", ".yml", ".toml", ".md", ".txt",
    ".csv", ".sql", ".sh", ".bash", ".rs", ".go",
    ".java", ".c", ".cpp", ".h", ".hpp", ".rb", ".php",
}
IMAGE_EXTS = {".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp"}
DEFAULT_SYSTEM = """\
You are an expert coding assistant. When you write code:
- Always wrap it in a markdown code block with the language tag
- Write complete, working code — not fragments
- Briefly explain what the code does
You have a code-runner tool. Use it to validate logic when helpful.\
"""

Los conjuntos TEXT_EXTS e IMAGE_EXTS controlan dos comportamientos distintos de adjuntos. Los archivos de texto/código se leen y se inyectan como contexto en el prompt, mientras que las imágenes se codifican en base64 y se envían en el campo images para las capacidades de visión de Gemma 4.

El prompt DEFAULT_SYSTEM define el estilo de generación de código del modelo, pidiéndole explícitamente bloques completos con etiquetas de lenguaje, ya que la app los analiza para volcar el código en el editor.

Paso 3: definir herramientas de agente

El asistente puede funcionar en modo agente y llamar a herramientas durante la inferencia. Definimos dos herramientas con el esquema estándar de function-calling que admite Ollama:

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "run_code",
            "description": (
                "Execute Python code in a sandboxed subprocess and return "
                "stdout + stderr. Use this to validate, test, or demonstrate code."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "Python code to run (max ~50 lines, 5 s timeout).",
                    }
                },
                "required": ["code"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "calculate",
            "description": "Evaluate a mathematical expression precisely.",
            "parameters": {
                "type": "object",
                "properties": {
                    "expression": {
                        "type": "string",
                        "description": "Python-compatible math expression, e.g. 'math.sqrt(2) * 100'",
                    }
                },
                "required": ["expression"],
            },
        },
    },
]

El fragmento anterior define la herramienta run_code, que ejecuta Python en un archivo temporal mediante un subproceso con timeout de 5 segundos y captura stdout y stderr. Así el modelo puede validar lógica, ejecutar ejemplos o producir salida en vivo, no solo texto estático.

Por su parte, la herramienta calculate evalúa expresiones matemáticas en un espacio de nombres restringido usando solo el módulo math y built-ins seguros. Sirve cuando el modelo necesita resultados numéricos precisos sin levantar un proceso completo de Python.

Paso 4: ejecución de herramientas

La capa de ejecución mapea nombres de herramientas a sus implementaciones. Se invoca durante el bucle agente cuando el modelo devuelve un bloque tool_calls.

def _run_python(code: str) -> str:
    with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
        f.write(code)
        tmp = f.name
    try:
        r = subprocess.run(
            ["python3", tmp],
            capture_output=True, text=True, timeout=5,
        )
        out = (r.stdout + r.stderr).strip()
        return out[:3000] if out else "(no output)"
    except subprocess.TimeoutExpired:
        return "⏱ Timed out (>5 s)"
    except Exception as e:
        return f"Error: {e}"
    finally:
        os.unlink(tmp)

def _calculate(expr: str) -> str:
    ns = {k: getattr(math, k) for k in dir(math) if not k.startswith("_")}
    ns.update({"abs": abs, "round": round})
    try:
        return str(eval(expr, {"__builtins__": {}}, ns))  # noqa: S307
    except Exception as e:
        return f"Error: {e}"

def execute_tool(name: str, args: dict) -> str:
    if name == "run_code":
        return _run_python(args.get("code", ""))
    if name == "calculate":
        return _calculate(args.get("expression", ""))
    return f"Unknown tool: {name}"

Algunas decisiones de seguridad destacadas en la ejecución de herramientas:

  • _run_python() escribe en un archivo temporal y lo elimina, evitando residuos incluso ante errores

  • La salida se limita a 3.000 caracteres para no inundar el contexto con impresiones masivas

  • La función _calculate() usa eval() con __builtins__ vacío, evitando acceso a built-ins fuera de las funciones de math permitidas explícitamente

  • El timeout es de 5 segundos: suficiente para validar, corto para evitar procesos desbocados

Paso 5: utilidades auxiliares

Antes de implementar la lógica del chat, necesitamos funciones auxiliares para rutas de archivos, codificación de imágenes y extracción de código. Se usan en toda la canalización de streaming.

def encode_image(path: str) -> str | None:
    if not path:
        return None
    try:
        with open(path, "rb") as f:
            return base64.b64encode(f.read()).decode()
    except Exception:
        return None

def file_as_context(path: str) -> str | None:
    if not path:
        return None
    p = Path(path)
    if p.suffix.lower() not in TEXT_EXTS:
        return None
    try:
        content = p.read_text(encoding="utf-8", errors="replace")[:8000]
        lang = p.suffix.lstrip(".")
        return f"\n\n**Attached file — {p.name}:**\n```{lang}\n{content}\n```"
    except Exception:
        return None

def resolve_gradio_path(val) -> str | None:
    if val is None:
        return None
    if isinstance(val, Path):
        s = str(val)
        return s if s.strip() else None
    if isinstance(val, str):
        s = val.strip()
        return s if s else None
    if isinstance(val, dict):
        p = val.get("path")
        if isinstance(p, str) and p.strip():
            return p.strip()
        nested = val.get("file")
        if isinstance(nested, dict):
            np = nested.get("path")
            if isinstance(np, str) and np.strip():
                return np.strip()
        return None
    name = getattr(val, "name", None)
    if isinstance(name, str) and name.strip():
        return name.strip()
    return None

def is_image_path(path: str | None) -> bool:
    return bool(path) and Path(path).suffix.lower() in IMAGE_EXTS

def extract_last_code_block(text: str) -> tuple[str | None, str]:
    blocks = re.findall(r"```(\w*)\n(.*?)```", text, re.DOTALL)
    if blocks:
        lang, code = blocks[-1]
        return code.strip(), lang.strip() or "python"
    return None, "python"

def ollama_ok() -> bool:
    try:
        requests.get(f"{OLLAMA_BASE}/", timeout=2)
        return True
    except Exception:
        return False

def _gradio_content_to_text(content) -> str:
    if content is None:
        return ""
    if isinstance(content, str):
        return content
    if isinstance(content, list):
        parts: list[str] = []
        for block in content:
            if isinstance(block, dict):
                if block.get("type") == "text":
                    parts.append(str(block.get("text", "")))
                elif "text" in block:
                    parts.append(str(block["text"]))
            elif isinstance(block, str):
                parts.append(block)
        return "".join(parts)
    return str(content)

def _append_chat_turn(
    history: list | None, user_text: str, assistant_text: str
) -> list:
    base = list(history) if history else []
    return base + [
        {"role": "user", "content": user_text},
        {"role": "assistant", "content": assistant_text},
    ]

def run_code_btn(code: str) -> str:
    if not code.strip():
        return "Nothing to run."
    result = _run_python(code)
    return result

Estas utilidades permiten gestionar sin fricciones entradas multimodales y salidas estructuradas:

  • encode_image(): convierte una imagen a cadena base64 para enviarla en el campo images de Ollama. Así Gemma puede procesar imágenes junto a texto.

  • file_as_context(): lee archivos de texto/código y los inyecta directamente en el prompt como bloque markdown formateado. Evita montar un sistema de recuperación aparte: todo va inline como contexto.

  • resolve_gradio_path(): normaliza los distintos formatos de archivo que devuelve Gradio a una ruta utilizable. Evita errores de borde en el manejo de ficheros.

  • is_image_path(): comprobación rápida de si un archivo es imagen. Ayuda a encaminar correctamente la entrada.

  • extract_last_code_block(): extraemos el último bloque de código de la respuesta del modelo.

  • ollama_ok(): verificamos que el servidor local de Ollama esté operativo antes de hacer peticiones.

  • _gradio_content_to_text() y _append_chat_turn(): aplanamos el formato estructurado de mensajes de Gradio a texto plano y mantenemos el historial del chat.

  • run_code_btn(): ejecutamos el código generado cuando el usuario pulsa el botón Run code en la UI.

Con estas utilidades listas, implementamos la función central chat().

Paso 6: generador central de streaming del chat

Esta función impulsa todo el bucle de interacción: prepara entradas, transmite respuestas y gestiona la ejecución de herramientas.

A alto nivel, chat():

  • construye el historial de la conversación
  • enriquece la entrada del usuario con contexto (código, archivos, imágenes)
  • envía una petición en streaming a Ollama
  • ejecuta herramientas opcionalmente (modo agente)
  • va emitiendo respuestas parciales para actualizar la UI en tiempo real
def chat(
    message, history, image_path, file_path,
    editor_code, language, system_prompt,
    agentic, thinking, temperature,
):

La función sigue esta secuencia paso a paso:

Paso 1: construir el historial

Convertimos turnos anteriores en el formato de mensajes de Ollama. Anteponemos el system prompt para guiar el comportamiento del modelo y asegurar que tenga todo el contexto conversacional antes de responder.

for h in history or []:
        if not isinstance(h, dict):
            continue
        role = h.get("role")
        if role not in ("user", "assistant"):
            continue
        messages.append(
            {"role": role, "content": _gradio_content_to_text(h.get("content"))}
        )
    content = message

Paso 2: componer el turno del usuario

Construimos el mensaje actual del usuario inyectando contexto adicional. Si está trabajando con código, añadimos el contenido del editor:

if editor_code.strip() and editor_code.strip() != STARTER_CODE.strip():
    content += (
        f"\n\n**Current code in editor ({language}):**\n"
        f"```{language}\n{editor_code}\n```"
    )

Igualmente, los archivos subidos se añaden inline y las imágenes se codifican en base64 y se pasan por el campo images. Así el modelo razona sobre texto, código e imágenes a la vez.

Paso 3: enviar la petición a Ollama

La carga incluye el nombre del modelo, el historial, el modo streaming y opciones como sigue:

payload = {
    "model": MODEL,
    "messages": messages,
    "stream": True,
    "options": options,
}

if agentic:
    payload["tools"] = TOOLS

Si activas el modo thinking, se establece options["think"] = True, lo que activa un razonamiento de cadena extendido en los modelos compatibles.

Paso 4: gestionar llamadas a herramientas (modo agente)

Si el modo agente está activado, el modelo puede devolver llamadas a herramientas en lugar de texto. Ejecutamos cada herramienta, añadimos sus resultados a la conversación y enviamos una nueva petición para continuar la generación.

if agentic and msg.get("tool_calls"):
    for tc in msg["tool_calls"]:
        fn_name = tc["function"]["name"]
        fn_args = tc["function"]["arguments"]
        result = execute_tool(fn_name, fn_args)
        if fn_name == "run_code" and fn_args.get("code"):
            new_code = fn_args["code"]
        messages.append(msg)
        messages.append({"role": "tool", "content": result})
    resp2 = requests.post(f"{OLLAMA_BASE}/api/chat", ...)

Esto crea un bucle de agente de un turno: el modelo llama a una herramienta, ve el resultado y continúa con la respuesta final. Los registros de llamadas se muestran al usuario en el chat.

Paso 5: extraer código y actualizar el editor

Al terminar el streaming, extraemos el último bloque de código de la respuesta:

extracted, _ = extract_last_code_block(full_response)

if extracted:
    new_code = extracted

Así, el modelo genera el código y el editor se actualiza automáticamente sin necesidad de copiar y pegar.

Paso 7: diseño de la UI en Gradio

Con la lógica lista, diseñamos la interfaz en Gradio. Buscamos un layout que combine flujo de código y asistencia de IA en paralelo.

Usamos gr.Blocks para definir dos columnas:

  • panel izquierdo para edición y ejecución de código
  • panel derecho para chat, adjuntos y controles del modelo
with gr.Blocks(title="Gemma 4 · Code Assistant") as demo:
    with gr.Row(equal_height=False):
        # LEFT: Code Editor
        with gr.Column(scale=11):
            with gr.Row():
                lang_sel = gr.Dropdown(choices=LANGUAGES, value="python", label="Language")
                run_btn  = gr.Button("Run Code", elem_classes=["run-btn"])
                clear_ed = gr.Button("Clear")
            code_editor = gr.Code(
                value=STARTER_CODE,
                language="python",
                label="Editor",
                lines=24,
                interactive=True,
            )
            run_output = gr.Textbox(
                label="Output",
                lines=6,
                interactive=False,
                elem_id="run-output",
            )
        # RIGHT: Chat
        with gr.Column(scale=9):
            chatbot = gr.Chatbot(value=[], elem_id="chatbot", height=430)
            with gr.Row():
                image_upload = gr.Image(label="Image (vision)", type="filepath")
                file_upload  = gr.File(label="Code / text file")
            with gr.Row():
                msg_input = gr.Textbox(placeholder="Ask the agent...", scale=6)
                send_btn  = gr.Button("Send", variant="primary")
            with gr.Row():
                agentic_cb  = gr.Checkbox(label="Enable Agentic", value=True)
                thinking_cb = gr.Checkbox(label="Enable Thinking", value=False)
                clear_chat  = gr.Button("Clear chat")
            with gr.Accordion("Settings", open=False):
                sys_prompt  = gr.Textbox(value=DEFAULT_SYSTEM, label="System prompt")
                temperature = gr.Slider(minimum=0.0, maximum=2.0, value=0.7)

Así encaja la UI con los componentes descritos:

  • Espacio de código: el panel izquierdo incluye selector de lenguaje, editor y controles de ejecutar/limpiar. La salida aparece en una caja destacada.
  • Chat e interacción: el panel derecho contiene el chatbot, el cuadro de entrada y soporte de adjuntos: imágenes para razonamiento multimodal y archivos para inyección de contexto. Los interruptores activan herramientas de agente y modos de razonamiento opcionales.
  • Diseño y usabilidad: distribución en dos columnas con división 55/45, priorizando el editor sin perder el chat de vista. Favorece un flujo fluido entre codificar, recibir ayuda y ejecutar.

Paso 8: conexión de eventos

Los eventos de enviar y enviar con Enter comparten las mismas entradas y salidas, así que tanto el clic en el botón como pulsar Enter disparan el mismo comportamiento:

_inputs = [
    msg_input, chatbot, image_upload, file_upload,
    code_editor, lang_sel,
    sys_prompt, agentic_cb, thinking_cb, temperature,
]
_outputs = [chatbot, code_editor, msg_input]
send_btn.click(fn=respond, inputs=_inputs, outputs=_outputs)
msg_input.submit(fn=respond, inputs=_inputs, outputs=_outputs)

El wrapper respond() resuelve los objetos de ruta de Gradio a cadenas de ruta antes de pasarlos al generador en streaming. Luego emite (history, code, "") en cada fragmento para vaciar el campo de texto en el primer envío.

Paso 9: tema y CSS

Para mejorar la usabilidad y la consistencia visual, añadimos un tema y CSS personalizados sobre el estilo por defecto de Gradio. Le da un acabado tipo GitHub, con soporte claro/oscuro. Es totalmente opcional.

Empezamos definiendo un tema base con gr.themes.Base:

THEME = gr.themes.Base(
    primary_hue   = "blue",
    secondary_hue = "slate",
    neutral_hue   = "slate",
    font      = [gr.themes.GoogleFont("Inter"), "system-ui", "sans-serif"],
    font_mono = [gr.themes.GoogleFont("JetBrains Mono"), "monospace"],
)

Esto fija una paleta coherente y tipografías limpias (Inter) con una monoespaciada cómoda para desarrolladores (JetBrains Mono). Después, sobrescribimos variables CSS clave para controlar el aspecto:

gradio-app {
    --body-background-fill:   #f0f3f7;
    --block-background-fill:  #ffffff;
    --body-text-color:        #1f2328;
    --button-primary-background-fill: #1a7f37;
}

body.dark gradio-app {
    --body-background-fill:   #0d1117;
    --block-background-fill:  #1c2128;
    --body-text-color:        #e6edf3;
    --button-primary-background-fill: #238636;
}

El primer bloque define el tema claro; el segundo, las variables para el modo oscuro. Aunque opcional, este tematizado mejora mucho la experiencia de uso.

Con la UI estructurada y el estilo aplicado, vamos con el último paso: lanzar la aplicación.

Paso 10: lanzamiento

Finalmente, lanzamos la app con:

if __name__ == "__main__":
    print(f"Model  : {MODEL}")
    print(f"Ollama : {OLLAMA_BASE}")
    if not ollama_ok():
        print("Ollama not detected — run ollama serve before chatting")
    demo.launch(
        server_name="0.0.0.0",
        server_port=7860,
        share=False,
        theme=THEME,
        css=CSS,
    )

Aquí, server_name="0.0.0.0" hace que la app sea accesible desde tu red local y share=False mantiene todo en local. La comprobación ollama_ok() realiza un GET rápido a localhost:11434 y avisa al iniciar si Ollama no está en marcha, en lugar de fallar al primer mensaje.

Por último, navega a http://localhost:7860 cuando la app esté ejecutándose.

Así es el flujo completo desde la perspectiva del usuario:

Demo with code generation

  • El usuario escribe un mensaje en el chat, opcionalmente sube una imagen o archivo de código y activa el modo agente/pensamiento

  • Al enviar, respond() construye la petición completa a Ollama, incluyendo el código actual del editor y adjuntos como contexto

  • La respuesta se transmite token a token y se van rindiendo fragmentos en el chatbot de Gradio

  • Si el modo agente está activo y el modelo decide llamar a una herramienta, esta se ejecuta en local, se añaden los resultados a la conversación y una segunda petición transmite la respuesta final

  • Al terminar, se extrae el último bloque de código con fences y se vuelca automáticamente en el editor

Conclusión

En este tutorial hemos creado un asistente de código de IA totalmente local con Gemma 4, Ollama y Gradio. La app admite entrada multimodal, uso real de herramientas, respuestas en streaming y un editor de código en vivo, todo en tu propia máquina y sin APIs externas.

El enfoque de inyectar el código del editor directamente en cada prompt es más simple que un RAG para flujos de un único archivo, y funciona especialmente bien para explicar, refactorizar o ampliar el código que estás editando.

A partir de aquí, puedes ampliar el proyecto en varias direcciones:

  • Añadir un panel de árbol de archivos para proyectos multiarchivo e inyectar como contexto los seleccionados
  • Añadir compatibilidad con más modelos de Ollama desde un selector para alternar entre Gemma 4, Llama 3 y otros
  • Persistir el historial de conversación en disco para conservar sesiones entre reinicios

Aashi Dutt's photo
Author
Aashi Dutt
LinkedIn
Twitter

Soy experta Google Developers en ML (Gen AI), triple experta en Kaggle y embajadora de Women Techmakers, con más de tres años de experiencia en el sector tecnológico. Cofundé una startup de salud en 2020 y actualmente curso un máster en informática en Georgia Tech, con especialización en aprendizaje automático.

Preguntas frecuentes sobre Gemma 4

¿Esto requiere una GPU?

No necesariamente. Gemma 4 e4b es un modelo cuantizado que puede ejecutarse en CPU, aunque una GPU acelerará notablemente la inferencia.

¿Cuál es la diferencia entre el modo agente y el chat normal?

En modo normal, el modelo solo transmite texto. En modo agente, el modelo puede llamar a run_code o calculate, comprobar los resultados e incorporarlos antes de finalizar su respuesta.

¿Cómo se actualiza el editor automáticamente cuando el agente escribe código?

La función auxiliar extract_last_code_block() detecta el último bloque de código con fences en la respuesta del asistente y lo envía al editor al terminar el streaming. Por eso el system prompt pide envolver siempre el código en bloques con etiqueta de lenguaje.

¿Qué ocurre si Ollama no está en marcha?

La comprobación ollama_ok() detecta esto al inicio y en cada envío del chat. Si Ollama no es accesible, el chat devuelve un error formateado en lugar de bloquearse.

Temas
Inteligencia Artificial

Aprende con DataCamp

Curso

IA práctica con Google Gemini y NotebookLM

2 h
9.8K
Domina Gemini y NotebookLM para automatizar tareas, aumentar la productividad y trabajar de forma más inteligente en todo el ecosistema de IA de Google.
Ver detallesRight Arrow
Empezar Curso
Ver másRight Arrow
Relacionado
An AI juggles tasks

blog

Cinco proyectos que puedes crear con modelos de IA generativa (con ejemplos)

Aprende a utilizar modelos de IA generativa para crear un editor de imágenes, un chatbot similar a ChatGPT con pocos recursos y una aplicación clasificadora de aprobación de préstamos y a automatizar interacciones PDF y un asistente de voz con GPT.
Abid Ali Awan's photo

Abid Ali Awan

10 min

Tutorial

RAG Con Llama 3.1 8B, Ollama y Langchain: Tutorial

Aprende a crear una aplicación RAG con Llama 3.1 8B utilizando Ollama y Langchain, configurando el entorno, procesando documentos, creando incrustaciones e integrando un recuperador.
Ryan Ong's photo

Ryan Ong

12 min

Tutorial

Tutorial de la API de OpenAI Assistants

Una visión completa de la API Assistants con nuestro artículo, que ofrece una mirada en profundidad a sus características, usos en la industria, guía de configuración y las mejores prácticas para maximizar su potencial en diversas aplicaciones empresariales.
Zoumana Keita 's photo

Zoumana Keita

14 min

Tutorial

Ajuste fino de LLaMA 2: Guía paso a paso para personalizar el modelo de lenguaje grande

Aprende a ajustar Llama-2 en Colab utilizando nuevas técnicas para superar las limitaciones de memoria y computación y hacer más accesibles los grandes modelos lingüísticos de código abierto.
Abid Ali Awan's photo

Abid Ali Awan

12 min

Tutorial

Guía para principiantes de la API de OpenAI: Tutorial práctico y prácticas recomendadas

Este tutorial te presenta la API de OpenAI, sus casos de uso, un enfoque práctico para utilizar la API y todas las prácticas recomendadas que debes seguir.
Arunn Thevapalan's photo

Arunn Thevapalan

13 min

Tutorial

Guía de torchchat de PyTorch: Configuración local con Python

Aprende a configurar el torchat de PyTorch localmente con Python en este tutorial práctico, que proporciona orientación paso a paso y ejemplos.
Ver MásVer Más