Curso
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.

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:

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/chatde 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.

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:
-
gradiopara el editor de panel dividido y la UI de chat -
requestspara comunicar con la API HTTP de Ollama -
pillowpara 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()usaeval()con__builtins__vacío, evitando acceso a built-ins fuera de las funciones demathpermitidas 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 cadenabase64para enviarla en el campoimagesde 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:

-
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
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.




