# Integração do Harbor para Treinamento de LLMs com Ambientes

[Harbor](https://www.harborframework.com) é um framework para executar tarefas agênticas em sandboxes. Ele desacopla uma **tarefa** (instrução + imagem de sandbox + verificador), um **harness/agent** (a superfície de ferramentas + loop) e uma **sandbox** (`docker`, `e2b`, `daytona`, `gke`, …) para que possam ser combinados livremente. Isso o torna uma escolha natural para RL: o mesmo conjunto de tarefas pode ser treinado com diferentes superfícies de ferramentas, em qualquer backend de sandbox que você preferir.

Este guia aborda **como integrar o Harbor com o TRL**. Para o próprio Harbor, consulte a [documentação do Harbor](https://www.harborframework.com/docs).

> [!NOTE]
> A integração está em `trl.experimental.harbor` e é controlada pelo extra `trl[harbor]` (importação preguiçosa — não usuários não pagam nada).

## Quando usar ambientes Harbor

O [GRPOTrainer](/docs/trl/main/pt/grpo_trainer#trl.GRPOTrainer) suporta treinamento baseado em ambientes por meio do slot `environment_factory` — consulte [OpenEnv](openenv) para o contrato geral. Use o Harbor quando quiser treinar contra uma **suíte de tarefas do Harbor**: uma árvore de diretórios de tarefas, cada uma sendo um sandbox + verificador autossuficiente (por exemplo, uma suíte de agentes de análise de dados em que o modelo explora arquivos em um sandbox e escreve uma resposta que um avaliador verifica).

## Instalação

```bash
pip install trl[harbor]
```

> [!IMPORTANT]
> Harbor impulsiona a geração por meio do vLLM e usa `environment_factory`, que requer `vllm` e `transformers>=5.2.0`.
>
> ```bash
> pip install vllm
> ```

Isso instala o framework `harbor` (Python >= 3.12). A integração importa `harbor` de forma preguiçosa e o executa **no processo**, de modo que usuários que não utilizam `trl.experimental.harbor` não são afetados.

Um backend de sandbox também deve estar instalado e acessível no momento do treinamento. O Harbor mantém os backends de nuvem atrás de seus próprios extras, portanto, instale aquele que você pretende usar e forneça suas credenciais:

```bash
pip install "harbor[e2b]"      # E2B cloud sandbox  -> environment_type="e2b",  needs E2B_API_KEY
# docker backend (environment_type="docker", Harbor's default) just needs a reachable Docker daemon
```

## Início rápido

`HarborSpec` conecta um único conjunto de tarefas do Harbor aos três slots do treinador TRL — `train_dataset`, `environment_factory`, `reward_funcs` — expondo propriedades que mapeiam 1:1 para esses nomes de kwarg:

```python
from trl import GRPOConfig, GRPOTrainer
from trl.experimental.harbor import HarborSpec

spec = HarborSpec("AdithyaSK/data_agent_rl_environment_train", agent="bash", num_tasks=64)

trainer = GRPOTrainer(
    model="Qwen/Qwen3-4B",
    args=GRPOConfig(
        num_generations=8,
        max_steps=50,
        max_tool_calling_iterations=25,
        log_completions=True,
    ),
    train_dataset=spec.train_dataset,
    environment_factory=spec.environment_factory,
    reward_funcs=spec.reward_funcs,
)
trainer.train()
```

Por baixo dos panos, `HarborSpec` faz três coisas, de forma preguiçosa no primeiro acesso:

1. **`spec.train_dataset`**: resolve a suíte de tarefas para diretórios locais de tarefas (baixando o dataset do HF, se necessário) e constrói um `datasets.Dataset` com `prompt` (vazio — a instrução do ambiente é adicionada no `reset`), `task_dir`, `task_index`, além de colunas de metadados do `task.toml` por tarefa.
2. **`spec.environment_factory`**: retorna um chamável sem argumentos que produz uma nova instância de [HarborEnv](/docs/trl/main/pt/harbor#trl.experimental.harbor.HarborEnv) para cada rollout. Em `reset(task_dir)`, ele inicia o sandbox Harbor da tarefa e retorna sua instrução; os métodos de ferramenta executam dentro do sandbox; `env.reward` executa o verificador uma vez após o rollout.
3. **`spec.reward_funcs`**: uma recompensa de resultado que lê o escalar do verificador do Harbor por rollout.

## O conjunto de dados

`dataset` é um id de repositório de dataset do Hugging Face contendo uma árvore de tarefas Harbor, ou um caminho local contendo uma subárvore `tasks/`. Cada tarefa é um diretório:

```
tasks/<task_id>/
├── instruction.md          # the task prompt (returned by reset)
├── task.toml               # config + metadata (gold answer, difficulty, ...)
├── environment/            # Dockerfile (+ any pre-agent data hooks)
└── tests/                  # test.sh / grader → writes the reward
```

Selecione um subconjunto com `num_tasks` ou `indices` (mutuamente exclusivos):

```python
spec = HarborSpec("AdithyaSK/data_agent_rl_environment_train", num_tasks=10)        # first 10
spec = HarborSpec("AdithyaSK/data_agent_rl_environment_train", indices=[0, 5, 13])  # specific
```

## Agentes: externos vs instalados

O Harbor suporta duas formas de um agente conduzir uma tarefa, e essa distinção determina o que pode ser treinado com RL:

- [**External agents**](https://www.harborframework.com/docs/agents#external-agents) run *outside* the sandbox and drive the loop themselves, issuing commands into the container through Harbor's environment interface ("typically by executing bash commands via the `exec` method"). The agent decides each action and interprets each result; the sandbox only executes.
- [**Agentes instalados**](https://www.harborframework.com/docs/agents#installed-agents) são instalados *na imagem do container* e executados lá como um subprocesso sem interface (estendendo `BaseInstalledAgent`). O Harbor inicia o agente dentro do sandbox e, em seguida, analisa seu arquivo de trajetória (`populate_context_post_run`); o agente opera de forma autônoma com sua própria inferência.

**A integração do TRL é o padrão de agente externo, e apenas esse padrão é suportado por enquanto.** O treinamento de RL exige que o trainer conduza o rollout turno a turno: o *modelo de política em treinamento* gera cada turno, e o TRL captura seus tokens e log-probs e aplica a máscara do ambiente — exatamente o que `environment_factory` fornece sobre um `rollout_func` de caixa preta. Um agente instalado é opaco para isso: ele roda dentro do container com seu *próprio* modelo e apenas emite uma trajetória a posteriori, de modo que não há tokens de política nem log-probs para o trainer otimizar, e o modelo em treinamento nunca é invocado. Um [HarborEnv](/docs/trl/main/pt/harbor#trl.experimental.harbor.HarborEnv) é, portanto, um agente externo — seus métodos de ferramenta `exec` no sandbox, mas o loop, e o modelo em treinamento, permanecem no TRL.

## Selecionando o agente base (harness)

O **agente base** é a estrutura — quais métodos de ferramenta o env expõe e como ele envia. Selecione-o com `agent=`:

```python
HarborSpec(dataset, agent="bash")                          # built-in single-bash-tool harness
HarborSpec(dataset, agent="my_pkg.harnesses:JupyterEnv")   # import path to your HarborEnv subclass
HarborSpec(dataset, agent="path/to/harness.py:JupyterEnv") # file path to your HarborEnv subclass
HarborSpec(dataset, agent=MyHarborEnv)                     # a HarborEnv subclass directly
```

O harness `"bash"` embutido ([HarborBashEnv](/docs/trl/main/pt/harbor#trl.experimental.harbor.HarborBashEnv)) expõe uma ferramenta `bash` e envia a resposta escrevendo em `/workdir/answer.txt`. Dois harnesses mais completos são fornecidos como exemplos — cada um em sua própria pasta com um README listando suas ferramentas — em [`examples/grpo_harbor/harnesses/`](https://github.com/huggingface/trl/tree/main/examples/grpo_harbor/harnesses):

- [`jupyter/`](https://github.com/huggingface/trl/tree/main/examples/grpo_harbor/harnesses/jupyter) (`JupyterEnv`) — um kernel Python com estado (as variáveis persistem entre as células) + uma ferramenta de shell.
- [`terminal_notes/`](https://github.com/huggingface/trl/tree/main/examples/grpo_harbor/harnesses/terminal_notes) (`TerminalNotesEnv`) — 6 ferramentas de shell (incluindo processos em segundo plano) + um kit de ferramentas de notas persistente com 4 ferramentas.

```python
HarborSpec(dataset, agent="examples/grpo_harbor/harnesses/jupyter/env.py:JupyterEnv")
HarborSpec(dataset, agent="examples/grpo_harbor/harnesses/terminal_notes/env.py:TerminalNotesEnv")
```

Para escrever seu próprio harness, crie uma subclasse de [HarborEnv](/docs/trl/main/pt/harbor#trl.experimental.harbor.HarborEnv) e adicione métodos de ferramenta — todo método público se torna uma ferramenta (o TRL os descobre com `inspect.getmembers`), então dê a cada um uma assinatura tipada e um docstring (usado para construir o schema da ferramenta). Mantenha os auxiliares com prefixo de sublinhado. Use `self._exec(cmd)` para executar comandos de shell no sandbox e defina `PROMPT_SUFFIX` para anexar orientações do harness à instrução da tarefa:

```python
from trl.experimental.harbor import HarborEnv

class GrepEnv(HarborEnv):
    PROMPT_SUFFIX = "\n\nUse `grep` and `read_file`. Submit by writing /workdir/answer.txt."

    def grep(self, pattern: str, path: str) -> str:
        """Search for `pattern` under `path`.

        Args:
            pattern: The regex to search for.
            path: The file or directory to search.
        """
        return self._exec(f"grep -rn {pattern!r} {path!r}")
```

## O backend de sandbox

`environment_type` é passado diretamente para o Harbor (não validado pelo TRL):

```python
HarborSpec(dataset, environment_type="e2b")   # cloud sandbox (offloads provisioning), needs E2B_API_KEY
HarborSpec(dataset, environment_type="docker")  # default; needs a local Docker daemon
```

`e2b` é recomendado para treinamento em cluster: apenas `environment.exec` atravessa para o sandbox na nuvem, de modo que as GPUs permanecem dedicadas à política e você pode executar muitos rollouts simultaneamente.

## Funções de recompensa

`spec.reward_funcs` tem como padrão uma recompensa de resultado — por rollout, ela lê o escalar do verificador do Harbor (`env.reward`), calculado uma única vez após o rollout, executando o verificador `tests/` da tarefa no sandbox. Para uma recompensa personalizada, escreva uma função de recompensa TRL regular:

```python
def my_reward(environments, **kwargs) -> list[float]:
    return [env.reward for env in environments]
```

## API[[trl.experimental.harbor.HarborSpec]]

#### trl.experimental.harbor.HarborSpec[[trl.experimental.harbor.HarborSpec]]

```python
trl.experimental.harbor.HarborSpec(dataset: str, agent: str | type[HarborEnv] = 'bash', environment_type: str = 'docker', num_tasks: int | None = None, indices: list[int] | None = None, include_metadata: bool = True)
```

[Fonte](https://github.com/huggingface/trl/blob/main/trl/experimental/harbor/_spec.py#L113)

**Parâmetros:**

dataset (`str`) : Um id de repositório de dataset do Hugging Face contendo uma árvore de tarefas Harbor (por exemplo, `"AdithyaSK/data_agent_rl_environment_train"`), ou um caminho local para um diretório contendo uma subárvore `tasks/`. Cada tarefa é um diretório com `instruction.md` / `task.toml` / `environment/` / `tests/`.

agent (`str` ou `type`, *opcional*, padrão `"bash"`) : O agente base / harness — ou seja, a superfície de ferramentas que o env expõe. Um dos seguintes: um nome embutido (`"bash"`), um caminho de importação `"package.module:ClassName"`, um caminho de arquivo `"path/to/file.py:ClassName"` ou uma subclasse de [HarborEnv](/docs/trl/main/pt/harbor#trl.experimental.harbor.HarborEnv) diretamente.

environment_type (`str`, *opcional*, padrão `"docker"`) : Backend de sandbox do Harbor, repassado ao Harbor (o que ele suporta — `"docker"`, `"e2b"`, `"daytona"`, `"gke"`, `"modal"`, `"runloop"`, ...). Não é validado aqui; o Harbor valida. `"docker"` é o padrão próprio do Harbor; escolha `"e2b"` para transferir o sandbox para a nuvem.

num_tasks (`int`, *opcional*) : Limite para o número de tarefas extraídas para o conjunto de dados. `None` usa todas as tarefas na árvore.

indices (`list[int]`, *opcional*) : Índices de tarefas específicas (na lista de tarefas ordenada). Mutuamente exclusivo com `num_tasks`.

include_metadata (`bool`, *opcional*, padrão `True`) : Incorpora os metadados por tarefa do `task.toml` (gold_answer, difficulty, ...) nas linhas do dataset.

Objeto de especificação única que conecta um conjunto de tarefas do Harbor a um treinador do TRL.

#### trl.experimental.harbor.HarborEnv[[trl.experimental.harbor.HarborEnv]]

```python
trl.experimental.harbor.HarborEnv(environment_type: str = 'docker')
```

[Fonte](https://github.com/huggingface/trl/blob/main/trl/experimental/harbor/_env.py#L37)

**Parâmetros:**

environment_type (`str`, *opcional*, padrão `"docker"`) : Backend de sandbox do Harbor, transmitido ao Harbor (`"docker"`, `"e2b"`, `"daytona"`, ...).

Ambiente TRL base suportado por um sandbox Harbor + verificador.

Subclasses definem os métodos da ferramenta (o harness). O ciclo de vida que o TRL dirige por rollout: `reset(task_dir)` (inicia o sandbox da tarefa, retorna sua instrução) -> métodos da ferramenta (executa no sandbox) -> `reward` (executa o verificador uma vez, de forma preguiçosa, após o rollout).

#### trl.experimental.harbor.HarborBashEnv[[trl.experimental.harbor.HarborBashEnv]]

```python
trl.experimental.harbor.HarborBashEnv(environment_type: str = 'docker')
```

[Fonte](https://github.com/huggingface/trl/blob/main/trl/experimental/harbor/_env.py#L210)

Harness com uma única ferramenta `bash`; envie escrevendo em `/workdir/answer.txt`.

#### bash[[trl.experimental.harbor.HarborBashEnv.bash]]

```python
bash(command: str)
```

[Fonte](https://github.com/huggingface/trl/blob/main/trl/experimental/harbor/_env.py#L215)

**Parâmetros:**

command : O comando de shell a ser executado.

**Retorna:**

A saída combinada de stdout e stderr do comando.

Execute um comando de shell no sandbox e retorne seu stdout+stderr combinado. O shell não é persistente entre as chamadas. Use-o para explorar arquivos (ls, head, cat), executar Python (`python3 -c "..."`) e enviar a resposta (`echo -n "" > /workdir/answer.txt`).

## Limitações

- A integração está em `trl.experimental` — as APIs podem mudar. Defina `TRL_EXPERIMENTAL_SILENCE=1` para silenciar o aviso nos logs de CI.
- O cliente de sandbox assíncrono do Harbor é vinculado a um único event loop, de modo que cada env executa start/exec/verify de forma síncrona em seu próprio loop; o provisionamento de sandboxes é, portanto, sequencial em todo o lote de geração (backends em nuvem como `e2b` mitigam o custo por sandbox).
- Um único `HarborSpec` cobre um conjunto de tarefas + um harness; o treinamento com múltiplos conjuntos de tarefas ainda não é suportado.

## Referência

- [Framework Harbor](https://www.harborframework.com)
- [Documentação de treinamento do Harbor RL](https://www.harborframework.com/docs/training-workflows/rl)

