Agent
Agent
laya.Agent 加载一个 checkpoint,回答关于某个状态的类型化问题。laya.load 是 Agent(...)
的快捷方式,laya.RLAgent 是 Agent 的别名。ONNXAgent 在 CPU 上运行导出的 ONNX 模型;
从 laya.onnx_agent 导入它。
名称、类型、默认值与代码保持英文;其余为译文(尚未翻译的条目暂显示英文原文)。
Agent
Agent(
model_id_or_path: str = "convaiinnovations/laya",
device: Optional[str] = None,
token: Optional[str] = None,
subfolder: Optional[str] = None,
fast: bool = False,
compile: bool = False,
revision: Optional[str] = None,
expected_sha256: Optional[Dict[str, str]] = None,
lang_temperatures: Optional[Dict[str, Dict[str, 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,
calibration: Optional[str] = None,
)基类: HookRegistry
System 1 决策模型运行时:快速、非自回归、经过校准的决策。
dtype 是自动转换的目标类型,不是每次调用的精度。在 MPS 上,只有行数达到 mps_amp_min_rows 时调用才会自动转换,所以 dtype 可以是 float16,而某次调用实际以 float32 运行。dtype_for(rows) 返回行数为 rows 的调用所用的精度。
加载一个 Laya checkpoint。
revision 可选地把 Hub 下载固定到某个明确的 commit SHA/分支/tag;不给时,用 huggingface_hub 的常规默认值和已有的离线缓存。expected_sha256({相对 checkpoint 目录的路径: 十六进制摘要})在任何权重被解析或执行之前校验产物完整性;它是可选的,对本地目录同样生效。产物缺失会抛 FileNotFoundError,摘要不匹配会抛 ValueError;两者都会拒绝这次加载。
fast=True 把编码器/决策头的前向换成 TileLang 快速路径(仅 CUDA,需要 pip install laya[fast]);见 Agent.accelerate。
compile=True 让模型跑在 torch.compile 下,并打开 ModernBERT 编码器的 reference_compile。torch.compile 会按输入形状特化,而 Laya 几乎每个请求都会遇到新形状,所以那些图通常是入不敷出;流量重复时才用它。fast=True 优先,因为 TileLang 路径替换掉的正是将要被编译的那个前向。
subfolder 从捆绑了多个 checkpoint 的仓库里挑一个,例如 Agent("convaiinnovations/laya", subfolder="multilingual")。只会下载那个子目录,所以捆绑不会让每个用户都付出整个家族的代价。
calibration 是可选的 JSON 路径,含 temperature 与 temperature_by_options。它在 checkpoint 配置之后应用,因此拟合出来的映射可以覆盖随包发布的标量,而不必重写 model.safetensors。
hooks / on_predict_start / on_predict_end 观察或塑造每一次预测;见 laya.hooks。hooks_raise=False 时钩子失败只警告并继续,hooks_concurrent=False 会把不适合并行运行的钩子串行化,hooks_timeout 以秒为单位限制每次钩子调用(None 表示不限制)。
参数
model_id_or_pathstr="convaiinnovations/laya"deviceOptional[str]=NonetokenOptional[str]=NonesubfolderOptional[str]=Nonefastbool=Falsecompilebool=FalserevisionOptional[str]=Noneexpected_sha256Optional[Dict[str, str]]=Nonelang_temperaturesOptional[Dict[str, Dict[str, Any]]]=Nonehooks=Noneon_predict_start=Noneon_predict_end=Nonehooks_raisebool=Truehooks_concurrentbool=Truehooks_timeoutOptional[float]=NonecalibrationOptional[str]=None
accelerate
accelerate(use_graphs: bool = True, strict: bool = False)把模型的前向换成 TileLang 快速路径(融合的 GEMM/GEGLU/LayerNorm/RoPE 内核、滑窗 flash attention、16 位常驻权重、按形状桶构建的 CUDA graph)。
快速路径按调用当时 agent 的自动转换 dtype 运行(bf16 或 fp16),所以它与被它替换掉的原始前向在舍入误差内一致(见 benchmarks/parity_fast.py)。改过 agent.dtype 之后,先调用 deaccelerate() 再调用 accelerate() 来重建它。启用成功返回 True。strict=False 时任何失败(没有 CUDA、缺 tilelang)都会保留原始路径。
参数
use_graphsbool=Truestrictbool=False
warmup
warmup(shapes=None) -> float立刻用每种形状的合成输入跑一遍前向,返回花掉的秒数。
compile=True 会在第一个需要 graph 的请求上做追踪与编译(在 GPU 上是几十秒),而 fast=True 会在首次使用时按形状桶构建它的内核与 CUDA graph。在加载之后、开始服务之前调用它,就能把这份代价从最初的几个请求里挪走。用原始前向时,这只是几次普通的前向传播。shapes 是 (rows, tokens, markers) 的列表;tokens 会被限制在 agent 的 max_len 以内。不会向任何调用方返回或记录任何东西,钩子也不会运行。
参数
shapes=None
deaccelerate
deaccelerate()恢复原始前向。
dtype_for
dtype_for(rows: int) -> torch.dtype行数为 rows 个问题行的一次前向所用的精度。
dtype 是自动转换的目标类型,在加载时设定一次。一次前向是否做自动转换是按调用决定的:在 MPS 上只有行数达到 mps_amp_min_rows 才会。行数为 rows 的前向会做自动转换时返回 dtype,否则返回 torch.float32。一次 predict 调用每个问题占一行。
参数
rowsint
predict_batch
predict_batch(
states: List[Union[str, dict, list]],
questions: Dict[str, Dict[str, Any]],
batch_size: Optional[int] = None,
lang: Optional[str] = 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,
sort_by_length: bool = False,
min_confidence: Optional[float] = None,
) -> List[Dict[str, Any]]对多个状态评估同一组问题,把它们打包进共享的前向传播。
这是吞吐路径。system_one/predict 每次前向只处理一个状态;在 GPU 上那会让批次维度大部分空着。predict_batch 把多个状态的问题行归并进同一个张量,于是一次本来要 N 次串行前向的调用只需一次(或 ceil(len(states) / batch_size) 次),在 GPU 上每次决策快好几倍。
参数
statesList[Union[str, dict, list]]状态列表(每一项是文本字符串、JSON 字典或对话轮次列表)。同一组
questions会对照每一个状态评估。questionsDict[str, Dict[str, Any]]问题定义,与
system_one接受的完全一致。batch_sizeOptional[int]=None每次前向传播中状态数的可选上限。
None表示一次全发;批量处理很多或很长的状态时,设上它可以给峰值内存封顶。langOptional[str]=NonehooksHookArg=None每次调用的钩子,追加在 Agent 上已安装的钩子之后。见
laya.hooks。on_predict_startPredictHookArg=None每次调用的起始钩子。它可以改写状态/问题,或调用
ctx.skip(...)短路推理。on_predict_endPredictHookArg=None每次调用的结束钩子。它可以改写结果。
hooks_raiseOptional[bool]=None覆盖本次调用中 Agent 的
hooks_raise。hooks_timeoutOptional[float]=None覆盖本次调用中 Agent 的
hooks_timeout。max_lenOptional[int]=None覆盖本次调用中 agent 配置的
max_len。起始钩子也可以设置ctx.max_len来塑造 token 预算。head_max_lenOptional[int]=None覆盖本次调用中 agent 配置的
head_max_len。起始钩子也可以设置ctx.head_max_len。sort_by_lengthbool=False把编码后长度相近的状态按「八个批次」为一组归到一起,以减少 padding。需要显式给出大于 1、且小于状态数的
batch_size;否则没有任何效果。结果保持输入顺序。这样会缓存最多八个批次的已分词状态,而不是一个。改变批次形状可能轻微改变浮点预测结果。min_confidenceOptional[float]=None
返回值
每个状态一个结果字典的列表,形状与 system_one 的输出完全相同,并按下标与 states 对齐。
predict_long
predict_long(
state: Union[str, dict, list],
questions: Dict[str, Dict[str, Any]],
window: Optional[int] = None,
stride: Optional[int] = None,
aggregate: str = "auto",
batch_size: Optional[int] = None,
lang: Optional[str] = None,
hooks=None,
on_predict_start=None,
on_predict_end=None,
hooks_raise: Optional[bool] = None,
hooks_timeout: Optional[float] = None,
) -> Dict[str, Any]对超出上下文窗口的状态评估问题:用互相重叠的窗口扫描它,并按问题聚合。
system_one/predict 会把超出 max_len 的状态截断到一个窗口(第一个;对话列表则取最后一个),其余部分被静默丢弃。predict_long 只把状态分词一次,切成互相重叠的 token 窗口,在共享的前向传播里给每个窗口打分(经由 predict_batch),再把各窗口的答案合并起来:
- noul -> P(true) 取各窗口的最大值(只要有一个窗口支持,该陈述就成立)
- choice-> 取单个最自信窗口的答案,这样局部信号不会被长文档里占绝大多数的中性窗口投票压过去 (取平均会把它淹没 —— 中性多数说了算)
- score -> 同样取最自信窗口的档位
返回的概率/置信度是作出决定的那个窗口的,不是针对整篇文档校准过的数字:没有任何信号时,noul 在多窗口上取最大值也会随窗口数往上漂;而当文档里没有任何决定性的内容时,choice 可能落在一个自信地中性的窗口上。因此每个答案都带着 answer["window"] —— 作出决定的窗口的 index、在分词后状态中的 token_start/token_end,以及窗口总数 count —— 这样调用方可以查看答案来自哪一段,而不是盲信那个原始数字。
已经装得进一个窗口的状态会直接交给 system_one(输出完全相同)。
钩子包住的是「为该状态作答的那次推理」——对一个需要多个窗口的文档来说,就是那次统一的、覆盖所有窗口的 predict_batch:on_predict_start 只触发一次,而 ctx.states 里按扫描顺序放着解码后的窗口文本 —— 不是调用方传入的 state,后者已被分词用以产生这些窗口。根据这条链最后留下什么,有三种结果:
ctx.skip([result])直接为文档作答:载荷回来时没有窗口归属信息,usage["windows"]为 0,因为什么都没打分- 保持本方法构建出来的扫描:每个窗口都被打分,每个答案都带
answer["window"],usage["windows"]就是窗口数 - 被改写过的扫描(
ctx.states以任何方式被替换):答案按实际打过分的那些状态聚合,但没有任何答案带answer["window"]—— 上面那些偏移描述的是本方法的窗口,不是模型读到的文本
参数
stateUnion[str, dict, list]questionsDict[str, Dict[str, Any]]windowOptional[int]=None每个窗口容纳的状态 token 数。默认取按问题计的状态预算(
max_len - head_max_len - 8)—— 也就是每个问题都放得下的最大值。窗口更小能更好地隔离局部信号(一段很短的决定性文本在它所在窗口里占比更大,那个窗口就能清楚地把它分类出来),代价是窗口数更多;默认的大窗口偏向上下文与吞吐。noul对此不敏感;而当决定性的一段只占一份长文档很小的一部分、其余都是中性内容时,choice/score会受益于更小的窗口。strideOptional[int]=None窗口之间的 token 步长。默认是
window // 2(50% 重叠),这样靠近边界的片段仍然能完整落进某个窗口。aggregatestr="auto""auto"(即上面那套按类型的规则)是目前唯一的模式。
batch_sizeOptional[int]=None每次前向传播的窗口数上限,用来给超长状态的内存用量封顶。
langOptional[str]=None按语言选择温度,与
system_one一致。hooksHookArg=None每次调用的钩子,追加在 Agent 上已安装的钩子之后。见
laya.hooks。on_predict_startPredictHookArg=None每次调用的起始钩子,与
system_one一致。on_predict_endPredictHookArg=None每次调用的结束钩子,与
system_one一致。hooks_raiseOptional[bool]=None覆盖本次调用中 Agent 的
hooks_raise。hooks_timeoutOptional[float]=None覆盖本次调用中 Agent 的
hooks_timeout。
返回单个结果字典,形状与 system_one 相同,并加上 usage["windows"]。这个键始终存在,计的是模型为得出答案而打分的窗口数:装得进一个窗口的状态是 1;用 N 个重叠窗口扫描的文档是 N(起始钩子改写后就是它改写成的那个 N);起始钩子直接为文档作答、或者在任何窗口被读取之前就没有留下要打分的状态时是 0 —— 两条路径都是如此,所以缓存下来的答案永远不会被读成「模型读过的窗口」。
跨多个窗口时,截断相关的键与其它 usage 字段一样合并:truncated、state_tokens 与 state_tokens_dropped 求和(因此 truncated 是被截断的窗口数,而 token 计数里包含重叠部分),truncated_questions 则是最后一个窗口的列表。两者可以不一致:只有靠前的某个窗口被截断时,truncated 大于 0 而 truncated_questions 是空的。当某个窗口大于该问题决策头留出的空间时,它就被截断 —— 这来自高于默认值的 window,或来自收窄了 max_len / head_max_len 的起始钩子。这里要判断的是 usage["truncated"] > 0,而不是 is True。
system_one
system_one(
state: Union[str, dict, list],
questions: Dict[str, Dict[str, Any]],
lang: Optional[str] = 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]在一次并行的前向传播里,对状态评估一组类型化问题。
参数
stateUnion[str, dict, list]文本字符串、JSON 字典或对话轮次列表。
questionsDict[str, Dict[str, Any]]把 question_id 映射到问题定义的字典。
- choice: {"type": "choice", "instructions": "...", "criteria": {"optA": "...", ...}}
- score: {"type": "score", "instructions": "...", "criteria": ["lvl0", "lvl1", ...]}
- noul: {"type": "noul", "instructions": "...", "criteria": {"false": "...", "true": "..."}, "labels": {"false": "B", "true": "A"}}
Noul 的 criteria 与 labels 都是可选的。labels 只控制展示给模型的文字;它们的键仍然保持 false/true 的语义,返回的
noul值永远表示 P(true)。为兼容起见,labels 默认为 false/true。langOptional[str]=Nonehooks=Noneon_predict_start=Noneon_predict_end=Nonehooks_raiseOptional[bool]=Nonehooks_timeoutOptional[float]=Nonemax_lenOptional[int]=Nonehead_max_lenOptional[int]=Nonemin_confidenceOptional[float]=None
返回值
含答案、概率、校准后的置信度与 token 用量的字典。问题为空时返回空答案与零 token 用量,不做分词也不做模型前向。
当决策头预算让两个选项落在同一段 token 上时,usage 会为碰巧如此的每个问题带一个 options 条目 —— total、distinct 与 tokens_per_option —— 因为在 58 段可区分的跨度里只挑得出 42 个时,这个天花板是预算造成的,不是模型造成的。选项全部存活的问题不会出现,所以什么都没被压掉的请求与原来完全一样。
usage 还会报告状态是否装得下:truncated、state_tokens、state_tokens_dropped,以及 truncated_questions(决策头留下的空间太少的那几个问题)。关心答案是否看到了整个状态的调用方,应该读 usage["truncated"],而不是拿自己发出去的内容长度去估算。
要一次性给很多状态打分,见 predict_batch,它让这些状态共用前向传播。
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把 state 对照一个 schema(JSON schema 或 pydantic 模型)作答,返回类型化的值。
见 laya.structured。schema 与 questions 只能给一个;额外的关键字参数会透传给 predict / system_one。
参数
stateUnion[str, dict, list]schemaAny=NonequestionsOptional[Dict[str, Any]]=Nonereturn_detailsbool=Falsemin_confidenceOptional[float]=Nonepredict_kwargs
decide_batch
decide_batch(
states: List[Union[str, dict, list]],
schema: Any = None,
questions: Optional[Dict[str, Any]] = None,
return_details: bool = False,
min_confidence: Optional[float] = None,
predict_kwargs,
) -> List[Any]一次性把多个状态对照同一个 schema(JSON schema 或 pydantic 模型)作答。
这是 :meth:decide 的吞吐版本:schema 只规划一次,它的问题通过 :meth:predict_batch 跑遍每一个状态(共享的前向传播,结果保持输入顺序),然后像 decide 那样把每个状态的答案投影出来。额外的关键字参数(batch_size=、lang=、hooks= 等)会透传给 predict_batch。见 laya.structured。
参数
statesList[Union[str, dict, list]]schemaAny=NonequestionsOptional[Dict[str, Any]]=Nonereturn_detailsbool=Falsemin_confidenceOptional[float]=Nonepredict_kwargs
fit_temperatures
fit_temperatures(records, compute_ece: bool = False, seed: int = 0) -> Dict[str, Any]用 CPU 上的记录拟合逐桶温度,并存到这个 agent 上。
records 是 (qtype, logits, target, k)。手上有带标签的前向记录时,用 laya.calibrate.records_from_labeled 构造它们;这个方法不下载权重,也不写 model.safetensors。seed 只在 compute_ece 为真时影响留出的 ECE 切分。checkpoint 的 cfg 保持加载时的样子。
参数
recordscompute_ecebool=Falseseedint=0
save_calibration
save_calibration(path: str) -> None写出温度,以及它们是为哪个 checkpoint 拟合的。不写权重。
参数
pathstr
load_calibration
load_calibration(path: str) -> None把 save_calibration 写出的 JSON 映射读进这个 agent。
没有 version 的文件会被当作版本 1,仍然能加载。版本更新、但记录的 checkpoint 与这个 agent 对不上的文件会给出警告,也仍然加载。不是数字、或落在 [TEMP_MIN, TEMP_MAX] 之外的值,会像加载 checkpoint 时那样用 clamp_temperature 夹住。
参数
pathstr
load
load(
model_id_or_path: str = "convaiinnovations/laya",
device: Optional[str] = None,
token: Optional[str] = None,
subfolder: Optional[str] = None,
fast: bool = False,
compile: bool = False,
revision: Optional[str] = None,
expected_sha256: Optional[Dict[str, str]] = None,
lang_temperatures: Optional[Dict[str, Dict[str, 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,
calibration: Optional[str] = None,
) -> Agent加载一个 Laya agent。
subfolder 从捆绑了多个 checkpoint 的仓库里挑一个:
laya.load("convaiinnovations/laya") # English (repo root)
laya.load("convaiinnovations/laya", subfolder="multilingual")
laya.load("convaiinnovations/laya", fast=True) # TileLang GPU fast path
laya.load("convaiinnovations/laya", compile=True) # torch.compile the model
revision/expected_sha256 会固定并校验下载下来的产物;见 Agent。hooks / on_predict_start / on_predict_end 观察或塑造每一次预测;见 laya.hooks。calibration 就是 Agent 接受的那个可选 JSON 路径。
参数
model_id_or_pathstr="convaiinnovations/laya"deviceOptional[str]=NonetokenOptional[str]=NonesubfolderOptional[str]=Nonefastbool=Falsecompilebool=FalserevisionOptional[str]=Noneexpected_sha256Optional[Dict[str, str]]=Nonelang_temperaturesOptional[Dict[str, Dict[str, Any]]]=Nonehooks=Noneon_predict_start=Noneon_predict_end=Nonehooks_raisebool=Truehooks_concurrentbool=Truehooks_timeoutOptional[float]=NonecalibrationOptional[str]=None
ONNXAgent
ONNXAgent(
model_id_or_path: str,
onnx_path: str = "laya.onnx",
token: Optional[str] = None,
subfolder: Optional[str] = None,
revision: Optional[str] = None,
expected_sha256: Optional[Dict[str, str]] = None,
hooks=None,
on_predict_start=None,
on_predict_end=None,
hooks_raise: bool = True,
hooks_concurrent: bool = True,
hooks_timeout: Optional[float] = None,
lang_temperatures: Optional[Dict[str, Dict[str, Any]]] = None,
calibration: Optional[str] = None,
)基类: HookRegistry
通过 ONNX 运行的 System 1 决策模型:针对 CPU 优化的快速决策。
加载一个由 ONNX Runtime 支撑的 Laya agent。
参数
model_id_or_pathstrHuggingFace Hub ID,或原始 PyTorch checkpoint 的本地路径(用来加载分词器与配置)。
onnx_pathstr="laya.onnx"导出的 .onnx 文件的路径。
tokenOptional[str]=None私有或受限 checkpoint 用的可选 HuggingFace token;不给时退回
$HF_TOKEN,与Agent完全一致。只会去取分词器与配置 —— 计算图本身就是本地的onnx_path。subfolderOptional[str]=None从捆绑仓库下载时的可选子目录。
revisionOptional[str]=None可选的 Hub 版本(commit SHA/分支/tag)。不给时,用 huggingface_hub 的常规默认值和已有的离线缓存。
expected_sha256Optional[Dict[str, str]]=None可选的 {相对 checkpoint 目录的路径: 十六进制摘要},在任何 checkpoint 文件被解析之前校验;它是可选的,对本地目录同样生效。产物缺失会抛
FileNotFoundError,摘要不匹配会抛ValueError;两者都会拒绝这次加载。hooksHookArg=None可选的预测钩子;见
laya.hooks。on_predict_startPredictHookArg=None可选的起始钩子,在推理之前运行。
on_predict_endPredictHookArg=None可选的结束钩子,在推理之后运行。
hooks_raisebool=True为 False 时,钩子失败只警告,推理继续。
hooks_concurrentbool=True为 False 时,钩子用锁串行化。
hooks_timeoutOptional[float]=None以秒为单位限制每次钩子调用;None 表示不限制。
lang_temperaturesOptional[Dict[str, Dict[str, Any]]]=None可选的按语言温度覆盖,按语言代码索引,每项是
{"temperature": [3 floats], "temperature_by_options": {}}。当system_one/predict收到lang=时应用,与 PyTorch 的Agent对齐;否则跨后端切换会丢掉校准。calibrationOptional[str]=None
load_calibration
load_calibration(path: str) -> None把 save_calibration 写出的 JSON 映射读进这个 agent。
参数
pathstr
system_one
system_one(
state: Union[str, dict, list],
questions: Dict[str, Dict[str, Any]],
lang: Optional[str] = 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]在一次 ONNX Runtime 会话运行里,对状态评估一组类型化问题。
lang 选择按语言的温度覆盖(见 lang_temperatures),与 PyTorch Agent.system_one 的签名一致,因此两个后端可以互换使用。
它是基于 predict_batch 定义的,与 PyTorch 的 Agent.system_one 完全一样,这样单状态路径与批量路径就不会各自漂移。
参数
stateUnion[str, dict, list]文本字符串、JSON 字典或对话轮次列表。
questionsDict[str, Dict[str, Any]]问题定义,形状与
Agent.system_one接受的一致。langOptional[str]=None按语言的温度覆盖(见
lang_temperatures)。hooksHookArg=None每次调用的钩子,追加在 agent 上已安装的钩子之后。
on_predict_startPredictHookArg=None每次调用的起始钩子。它可以改写状态/问题,或调用
ctx.skip(...)短路推理。on_predict_endPredictHookArg=None每次调用的结束钩子。它可以改写结果。
hooks_raiseOptional[bool]=None覆盖本次调用中 agent 的
hooks_raise。hooks_timeoutOptional[float]=None覆盖本次调用中 agent 的
hooks_timeout。max_lenOptional[int]=None覆盖本次调用中配置的
max_len。head_max_lenOptional[int]=None覆盖本次调用中配置的
head_max_len。min_confidenceOptional[float]=None可选的弃权阈值,作用在
answer_confidence上(#361);低于它的答案会带上low_confidence: True返回。
返回值
含答案、概率、校准后的置信度与 token 用量的字典。
要一次性给很多状态打分,见 predict_batch,它让这些状态共用会话运行。
predict_batch
predict_batch(
states: List[Union[str, dict, list]],
questions: Dict[str, Dict[str, Any]],
batch_size: Optional[int] = None,
lang: Optional[str] = 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,
sort_by_length: bool = False,
min_confidence: Optional[float] = None,
) -> List[Dict[str, Any]]对多个状态评估同一组问题,共用 ONNX Runtime 的会话运行。
这是吞吐路径,与 laya.agent.Agent.predict_batch 对应:system_one 每次会话运行只归并一个状态的问题行,所以 N 个状态要 N 次运行。predict_batch 把多个状态的行归并进一次运行 —— 或 ceil(len(states) / batch_size) 次 —— 这正是 ONNX Runtime 自身的并行在 CPU 上发挥价值的地方。
参数
statesList[Union[str, dict, list]]状态列表(每一项是文本字符串、JSON 字典或对话轮次列表)。同一组
questions会对照每一个状态评估。questionsDict[str, Dict[str, Any]]问题定义,与
system_one接受的完全一致。batch_sizeOptional[int]=None每次会话运行中状态数的可选上限。
None表示一次全发;批量处理很多或很长的状态时,设上它可以给峰值内存封顶。langOptional[str]=None应用到每一个状态的按语言温度覆盖;见
lang_temperatures。hooksHookArg=None每次调用的钩子,追加在 agent 上已安装的钩子之后。
on_predict_startPredictHookArg=None每次调用的起始钩子。它可以改写状态/问题,或调用
ctx.skip(...)短路推理。on_predict_endPredictHookArg=None每次调用的结束钩子。它可以改写结果。
hooks_raiseOptional[bool]=None覆盖本次调用中 agent 的
hooks_raise。hooks_timeoutOptional[float]=None覆盖本次调用中 agent 的
hooks_timeout。max_lenOptional[int]=None覆盖本次调用中配置的
max_len。head_max_lenOptional[int]=None覆盖本次调用中配置的
head_max_len。sort_by_lengthbool=False把编码后长度相近的状态按「八个批次」为一组归到一起以减少 padding,与
Agent.predict_batch完全一样。需要显式给出大于 1、且小于状态数的batch_size;否则没有任何效果。结果保持输入顺序。改变批次形状可能让决策阈值附近的浮点预测结果轻微变化。min_confidenceOptional[float]=None可选的弃权阈值,作用在
answer_confidence上(#361);低于它的答案会带上low_confidence: True返回。
返回值
每个状态一个结果字典的列表,形状与 system_one 的输出完全相同,并按下标与 states 对齐。
predict_long
predict_long(
state: Union[str, dict, list],
questions: Dict[str, Dict[str, Any]],
window: Optional[int] = None,
stride: Optional[int] = None,
aggregate: str = "auto",
batch_size: Optional[int] = None,
lang: Optional[str] = None,
hooks=None,
on_predict_start=None,
on_predict_end=None,
hooks_raise: Optional[bool] = None,
hooks_timeout: Optional[float] = None,
) -> Dict[str, Any]对超出上下文窗口的状态评估问题:用互相重叠的窗口扫描它,并按问题聚合。
这是 laya.agent.Agent.predict_long 的 ONNX 版本,聚合规则相同:system_one 会把超出 max_len 的状态截断到一个窗口,其余部分被静默丢弃。predict_long 只把状态分词一次,切成互相重叠的 token 窗口,通过 predict_batch 给每个窗口打分 —— 于是这些窗口共用 ONNX Runtime 的会话运行,而不是各付一次 —— 再把各窗口的答案合并起来:
- noul -> P(true) 取各窗口的最大值(只要有一个窗口支持,该陈述就成立)
- choice-> 取单个最自信窗口的答案,这样局部信号不会被长文档里占绝大多数的中性窗口投票压过去
- score -> 同样取最自信窗口的档位
返回的概率/置信度是作出决定的那个窗口的,不是针对整篇文档校准过的数字,理由与 PyTorch 那边的说明相同。每个答案都带着 answer["window"] —— 作出决定的窗口的 index、在分词后状态中的 token_start/token_end,以及窗口总数 count。
已经装得进一个窗口的状态会直接交给 system_one(输出完全相同)。
参数
stateUnion[str, dict, list]文本字符串、JSON 字典或对话轮次列表。
questionsDict[str, Dict[str, Any]]问题定义,与
system_one接受的完全一致。windowOptional[int]=None每个窗口容纳的状态 token 数。默认取按问题计的状态预算(
max_len - head_max_len - 8)。与Agent.predict_long一样,窗口更小能更好地隔离局部信号,代价是窗口数更多。strideOptional[int]=None窗口之间的 token 步长。默认是
window // 2(50% 重叠)。aggregatestr="auto""auto"(即上面那套按类型的规则)是目前唯一的模式。
batch_sizeOptional[int]=None每次会话运行的窗口数上限,用来给超长状态的内存用量封顶。
langOptional[str]=None按语言选择温度,与
system_one一致。hooksHookArg=None每次调用的钩子,追加在 agent 上已安装的钩子之后。它们遵循
Agent.predict_long的约定:包住为状态作答的那次推理;直接作答的起始钩子(ctx.skip(...))会得到usage["windows"] == 0且没有窗口归属信息;被改写过的扫描在聚合时不带answer["window"]。on_predict_startPredictHookArg=None每次调用的起始钩子,与
system_one一致。on_predict_endPredictHookArg=None每次调用的结束钩子,与
system_one一致。hooks_raiseOptional[bool]=None覆盖本次调用中 agent 的
hooks_raise。hooks_timeoutOptional[float]=None覆盖本次调用中 agent 的
hooks_timeout。
返回单个结果字典,形状与 system_one 相同,并加上 usage["windows"]。跨多个窗口时,截断相关的键与 Agent.predict_long 中的合并方式相同:truncated 是窗口数,truncated_questions 是最后一个窗口的列表,所以 truncated 大于 0 而列表为空是可能的。
decide
decide(
state: Union[str, dict, list],
schema: Any = None,
questions: Optional[Dict[str, Dict[str, Any]]] = None,
return_details: bool = False,
min_confidence: Optional[float] = None,
predict_kwargs,
) -> Any把 state 对照一个 schema(JSON schema 或 pydantic 模型)作答,返回类型化的值。
见 laya.structured。schema 与 questions 只能给一个;额外的关键字参数会透传给 predict / system_one。
参数
stateUnion[str, dict, list]schemaAny=NonequestionsOptional[Dict[str, Dict[str, Any]]]=Nonereturn_detailsbool=Falsemin_confidenceOptional[float]=Nonepredict_kwargs
decide_batch
decide_batch(
states: List[Union[str, dict, list]],
schema: Any = None,
questions: Optional[Dict[str, Dict[str, Any]]] = None,
return_details: bool = False,
min_confidence: Optional[float] = None,
predict_kwargs,
) -> List[Any]通过 predict_batch 把多个状态对照同一个 schema 作答;见 laya.structured。
参数
statesList[Union[str, dict, list]]schemaAny=NonequestionsOptional[Dict[str, Dict[str, Any]]]=Nonereturn_detailsbool=Falsemin_confidenceOptional[float]=Nonepredict_kwargs
量化导出
scripts/export_onnx.py --quantize 会在 fp32 导出的旁边写出一份 INT8 仅权重量化的副本
(laya.onnx 也会生成 laya.int8.onnx)。动态的逐通道量化把 MatMul 权重转成 int8,激活值
保持 fp32,所以不需要校准数据集,ONNXAgent 只要把 onnx_path 指向它就能加载结果。在英文
checkpoint 上,CPU(M 系列,20 个客服工单状态 x choice/noul/score):模型文件 1.6 GB -> 581 MB,
每状态 p50 延迟 ~340 ms -> ~250 ms(~1.35x),且与 fp32 相比决策零变化(单次概率最大漂移
0.09)。用逐张量 scale 代替逐通道,20 个状态里有 3 个翻转,漂移最高 0.29,这就是导出器用逐通道
的原因。int8 图只能跑在 CPU 上:ONNX Runtime 在 CUDAExecutionProvider 上没有 INT8 MatMul 内核,
GPU provider 会逐节点静默回退。
python scripts/export_onnx.py --model convaiinnovations/laya --output laya.onnx --quantize