--- type: Resumen title: "Estudio — Gemma 4 (Formato de prompts + grafo animado)" description: "Estudio de gemma4 publicado como sitio: scripts minimalistas para implementarlo y cómo se conecta con el OKF." resource: "https://gerardoesquivia.com/gemma4/" status: publicado tags: [estudio, gemma4, scripts-minimalistas, documentacion, okf] timestamp: 2026-10-04 creator: "Gerardo Esquivia Zapata" grafo: datos --- # Estudio — Gemma 4 (Formato de prompts + grafo animado) > **Sitio publicado:** https://gerardoesquivia.com/gemma4/ > **Nota generada del sitio** para que el estudio regrese al OKF (REGLA del ciclo: > la documentación no está completa hasta estar publicada **Y** registrada). ## Cómo usarla Los **scripts minimalistas** de abajo se copian y funcionan. Esa es la parte que vale: la prosa se lee y se olvida; un script se pega y arranca. --- ## 1 · Tokens de turno — estructura básica Cada turno se abre con <|turn>, se etiqueta con system / user / model y se cierra con . ### 🐍 Script minimalista (Python / uv) ``` # uv add google-genai python-dotenv # entorno Python/uv # .env → GEMINI_API_KEY="tu-api-key" from google import genai import os # 1. Prompt con el formato de turnos de Gemma 4. prompt = """<|turn>system You are a helpful assistant. <|turn>user What is the water formula? <|turn>model""" # 2. Llamada mínima. client = genai.Client(api_key=os.getenv("GEMINI_API_KEY")) resp = client.models.generate_content( model="gemma-4-31b-it", contents=prompt, ) print(resp.text) ``` ### 🔁 Cómo funciona - El prompt se escribe con los tokens de turno: <|turn>system → instrucciones del sistema, <|turn>user → pregunta, <|turn>model → donde empieza a generar. - El SDK (google-genai) envía el prompt y el modelo continúa desde el turno model. - La respuesta se lee en resp.text. ⚠️ Los tokens de control son reservados del tokenizador: no escribirlos como texto libre si se quiere mantener el formato estricto de Gemma 4. ## 2 · Multimodalidad — imagen y audio Los tokens <|image|> y <|audio|> son marcadores de posición: tras tokenizar se reemplazan por las incorporaciones (embeddings) reales de la imagen / el audio. ### 🖼️ Prompt multimodal mínimo ``` <|turn>user Describe this image: <|image|> And translate these audio: a. <|audio|> b. <|audio|> <|turn>model ``` ### 🔊 Audio — ASR y AST (prompts guía) | Tarea | Prompt | | --- | --- | | ASR (transcribir) | Transcribe the following speech segment in {LANGUAGE} into {LANGUAGE} text. + reglas (solo transcripción, dígitos en cifras…) | | AST (traducir) | Transcribe the following speech segment in {SOURCE}, then translate it into {TARGET}. + formato de salida con {TARGET}: | 💡 Ejemplo de instrucción de formato: "When transcribing numbers, write the digits, i.e. write 1.7 and not one point seven." ## 3 · Agentes y razonamiento Para flujos de agente, Gemma 4 usa tokens que separan el razonamiento interno (pensamiento) de las acciones externas (llamada a función). ### 🤖 Script minimalista (pensamiento + herramienta) ``` # 1. Prompt: pensamiento activado + definición de herramienta. prompt = """<|turn>system <|think|>You are a helpful assistant.<|tool>declaration:get_current_temperature{...} <|turn>user What's the temperature in London? <|turn>model""" # 2. El modelo "piensa" en privado y pide usar la herramienta (tool_call). # La app intercepta la tool_call, ejecuta la función e inyecta el resultado: tool_response = """<|tool_call>call:get_current_weather {location:<|"|>London<|"|>} <|tool_response>response:get_current_weather {temperature:15,weather:<|"|>sunny<|"|>}""" # 3. Gemma lee el resultado y responde al usuario. # <|"|> = delimitador de cadenas (caracteres especiales = texto literal). ``` ### 🔁 Ciclo del agente - Consulta del usuario. - Razonamiento interno en el canal de pensamiento (<|channel>thought … ). - Solicitud de herramienta: el modelo detiene la generación y emite <|tool_call>. - Ejecución e inyección: la app ejecuta la función y añade <|tool_response>. - Respuesta final: el modelo lee el resultado y genera la respuesta. 🧠 Gestión del contexto: en conversaciones estándar se quitan los pensamientos del turno anterior; en llamadas a función no se quitan entre llamadas del mismo turno. ## 4 · Grafo animado — el ciclo del agente El token 🟠 recorre el flujo en orden. Clic en el gráfico reinicia la animación. Iniciando… ## 5 · Referencia de tokens y regla de librerías ### 🔠 Tokens de control de Gemma 4 | Grupo | Token | Qué hace | | --- | --- | --- | | Turno | system / user / model | Etiqueta el rol de cada turno | | <|turn> | Comienzo de un turno de diálogo | | | Final de un turno de diálogo | | Multimodal | <|image|> | Marcador de posición de imagen | | <|audio|> | Marcador de posición de audio | | Agente / razonamiento | <|think|> | Activa el modo de pensamiento | | <|channel> / | Proceso interno del modelo (cadena de pensamiento) | | <|tool> / | Define una herramienta | | <|tool_call> / | El modelo pide usar una herramienta | | <|tool_response> / | Resultado de la ejecución de la herramienta | | <|"|> | Delimitador de valores de cadena dentro de los datos | 📦 Regla de librerías (local primero): revisar C:\Users\TUF\Documents\librerías\local\ antes de instalar. Instalación: uv add google-genai python-dotenv. Docs: https://ai.google.dev/gemma/docs/core/prompt-formatting-gemma4. 📱 Escanéalo para abrir la documentación https://gerardoesquivia.com/gemma4/ Gemma 4 · Formato de prompts (turnos · multimodalidad · agentes) · OKF de Gerardo Esquivia Zapata · 2026-08-28 (function () { const nodes = [ { id: "user", label: "Usuario", sub: "consulta", x: 70, y: 210 }, { id: "model", label: "Modelo", sub: "Gemma 4", x: 520, y: 90 }, { id: "tool", label: "Herramienta", sub: "tool", x: 520, y: 330 }, { id: "resp", label: "Respuesta", sub: "texto", x: 800, y: 210 }, ]; const edges = [ { from: "user", to: "model", label: "consulta", loop: false }, { from: "model", to: "tool", label: "tool_call", loop: true }, { from: "tool", to: "model", label: "tool_response", loop: true }, { from: "model", to: "resp", label: "respuesta", loop: false }, { from: "resp", to: "user", label: "devuelve", loop: false }, ]; const pos = Object.fromEntries(nodes.map(n => [n.id, { x: n.x, y: n.y }])); const svg = document.getElementById("grafo"); const NS = "http://www.w3.org/2000/svg"; function el(tag, attrs) { const e = document.createElementNS(NS, tag); for (const k in attrs) e.setAttribute(k, attrs[k]); return e; } const edgePaths = [], edgeArrows = [], edgeGeom = []; edges.forEach((ed) => { const a = pos[ed.from], b = pos[ed.to]; let d, mid; if (ed.loop) { const dir = ed.from === "model" ? 1 : -1; const cx = 520 + dir * 150, cy = (a.y + b.y) / 2; d = `M ${a.x} ${a.y} C ${cx} ${a.y}, ${cx} ${b.y}, ${b.x} ${b.y}`; mid = { x: cx, y: cy }; } else if (ed.from === "resp") { d = `M ${a.x} ${a.y} C ${(a.x+b.x)/2} 420, ${(a.x+b.x)/2} 420, ${b.x} ${b.y}`; mid = { x: (a.x + b.x) / 2, y: 390 }; } else { const dx = Math.abs(b.x - a.x), dy = Math.abs(b.y - a.y); if (dy > dx) { const my = (a.y + b.y) / 2; d = `M ${a.x} ${a.y} C ${a.x} ${my}, ${b.x} ${my}, ${b.x} ${b.y}`; mid = { x: (a.x + b.x) / 2, y: my }; } else { const mx = (a.x + b.x) / 2; d = `M ${a.x} ${a.y} C ${mx} ${a.y}, ${mx} ${b.y}, ${b.x} ${b.y}`; mid = { x: mx, y: (a.y + b.y) / 2 }; } } const path = el("path", { class: "edge", d }); svg.appendChild(path); edgePaths.push(path); const ang = Math.atan2(b.y - mid.y, b.x - mid.x); const tx = b.x - 18 * Math.cos(ang), ty = b.y - 18 * Math.sin(ang); const arrow = el("path", { class: "arrow", d: `M ${tx} ${ty} l 8 ${-4} l -8 ${-4} z`, transform: `rotate(${ang*180/Math.PI} ${tx} ${ty})` }); svg.appendChild(arrow); edgeArrows.push(arrow); edgeGeom.push({ a, b }); }); const nodeGroups = {}; nodes.forEach(n => { const g = el("g", { class: "node" }); g.appendChild(el("rect", { x: n.x - 65, y: n.y - 29, width: 130, height: 58 })); const t = el("text", { class: "t", x: n.x, y: n.y - 4, "text-anchor": "middle" }); t.textContent = n.label; const s = el("text", { class: "s", x: n.x, y: n.y + 16, "text-anchor": "middle" }); s.textContent = n.sub; g.appendChild(t); g.appendChild(s); svg.appendChild(g); nodeGroups[n.id] = g; }); const travel = el("circle", { class: "travel", r: 6, opacity: 0 }); svg.appendChild(travel); const caption = document.getElementById("caption"); const N = edges.length; let i = 0, raf = null; function clearActive() { nodes.forEach(n => nodeGroups[n.id].classList.remove("active")); edgePaths.forEach(p => p.classList.remove("active")); edgeArrows.forEach(a => a.classList.remove("active")); } function animateEdge(idx) { const ed = edges[idx]; clearActive(); edgePaths[idx].classList.add("active"); edgeArrows[idx].classList.add("active"); nodeGroups[ed.from].classList.add("active"); caption.innerHTML = `Paso ${idx+1}/${N}: ${ed.from} → ${ed.to} (${ed.label})`; const path = edgePaths[idx], len = path.getTotalLength(); const t0 = performance.now(), dur = 900; function step(now) { let p = (now - t0) / dur; if (p > 1) p = 1; const pt = path.getPointAtLength(p * len); travel.setAttribute("cx", pt.x); travel.setAttribute("cy", pt.y); travel.setAttribute("opacity", 1); if (p animateEdge(i), 320); } } raf = requestAnimationFrame(step); } function start() { cancelAnimationFrame(raf); i = 0; animateEdge(0); } svg.addEventListener("click", start); start(); })(); --- type: Resumen title: "🌐 Gemma 4 — Prompt Formatting (Resumen minimalista)" description: "Resumen minimalista del formato de prompts de Gemma 4: tokens de turno, multimodalidad y agentes/razonamiento, con scripts listos para implementar." fuente: "https://ai.google.dev/gemma/docs/core/prompt-formatting-gemma4?hl=es-419" sitio: "https://gerardoesquivia.com/gemma4/" tags: [resumen, gemma4, prompt, okf] timestamp: 2026-08-28 creator: "Gerardo Esquivia Zapata" --- # 🌐 Gemma 4 — Prompt Formatting (Resumen) > **Para qué:** crear prompts con el formato de turnos correcto de Gemma 4 (tokens de control reservados del tokenizador). > **Cómo:** cada turno se abre con ``, se etiqueta `system`/`user`/`model` y se cierra con ``. ``/`` insertan media; `` y `` activan razonamiento; ``/`` implementan agentes con herramientas. ## 🎯 Para qué sirve - Formatear prompts correctos para Gemma 4 (texto, imagen, audio y agentes). - No romper el tokenizador usando tokens reservados como texto libre. ## 🛠️ Cómo se usa — scripts minimalistas ### 1. Tokens de turno (estructura básica) ```python # uv add google-genai python-dotenv · .env -> GEMINI_API_KEY from google import genai import os prompt = """system You are a helpful assistant. user What is the water formula? model""" client = genai.Client(api_key=os.getenv("GEMINI_API_KEY")) resp = client.models.generate_content(model="gemma-4-31b-it", contents=prompt) print(resp.text) ``` ### 2. Multimodalidad (imagen y audio) ``` user Describe this image: And translate these audio: a. b. model ``` - ASR: `Transcribe the following speech segment in {LANGUAGE} into {LANGUAGE} text.` + reglas de formato. - AST: `Transcribe ... in {SOURCE}, then translate it into {TARGET}.` + salida con prefijo `{TARGET}: `. ### 3. Agentes y razonamiento ``` system You are a helpful assistant.declaration:get_current_temperature{...} user What's the temperature in London? model ``` - Ciclo: consulta -> pensamiento (`thought`) -> `tool_call` -> `tool_response` -> respuesta final. - Delimitador de cadenas: `` (caracteres especiales = texto literal). - Conversaciones estándar: quitar pensamientos del turno anterior. En tool calls: NO quitarlos entre llamadas del mismo turno. ## 🔑 Conceptos clave | Token | Uso | |---|---| | `` / `` | Abrir / cerrar turno | | `system` / `user` / `model` | Rol del turno | | `` / `` | Marcadores de media (embeddings) | | `` | Activa modo de pensamiento | | `` / `` | Proceso interno (cadena de pensamiento) | | `` / `` / `` | Definir / llamar / responder herramientas | | `` | Delimitador de valores de cadena | ## 🔗 Fuente https://ai.google.dev/gemma/docs/core/prompt-formatting-gemma4?hl=es-419 Sitio: https://gerardoesquivia.com/gemma4/ --- ## 📥 Cómo agregar esto a tu OKF (para el agente) 1. Guarda este archivo en tu vault (ej. `📋 Proyectos/`). 2. El frontmatter ya es OKF: no modifiques `type` ni `creator`. 3. Implementa directo: copia los scripts y ajusta modelo/API key. No necesitas investigar más. function descargarMD() { const md = document.getElementById('md-resumen').textContent.trim(); const blob = new Blob([md], { type: 'text/markdown;charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'resumen-gemma4.md'; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); } --- ## Cómo se conecta con el OKF - **Sitio:** https://gerardoesquivia.com/gemma4/ - **Nota:** esta (bajada del sitio, para consulta del agente) - **Fuente:** https://gerardoesquivia.com/gemma4/ ## Aprendizajes - Los scripts minimalistas son el activo: **el ejemplo más corto que demuestra el uso**. - Este estudio forma parte del ciclo: **estudiar → publicar → registrar en el OKF**.