Router
laya.Router detecta o idioma de cada estado e envia a solicitação ao checkpoint
correspondente, carregando os checkpoints no primeiro uso.
Nomes, tipos, valores padrão e código permanecem em inglês; o restante é traduzido (entradas ainda não traduzidas são exibidas no original em inglês).
Router
Router(
models: Optional[Dict[str, str]] = None,
device: Optional[str] = None,
token: Optional[str] = None,
revision: Optional[str] = None,
revisions: Optional[Dict[str, Optional[str]]] = None,
max_loaded: int = 2,
default: str = "english",
auto_task_detection: bool = False,
standalone_repos: bool = False,
preload: bool = False,
lang_guess: Optional[Any] = None,
hooks=None,
on_predict_start=None,
on_predict_end=None,
hooks_raise: bool = True,
hooks_concurrent: bool = True,
hooks_timeout: Optional[float] = None,
agent_kwargs: Optional[Dict[str, Any]] = None,
sha256_digests: Optional[Dict[str, Optional[Dict[str, str]]]] = None,
)Classes base: HookRegistry
Carrega os checkpoints do Laya sob demanda e envia cada requisição ao correto.
from laya import Router
r = Router()
r.predict({"message": "Mein Konto wurde zweimal belastet"}, questions) # -> multilingual
r.predict({"message": "I was charged twice"}, questions) # -> english
r.predict(state, questions, model="typed-decisions") # explicit
Os modelos são baixados e construídos no primeiro uso. max_loaded limita quantos permanecem residentes
(o usado menos recentemente é despejado), porque os três juntos são ~1.16B de parâmetros.
O padrão é 2, porque o roteamento automático só escolhe entre english e
multilingual: um limite de um reconstrói o checkpoint que acabou de despejar a cada troca de idioma,
o que são segundos por requisição exatamente no tráfego para o qual o Router existe. O tráfego que só
vê um idioma nunca constrói o segundo checkpoint, então o padrão não lhe custa nada.
Reduza-o para 1 em um host com memória limitada, e aumente-o para 3 (ou pré-carregue) quando
auto_task_detection, um model= explícito ou um task= explícito também puderem alcançar
typed-decisions.
Para um servidor ou uma demo, pré-carregue: um carregamento a frio custa segundos, enquanto a detecção custa microssegundos, então até o padrão ainda paga um carregamento na primeira vez que um idioma aparece.
r = Router(preload=True) # all three resident, routing is free
r = Router(preload=True, device="cuda")
r.preload(["english", "multilingual"]) # or just the two you serve
As revisões do Hub são opt-in. revision aplica um commit a todos os modelos;
revisions={"english": "...", "multilingual": "..."} sobrescreve isso por modelo,
o que é útil quando repositórios independentes foram revisados em commits diferentes.
Sem nenhum dos dois, usa o padrão normal do huggingface_hub e o cache offline existente.
Uma entrada de revisions que é None ou em branco significa "sem sobrescritura para este modelo", então o modelo
herda revision -- a forma que {"english": os.environ.get("EN_SHA")} escreve quando a
variável não está definida, o que não deve custar ao chamador a fixação que ele pediu. Nada em
revisions pode desafixar um modelo enquanto revision fixa o resto; deixe revision não definido e
nomeie os modelos que você quer fixar.
Um revision em branco é lido da mesma forma, o que é uma mudança deliberada no que o Router
repassa: Router(revision=" ") costumava chegar a resolve_revision, onde uma string
verdadeira mas em branco suprimia o fallback de LAYA_REVISION e deixava o padrão do huggingface_hub, e agora é
descartado antes de chegar lá, então um Router configurado com espaços em branco se comporta como um
configurado com nada e $LAYA_REVISION se aplica. É isso que "esta linha de configuração nunca
foi preenchida" tem de significar se revision e uma entrada de revisions devem ser lidos da mesma forma.
É um dos dois lugares em que uma fonte mais fraca fica à frente de um argumento explícito. O outro é uma
entrada de digest por checkpoint vinda de LAYA_SHA256_DIGESTS, que vence um expected_sha256
passado por agent_kwargs; consulte a docstring da classe.
Qualquer outra coisa que laya.Agent aceite é acessível através de agent_kwargs, que é mesclado em
cada checkpoint que o Router constrói:
Router(agent_kwargs={"lang_temperatures": {"de": {"temperature": [1.0, 1.4, 2.0]}}})
Router(agent_kwargs={"expected_sha256": {"model.safetensors": "a3f1..."}})
Router(agent_kwargs={"fast": True})
expected_sha256 ali fixa os mesmos arquivos em cada checkpoint, que é o que um único
checkpoint residente ou um tokenizer.json compartilhado quer. Ele nunca é descartado por completo pelos
digests do próprio checkpoint: quando um também tem uma entrada, de sha256_digests ou de um
LAYA_SHA256_DIGESTS por checkpoint, os dois mapas são mesclados arquivo por arquivo, então um arquivo
que só um deles nomeia ainda é verificado.
Duas exceções, ambas deliberadas e ambas testadas, porque "mesclado arquivo por arquivo" não é a história toda e a diferença é um controle de cadeia de suprimentos:
- Um
LAYA_SHA256_DIGESTSplano --{artifact: digest}em vez de{model: {...}}-- não é uma camada aqui. Overify_digestso aplica por conta própria, mas apenas quando nada mais fixa (if expected is None), então QUALQUERexpected_sha256que chegue aoAgent, daqui ou de uma entrada de checkpoint, significa que a variável plana não é consultada para aquele carregamento. Verificado em arquivos reais: uma variável plana fixandomodel.safetensorsmais um mapa emagent_kwargsfixandotokenizer.jsoncarrega ummodel.safetensorsadulterado. Use a forma por checkpoint, ou nomeie todos os arquivos que importam em um mapa, se precisar dos dois. Isto não mudou em relação amain. - Uma entrada explícita
{}ouNoneMASCARA o que se aplicaria de outra forma -- é o que "carregar este sem verificação" tem de significar, etest_an_explicit_none_entry_masks_a_flat_environment_mapfixa isso.
E a precedência é por checkpoint sobre o compartilhado, não importa de onde cada um veio, então uma
entrada por checkpoint sintetizada de LAYA_SHA256_DIGESTS vence um expected_sha256
passado aqui no código. Vale dizer com clareza que uma variável de ambiente vence um argumento explícito
em um controle como este; test_an_environment_pin_overrides_the_shared_one_per_checkpoint
é onde isso é fixado.
Para um arquivo que ambos nomeiam, a entrada por checkpoint vence. As duas não são igualmente específicas: o
mapa agent_kwargs alcança todo checkpoint que o Router constrói, e model.safetensors é o único
nome que todo checkpoint usa para um arquivo diferente, então uma entrada compartilhada para ele não pode ser
uma afirmação correta sobre todos ao mesmo tempo. Nada lança por causa dessa sobreposição -- recusá-la
rejeitaria uma fixação compartilhada mais uma sobrescritura por checkpoint, que é a forma comum e que
carregava corretamente antes de tudo isto existir. Se você precisa saber contra qual digest um checkpoint foi
verificado, leia de volta: o mapa entregue a cada Agent é a mesclagem descrita acima.
Tanto agent_kwargs quanto sha256_digests são públicos e mutáveis, e a entrada de um checkpoint é lida
no carregamento e não na construção, então uma fixação atribuída depois -- ou adicionada a uma
entrada existente no lugar -- conta.
Os nomes que o Router define para si mesmo -- model_id_or_path, device, token, subfolder,
revision e os argumentos de hook -- são recusados aqui em vez de serem sombreados em silêncio, e os
nomes restantes são verificados contra Agent.__init__ na construção, então uma opção escrita errado
falha na linha Router(...) em vez de na primeira requisição.
Os digests de artefatos são opt-in e sempre por modelo: sha256_digests={"english": {...}}
passa esse mapa {path relative to the checkpoint dir: hexdigest} ao Agent que
o carrega, então um arquivo de pesos adulterado ou substituído é recusado antes de ser analisado. Não
há um equivalente de revision para todo o Router porque os digests, ao contrário de um commit SHA, não
são compartilháveis: o repositório empacotado traz um model.safetensors separado para cada um de
english, multilingual e typed-decisions, então um único mapa plano só pode corresponder a um
deles. Um modelo listado com None ou {} não adiciona arquivos próprios, o que o carrega
sem verificação a menos que agent_kwargs["expected_sha256"] o fixe; ele ainda mascara um LAYA_SHA256_DIGESTS
plano, que é para o que serve listá-lo assim.
A mesma divisão está disponível para um processo configurado apenas por ambiente: quando
LAYA_SHA256_DIGESTS contém um mapa indexado por modelo ({"english": {...}, "multilingual": {...}})
isto o semeia por checkpoint, então um servidor que mantém vários residentes pode fixar cada um com seus
próprios digests em vez de se recusar a iniciar no segundo. Um LAYA_SHA256_DIGESTS plano
mantém seu significado existente, aplicado por laya.revisions a cada checkpoint que o processo
carrega, o que é correto para um de um único checkpoint. Uma entrada de argumento vence o
ambiente para o modelo que ela nomeia. Uma variável aninhada que nomeia alguns checkpoints e não
outros não diz nada sobre os outros: eles mantêm aquilo com que agent_kwargs["expected_sha256"]
os fixa, porque fixar um checkpoint a partir do ambiente não é um pedido para parar
de verificar o resto.
Os hooks são opt-in e rodam no nível do Router: on_route vê a decisão de roteamento,
on_load / on_evict veem o ciclo de vida do modelo, e on_predict_start / on_predict_end
envolvem toda a chamada de route+infer. Consulte laya.hooks.
Parâmetros
modelsOptional[Dict[str, str]]=NonedeviceOptional[str]=NonetokenOptional[str]=NonerevisionOptional[str]=NonerevisionsOptional[Dict[str, Optional[str]]]=Nonemax_loadedint=2defaultstr="english"auto_task_detectionbool=Falsestandalone_reposbool=Falsepreloadbool=Falselang_guessOptional[Any]=Nonehooks=Noneon_predict_start=Noneon_predict_end=Nonehooks_raisebool=Truehooks_concurrentbool=Truehooks_timeoutOptional[float]=Noneagent_kwargsOptional[Dict[str, Any]]=Nonesha256_digestsOptional[Dict[str, Optional[Dict[str, str]]]]=None
load
load(name: str)Retorna o Agent para name, baixando-o e construindo-o no primeiro uso.
Chamadores concorrentes compartilham um único Agent em vez de construir duplicatas.
Parâmetros
namestr
attach
attach(name: str, agent: Any)Registra um Agent já construído sob name em vez de carregar uma segunda cópia.
Útil quando o processo tem um checkpoint carregado por outros motivos: uma demo que já
construiu convaiinnovations/laya pode entregá-lo ao router em vez de pagar por -- e manter
na memória -- uma duplicata de 421M de parâmetros.
Parâmetros
namestragentAny
preload
preload(names: Optional[List[str]] = None)Baixa e constrói os checkpoints antecipadamente para que nenhuma requisição pague um carregamento de modelo.
Um carregamento a frio custa segundos; a detecção de idioma custa microssegundos. Com cada
checkpoint residente, o roteamento é efetivamente grátis -- que é o que você quer em um
servidor ou uma demo. max_loaded é elevado para caber tanto os checkpoints solicitados quanto
todos os agentes já residentes, então o pré-carregamento incremental não despeja nenhum dos dois.
Parâmetros
namesOptional[List[str]]=None
unload
unload(name: Optional[str] = None)Libera um modelo, ou todos eles.
Parâmetros
nameOptional[str]=None
loaded_revisions
loaded_revisions: Dict[str, Optional[str]]Commit SHA do qual cada agente residente foi carregado (None para caminhos locais).
route
route(
state: Union[str, dict, list, None],
questions: Optional[Dict[str, Any]] = None,
model: Optional[str] = None,
task: Optional[str] = None,
lang: Optional[str] = None,
lang_guess: Optional[Any] = None,
hooks=None,
hooks_raise: Optional[bool] = None,
hooks_timeout: Optional[float] = None,
) -> RouteDecisionDecide qual checkpoint usar e então deixa os hooks on_route observá-lo ou substituí-lo.
ctx.decision é o RouteDecision; um hook pode substituí-lo (por exemplo, para fixar um
checkpoint) e a substituição é o que é retornado e usado. hooks são hooks por chamada,
anexados depois dos que estiverem instalados no Router.
Parâmetros
stateUnion[str, dict, list, None]questionsOptional[Dict[str, Any]]=NonemodelOptional[str]=NonetaskOptional[str]=NonelangOptional[str]=Nonelang_guessOptional[Any]=Nonehooks=Nonehooks_raiseOptional[bool]=Nonehooks_timeoutOptional[float]=None
predict
predict(
state: Union[str, dict, list],
questions: Dict[str, Any],
model: Optional[str] = None,
task: Optional[str] = None,
lang: Optional[str] = None,
lang_guess: Optional[Any] = None,
hooks=None,
on_predict_start=None,
on_predict_end=None,
hooks_raise: Optional[bool] = None,
hooks_timeout: Optional[float] = None,
max_len: Optional[int] = None,
head_max_len: Optional[int] = None,
min_confidence: Optional[float] = None,
) -> Dict[str, Any]Roteia e então responde a cada pergunta em uma passagem direta sobre o checkpoint escolhido.
O resultado é o payload habitual de system_one mais uma chave routing que registra a decisão.
Os hooks on_predict_start / on_predict_end no nível do Router envolvem toda a chamada de route+infer
e veem ctx.decision; consulte laya.hooks. max_len / head_max_len sobrescrevem o orçamento de
tokens do agente para esta chamada (um hook de início pode definir ctx.max_len / ctx.head_max_len).
Parâmetros
stateUnion[str, dict, list]questionsDict[str, Any]modelOptional[str]=NonetaskOptional[str]=NonelangOptional[str]=Nonelang_guessOptional[Any]=Nonehooks=Noneon_predict_start=Noneon_predict_end=Nonehooks_raiseOptional[bool]=Nonehooks_timeoutOptional[float]=Nonemax_lenOptional[int]=Nonehead_max_lenOptional[int]=Nonemin_confidenceOptional[float]=None
predict_long
predict_long(
state: Union[str, dict, list],
questions: Dict[str, Any],
model: Optional[str] = None,
task: Optional[str] = None,
lang: Optional[str] = None,
lang_guess: Optional[Any] = None,
window: Optional[int] = None,
stride: Optional[int] = None,
aggregate: str = "auto",
batch_size: Optional[int] = None,
hooks=None,
on_predict_start=None,
on_predict_end=None,
hooks_raise: Optional[bool] = None,
hooks_timeout: Optional[float] = None,
) -> Dict[str, Any]Roteia e então escaneia cada janela do estado em vez de apenas a primeira.
predict pontua um estado a partir de uma única janela: tudo que passa de max_len é cortado (a
primeira janela, ou para uma lista de conversa a última) e nunca alcança o modelo. Isto
roteia exatamente como predict faz -- as mesmas dicas model/task/lang, os mesmos
hooks no nível do router, a mesma chave routing e usage -- e pontua o estado roteado com
o predict_long daquele agente, que o divide em janelas sobrepostas e agrega por
pergunta. As regras de agregação são as de laya.agent.Agent.predict_long: noul toma a
janela mais forte, choice/score a mais confiante.
Os hooks por chamada (hooks, on_predict_start, on_predict_end, hooks_raise,
hooks_timeout) envolvem todo o route+scan exatamente como envolvem predict: a varredura roda
por último, então vence um hook de início que responde (ctx.skip(...)) ou reescreve o estado.
max_len / head_max_len não são aceitos aqui -- uma janela é dimensionada por window ou pelo
orçamento do checkpoint, e sobrescrever o truncamento de janela única é para o que serve predict_long.
Parâmetros
stateUnion[str, dict, list]questionsDict[str, Any]modelOptional[str]=NonetaskOptional[str]=NonelangOptional[str]=Nonelang_guessOptional[Any]=NonewindowOptional[int]=Nonetokens de estado por janela. O padrão é o orçamento do checkpoint roteado (
max_len - head_max_len - 8), limitado ao espaço que as perguntas deixam para o estado, para que nenhuma janela seja truncada de novo na entrada; uma janela menor isola um trecho localizado.strideOptional[int]=Nonepasso de tokens entre janelas; o padrão é metade da janela efetiva (50% de sobreposição). Um passo além dessa janela é um
ValueError, já que os tokens entre as janelas não alcançariam modelo algum.aggregatestr="auto""auto" (as regras por tipo acima) é o único modo.
batch_sizeOptional[int]=Nonelimite de janelas por passagem direta, para limitar a memória em estados muito longos.
hooks=Noneon_predict_start=Noneon_predict_end=Nonehooks_raiseOptional[bool]=Nonehooks_timeoutOptional[float]=None
Retorna
O payload habitual de predict, com usage["windows"] contando as janelas pontuadas.
Exceções
TypeError: o agente roteado não tem predict_long -- um anexado à mão, já que tanto o
Agent quanto o ONNXAgent o implementam -- então não há com o que escanear.
Sempre lançado, qualquer que seja o hooks_raise, e o mesmo vale para qualquer outro erro que a
própria varredura lance -- nenhum é capturado: a varredura é trabalho deste método, não de um
hook do chamador, então a política de erro de hook não decide se ela pode ser
pulada. Antes ele rodava como um hook de início, onde hooks_raise=False engolia
isto e retornava uma janela pontuada por system_one -- uma pergunta diferente da
que foi feita. Um agente cujo predict_long não tem parâmetro lang é varrido
sem um e avisado, não falhado; isso é uma verificação de assinatura, não um
erro engolido.
decide
decide(
state: Union[str, dict, list],
schema: Any = None,
questions: Optional[Dict[str, Any]] = None,
return_details: bool = False,
min_confidence: Optional[float] = None,
predict_kwargs,
) -> AnyResponde a state contra um schema (JSON schema ou modelo pydantic) e retorna valores tipados.
Consulte laya.structured. Passe exatamente um de schema ou questions; os argumentos de palavra-chave extras
(por exemplo model=, task=, hooks=) são repassados a predict.
Parâmetros
stateUnion[str, dict, list]schemaAny=NonequestionsOptional[Dict[str, Any]]=Nonereturn_detailsbool=Falsemin_confidenceOptional[float]=Nonepredict_kwargs
decide_batch
decide_batch(
states: Sequence[Any],
schema: Any = None,
questions: Optional[Dict[str, Any]] = None,
return_details: bool = False,
min_confidence: Optional[float] = None,
predict_kwargs,
) -> List[Any]Responde a muitos estados contra um schema (JSON schema ou modelo pydantic) em uma única chamada em lote.
A forma de rendimento de :meth:decide: o schema é planejado uma vez e suas perguntas
rodam sobre cada estado através de :meth:predict_batch (passagens diretas agrupadas, resultados na
ordem de entrada), e então as respostas de cada estado são projetadas como decide faz. Os argumentos
de palavra-chave extras (batch_size=, model=, hooks=, ...) são repassados a
predict_batch. Consulte laya.structured.
Parâmetros
statesSequence[Any]schemaAny=NonequestionsOptional[Dict[str, Any]]=Nonereturn_detailsbool=Falsemin_confidenceOptional[float]=Nonepredict_kwargs
route_batch
route_batch(
requests: Sequence[Dict[str, Any]],
hooks_timeout: Optional[float] = None,
hooks=None,
hooks_raise: Optional[bool] = None,
) -> List[RouteDecision]Roteia um lote de requisições heterogêneas sem carregar nenhum checkpoint.
Cada requisição é um mapping com state e questions mais as mesmas sobrescrituras
de roteamento opcionais aceitas por :meth:route: model, task, lang e
lang_guess. As decisões retornadas preservam a ordem de entrada.
Isto é intencionalmente separado da inferência para que os chamadores possam inspecionar ou agregar as decisões de roteamento antes de pagar o custo de carregamento do modelo.
Parâmetros
requestsSequence[Dict[str, Any]]Sequência de dicionários de requisição, cada um exigindo
stateequestions.hooks_timeoutOptional[float]=NoneSobrescreve o
hooks_timeoutdo Router para esta chamada, aplicado ao despachoon_routede cada requisição, como em :meth:route.hooksHookArg=NoneHook por chamada ou sequência de hooks para esta chamada.
hooks_raiseOptional[bool]=NoneSobrescreve a política
hooks_raisedo Router para esta chamada.
predict_batch
predict_batch(
requests: Sequence[Dict[str, Any]],
batch_size: Optional[int] = None,
hooks_timeout: Optional[float] = None,
min_confidence: Optional[float] = None,
sort_by_length: bool = False,
hooks=None,
on_predict_start=None,
on_predict_end=None,
hooks_raise: Optional[bool] = None,
) -> List[Dict[str, Any]]Roteia e executa um lote de requisições heterogêneas com o mínimo de troca de modelo.
As requisições são roteadas primeiro e agrupadas por checkpoint. Dentro de cada checkpoint,
as requisições que compartilham o mesmo schema de perguntas são passadas a
Agent.predict_batch para que seus estados possam compartilhar passagens diretas. Os resultados são
então restaurados à ordem original das requisições.
As requisições podem especificar independentemente model, task, lang,
lang_guess, max_len ou head_max_len e podem usar schemas de perguntas diferentes.
max_len / head_max_len são a forma por requisição da sobrescritura do orçamento de tokens que
predict recebe como argumentos de chamada: eles definem os orçamentos de estado e de cabeça de perguntas
do checkpoint para aquela única requisição, então uma pergunta ampla pode ser feita sem encolher as
outras requisições do lote para a mesma janela. As requisições que pedem orçamentos diferentes são
divididas em passagens diretas separadas, já que uma chamada a Agent.predict_batch carrega um único
orçamento para todos os seus estados. Um hook de início ainda pode substituir qualquer um dos dois valores em ctx.
Os hooks de predição no nível do Router rodam por requisição, como predict os executa: cada requisição
obtém seu próprio PredictContext, então on_predict_start pode substituir o estado,
as perguntas ou o orçamento de tokens daquela requisição, ou fazer ctx.skip(...) nela, e on_predict_end
vê e pode substituir seu resultado. As requisições são agrupadas para a passagem direta depois
que seus hooks de início rodaram, e as requisições de um grupo de checkpoint terminam na ordem inversa à
que começaram. Se um grupo de checkpoint falha, toda requisição dele cujo hook de início
rodou falha com a exceção, inclusive uma que acertou o cache: cada uma recebe on_error e então
on_predict_end antes que a exceção se propague.
Parâmetros
requestsSequence[Dict[str, Any]]Sequência de dicionários de requisição. Cada item exige
stateequestionse pode incluir as sobrescrituras de roteamentomodel,task,langoulang_guesse as sobrescrituras do orçamento de tokensmax_len/head_max_len.batch_sizeOptional[int]=NoneNúmero máximo opcional de estados por lote de passagem direta do Agent.
hooks_timeoutOptional[float]=NoneSobrescreve o
hooks_timeoutdo Router para esta chamada.min_confidenceOptional[float]=NoneFloat opcional ou mapeamento por bucket para o gating de confiança.
sort_by_lengthbool=FalseRepassado a cada chamada a
Agent.predict_batch, então cada grupo de perguntas preenche até um máximo mais curto; consulteAgent.predict_batch. Os resultados mantêm a ordem de entrada em qualquer caso. É descartado em silêncio para um agente anexado cujopredict_batché anterior a esta opção (#294).hooksHookArg=NoneHook por chamada ou sequência de hooks para esta chamada.
on_predict_startPredictHookArg=NoneCallable simples ou sequência de callables para eventos de início.
on_predict_endPredictHookArg=NoneCallable simples ou sequência de callables para eventos de fim.
hooks_raiseOptional[bool]=NoneSobrescreve a política
hooks_raisedo Router para esta chamada.
Retorna
Um resultado normal de predição do Router por requisição, na mesma ordem da entrada.
RouteDecision
RouteDecision()Classes base: dict
O resultado do roteamento: qual modelo, por quê e o que foi detectado.
Se comporta como um dict, então é serializado diretamente em uma resposta de API.
DEFAULT_MODELS
DEFAULT_MODELS = {
"english": (BUNDLE_REPO, None),
"multilingual": (BUNDLE_REPO, "multilingual"),
"typed-decisions": (BUNDLE_REPO, "typed-decisions"),
}