Você tem um agente de IA e quer que ele execute em um ambiente seguro, com acesso aos recursos certos, como um sistema de arquivos e a capacidade de executar comandos (ex.: comandos shell) sem o risco de “quebrar nada”. Quais são suas opções?
A melhor abordagem é dar ao seu agente de IA uma sandbox. Dentro de uma sandbox, o agente pode interagir com segurança com uma máquina Linux, trabalhar com o sistema de arquivos e executar comandos específicos, enquanto é restrito de executar operações potencialmente prejudiciais.
Com essa configuração, podemos construir aplicações poderosas. Por exemplo, um agente de codificação que pode:
- Criar e editar arquivos de código no sistema de arquivos
- Executar comandos como git, python ou node
- Colaborar com desenvolvedores executando e testando código diretamente no ambiente
Neste artigo, vamos guiá-lo na construção de um agente de codificação como este. Usaremos os LLMs da Novita com chamada de funções, combinados com o sandbox de agente da Novita como nosso ambiente seguro. Para finalizar, criaremos uma interface amigável com Gradio e a implantaremos no Hugging Face Spaces.
Antes de escolher um modelo para esta configuração, revise Casos de Uso de Large Language Models para Agentes de Codificação para padrões práticos como Q&A de repositório, triagem de testes, refatoração e fluxos de trabalho orientados por ferramentas.
Vamos mergulhar!
Sandbox de Agente
O Sandbox de Agente da Novita é um ambiente de execução projetado especificamente para agentes de IA. Ele fornece uma configuração em nuvem segura e isolada que funciona como um computador virtual. Dentro deste ambiente, os agentes podem executar com segurança o código gerado sem arriscar o sistema subjacente.
Principais Características do Sandbox de Agente da Novita
- Seguro: A sandbox é totalmente isolada, então o agente tem acesso apenas aos seus próprios recursos.
- Inicialização rápida: Novos ambientes são iniciados em menos de 200 ms.
- Máquina virtual: Como a sandbox se comporta como uma VM, os agentes podem executar código em qualquer linguagem de programação.
- Pausar e retomar: Você pode pausar uma sandbox a qualquer momento e retomá-la depois.
- Tarefas em segundo plano: Os agentes podem executar tarefas em segundo plano e recuperar resultados de forma assíncrona.
Instalando o SDK
Para usar a Sandbox da Novita, você precisará do SDK, que suporta Python e TypeScript/JavaScript. Para este tutorial, usaremos o SDK Python:
pip install novita-sandbox
Após a instalação, defina sua chave de API da Novita como uma variável de ambiente:
export NOVITA_API_KEY=sua_chave_api_aqui
Testando a Sandbox
Com tudo configurado, vamos criar uma sandbox e executar algumas operações básicas:
from novita_sandbox.code_interpreter import Sandbox
sandbox = Sandbox.create()
files = sandbox.files.list("/")
for file in files:
print(file.name)
result = sandbox.commands.run('pwd')
print(result)
sandbox.kill()
Este exemplo mostra como:
- Criar uma instância de sandbox
- Acessar o sistema de arquivos com o objeto files
- Executar comandos usando o método commands.run
- Liberar recursos com kill quando terminar
Agora que exploramos o básico de acessar o sistema de arquivos e executar comandos, estamos prontos para construir nosso agente de codificação que usa essas capacidades da sandbox como ferramentas.
Construindo um Agente de Codificação
Para construir nosso agente de codificação, precisamos de um LLM que suporte chamada de funções. A Novita fornece vários modelos que fazem isso. Para que nosso agente se comporte como um assistente de codificação, ele deve ter o conjunto certo de funções.
Vamos pensar no que um codificador humano faz. Eles geralmente escrevem, leem e executam código. Portanto, nosso agente deve ser capaz de:
- Escrever em um arquivo
- Ler de um arquivo
- Executar comandos
- Escrever em vários arquivos de uma vez
Configurando o Agente
Como os modelos da Novita são compatíveis com OpenAI, podemos usar o SDK OpenAI para interagir com eles. Vamos instalá-lo:
pip install openai
Após a instalação, defina sua chave de API da Novita como uma variável de ambiente, assim como fizemos anteriormente. Depois disso, podemos começar a codificar adicionando nossas importações:
from openai import OpenAI
import os
import json
from novita_sandbox.code_interpreter import Sandbox
Agora, vamos criar nossa instância do cliente OpenA:
client = OpenAI(
base_url="https://api.novita.ai/openai",
api_key=os.environ["NOVITA_API_KEY"],
)
Aqui, estamos apontando o cliente para a URL base da Novita em vez da OpenA e usando nossa chave de API da Novita para autenticação.
Em seguida, criaremos a instância da sandbox que nosso agente usará:
sandbox = Sandbox.create(timeout=1200)
O parâmetro timeout especifica quanto tempo a sandbox deve permanecer ativa. Neste caso, definimos para 10 minutos.
Definições das Funções
Agora podemos definir as funções que nosso agente usará.
1. Ler Arquivo
Esta função recebe um caminho de arquivo e lê seu conteúdo usando o objeto files da sandbox.
def read_file(path: str):
print(f"[DEBUG] read_file called with path: {path}")
try:
content = sandbox.files.read(path)
print(f"[DEBUG] read_file result: {content}")
return content # returns string content
except Exception as e:
print(f"[DEBUG] read_file error: {e}")
return f"Error reading file: {e}"
2. Escrever Arquivo
Esta função escreve dados em um caminho de arquivo específico.
def write_file(path: str, data: str):
print(f"[DEBUG] write_file called with path: {path}")
try:
sandbox.files.write(path, data)
msg = f"File created successfully at {path}"
print(f"[DEBUG] {msg}")
return msg
except Exception as e:
print(f"[DEBUG] write_file error: {e}")
return f"Error writing file: {e}"
3. Escrever Vários Arquivos
Esta função funciona como write_file, mas lida com vários arquivos de uma vez.
def write_files(files: list):
print(f"[DEBUG] write_files called with {len(files)} files")
try:
sandbox.files.write_files(files)
msg = f"{len(files)} file(s) created successfully"
print(f"[DEBUG] {msg}")
return msg
except Exception as e:
print(f"[DEBUG] write_files error: {e}")
return f"Error writing multiple files: {e}"
4. Executar Comandos
Esta função executa comandos shell dentro da sandbox e retorna a saída padrão.
def run_commands(command: str):
print(f"[DEBUG] run_commands called with commands: {command}")
try:
result = sandbox.commands.run(command)
print(f"[DEBUG] run_commands result: {result}")
return result.stdout # returns CommandResult object
except Exception as e:
print(f"[DEBUG] run_commands error: {e}")
return f"Error running commands: {e}"
Registro das Ferramentas
Agora que temos todas as nossas funções, vamos registrá-las como ferramentas que o LLM pode chamar quando necessário. Cada definição de ferramenta inclui o nome da função, descrição e esquema de parâmetros.
tools = [
{
"type": "function",
"function": {
"name": "read_file",
"description": "Read contents of a file inside the sandbox",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "File path in the sandbox"}
},
"required": ["path"],
},
},
},
{
"type": "function",
"function": {
"name": "write_file",
"description": "Write a single file inside the sandbox",
"parameters": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "File path in the sandbox"},
"data": {"type": "string", "description": "Content to write"},
},
"required": ["path", "data"],
},
},
},
{
"type": "function",
"function": {
"name": "write_files",
"description": "Write multiple files inside the sandbox",
"parameters": {
"type": "object",
"properties": {
"files": {
"type": "array",
"items": {
"type": "object",
"properties": {
"path": {"type": "string"},
"data": {"type": "string"},
},
"required": ["path", "data"],
},
}
},
"required": ["files"],
},
},
},
{
"type": "function",
"function": {
"name": "run_commands",
"description": "Run a single shell command inside the sandbox working directory",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The shell command to run, e.g. 'ls' or 'python main.py'",
}
},
"required": ["command"],
},
},
}
]
Com as ferramentas registradas, vamos avançar para a criação de um loop de chat que utilizará nosso agente e todas as ferramentas que definimos.
Loop de Chat
Agora criaremos um loop de chat simples que permite ao usuário interagir com o agente de codificação. O loop man terá uma lista de mensagens e lidará com chamdas de funções sempre que o agente solicitar uma.
messages = []
print("💬 Enter your queries (type 'exit' to quit):")
while True:
user_input = input("You: ")
if user_input.lower() == "exit":
break
# Append user message
messages.append({"role": "user", "content": user_input})
# Send to model
response = client.chat.completions.create(
model=model,
messages=messages,
tools=tools,
)
assistant_msg = response.choices[0].message
messages.append(assistant_msg)
if assistant_msg.tool_calls:
print(f"[DEBUG] Assistant requested {len(assistant_msg.tool_calls)} tool call(s).")
for tool_call in assistant_msg.tool_calls:
fn_name = tool_call.function.name
fn_args = json.loads(tool_call.function.arguments)
print(f"[DEBUG] Tool call detected: {fn_name} with args {fn_args}")
if fn_name == "read_file":
fn_result = read_file(**fn_args)
elif fn_name == "write_file":
fn_result = write_file(**fn_args)
elif fn_name == "write_files":
fn_result = write_files(**fn_args)
elif fn_name == "run_commands":
fn_result = run_commands(**fn_args)
else:
fn_result = f"Error: Unknown tool {fn_name}"
print(f"[DEBUG] Unknown tool requested: {fn_name}")
# Append result back
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"content": str(fn_result),
})
# Get model's final answer with tool results
follow_up = client.chat.completions.create(
model=model,
messages=messages,
)
final_answer = follow_up.choices[0].message
messages.append(final_answer)
print("Assistant:", final_answer.content)
else:
print("Assistant:", assistant_msg.content)
sandbox.kill()
print("[DEBUG] Sandbox terminated. 👋")
Este loop de chat mantém a interação em execução, permite que o agente chame qualquer uma das ferramentas registradas quando necessário e limpa a sandbox quando o usuário sair.
Criando uma Interface com Gradio
Agora temos um agente de codificação totalmente funcional que pode conversar conosco, mas interagir através de um REPL não é muito empolgante. Vamos tornar a experiência mais envolvente, dando ao nosso agente uma interface Gradio simples.
Criar uma interface Gradio é simples. Usaremos o gr.ChatInterface para gerenciar nossas interações de chat e vinculá-lo à lógica que construímos anteriormente. Junto com isso, incluiremos uma interface de comandos para executar comandos shell dentro da sandbox, bem como um menu suspenso que nos permite selecionar qual modelo usar.
Para atualizar nosso código anterior para suportar Gradio, substituiremos o loop de chat e as duas últimas linhas pelo seguinte:
# --- Persistent chat messages ---
messages = []
# --- Global model setter ---
def set_model(selected_model):
global model
model = selected_model
print(f"[DEBUG] Model switched to: {model}")
return f"✅ Model switched to **{model}**"
def chat_fn(user_message, history):
global messages, model
messages.append({"role": "user", "content": user_message})
# Send to model
response = client.chat.completions.create(
model=model,
messages=messages,
tools=tools,
)
assistant_msg = response.choices[0].message
messages.append(assistant_msg)
output_text = ""
if assistant_msg.tool_calls:
print(f"[DEBUG] Assistant requested {len(assistant_msg.tool_calls)} tool call(s).")
for tool_call in assistant_msg.tool_calls:
fn_name = tool_call.function.name
fn_args = json.loads(tool_call.function.arguments)
print(f"[DEBUG] Tool call detected: {fn_name} with args {fn_args}")
if fn_name == "read_file":
fn_result = read_file(**fn_args)
elif fn_name == "write_file":
fn_result = write_file(**fn_args)
elif fn_name == "write_files":
fn_result = write_files(**fn_args)
elif fn_name == "run_commands":
fn_result = run_commands(**fn_args)
else:
fn_result = f"Error: Unknown tool {fn_name}"
messages.append({
"tool_call_id": tool_call.id,
"role": "tool",
"content": str(fn_result),
})
follow_up = client.chat.completions.create(
model=model,
messages=messages,
)
final_answer = follow_up.choices[0].message
messages.append(final_answer)
output_text = final_answer.content
else:
output_text = assistant_msg.content
return output_text
# --- Command Interface function ---
def execute_command(command):
if not command.strip():
return "⚠️ Please enter a command."
print(f"[DEBUG] Executing command from interface: {command}")
output = run_commands(command)
return f"```bash\n{output}\n```" if output else "✅ Command executed (no output)."
# --- Gradio UI ---
with gr.Blocks(title="Novita Sandbox App") as demo:
gr.Markdown("## 🧠 Novita Sandbox Agent")
gr.Markdown(
"This app is an AI-powered **code agent** that lets you chat with intelligent assistants backed by **Novita AI LLMs**. These agents can write, read, and execute code safely inside a **Novita sandbox**, providing a secure environment for running commands, testing scripts, and managing files, all through an intuitive chat interface with model selection and command execution built right in."
)
with gr.Row(equal_height=True):
# Left: Chat Interface
with gr.Column(scale=2):
gr.Markdown("### 💬 Chat Interface")
gr.ChatInterface(chat_fn)
# Right: Command Interface
with gr.Column(scale=1):
gr.Markdown("### 💻 Command Interface")
# Model selector
model_selector = gr.Dropdown(
label="Select Model",
choices=[
"meta-llama/llama-3.3-70b-instruct",
"deepseek/deepseek-v3.2-exp",
"qwen/qwen3-coder-30b-a3b-instruct",
"openai/gpt-oss-120b",
"moonshotai/kimi-k2-instruct",
],
value=model,
interactive=True,
)
model_status = gr.Markdown(f"✅ Current model: **{model}**")
model_selector.change(set_model, inputs=model_selector, outputs=model_status)
command_input = gr.Textbox(
label="Command",
placeholder="e.g., ls, python main.py",
lines=1,
)
with gr.Row():
run_btn = gr.Button("Run", variant="primary", scale=0)
command_output = gr.Markdown("Command output will appear here...")
run_btn.click(execute_command, inputs=command_input, outputs=command_output)
# --- Cleanup on exit ---
atexit.register(lambda: (sandbox.kill(), print("[DEBUG] Sandbox terminated. 👋")))
if __name__ == "__main__":
demo.launch()
Nesta versão, a função chat_fn lida com cada troca de mensagens entre o usuário e o agente. O gr.ChatInterface recebe esta função como entrada e gerencia as interações da interface automaticamente.
Quando o aplicativo Gradio inicia, ele executa seu agente no navegador, dando ao usuário uma interface de chat limpa e interativa. Finalmente, registramos uma rotina de limpeza usando atexit para garantir que a sandbox seja encerrada corretamente quando o aplicativo parar.
Agora temos um agente de codificação alimentado por IA executando com segurança em uma sandbox, completo com uma interface de chat Gradio amigável.
Você pode encontrar o código completo no GitHub.
Testando o Agente de Codificação
Para usar o agente, precisamos executar nosso código gradio como um script.
python gradio_chat.py
Quando fazemos isso, teremos nosso aplicativo gradio rodando em localhost. Com isso, podemos ter conversas com nosso agente de codificação e o agente executará todas as nossas ações dentro da sandbox.
No aplicativo gradio, tudo o que vemos são os chats do nosso agente, mas se formos ao nosso terminal, também podemos ver as saídas de depuração de qual comando a função que o agente chamou para atender à solicitação do usuário.
O fato de termos acesso a uma ferramenta de arquivo e uma ferramenta de comando significa que quase não há nada que não possamos codificar, mas em vez de programar diretamente, estamos dando instruções ao nosso agente e ele escreve e executa os códigos para nós.
Implantando no Hugging Face Spaces
Atualmente, temos nosso agente de codificação rodando localmente em nosso computador. Agora, vamos torná-lo acessível ao resto do mundo, implantando-o no Hugging Face Spaces. O Hugging Face Spaces nos permite hospedar tanto nosso código quanto o aplicativo em um só lugar. Vamos começar.
Criar o Space
Vá para o Hugging Face e crie um novo Space para seu agente de codificação, dando a ele um nome único.

Em seguida, selecione o SDK para o Space, que no nosso caso é Gradio. Escolha o modelo Blank, já que já temos nosso código de aplicativo.

Depois, selecione o hardware. Como nosso agente e sandbox são alimentados pela Novita, não precisamos de hardware especializado. A opção Basic CPU é suficiente. Depois de pronto, clique em Create Space.

O Hugging Face criará o Space com um arquivo README.md e um .gitignore.
Existem várias maneiras de adicionar seu código, mas a mais simples é clicar em Contribute → Add file.

Crie um arquivo requirements.txt e inclua as seguintes dependências:
openai
novita-sandbox
Adicionar Variáveis de Ambiente
Antes de executar nosso aplicativo, precisamos definir nossa NOVITA_API_KEY como uma variável de ambiente.
Para fazer isso, navegue até as Configurações do seu Space, role até a seção Variables and secrets e adicione um novo segredo chamado NOVITA_API_KEY com sua chave de API como valor.
Configurar o Aplicativo
Com a variável de ambiente definida, é hora de criar nosso aplicativo.
Crie um novo arquivo chamado app.py e cole todo o código do nosso agente Gradio nele.

Depois de salvar o arquivo, o Hugging Face começará automaticamente a construir seu Space.

Após a conclusão do processo de construção, seu agente de codificação estará disponível e acessível no Hugging Face Spaces.
Agora você pode conversar com seu agente através da interface de chat interativa.
Além disso, você pode monitorar os logs para ver as ferramentas que seu agente chama durante a execução.
E é isso, agora você tem um agente de codificação totalmente funcional executando em uma sandbox segura, equipado com uma interface Gradio e implantado perfeitamente no Hugging Face Spaces.
Conclusão
Neste artigo, exploramos como aproveitar a Sandbox da Novita para construir um agente de codificação totalmente funcional, capaz de ler e criar arquivos, executar comandos e operar com segurança dentro de um ambiente seguro.
O que construímos aqui é apenas o começo. A sandbox abre portas para inúmeras possibilidades, desde a criação de agentes de visualização de dados alimentados por IA até o desenvolvimento de agentes de uso de computador que podem interagir com sistemas de forma inteligente.
Quase tudo é possível quando você combina um agente com um conjunto de ferramentas dedicado como a sandbox.