Router
laya.Router deteta o idioma de cada estado e envia o pedido para o checkpoint
correspondente, carregando os checkpoints na primeira utilização.
Os nomes, tipos, valores predefinidos e código mantêm-se em inglês; o resto é traduzido (as entradas ainda não traduzidas são mostradas 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 da Laya de forma preguiçosa e envia cada pedido para o 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 transferidos 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 parâmetros.
O valor predefinido é 2, porque o encaminhamento automático só escolhe entre english e
multilingual: um limite de um reconstrói o checkpoint que acabou de despejar em cada mudança de idioma,
o que são segundos por pedido exatamente no tráfego para o qual o Router existe. O tráfego que só
vê um idioma nunca constrói o segundo checkpoint, pelo que o valor predefinido não lhe custa nada.
Baixa-o para 1 num anfitrião com memória limitada, e sobe-o para 3 (ou pré-carrega) 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é-carrega em vez disso: um carregamento a frio custa segundos, enquanto a deteção custa microssegundos, pelo que mesmo o valor predefinido 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 opcionais. revision aplica um commit a todos os modelos;
revisions={"english": "...", "multilingual": "..."} sobrepõe-se a isso por modelo,
o que é útil quando repositórios autónomos foram revistos em commits diferentes.
Sem nenhum dos dois, usam-se o valor predefinido normal do huggingface_hub e a cache offline existente.
Uma entrada de revisions que é None ou em branco significa "sem sobreposição para este modelo", pelo que 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 a quem chama a fixação que pediu. Nada em
revisions pode desfixar um modelo enquanto revision fixa o resto; deixa revision não definido e
nomeia os modelos que queres fixar.
Um revision em branco é lido da mesma forma, o que é uma mudança deliberada no que o Router
transmite: Router(revision=" ") costumava chegar a resolve_revision, onde uma cadeia
verdadeira mas em branco suprimia o fallback de LAYA_REVISION e deixava o valor predefinido do huggingface_hub, e agora é
descartado antes de lá chegar, pelo que um Router configurado com espaços em branco comporta-se como um
configurado com nada e $LAYA_REVISION aplica-se. É 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 ganha a um expected_sha256
passado por agent_kwargs; consulta a docstring da classe.
Qualquer outra coisa que laya.Agent aceite é acessível através de agent_kwargs, que é fundido 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 ficheiros em cada checkpoint, que é o que um único
checkpoint residente ou um tokenizer.json partilhado quer. 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 fundidos ficheiro a ficheiro, pelo que um ficheiro
que só um deles nomeia ainda é verificado.
Duas exceções, ambas deliberadas e ambas testadas, porque "fundido ficheiro a ficheiro" não é a história toda e a diferença é um controlo da cadeia de abastecimento:
- Um
LAYA_SHA256_DIGESTSplano --{artifact: digest}em vez de{model: {...}}-- não é uma camada aqui. Overify_digestsaplica-o ele próprio, mas apenas quando nada mais fixa (if expected is None), pelo que QUALQUERexpected_sha256que chegue aoAgent, daqui ou de uma entrada de checkpoint, significa que a variável plana não é consultada para esse carregamento. Verificado em ficheiros reais: uma variável plana que fixamodel.safetensorsmais um mapa emagent_kwargsque fixatokenizer.jsoncarrega ummodel.safetensorsadulterado. Usa a forma por checkpoint, ou nomeia todos os ficheiros que te importam num mapa, se precisares 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 partilhado, independentemente de onde cada um veio, pelo que uma
entrada por checkpoint sintetizada de LAYA_SHA256_DIGESTS ganha a um expected_sha256
passado aqui no código. Vale a pena dizer claramente que uma variável de ambiente ganha a um argumento explícito
num controlo como este; test_an_environment_pin_overrides_the_shared_one_per_checkpoint
é onde isso é fixado.
Para um ficheiro que ambos nomeiam, a entrada por checkpoint ganha. As duas não são igualmente específicas: o
mapa agent_kwargs alcança todos os checkpoints que o Router constrói, e model.safetensors é o único
nome que todos os checkpoints usam para um ficheiro diferente, pelo que uma entrada partilhada 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 partilhada mais uma sobreposição por checkpoint, que é a forma comum e que
carregava corretamente antes de tudo isto existir. Se precisas de saber contra que digest um checkpoint foi
verificado, lê-o de volta: o mapa entregue a cada Agent é a fusão descrita acima.
Tanto agent_kwargs como sha256_digests são públicos e mutáveis, e a entrada de um checkpoint é lida
no carregamento e não na construção, pelo que uma fixação atribuída depois -- ou adicionada a uma
entrada existente no lugar -- conta.
Os nomes que o Router define para si próprio -- 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, pelo que uma opção mal escrita
falha na linha Router(...) em vez de no primeiro pedido.
Os digests dos artefactos são opcionais e sempre por modelo: sha256_digests={"english": {...}}
passa esse mapa {path relative to the checkpoint dir: hexdigest} ao Agent que
o carrega, pelo que um ficheiro 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 partilháveis: o repositório empacotado traz um model.safetensors separado para cada um de
english, multilingual e typed-decisions, pelo que um único mapa plano só pode corresponder a um
deles. Um modelo listado com None ou {} não adiciona ficheiros próprios, o que o carrega
sem verificação a menos que agent_kwargs["expected_sha256"] o fixe; 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 semeia-o por checkpoint, pelo que um servidor que mantém vários residentes pode fixar cada um com os seus
próprios digests em vez de se recusar a arrancar no segundo. Um LAYA_SHA256_DIGESTS plano
mantém o seu significado existente, aplicado por laya.revisions a cada checkpoint que o processo
carrega, o que é correto para um de um só checkpoint. Uma entrada de argumento ganha sobre o
ambiente para o modelo que nomeia. Uma variável aninhada que nomeia alguns checkpoints e não
outros não diz nada sobre os outros: 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 opcionais e correm ao nível do Router: on_route vê a decisão de encaminhamento,
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. Consulta 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)Devolve o Agent para name, transferindo-o e construindo-o no primeiro uso.
Os chamadores concorrentes partilham um único Agent em vez de construírem duplicados.
Parâmetros
namestr
attach
attach(name: str, agent: Any)Regista 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
em memória -- um duplicado de 421M parâmetros.
Parâmetros
namestragentAny
preload
preload(names: Optional[List[str]] = None)Transfere e constrói os checkpoints antecipadamente para que nenhum pedido pague um carregamento de modelo.
Um carregamento a frio custa segundos; a deteção de idioma custa microssegundos. Com cada
checkpoint residente, o encaminhamento é efetivamente gratuito -- que é o que queres num
servidor ou numa demo. max_loaded é elevado para acomodar tanto os checkpoints pedidos como
todos os agents já residentes, pelo que a pré-carga incremental não despeja nenhum dos dois.
Parâmetros
namesOptional[List[str]]=None
unload
unload(name: Optional[str] = None)Liberta um modelo, ou todos eles.
Parâmetros
nameOptional[str]=None
loaded_revisions
loaded_revisions: Dict[str, Optional[str]]Commit SHA a partir do qual cada agent 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 o checkpoint a usar e depois 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 é devolvido e usado. hooks são hooks por chamada,
acrescentados depois dos que estejam 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]Encaminha e depois responde a cada pergunta numa única passagem sobre o checkpoint escolhido.
O resultado é a carga habitual de system_one mais uma chave routing que regista a decisão.
Os hooks on_predict_start / on_predict_end ao nível do Router envolvem toda a chamada de route+infer
e veem ctx.decision; consulta laya.hooks. max_len / head_max_len sobrepõem-se ao orçamento
de tokens do agent 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]Encaminha e depois analisa cada janela do estado em vez de apenas a primeira.
predict pontua um estado a partir de uma única janela: tudo o que passa de max_len é cortado (a
primeira janela, ou para uma lista de conversa a última) e nunca chega ao modelo. Isto
encaminha exatamente como predict o faz -- as mesmas pistas model/task/lang, os mesmos
hooks ao nível do router, a mesma chave routing e usage -- e pontua o estado encaminhado com
o predict_long desse agent, 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 análise corre
por último, pelo que ganha um hook de início que responde (ctx.skip(...)) ou reescreve o estado.
max_len / head_max_len não são aceites aqui -- uma janela é dimensionada por window ou pelo
orçamento do checkpoint, e sobrepor-se ao truncamento de uma única janela é para isso 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. Por predefinição é o orçamento do checkpoint encaminhado (
max_len - head_max_len - 8), limitado ao espaço que as perguntas deixam para o estado, para que nenhuma janela seja truncada outra vez à entrada; uma janela mais pequena isola um troço localizado.strideOptional[int]=Nonepasso de tokens entre janelas; por predefinição é metade da janela efetiva (50% de sobreposição). Um passo além dessa janela é um
ValueError, uma vez que os tokens entre as janelas não chegariam a modelo nenhum.aggregatestr="auto""auto" (as regras por tipo acima) é o único modo.
batch_sizeOptional[int]=Nonelimite de janelas por passagem, para limitar a memória em estados muito longos.
hooks=Noneon_predict_start=Noneon_predict_end=Nonehooks_raiseOptional[bool]=Nonehooks_timeoutOptional[float]=None
Retorna
A carga habitual de predict, com usage["windows"] a contar as janelas pontuadas.
Exceções
TypeError: o agent encaminhado não tem predict_long -- um anexado à mão, uma vez que tanto o
Agent como o ONNXAgent o implementam -- pelo que não há nada com que analisar.
Lançado sempre, seja qual for o hooks_raise, e o mesmo para qualquer outro erro que a
própria análise lance -- nenhum é capturado: a análise é trabalho deste método, não de um
hook de quem chama, pelo que a política de erro de hook não decide se pode ser
ignorada. Antes corria como um hook de início, onde hooks_raise=False engolia
isto e devolvia uma janela pontuada por system_one -- uma pergunta diferente da
que foi feita. Um agent cujo predict_long não tem parâmetro lang é analisado
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 devolve valores tipados.
Consulta laya.structured. Passa exatamente um de schema ou questions; os argumentos de palavra-chave adicionais
(por exemplo model=, task=, hooks=) são reencaminhados para 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) numa única chamada em lote.
A variante de elevado débito de :meth:decide: o schema é planeado uma vez e as suas perguntas
correm sobre cada estado através de :meth:predict_batch (passagens agrupadas, resultados por
ordem de entrada), e depois as respostas de cada estado são projetadas como decide o faz. Os argumentos de
palavra-chave adicionais (batch_size=, model=, hooks=, ...) são reencaminhados para
predict_batch. Consulta 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]Encaminha um lote de pedidos heterogéneos sem carregar nenhum checkpoint.
Cada pedido é um mapping com state e questions mais as mesmas sobreposições
de encaminhamento opcionais aceites por :meth:route: model, task, lang e
lang_guess. As decisões devolvidas preservam a ordem de entrada.
Isto está separado da inferência de propósito, para que os chamadores possam inspecionar ou agregar as decisões de encaminhamento antes de pagar o custo de carregamento do modelo.
Parâmetros
requestsSequence[Dict[str, Any]]Sequência de dicionários de pedido, cada um a exigir
stateequestions.hooks_timeoutOptional[float]=NoneSobrepõe o
hooks_timeoutdo Router para esta chamada, aplicado ao despachoon_routede cada pedido, como em :meth:route.hooksHookArg=NoneHook por chamada ou sequência de hooks para esta chamada.
hooks_raiseOptional[bool]=NoneSobrepõe 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]]Encaminha e executa um lote de pedidos heterogéneos com o mínimo de troca de modelo.
Os pedidos são encaminhados primeiro e agrupados por checkpoint. Dentro de cada checkpoint,
os pedidos que partilham o mesmo schema de perguntas são passados a
Agent.predict_batch para que os seus estados possam partilhar passagens. Os resultados são
depois restaurados à ordem original dos pedidos.
Os pedidos 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 pedido da sobreposição do orçamento de tokens que
predict toma como argumentos de chamada: definem os orçamentos de estado e de cabeça de perguntas
do checkpoint para esse único pedido, de modo que se pode fazer uma pergunta ampla sem encolher os
outros pedidos do lote para a mesma janela. Os pedidos que pedem orçamentos diferentes são
divididos em passagens separadas, uma vez que uma chamada a Agent.predict_batch transporta um só
orçamento para todos os seus estados. Um hook de início ainda pode substituir qualquer dos valores em ctx.
Os hooks de previsão ao nível do Router correm por pedido, como predict os corre: cada pedido
obtém o seu próprio PredictContext, pelo que on_predict_start pode substituir o estado,
as perguntas ou o orçamento de tokens desse pedido, ou fazer ctx.skip(...), e on_predict_end
vê e pode substituir o seu resultado. Os pedidos são agrupados para a passagem depois de
os seus hooks de início correrem, e os pedidos de um grupo de checkpoint terminam em ordem inversa à
que começaram. Se um grupo de checkpoint falhar, todos os pedidos dele cujo hook de início
correu falham com a exceção, incluindo um que tenha acertado na cache: cada um recebe on_error e depois
on_predict_end antes de a exceção se propagar.
Parâmetros
requestsSequence[Dict[str, Any]]Sequência de dicionários de pedido. Cada item exige
stateequestionse pode incluir as sobreposições de encaminhamentomodel,task,langoulang_guesse as sobreposições do orçamento de tokensmax_len/head_max_len.batch_sizeOptional[int]=NoneNúmero máximo opcional de estados por lote de passagem do Agent.
hooks_timeoutOptional[float]=NoneSobrepõe o
hooks_timeoutdo Router para esta chamada.min_confidenceOptional[float]=NoneFloat opcional ou mapeamento por cubo para o gating de confiança.
sort_by_lengthbool=FalseReencaminhado para cada chamada a
Agent.predict_batch, pelo que cada grupo de perguntas preenche até um máximo mais curto; consultaAgent.predict_batch. Os resultados mantêm a ordem de entrada de qualquer forma. É descartado em silêncio para um agent 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]=NoneSobrepõe a política
hooks_raisedo Router para esta chamada.
Retorna
Um resultado normal de previsão do Router por pedido, na mesma ordem da entrada.
RouteDecision
RouteDecision()Classes base: dict
O resultado do encaminhamento: que modelo, porquê e o que foi detetado.
Comporta-se como um dict, pelo que se serializa diretamente numa resposta de API.
DEFAULT_MODELS
DEFAULT_MODELS = {
"english": (BUNDLE_REPO, None),
"multilingual": (BUNDLE_REPO, "multilingual"),
"typed-decisions": (BUNDLE_REPO, "typed-decisions"),
}