Pular para o conteúdo principal

Tutorial Gemma 4: crie um agente local de IA para código com Gradio e Ollama

Aprenda a criar um assistente de codificação multimodal totalmente local com Gemma 4 via Ollama, com uso de ferramentas de agente na interface do Gradio.
Actualizado 17 de set. de 2026  · 12 min leer

Explore com IA

ChatGPTClaudePerplexity

Os LLMs locais chegaram a um ponto de virada. Com a Gemma 4, sua janela de contexto longa, suporte multimodal nativo e a acessibilidade do Ollama, agora é prático rodar um assistente de codificação com capacidades de agente totalmente na sua própria máquina.

Neste tutorial, vou mostrar como construir um assistente de codificação usando Gemma 4 via Ollama, com uma interface em Gradio. O app traz um layout em duas colunas, com um editor de código ao vivo à esquerda e um painel de chat com agente à direita. Você pode enviar imagens ou arquivos de código como contexto, ativar o uso de ferramentas para o modelo executar e validar código e alternar um modo de "raciocínio" para problemas mais difíceis.

Ao final, você terá um app local capaz de:

  • Escrever, explicar e depurar código em 15+ linguagens
  • Executar código Python em um subprocesso isolado e retornar os resultados
  • Aceitar imagens e arquivos de texto como contexto multimodal
  • Transmitir respostas em tempo real de um modelo Gemma 4 rodando localmente
  • Operar em um loop de agente, chamando ferramentas e iterando com base nos resultados

O código completo deste tutorial está disponível aqui.

O que é o Gemma 4?

Gemma 4 é a família de modelos de pesos abertos do Google DeepMind, pensada para implantação local e pesquisa. Ela evolui a linhagem Gemma com melhor obediência a instruções, janelas de contexto maiores e entrada multimodal nativa, construída na mesma base de pesquisa do Gemini 3.

Desempenho do modelo vs tamanho

Figura: desempenho do modelo vs tamanho (fonte: blog Gemma 4)

Modelos como Gemma-4-26B(MOE) e Gemma-4-31B alcançam pontuações Elo comparáveis a modelos bem maiores, indicando forte desempenho por parâmetro. O 31B hoje ocupa a 3ª posição entre os modelos abertos no ranking de texto da Arena AI, e o 26B está em 6º lugar. Isso torna o Gemma 4 especialmente adequado para implantações locais e com recursos limitados, sem abrir mão de capacidade.

A família de modelos Gemma 4

O Gemma 4 é lançado em quatro tamanhos versáteis: Effective 2B (E2B), Effective 4B (E4B), 26B Mixture of Experts (MoE) e 31B Dense. A família se divide em dois níveis, de acordo com o alvo de implantação:

Modelo

Arquitetura

Parâmetros totais

Parâmetros ativos/efetivos

Comprimento do contexto

Modalidades

Gemma-4-31B

Transformer denso

31B

31B

256K tokens

Texto, visão, vídeo

Gemma-4-26B-A4B

MoE (128 experts)

26B

3,8B ativos

256K tokens

Texto, visão, vídeo

Gemma-4-E4B

Transformer denso

7,9B (com embeddings)

4,5B efetivos

128K tokens

Texto, áudio, visão, vídeo

Gemma-4-E2B

Transformer denso

5,1B (com embeddings)

2,3B efetivos

128K tokens

Texto, áudio, visão, vídeo

Vamos analisar mais a fundo cada variante:

Guia visual do Gemma 4

Figura: guia visual do Gemma 4 (fonte)

  • 31B Dense é o modelo principal, otimizado para data centers e cargas de trabalho de raciocínio complexas. Ele suporta janela de contexto de 256K tokens, com janela deslizante de 1024 tokens para processamento eficiente de contexto longo.
  • 26B-A4B (MoE) é o primeiro modelo MoE do Gemma, roteando tokens por 128 experts mantendo apenas 3,8B de parâmetros ativos por forward pass. Isso entrega qualidade próxima ao 31B com uma fração do custo computacional por token, ideal para serving de alto throughput.
  • E4B e E2B são a camada para dispositivo e mobile. Diferente das variantes maiores, incluem entrada de áudio nativa para reconhecimento de fala, além de visão e vídeo, tornando-os os modelos mais multimodais da família para edge.

Todos os quatro modelos estão sob licença Apache 2.0 e podem ser executados localmente via Ollama, vLLM, llama.cpp ou Unsloth.

Para tarefas de código, o Gemma 4 se destaca em:

  • Escrever código completo e estruturado, com explicações
  • Raciocinar sobre bases de código existentes quando fornecidas como contexto
  • Uso de ferramentas e fluxos de trabalho com agente quando acoplado a uma camada de orquestração
  • Manipular imagens junto com código (ex.: ler um print da UI e gerar HTML correspondente)

Neste tutorial, usamos a variante gemma4:e4b (9,6GB) via Ollama, uma versão quantizada, ideal para inferência local em hardware de consumo.

Executando o Gemma 4 via Ollama

O Ollama cuida do download do modelo, quantização, serving e oferece uma API HTTP compatível com OpenAI. Neste tutorial, o Ollama atua como backend de inferência e nosso app se comunica com ele em localhost:11434.

Para puxar e rodar o modelo:

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

Os comandos acima instalam o Ollama localmente usando o script oficial. Em seguida, baixamos a variante gemma 4:e4b para inferência no dispositivo. Por fim, ollama serve inicia o servidor do Ollama, permitindo que nosso app envie requisições ao modelo.

Com o servidor no ar, o app em Gradio se conecta automaticamente.

Demo Gemma 4: construa um assistente de código com Ollama

Nesta seção, vamos construir o assistente de código passo a passo. Em alto nível, o app faz o seguinte:

  • Recebe uma mensagem em linguagem natural no painel de chat, com opção de anexar imagem ou arquivo

  • Injeta o código atual do editor como contexto para o modelo

  • Envia uma requisição em streaming ao Gemma 4 pelo endpoint /api/chat do Ollama

  • Opcionalmente chama ferramentas (execução de código, avaliação matemática) em um loop de agente

  • Empurra blocos de código extraídos da resposta para o editor ao vivo

Vamos construir isso passo a passo.

Demo final

Passo 1: instalar dependências

O app requer um conjunto enxuto de bibliotecas para a UI, tratamento de imagem e comunicação HTTP. Como o modelo roda localmente via Ollama, não há dependências de SDK na nuvem.

pip install gradio requests pillow

Neste projeto, vamos usar:

  • gradio para o editor e a UI de chat em duas colunas

  • requests para conversar com a API HTTP do Ollama

  • pillow para suporte a imagens na UI

Isso mantém o ambiente leve e funciona em qualquer máquina com Ollama, incluindo macOS com Apple Silicon, Linux e Windows via WSL.

Passo 2: configuração e constantes

Antes da lógica, definimos os imports, o nome do modelo, a base URL do Ollama, as linguagens suportadas e um prompt de sistema padrão. Essas constantes controlam o comportamento do 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.\
"""

Os conjuntos TEXT_EXTS e IMAGE_EXTS determinam dois comportamentos diferentes para anexos. Arquivos de texto/código são lidos e injetados como contexto no prompt, enquanto imagens são base64-encoded e enviadas no campo images para as capacidades de visão do Gemma 4.

O prompt DEFAULT_SYSTEM molda o estilo de geração de código do modelo, pedindo blocos completos com tags de linguagem, já que o app os analisa para enviar o código ao editor.

Passo 3: definir ferramentas de agente

O assistente pode operar em modo agente, chamando ferramentas durante a inferência. Definimos duas ferramentas no esquema padrão de function calling suportado pelo 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"],
            },
        },
    },
]

O trecho acima define a ferramenta run_code, que executa Python em um arquivo temporário via subprocesso com timeout de 5 segundos e captura stdout e stderr. Assim, o modelo pode validar lógica, rodar exemplos ou produzir saída ao vivo, e não apenas gerar texto estático.

Já a ferramenta calculate avalia expressões matemáticas em um namespace restrito usando apenas o módulo math e built-ins seguros. Ela cobre casos em que o modelo precisa de resultados numéricos precisos sem abrir um processo Python completo.

Passo 4: execução das ferramentas

A camada de execução mapeia nomes de ferramentas para suas implementações. Ela é chamada durante o loop de agente sempre que o modelo retorna um bloco 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}"

Algumas escolhas de segurança importantes nessa pilha de execução:

  • _run_python() grava em arquivo temporário e faz a limpeza, evitando resíduos mesmo em caso de erro

  • A saída é limitada a 3.000 caracteres para não inundar o contexto com dumps enormes

  • A função _calculate() usa eval() com __builtins__ vazio, bloqueando acesso a built-ins fora das funções math explicitamente permitidas

  • O timeout é de 5 segundos: suficiente para validações rápidas e curto para evitar processos descontrolados

Passo 5: utilitários

Antes da lógica central de chat, precisamos de utilitários para caminhos de arquivos, codificação de imagens e extração de código. Essas funções dão suporte ao pipeline 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

Esses utilitários viabilizam o fluxo entre entradas multimodais e saídas estruturadas:

  • encode_image(): converte uma imagem em string base64 para ser enviada no campo images do Ollama. Assim, o Gemma processa imagens junto com texto para raciocínio multimodal.

  • file_as_context(): lê arquivos de texto/código e os injeta diretamente no prompt como markdown formatado. Dispensa um sistema de busca/recuperação separado, já que tudo vai inline como contexto.

  • resolve_gradio_path(): normaliza diferentes formatos de arquivo retornados pelo Gradio em um caminho utilizável, evitando bugs de borda.

  • is_image_path(): checa rapidamente se o arquivo é imagem para roteá-lo corretamente.

  • extract_last_code_block(): extrai o último bloco de código da resposta do modelo.

  • ollama_ok(): verifica se o servidor local do Ollama está rodando antes de enviar requisições.

  • _gradio_content_to_text() e _append_chat_turn(): achatam o formato estruturado do Gradio em texto puro e mantêm o histórico do chat.

  • run_code_btn(): executa o código gerado quando você clica no botão Run code na UI.

Agora que temos os utilitários, podemos implementar a função central chat().

Passo 6: gerador de streaming do chat

Essa função conduz todo o loop de interação, da preparação das entradas ao streaming das respostas e execução de ferramentas.

Em alto nível, a chat():

  • constrói o histórico da conversa
  • enriquece a entrada atual com contexto (código, arquivos, imagens)
  • envia uma requisição em streaming ao Ollama
  • opcionalmente executa ferramentas (modo agente)
  • emite respostas parciais para atualização em tempo real da UI
def chat(
    message, history, image_path, file_path,
    editor_code, language, system_prompt,
    agentic, thinking, temperature,
):

A função segue a sequência abaixo:

Passo 1: construir o histórico

Convertamos os turnos anteriores para o formato de mensagens do Ollama. O prompt de sistema é inserido no início para orientar o comportamento do modelo e garantir que ele tenha o contexto completo 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

Passo 2: compor a fala do usuário

Construímos a mensagem atual injetando contexto adicional. Se o usuário está trabalhando com código, anexamos o conteúdo do 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```"
    )

Da mesma forma, arquivos enviados são adicionados inline como contexto e imagens são codificadas em base64 e passadas via campo images. Assim, o modelo raciocina sobre texto, código e imagens em conjunto.

Passo 3: enviar a requisição ao Ollama

O payload inclui o nome do modelo, histórico, flag de streaming e opções, assim:

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

if agentic:
    payload["tools"] = TOOLS

Se o modo de raciocínio estiver ativado, define-se options["think"] = True, habilitando chain-of-thought estendido em modelos compatíveis.

Passo 4: tratar chamadas de ferramentas (modo agente)

Se o modo agente está ligado, o modelo pode retornar chamadas de ferramenta em vez de texto. Cada ferramenta é executada, resultados são anexados à conversa e uma nova requisição continua a geração.

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", ...)

Isso cria um loop agente de uma volta: o modelo chama a ferramenta, vê o resultado e segue gerando a resposta final. Os logs das ferramentas aparecem no chat para o usuário.

Passo 5: extrair código e atualizar o editor

Quando o streaming termina, extraímos o último bloco de código da resposta:

extracted, _ = extract_last_code_block(full_response)

if extracted:
    new_code = extracted

Assim, o modelo gera o código, o editor se atualiza automaticamente e você não precisa copiar e colar manualmente.

Passo 7: layout da UI em Gradio

Com a lógica pronta, vamos desenhar a interface usando Gradio. A ideia é ter um layout que suporte o fluxo de codificação e a interação com IA lado a lado.

Usamos gr.Blocks para criar duas colunas:

  • o painel esquerdo foca em edição e execução de código
  • o painel direito cuida do chat, anexos e controles do 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)

Veja como a UI trabalha em conjunto com os componentes acima:

  • Espaço de código: o painel esquerdo inclui seletor de linguagem, editor de código e botões de executar/limpar. A saída aparece em uma caixa destacada.
  • Chat e interação: o painel direito traz o chatbot, campo de entrada e suporte a anexos (imagens para raciocínio multimodal e arquivos para injeção de contexto). Há toggles para uso de ferramentas de agente e modos de raciocínio.
  • Layout e usabilidade: duas colunas com divisão 55/45, priorizando o editor, mantendo o chat acessível. Esse equilíbrio facilita o fluxo entre codificação, ajuda da IA e execução.

Passo 8: eventos

Os eventos de enviar e submeter compartilham as mesmas entradas/saídas, então tanto o clique no botão quanto Enter no campo disparam o mesmo comportamento:

_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)

O wrapper respond() resolve os paths retornados pelo Gradio em strings simples antes de passá-los ao gerador de streaming. Ele então emite (history, code, "") a cada chunk para limpar a caixa de mensagem logo na primeira atualização.

Passo 9: tema e CSS

Para melhorar a usabilidade e a consistência visual, adicionamos um tema e CSS customizados sobre o padrão do Gradio. Isso dá um visual polido, inspirado no GitHub, com suporte a modos claro e escuro. É totalmente opcional.

Começamos definindo um tema base com 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"],
)

Isso define uma paleta consistente e tipografia limpa (Inter) com monoespaçada amigável a devs (JetBrains Mono). Em seguida, sobrepomos variáveis CSS para ajustar a aparência:

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;
}

O primeiro bloco define o tema claro, o segundo substitui valores para o modo escuro. Embora opcional, o tema customizado melhora bastante a experiência.

Com a UI estruturada e estilizada, vamos ao passo final: lançar a aplicação.

Passo 10: execução

Por fim, iniciamos o app com:

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,
    )

Aqui, server_name="0.0.0.0" deixa o app acessível na sua rede local e share=False mantém tudo local. A verificação ollama_ok() faz um GET rápido para localhost:11434 e avisa na inicialização se o Ollama não estiver rodando, em vez de falhar só na primeira mensagem.

Por fim, acesse http://localhost:7860 quando o app estiver no ar.

Fluxo completo do ponto de vista do usuário:

Demo com geração de código

  • Você digita uma mensagem no chat, podendo anexar imagem ou arquivo de código e ativar agente/raciocínio

  • Ao enviar, a função respond() monta a requisição ao Ollama, incluindo o código do editor e anexos como contexto

  • A resposta é transmitida token a token e exibida ao vivo no chatbot do Gradio

  • Se o modo agente estiver ativo e o modelo decidir chamar uma ferramenta, ela roda localmente, o resultado é anexado e uma nova requisição transmite a resposta final

  • Ao final do streaming, o último bloco de código cercado é extraído e enviado automaticamente ao editor

Conclusão

Neste tutorial, criamos um assistente de codificação em IA totalmente local usando Gemma 4, Ollama e Gradio. O app aceita entrada multimodal, usa ferramentas reais, transmite respostas e traz um editor de código ao vivo — tudo rodando na sua máquina, sem API externa.

A estratégia de contexto total — injetar o código do editor em todo prompt — é mais simples que RAG para um workflow de arquivo único e funciona muito bem para explicar, refatorar ou estender o código que você está editando.

A partir daqui, você pode estender o projeto em várias direções:

  • Adicionar um painel de árvore de arquivos para projetos multi-arquivo e injetar selecionados como contexto
  • Adicionar suporte a outros modelos do Ollama em um dropdown, permitindo alternar entre Gemma 4, Llama 3 e outros
  • Persistir o histórico de conversa em disco para manter sessões após reiniciar o app

Aashi Dutt's photo
Author
Aashi Dutt
LinkedIn
Twitter

Sou Especialista Google Developers em ML (Gen AI), tricampeã no Kaggle e Embaixadora Women Techmakers, com mais de três anos de experiência na área de tecnologia. Cofundei uma startup de saúde em 2020 e atualmente faço um mestrado em ciência da computação na Georgia Tech, com foco em aprendizado de máquina.

Perguntas frequentes sobre o Gemma 4

Precisa de GPU para rodar?

Não necessariamente. O Gemma 4 e4b é um modelo quantizado que pode rodar em CPU, embora uma GPU melhore bastante a velocidade de inferência.

Qual a diferença entre o modo agente e o chat normal?

No modo regular, o modelo transmite apenas texto. No modo agente, ele pode chamar run_code ou calculate, conferir os resultados e incorporá-los antes de concluir a resposta.

Como o editor atualiza automaticamente quando o agente escreve código?

A função auxiliar extract_last_code_block() procura o último bloco de código cercado na resposta do assistente e o envia ao editor quando o streaming termina. Por isso o prompt de sistema instrui o modelo a sempre envolver o código em blocos cercados com tag de linguagem.

O que acontece se o Ollama não estiver rodando?

A checagem ollama_ok() detecta isso na inicialização e a cada envio no chat. Se o Ollama não estiver acessível, o chat retorna uma mensagem de erro formatada em vez de travar.

Temas
Inteligência Artificial

Aprenda com a DataCamp

Curso

IA na prática com Google Gemini e NotebookLM

2 h
9.8K
Domine o Gemini e o NotebookLM para automatizar tarefas, aumentar a produtividade e trabalhar de forma mais inteligente em todo o ecossistema de IA do Google.
Ver detalhesRight Arrow
Começar Curso
Ver maisRight Arrow
Relacionado

blog

Anunciando a série de codificação conjunta "Torne-se um desenvolvedor de IA

Comece a trabalhar com a IA generativa nesta nova série de código-along. Gratuito por tempo limitado.
DataCamp Team's photo

DataCamp Team

4 min

An avian AI exits its cage

blog

12 Alternativas de código aberto ao GPT-4

GPT-4 alternativas de código aberto que podem oferecer desempenho semelhante e exigem menos recursos computacionais para serem executadas. Esses projetos vêm com instruções, fontes de código, pesos de modelos, conjuntos de dados e interface de usuário do chatbot.
Abid Ali Awan's photo

Abid Ali Awan

9 min

Tutorial

RAG With Llama 3.1 8B, Ollama e Langchain: Tutorial

Aprenda a criar um aplicativo RAG com o Llama 3.1 8B usando Ollama e Langchain, configurando o ambiente, processando documentos, criando embeddings e integrando um retriever.
Ryan Ong's photo

Ryan Ong

12 min

Tutorial

Criando agentes LangChain para automatizar tarefas em Python

Um tutorial abrangente sobre a criação de agentes LangChain com várias ferramentas para automatizar tarefas em Python usando LLMs e modelos de bate-papo usando OpenAI.

Tutorial

Guia de torchchat do PyTorch: Configuração local com Python

Saiba como configurar o torchchat do PyTorch localmente com Python neste tutorial prático, que fornece orientação e exemplos passo a passo.

Tutorial

Tutorial da API de assistentes da OpenAI

Uma visão geral abrangente da API Assistants com nosso artigo, que oferece uma análise aprofundada de seus recursos, usos no setor, orientação de configuração e práticas recomendadas para maximizar seu potencial em vários aplicativos de negócios.
Zoumana Keita 's photo

Zoumana Keita

14 min

Ver MaisVer Mais