DeepSeek Harness: Isolamento de Serviço e Escopo
Última atualização: 2026-08-31
Em ambientes multi-Agent, multi-sessão, serviços compartilhados são tanto bênção quanto maldição — serviços globais são convenientes mas propensos a conflitos, serviços isolados são seguros mas comunicação custa mais. O sistema de escopo do Cordis equilibra ambos: compartilhado por padrão, isolado sob demanda.
📋 Pré-requisitos: Ter completado 19-service.md, entender a classe base Service
1. O Que Você Vai Aprender
- Escopo Global
- Escopo de Sessão
- Escopo de Requisição
- Configuração isolate realm
- Escopo e presets de Agent
- Isolamento de serviço multi-Agent
2. Escopo Global
(1) Comportamento Padrão
▶ Exemplo 1: Serviço Global (Singleton)
Por padrão, todos os Services são globais — há apenas uma instância em toda a instância DSH:
export default class CacheService extends Service {
constructor(ctx: Context) {
super(ctx, 'cache') // Globalmente único
}
}
(2) Características de Serviços Globais
| Característica | Descrição |
|---|---|
| Singleton | Apenas uma instância por processo |
| Compartilhado | Todas as sessões e requisições compartilham o mesmo estado |
| Sem isolamento | Dados modificados pela sessão A são visíveis à sessão B |
(3) Cenários Aplicáveis
- Gerenciamento de configuração (apenas uma config global necessária)
- Pools de conexão (conexões compartilhadas são mais eficientes)
- Serviços de logging (logs devem ser coletados centralmente)
- Adaptadores de modelo (chamadas de API podem ser reutilizadas entre sessões)
(4) Problema de Vazamento de Dados
// ❌ Cache global causa vazamento de dados entre sessões
export default class CacheService extends Service {
private data = new Map<string, any>()
set(key: string, value: any) {
this.data.set(key, value)
}
}
// Sessão A: ctx.cache.set('temp', 'secret-data')
// Sessão B: ctx.cache.get('temp') → 'secret-data' (vazou!)
3. Escopo de Sessão
(1) Conceito
▶ Exemplo 2: Serviço com Escopo de Sessão
Escopo de sessão cria uma instância de serviço independente para cada sessão:
export default class SessionCacheService extends Service {
static scope = 'session'
constructor(ctx: Context) {
super(ctx, 'session-cache')
}
}
(2) Diagrama de Ciclo de Vida
graph LR
S1[Sessão A criada] --> C1[Instância CacheService A]
S2[Sessão B criada] --> C2[Instância CacheService B]
S1 --> D1[Sessão A destruída → CacheService A destruído]
S2 --> D2[Sessão B destruída → CacheService B destruído]
(3) Declaração de Escopo
export default class SessionCacheService extends Service {
static scope = 'session'
// Ou
// static scope = Symbol('session')
}
(4) Cenários Aplicáveis
- Cache em nível de sessão
- Sobrescritas de configuração em nível de sessão
- Customização de conjunto de ferramentas em nível de sessão
- Histórico de sessão
(5) Efeito de Isolamento Entre Sessões
Sessão A:
ctx.sessionCache.set('key', 'value-A')
Sessão B:
ctx.sessionCache.get('key') → undefined (isolado)
Sessão A:
ctx.sessionCache.get('key') → 'value-A' (acessível dentro da sessão)
4. Escopo de Requisição
(1) Conceito
Escopo de requisição cria uma instância independente para cada chamada de ferramenta ou requisição LLM:
export default class RequestContextService extends Service {
static scope = 'request'
constructor(ctx: Context) {
super(ctx, 'request-context')
}
}
(2) Ciclo de Vida do Escopo de Requisição
graph LR
R1[Requisição 1 inicia] --> S1[Instância de serviço 1]
R2[Requisição 2 inicia] --> S2[Instância de serviço 2]
R1 --> E1[Requisição 1 completa → instância 1 destruída]
R2 --> E2[Requisição 2 completa → instância 2 destruída]
(3) Cenários Aplicáveis
- Informação de contexto em nível de requisição (IP do usuário, ID da requisição)
- Verificações de permissão em nível de requisição
- Timing de desempenho em nível de requisição
- Agregação de logs em nível de requisição
(4) Comparação dos Três Níveis de Escopo
| Dimensão | Global | Sessão | Requisição |
|---|---|---|---|
| Instâncias | 1 | 1 por sessão | 1 por requisição |
| Ciclo de vida | Tempo de vida do processo | Tempo de vida da sessão | Tempo de vida da requisição |
| Compartilhamento de estado | Globalmente compartilhado | Dentro da sessão | Apenas dentro da requisição |
| Memória | Baixa | Média | Alta |
| Melhor para | Config/pools de conexão | Cache/histórico de sessão | Permissões/timing |
5. Configuração isolate Realm
(1) Conceito de Realm
Um realm é o domínio de isolamento do Cordis — criando espaços de plugin independentes dentro da mesma instância DSH:
# cordis.yml
realms:
agent-a:
isolate: ['cache', 'tools']
plugins:
my-tool-a:
$insert: ./plugins/tool-a
agent-b:
isolate: ['cache', 'tools']
plugins:
my-tool-b:
$insert: ./plugins/tool-b
(2) Campo isolate
A lista isolate especifica quais serviços recebem instâncias independentes dentro do realm:
realms:
my-realm:
isolate:
- cache # serviço cache recebe instância independente
- tools # serviço tools recebe instância independente
# Serviços não listados permanecem globalmente compartilhados
(3) Instâncias de Serviço Dentro de um Realm
Global: llm (compartilhado)
realm-a: cache (independente), tools (independente)
realm-b: cache (independente), tools (independente)
Plugins no realm-a → ctx.cache = cache do realm-a
Plugins no realm-b → ctx.cache = cache do realm-b
Eles não afetam uns aos outros
(4) Casos de Uso de Realm
| Cenário | Descrição |
|---|---|
| Multi-Agent | Diferentes Agents têm diferentes conjuntos de ferramentas e caches |
| Multi-tenant | Serviços de diferentes tenants são mutuamente isolados |
| Testes | Realm de teste não afeta realm de produção |
| Teste A/B | Dois realms usam implementações de serviço diferentes |
(5) Comunicação Cross-Realm
▶ Exemplo 3: Comunicação entre Realms via Serviço Global
Realms são isolados por padrão mas podem se comunicar através de serviços globais:
// Serviço global (não afetado por isolate)
export default class EventBusService extends Service {
constructor(ctx: Context) {
super(ctx, 'event-bus') // Não na lista isolate → globalmente compartilhado
}
emit(event: string, data: any) { /* ... */ }
on(event: string, handler: Function) { /* ... */ }
}
// Plugin no realm-a
ctx.eventBus.emit('data-updated', { source: 'realm-a' })
// Plugin no realm-b
ctx.eventBus.on('data-updated', (data) => {
ctx.logger.info(`recebido de ${data.source}`)
})
6. Escopo e Presets de Agent
(1) Conceito de Preset de Agent
Um preset de Agent é uma configuração de Agent pré-definida incluindo conjunto de ferramentas, parâmetros de modelo e configurações de escopo:
presets:
coder:
model: deepseek-coder
tools: [file_edit, shell, search]
mode: standard
reviewer:
model: deepseek-chat
tools: [file_edit, search]
mode: minimal
isolate: [cache]
(2) Relação Preset e Escopo
Cada preset pode especificar uma lista isolate, criando instâncias de serviço isoladas para aquele Agent:
coder Agent: cache compartilhado, tools independente
reviewer Agent: cache independente, tools compartilhado
(3) Cenário Multi-Agent
# cordis.yml
agents:
coder:
preset: coder
isolate: [tools]
reviewer:
preset: reviewer
isolate: [tools, cache]
(4) Colaboração Inter-Agent
graph TB
subgraph Global
LLM[llm Service]
EVENT[event-bus Service]
end
subgraph Agent-Coder
CT[tools Service]
CC[cache Service]
end
subgraph Agent-Reviewer
RT[tools Service]
RC[cache Service]
end
CT --> LLM
RT --> LLM
CT --> EVENT
RT --> EVENT
7. Isolamento de Serviço Multi-Agent
(1) Seleção de Estratégia de Isolamento
Totalmente compartilhado: Todos os serviços globais → simples mas potencial de conflitos
Totalmente isolado: Todos os serviços independentes → seguro mas desperdício de recursos
Isolamento misto: Serviços centrais compartilhados + serviços de negócio isolados → abordagem equilibrada
Isolamento misto recomendado:
| Tipo de Serviço | Estratégia de Isolamento | Motivo |
|---|---|---|
| llm | Compartilhado | Chamadas de API podem ser reutilizadas |
| sessions | Compartilhado | Gerenciamento unificado de sessões |
| tools | Isolado | Cada Agent tem conjunto diferente de ferramentas |
| cache | Isolado | Cada Agent tem cache independente |
| fs | Compartilhado | Apenas um sistema de arquivos |
(2) Exemplo de Configuração Multi-Agent
agents:
frontend-dev:
preset: coder
isolate: [tools, cache]
tools:
- file_edit
- shell
- search
config:
cache:
maxSize: 100
backend-dev:
preset: coder
isolate: [tools, cache]
tools:
- file_edit
- shell
- search
- database
config:
cache:
maxSize: 200
(3) Estimativa de Consumo de Recursos
| Nível de Isolamento | Memória | CPU | Conexões |
|---|---|---|---|
| Compartilhado global | 1x | 1x | 1x |
| 2-Agent isolado | ~2x | ~1.5x | ~2x |
| 5-Agent isolado | ~5x | ~3x | ~5x |
(4) Detecção de Vazamento de Isolamento
// Monitorar contagens de instância de serviço
ctx.on('service/created', (name, instance) => {
ctx.logger.info(`serviço criado: ${name}, instâncias totais: ${countInstances(name)}`)
})
// Se a contagem de instâncias de um serviço excede em muito a contagem de Agents, pode haver vazamento
❓ Perguntas Frequentes
static scope é um singleton global por padrão.typescript constructor(ctx: Context) { super(ctx, 'cache') console.log(`instância cache criada: ${this.id}, escopo: ${this.scope}`) } 📖 Resumo
- Três níveis de escopo: global (padrão), sessão (independente por sessão), requisição (independente por requisição)
- Serviços globais para config/pools de conexão, serviços de sessão para cache/histórico, serviços de requisição para permissões/timing
- Configuração isolate realm cria instâncias de serviço independentes para espaços específicos
- Presets de Agent combinados com escopo permitem isolamento de conjunto de ferramentas e cache multi-Agent
- Estratégia de isolamento misto recomendada: serviços centrais compartilhados + serviços de negócio isolados
- Escolha de escopo afeta memória e desempenho; isole sob demanda, não exagere
📝 Exercícios
1. ⭐ Básico: Escreva um SessionStateService com escopo de sessão que mantém armazenamento chave-valor independente por sessão. Inicie duas sessões e verifique isolamento de dados.
2. ⭐⭐ Intermediário: Configure um realm que isola serviços de cache e tools. Acesse cache dentro e fora do realm, verificando que recebe instâncias diferentes.
3. ⭐⭐⭐ Desafio: Projete um sistema dual-Agent: coder e reviewer. Coder tem ferramentas file_edit/shell, reviewer apenas file_edit/search. Ambos compartilham llm e sessions, mas cache e conjunto de ferramentas são independentemente isolados. Verifique: a ferramenta shell do coder é invisível para o reviewer, e seus caches não afetam uns aos outros.