Documentação

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_DIGESTS plano -- {artifact: digest} em vez de {model: {...}} -- não é uma camada aqui. O verify_digests aplica-o ele próprio, mas apenas quando nada mais fixa (if expected is None), pelo que QUALQUER expected_sha256 que chegue ao Agent, 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 fixa model.safetensors mais um mapa em agent_kwargs que fixa tokenizer.json carrega um model.safetensors adulterado. 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 a main.
  • Uma entrada explícita {} ou None MASCARA o que se aplicaria de outra forma -- é o que "carregar este sem verificação" tem de significar, e test_an_explicit_none_entry_masks_a_flat_environment_map fixa 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]]= None
deviceOptional[str]= None
tokenOptional[str]= None
revisionOptional[str]= None
revisionsOptional[Dict[str, Optional[str]]]= None
max_loadedint= 2
defaultstr= "english"
auto_task_detectionbool= False
standalone_reposbool= False
preloadbool= False
lang_guessOptional[Any]= None
hooks= None
on_predict_start= None
on_predict_end= None
hooks_raisebool= True
hooks_concurrentbool= True
hooks_timeoutOptional[float]= None
agent_kwargsOptional[Dict[str, Any]]= None
sha256_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

namestr
agentAny

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,
) -> RouteDecision

Decide 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]]= None
modelOptional[str]= None
taskOptional[str]= None
langOptional[str]= None
lang_guessOptional[Any]= None
hooks= None
hooks_raiseOptional[bool]= None
hooks_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]= None
taskOptional[str]= None
langOptional[str]= None
lang_guessOptional[Any]= None
hooks= None
on_predict_start= None
on_predict_end= None
hooks_raiseOptional[bool]= None
hooks_timeoutOptional[float]= None
max_lenOptional[int]= None
head_max_lenOptional[int]= None
min_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]= None
taskOptional[str]= None
langOptional[str]= None
lang_guessOptional[Any]= None
windowOptional[int]= None

tokens 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]= None

passo 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]= None

limite de janelas por passagem, para limitar a memória em estados muito longos.

hooks= None
on_predict_start= None
on_predict_end= None
hooks_raiseOptional[bool]= None
hooks_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,
) -> Any

Responde 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= None
questionsOptional[Dict[str, Any]]= None
return_detailsbool= False
min_confidenceOptional[float]= None
predict_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= None
questionsOptional[Dict[str, Any]]= None
return_detailsbool= False
min_confidenceOptional[float]= None
predict_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 state e questions.

hooks_timeoutOptional[float]= None

Sobrepõe o hooks_timeout do Router para esta chamada, aplicado ao despacho on_route de cada pedido, como em :meth:route.

hooksHookArg= None

Hook por chamada ou sequência de hooks para esta chamada.

hooks_raiseOptional[bool]= None

Sobrepõe a política hooks_raise do 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 state e questions e pode incluir as sobreposições de encaminhamento model, task, lang ou lang_guess e as sobreposições do orçamento de tokens max_len / head_max_len.

batch_sizeOptional[int]= None

Número máximo opcional de estados por lote de passagem do Agent.

hooks_timeoutOptional[float]= None

Sobrepõe o hooks_timeout do Router para esta chamada.

min_confidenceOptional[float]= None

Float opcional ou mapeamento por cubo para o gating de confiança.

sort_by_lengthbool= False

Reencaminhado para cada chamada a Agent.predict_batch, pelo que cada grupo de perguntas preenche até um máximo mais curto; consulta Agent.predict_batch. Os resultados mantêm a ordem de entrada de qualquer forma. É descartado em silêncio para um agent anexado cujo predict_batch é anterior a esta opção (#294).

hooksHookArg= None

Hook por chamada ou sequência de hooks para esta chamada.

on_predict_startPredictHookArg= None

Callable simples ou sequência de callables para eventos de início.

on_predict_endPredictHookArg= None

Callable simples ou sequência de callables para eventos de fim.

hooks_raiseOptional[bool]= None

Sobrepõe a política hooks_raise do 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"),
}