Adapters customizados
Este guia cobre a integração de métodos próprios de forecast que não cabem nas famílias já suportadas pela engine.
Se a mudança for apenas adicionar mais um modelo dentro de uma família já existente, prefira estender o catálogo atual da família em vez de criar um adapter novo.
Decisão rápida
| Cenário | Caminho recomendado |
|---|---|
mesmo library_family e mesma convenção de artefato | ampliar catálogo e testes da família existente |
| nova lógica de treino/predição | criar uma nova família em src/infra/modeling/<family>/ |
Contrato mínimo
O ponto de extensão principal está em
src/control/modeling/shared/strategy_ports.py, com os DTOs de chamada em
src/control/modeling/shared/contracts.py.
Todo adapter customizado precisa implementar ModelStrategy:
class ModelStrategy(Protocol): def train(self, request: TrainRequest) -> TrainResult: ... def predict(self, request: PredictRequest) -> PredictResult: ...Regras que a engine espera:
train()precisa retornar métricas e tambémartifact_uriouartifact_payload;predict()precisa ler o artefato indicado emrequest.artifact_uri;PredictResult.forecast_frameprecisa voltar como frame canônico de forecast (period_start,value,uom,lower,upper,confidence);- erros de treino ou predição devem falhar explicitamente, sem falso sucesso.
Contrato de dados
O feature_frame entregue ao adapter vem do boundary canônico de
data-preparation. O control trata esse payload de forma genérica; a
representação concreta fica no adapter. No runtime atual de treino e predição,
essa execução é Polars, e a conversão para formatos externos deve continuar
restrita a infra/modeling/<family>/.
No treino e na predição, o frame de demanda chega com estas colunas:
organization_idsku_idstore_idsku_systemsku_keystore_systemstore_keygrainperiod_startquantityuomsourcecreated_at
Na volta, o adapter precisa produzir um frame de forecast com:
period_startvalueuomlowerupperconfidence
Esses nomes não devem ser trocados no adapter. O mapeamento para formatos
externos deve acontecer dentro de src/infra/modeling/..., não no domínio, no
control plane ou no data plane.
Passo a passo
1. Criar a família do adapter
Crie um diretório dedicado, por exemplo:
src/infra/modeling/my-family/Mantenha ali:
- a implementação concreta da estratégia;
- helpers de transformação de frame;
- codec de artefato, se houver;
- bootstrap de registro da família.
Evite espalhar detalhes da biblioteca em control, control/data_preparation ou domain.
2. Implementar treino e predição
A implementação costuma seguir este fluxo:
- validar que
request.library_familybate com a família esperada; - converter o frame canônico para o formato da biblioteca;
- treinar o modelo com
request.paramse as colunas já preparadas no frame; - serializar o artefato;
- devolver
TrainResult(metrics=..., artifact_payload=...); - na predição, recarregar o artefato e converter a saída de volta ao frame canônico.
request.params já chega como o snapshot efetivo do params_schema resolvido
para a estratégia. O adapter não precisa consultar repositório nem ler
configuração externa para descobrir hiperparâmetros.
3. Registrar a estratégia nos jobs
Os jobs chamados pelo Airflow resolvem estratégias por strategy_key usando
DefaultStrategyCatalog.
Na prática:
- crie um helper como
register_my_family_strategies(...); - registre cada
strategy_keycom a implementação concreta; - chame esse helper em
src/infra/jobs/bootstrap.py.
Sem esse registro, o treino falha com Unknown strategy key.
4. Expor a família na configuração HTTP
Se o ModelDefinition for criado ou atualizado via API, a família nova precisa
registrar sua chave de família no StrategyCatalogPort.
No runtime atual, isso acontece no helper de bootstrap da família, por exemplo
register_nixtla_strategies(...), chamando
register_library_family(...).
É esse catálogo que a aplicação consulta para validar:
- se o
library_familyé conhecido; - se o
strategy_keytem uma implementação registrada.
src/infra/http/schemas.py só traduz payloads para tipos internos; quem decide
se a família é válida agora é a aplicação.
5. Adicionar testes
O mínimo esperado é:
- teste do adapter para
train()epredict(); - teste de round-trip do artefato;
- teste de caso de uso cobrindo registro da estratégia e execução;
Os arquivos mais úteis como referência hoje são:
tests/test_nixtla_strategies.pytests/test_engine_use_cases.pytests/test_mlops_adapters.py
6. Documentar a família
Ao finalizar a integração:
- atualize esta seção de
ml-modelscom a nova família; - ajuste Configuração de model definition se o contrato de
params_schemamudar; - documente limitações reais da integração, sem esconder restrições.
Checklist final
Antes de considerar a integração pronta, confirme:
- a implementação fica restrita à camada
infra/modeling; strategy_keyelibrary_familyestão estáveis;train()sempre gera artefato utilizável empredict();- o forecast retornado usa o schema canônico;
- treino e promoção falham claramente quando a família é incompatível;
- testes cobrem o caminho feliz e os erros de contrato.