Skip to content

组件

Finetune

lazyllm.components.finetune.AlpacaloraFinetune

Bases: LazyLLMFinetuneBase

此类是 LazyLLMFinetuneBase 的子类,基于 alpaca-lora 项目提供的 LoRA 微调能力,用于对大语言模型进行 LoRA 微调。

Parameters:

  • base_model (str) –

    用于微调的基模型本地路径。

  • target_path (str) –

    微调后 LoRA 权重保存路径。

  • merge_path (Optional[str], default: None ) –

    合并 LoRA 权重后的模型保存路径,默认 None。 若未提供,则在 target_path 下创建 "lazyllm_lora" 与 "lazyllm_merge" 目录。

  • model_name (Optional[str], default: 'LLM' ) –

    模型名称,用于日志前缀,默认 LLM

  • cp_files (Optional[str], default: 'tokeniz*' ) –

    从基模型路径复制配置文件到 merge_path,默认 tokeniz*

  • launcher (launcher, default: remote(ngpus=1) ) –

    微调启动器,默认 launchers.remote(ngpus=1)

  • kw (dict, default: {} ) –

    用于更新默认训练参数的关键字参数,允许更新如下参数:

Other Parameters:

  • data_path (Optional[str]) –

    数据路径,默认 None

  • batch_size (Optional[int]) –

    批大小,默认 64。

  • micro_batch_size (Optional[int]) –

    微批大小,默认 4。

  • num_epochs (Optional[int]) –

    训练轮数,默认 2。

  • learning_rate (Optional[float]) –

    学习率,默认 5.e-4。

  • cutoff_len (Optional[int]) –

    截断长度,默认 1030。

  • filter_nums (Optional[int]) –

    过滤器数量,默认 1024。

  • val_set_size (Optional[int]) –

    验证集大小,默认 200。

  • lora_r (Optional[int]) –

    LoRA 秩,默认 8。

  • lora_alpha (Optional[int]) –

    LoRA 融合因子,默认 32。

  • lora_dropout (Optional[float]) –

    LoRA 丢弃率,默认 0.05。

  • lora_target_modules (Optional[str]) –

    LoRA 目标模块,默认 [wo,wqkv]

  • modules_to_save (Optional[str]) –

    全量微调模块,默认 [tok_embeddings,output]

  • deepspeed (Optional[str]) –

    DeepSpeed 配置路径,默认使用仓库预制 ds.json。

  • prompt_template_name (Optional[str]) –

    提示模板名称,默认 alpaca

  • train_on_inputs (Optional[bool]) –

    是否在输入上训练,默认 True

  • show_prompt (Optional[bool]) –

    是否显示提示,默认 False

  • nccl_port (Optional[int]) –

    NCCL 端口,默认随机在 19000-20500。

Examples:

>>> from lazyllm import finetune
>>> trainer = finetune.alpacalora('path/to/base/model', 'path/to/target')
Source code in lazyllm/components/finetune/alpacalora.py
class AlpacaloraFinetune(LazyLLMFinetuneBase):
    """此类是 ``LazyLLMFinetuneBase`` 的子类,基于 [alpaca-lora](https://github.com/tloen/alpaca-lora) 项目提供的 LoRA 微调能力,用于对大语言模型进行 LoRA 微调。

Args:
    base_model (str): 用于微调的基模型本地路径。
    target_path (str): 微调后 LoRA 权重保存路径。
    merge_path (Optional[str]): 合并 LoRA 权重后的模型保存路径,默认 ``None``。
        若未提供,则在 ``target_path`` 下创建 "lazyllm_lora" 与 "lazyllm_merge" 目录。
    model_name (Optional[str]): 模型名称,用于日志前缀,默认 ``LLM``。
    cp_files (Optional[str]): 从基模型路径复制配置文件到 ``merge_path``,默认 ``tokeniz*``。
    launcher (lazyllm.launcher): 微调启动器,默认 ``launchers.remote(ngpus=1)``。
    kw (dict): 用于更新默认训练参数的关键字参数,允许更新如下参数:

Keyword Args:
    data_path (Optional[str]): 数据路径,默认 ``None``。
    batch_size (Optional[int]): 批大小,默认 64。
    micro_batch_size (Optional[int]): 微批大小,默认 4。
    num_epochs (Optional[int]): 训练轮数,默认 2。
    learning_rate (Optional[float]): 学习率,默认 5.e-4。
    cutoff_len (Optional[int]): 截断长度,默认 1030。
    filter_nums (Optional[int]): 过滤器数量,默认 1024。
    val_set_size (Optional[int]): 验证集大小,默认 200。
    lora_r (Optional[int]): LoRA 秩,默认 8。
    lora_alpha (Optional[int]): LoRA 融合因子,默认 32。
    lora_dropout (Optional[float]): LoRA 丢弃率,默认 0.05。
    lora_target_modules (Optional[str]): LoRA 目标模块,默认 ``[wo,wqkv]``。
    modules_to_save (Optional[str]): 全量微调模块,默认 ``[tok_embeddings,output]``。
    deepspeed (Optional[str]): DeepSpeed 配置路径,默认使用仓库预制 ds.json。
    prompt_template_name (Optional[str]): 提示模板名称,默认 ``alpaca``。
    train_on_inputs (Optional[bool]): 是否在输入上训练,默认 ``True``。
    show_prompt (Optional[bool]): 是否显示提示,默认 ``False``。
    nccl_port (Optional[int]): NCCL 端口,默认随机在 19000-20500。


Examples:
    >>> from lazyllm import finetune
    >>> trainer = finetune.alpacalora('path/to/base/model', 'path/to/target')
    """
    defatult_kw = ArgsDict({
        'data_path': None,
        'batch_size': 64,
        'micro_batch_size': 4,
        'num_epochs': 2,
        'learning_rate': 5.e-4,
        'cutoff_len': 1030,
        'filter_nums': 1024,
        'val_set_size': 200,
        'lora_r': 8,
        'lora_alpha': 32,
        'lora_dropout': 0.05,
        'lora_target_modules': '[wo,wqkv]',
        'modules_to_save': '[tok_embeddings,output]',
        'deepspeed': '',
        'prompt_template_name': 'alpaca',
        'train_on_inputs': True,
        'show_prompt': False,
        'nccl_port': 19081,
    })
    auto_map = {'micro_batch_size': 'micro_batch_size'}

    def __init__(self,
                 base_model,
                 target_path,
                 merge_path=None,
                 model_name='LLM',
                 cp_files='tokeniz*',
                 launcher=launchers.remote(ngpus=1),  # noqa B008
                 **kw
                 ):
        if not merge_path:
            save_path = os.path.join(lazyllm.config['train_target_root'], target_path)
            target_path, merge_path = os.path.join(save_path, 'lazyllm_lora'), os.path.join(save_path, 'lazyllm_merge')
            os.makedirs(target_path, exist_ok=True)
            os.makedirs(merge_path, exist_ok=True)
        super().__init__(
            base_model,
            target_path,
            launcher=launcher,
        )
        self.folder_path = os.path.dirname(os.path.abspath(__file__))
        deepspeed_config_path = os.path.join(self.folder_path, 'alpaca-lora', 'ds.json')
        self.kw = copy.deepcopy(self.defatult_kw)
        self.kw['deepspeed'] = deepspeed_config_path
        self.kw['nccl_port'] = random.randint(19000, 20500)
        self.kw.check_and_update(kw)
        self.merge_path = merge_path
        self.cp_files = cp_files
        self.model_name = model_name

    def cmd(self, trainset, valset=None) -> str:
        """生成用于执行Alpaca-LoRA微调和模型合并的shell命令序列。

Args:
    trainset (str): 训练数据集路径,支持相对data_path配置的路径或绝对路径
    valset (str, optional): 验证数据集路径,未指定时将从训练集中自动划分

**Returns:**

- str or list: 当不需要合并模型时返回单个命令字符串,需要合并时返回包含微调命令、合并命令和文件拷贝命令的列表


Examples:
    >>> from lazyllm import finetune
    >>> trainer = finetune.alpacalora('path/to/base/model', 'path/to/target')
    >>> cmd = trainer.cmd("my_dataset.json")
    """
        thirdparty.check_packages(['datasets', 'deepspeed', 'fire', 'numpy', 'peft', 'torch', 'transformers'])
        if not os.path.exists(trainset):
            defatult_path = os.path.join(lazyllm.config['data_path'], trainset)
            if os.path.exists(defatult_path):
                trainset = defatult_path
        if not self.kw['data_path']:
            self.kw['data_path'] = trainset

        run_file_path = os.path.join(self.folder_path, 'alpaca-lora', 'finetune.py')
        cmd = (f'python {run_file_path} '
               f'--base_model={self.base_model} '
               f'--output_dir={self.target_path} '
            )
        cmd += self.kw.parse_kwargs()
        cmd += f' 2>&1 | tee {os.path.join(self.target_path, self.model_name)}_$(date +"%Y-%m-%d_%H-%M-%S").log'

        if self.merge_path:
            run_file_path = os.path.join(self.folder_path, 'alpaca-lora', 'utils', 'merge_weights.py')

            cmd = [cmd,
                   f'python {run_file_path} '
                   f'--base={self.base_model} '
                   f'--adapter={self.target_path} '
                   f'--save_path={self.merge_path} ',
                   f' cp {os.path.join(self.base_model, self.cp_files)} {self.merge_path} '
                ]

        # cmd = 'realpath .'
        return cmd

cmd(trainset, valset=None)

生成用于执行Alpaca-LoRA微调和模型合并的shell命令序列。

Parameters:

  • trainset (str) –

    训练数据集路径,支持相对data_path配置的路径或绝对路径

  • valset (str, default: None ) –

    验证数据集路径,未指定时将从训练集中自动划分

Returns:

  • str or list: 当不需要合并模型时返回单个命令字符串,需要合并时返回包含微调命令、合并命令和文件拷贝命令的列表

Examples:

>>> from lazyllm import finetune
>>> trainer = finetune.alpacalora('path/to/base/model', 'path/to/target')
>>> cmd = trainer.cmd("my_dataset.json")
Source code in lazyllm/components/finetune/alpacalora.py
    def cmd(self, trainset, valset=None) -> str:
        """生成用于执行Alpaca-LoRA微调和模型合并的shell命令序列。

Args:
    trainset (str): 训练数据集路径,支持相对data_path配置的路径或绝对路径
    valset (str, optional): 验证数据集路径,未指定时将从训练集中自动划分

**Returns:**

- str or list: 当不需要合并模型时返回单个命令字符串,需要合并时返回包含微调命令、合并命令和文件拷贝命令的列表


Examples:
    >>> from lazyllm import finetune
    >>> trainer = finetune.alpacalora('path/to/base/model', 'path/to/target')
    >>> cmd = trainer.cmd("my_dataset.json")
    """
        thirdparty.check_packages(['datasets', 'deepspeed', 'fire', 'numpy', 'peft', 'torch', 'transformers'])
        if not os.path.exists(trainset):
            defatult_path = os.path.join(lazyllm.config['data_path'], trainset)
            if os.path.exists(defatult_path):
                trainset = defatult_path
        if not self.kw['data_path']:
            self.kw['data_path'] = trainset

        run_file_path = os.path.join(self.folder_path, 'alpaca-lora', 'finetune.py')
        cmd = (f'python {run_file_path} '
               f'--base_model={self.base_model} '
               f'--output_dir={self.target_path} '
            )
        cmd += self.kw.parse_kwargs()
        cmd += f' 2>&1 | tee {os.path.join(self.target_path, self.model_name)}_$(date +"%Y-%m-%d_%H-%M-%S").log'

        if self.merge_path:
            run_file_path = os.path.join(self.folder_path, 'alpaca-lora', 'utils', 'merge_weights.py')

            cmd = [cmd,
                   f'python {run_file_path} '
                   f'--base={self.base_model} '
                   f'--adapter={self.target_path} '
                   f'--save_path={self.merge_path} ',
                   f' cp {os.path.join(self.base_model, self.cp_files)} {self.merge_path} '
                ]

        # cmd = 'realpath .'
        return cmd

lazyllm.components.finetune.CollieFinetune

Bases: LazyLLMFinetuneBase

此类是 LazyLLMFinetuneBase 的子类,基于 Collie 框架提供的 LoRA 微调能力,用于对大语言模型进行 LoRA 微调。

Parameters:

  • base_model (str) –

    用于微调的基模型路径。

  • target_path (str) –

    微调后 LoRA 权重保存路径。

  • merge_path (Optional[str], default: None ) –

    合并 LoRA 权重后的模型路径,默认 None。 若未提供,则在 target_path 下创建 "lazyllm_lora" 与 "lazyllm_merge" 目录。

  • model_name (Optional[str], default: 'LLM' ) –

    模型名称,用于日志前缀,默认 "LLM"。

  • cp_files (Optional[str], default: 'tokeniz*' ) –

    指定从基模型路径复制到 merge_path 的配置文件,默认 "tokeniz*"。

  • launcher (launcher, default: remote(ngpus=1) ) –

    微调启动器,默认 launchers.remote(ngpus=1)

  • kw (dict, default: {} ) –

    用于更新默认训练参数的关键字参数。仅允许更新如下参数:

Other Parameters:

  • data_path (Optional[str]) –

    数据路径,默认 None

  • batch_size (Optional[int]) –

    批大小,默认 64。

  • micro_batch_size (Optional[int]) –

    微批大小,默认 4。

  • num_epochs (Optional[int]) –

    训练轮数,默认 3。

  • learning_rate (Optional[float]) –

    学习率,默认 5.e-4。

  • dp_size (Optional[int]) –

    数据并行参数,默认 8。

  • pp_size (Optional[int]) –

    流水线并行参数,默认 1。

  • tp_size (Optional[int]) –

    张量并行参数,默认 1。

  • lora_r (Optional[int]) –

    LoRA 秩,默认 8。

  • lora_alpha (Optional[int]) –

    LoRA 融合因子,默认 16。

  • lora_dropout (Optional[float]) –

    LoRA 丢弃率,默认 0.05。

  • lora_target_modules (Optional[str]) –

    LoRA 目标模块,默认 [wo,wqkv]

  • modules_to_save (Optional[str]) –

    全量微调模块,默认 [tok_embeddings,output]

  • prompt_template_name (Optional[str]) –

    提示模板名称,默认 "alpaca"。

Examples:

>>> from lazyllm import finetune
>>> trainer = finetune.collie('path/to/base/model', 'path/to/target')
Source code in lazyllm/components/finetune/collie.py
class CollieFinetune(LazyLLMFinetuneBase):
    """此类是 ``LazyLLMFinetuneBase`` 的子类,基于 [Collie](https://github.com/OpenLMLab/collie) 框架提供的 LoRA 微调能力,用于对大语言模型进行 LoRA 微调。

Args:
    base_model (str): 用于微调的基模型路径。
    target_path (str): 微调后 LoRA 权重保存路径。
    merge_path (Optional[str]): 合并 LoRA 权重后的模型路径,默认 ``None``。
        若未提供,则在 ``target_path`` 下创建 "lazyllm_lora" 与 "lazyllm_merge" 目录。
    model_name (Optional[str]): 模型名称,用于日志前缀,默认 "LLM"。
    cp_files (Optional[str]): 指定从基模型路径复制到 ``merge_path`` 的配置文件,默认 "tokeniz*"。
    launcher (lazyllm.launcher): 微调启动器,默认 ``launchers.remote(ngpus=1)``。
    kw (dict): 用于更新默认训练参数的关键字参数。仅允许更新如下参数:

Keyword Args:
    data_path (Optional[str]): 数据路径,默认 ``None``。
    batch_size (Optional[int]): 批大小,默认 64。
    micro_batch_size (Optional[int]): 微批大小,默认 4。
    num_epochs (Optional[int]): 训练轮数,默认 3。
    learning_rate (Optional[float]): 学习率,默认 5.e-4。
    dp_size (Optional[int]): 数据并行参数,默认 8。
    pp_size (Optional[int]): 流水线并行参数,默认 1。
    tp_size (Optional[int]): 张量并行参数,默认 1。
    lora_r (Optional[int]): LoRA 秩,默认 8。
    lora_alpha (Optional[int]): LoRA 融合因子,默认 16。
    lora_dropout (Optional[float]): LoRA 丢弃率,默认 0.05。
    lora_target_modules (Optional[str]): LoRA 目标模块,默认 ``[wo,wqkv]``。
    modules_to_save (Optional[str]): 全量微调模块,默认 ``[tok_embeddings,output]``。
    prompt_template_name (Optional[str]): 提示模板名称,默认 "alpaca"。


Examples:
    >>> from lazyllm import finetune
    >>> trainer = finetune.collie('path/to/base/model', 'path/to/target')
    """
    defatult_kw = ArgsDict({
        'data_path': None,
        'batch_size': 64,
        'micro_batch_size': 4,
        'num_epochs': 3,
        'learning_rate': 5.e-4,
        'dp_size': 8,
        'pp_size': 1,
        'tp_size': 1,
        'lora_r': 8,
        'lora_alpha': 16,
        'lora_dropout': 0.05,
        'lora_target_modules': '[wo,wqkv]',
        'modules_to_save': '[tok_embeddings,output]',
        'prompt_template_name': 'alpaca',
    })
    auto_map = {
        'ddp': 'dp_size',
        'micro_batch_size': 'micro_batch_size',
        'tp': 'tp_size',
    }

    def __init__(self,
                 base_model,
                 target_path,
                 merge_path=None,
                 model_name='LLM',
                 cp_files='tokeniz*',
                 launcher=launchers.remote(ngpus=1),  # noqa B008
                 **kw
                 ):
        if not merge_path:
            save_path = os.path.join(lazyllm.config['train_target_root'], target_path)
            target_path, merge_path = os.path.join(save_path, 'lazyllm_lora'), os.path.join(save_path, 'lazyllm_merge')
            os.makedirs(target_path, exist_ok=True)
            os.makedirs(merge_path, exist_ok=True)
        super().__init__(
            base_model,
            target_path,
            launcher=launcher,
        )
        self.folder_path = os.path.dirname(os.path.abspath(__file__))
        self.kw = copy.deepcopy(self.defatult_kw)
        self.kw.check_and_update(kw)
        self.merge_path = merge_path
        self.cp_files = cp_files
        self.model_name = model_name

    def cmd(self, trainset, valset=None) -> str:
        thirdparty.check_packages(['numpy', 'peft', 'torch', 'transformers'])
        if not os.path.exists(trainset):
            defatult_path = os.path.join(lazyllm.config['data_path'], trainset)
            if os.path.exists(defatult_path):
                trainset = defatult_path
        if not self.kw['data_path']:
            self.kw['data_path'] = trainset

        run_file_path = os.path.join(self.folder_path, 'collie', 'finetune.py')
        cmd = (f'python {run_file_path} '
               f'--base_model={self.base_model} '
               f'--output_dir={self.target_path} '
            )
        cmd += self.kw.parse_kwargs()
        cmd += f' 2>&1 | tee {os.path.join(self.target_path, self.model_name)}_$(date +"%Y-%m-%d_%H-%M-%S").log'

        if self.merge_path:
            run_file_path = os.path.join(self.folder_path, 'alpaca-lora', 'utils', 'merge_weights.py')

            cmd = [cmd,
                   f'python {run_file_path} '
                   f'--base={self.base_model} '
                   f'--adapter={self.target_path} '
                   f'--save_path={self.merge_path} ',
                   f' cp {os.path.join(self.base_model, self.cp_files)} {self.merge_path} '
                ]

        return cmd

lazyllm.components.finetune.LlamafactoryFinetune

Bases: LazyLLMFinetuneBase

此类是 LazyLLMFinetuneBase 的子类,基于 LLaMA-Factory 框架提供的训练能力,用于对大语言模型(或视觉语言模型)进行训练。

Parameters:

  • base_model

    用于进行训练的基模型路径。支持本地路径,若路径不存在则尝试从配置的模型路径中查找。

  • target_path

    训练完成后,模型权重保存的目标路径。

  • merge_path (str, default: None ) –

    模型合并LoRA权重后的保存路径,默认为None。 如果未指定,将在 target_path 下自动创建两个目录: - "lazyllm_lora"(用于存放LoRA训练权重) - "lazyllm_merge"(用于存放合并后的模型权重)

  • config_path (str, default: None ) –

    训练配置的 YAML 文件路径,默认None。 如果未指定,则使用默认配置文件 llama_factory/sft.yaml。 配置文件支持覆盖默认训练参数。

  • export_config_path (str, default: None ) –

    LoRA权重合并导出配置的 YAML 文件路径,默认None。 如果未指定,则使用默认配置文件 llama_factory/lora_export.yaml

  • lora_r (int, default: None ) –

    LoRA的秩(rank),若提供则覆盖配置中的 lora_rank

  • modules_to_save (str, default: None ) –

    额外需要保存的模型模块名称列表,格式类似于Python列表字符串,如 "[module1,module2]"。

  • lora_target_modules (str, default: None ) –

    目标LoRA微调的模块名称列表,格式同上。

  • launcher (launcher, default: remote(ngpus=1, sync=True) ) –

    微调任务的启动器,默认为单卡同步远程启动器 launchers.remote(ngpus=1, sync=True)

  • **kw

    关键字参数,用于动态覆盖默认训练配置中的参数。

此类的关键字参数及其默认值如下:

Other Parameters:

  • stage (Literal['pt', 'sft', 'rm', 'ppo', 'dpo', 'kto']) –

    默认值是:sft。将在训练中执行的阶段。

  • do_train (bool) –

    默认值是:True。是否运行训练。

  • finetuning_type (Literal['lora', 'freeze', 'full']) –

    默认值是:lora。要使用的微调方法。

  • lora_target (str) –

    默认值是:all。要应用LoRA的目标模块的名称。使用逗号分隔多个模块。使用all指定所有线性模块。

  • template (Optional[str]) –

    默认值是:None。用于构建训练和推理提示的模板。

  • cutoff_len (int) –

    默认值是:1024。数据集中token化后输入的截止长度。

  • max_samples (Optional[int]) –

    默认值是:1000。出于调试目的,截断每个数据集的示例数量。

  • overwrite_cache (bool) –

    默认值是:True。覆盖缓存的训练和评估集。

  • preprocessing_num_workers (Optional[int]) –

    默认值是:16。用于预处理的进程数。

  • dataset_dir (str) –

    默认值是:lazyllm_temp_dir。包含数据集的文件夹的路径。如果没有明确指定,LazyLLM将在当前工作目录的 .temp 文件夹中生成一个 dataset_info.json 文件,供LLaMA-Factory使用。

  • logging_steps (float) –

    默认值是:10。每X个更新步骤记录一次日志。应该是整数或范围在 [0,1) 的浮点数。如果小于1,将被解释为总训练步骤的比例。

  • save_steps (float) –

    默认值是:500。每X个更新步骤保存一次检查点。应该是整数或范围在 [0,1) 的浮点数。如果小于1,将被解释为总训练步骤的比例。

  • plot_loss (bool) –

    默认值是:True。是否保存训练损失曲线。

  • overwrite_output_dir (bool) –

    默认值是:True。覆盖输出目录的内容。

  • per_device_train_batch_size (int) –

    默认值是:1。每个GPU/TPU/MPS/NPU核心/CPU的训练批次的大小。

  • gradient_accumulation_steps (int) –

    默认值是:8。在执行反向传播及参数更新前,要累积的更新步骤数。

  • learning_rate (float) –

    默认值是:1e-04。AdamW的初始学习率。

  • num_train_epochs (float) –

    默认值是:3.0。要执行的总训练周期数。

  • lr_scheduler_type (Union[SchedulerType, str]) –

    默认值是:cosine。要使用的调度器类型。

  • warmup_ratio (float) –

    默认值是:0.1。在总步骤的 warmup_ratio 分之一阶段内进行线性预热。

  • fp16 (bool) –

    默认值是:True。是否使用fp16(混合)精度,而不是32位。

  • ddp_timeout (Optional[int]) –

    默认值是:180000000。覆盖分布式训练的默认超时时间(值应以秒为单位给出)。

  • report_to (Union[NoneType, str, List[str]]) –

    默认值是:tensorboard。要将结果和日志报告到的集成列表。

  • val_size (float) –

    默认值是:0.1。验证集的大小,应该是整数或范围在[0,1)的浮点数。

  • per_device_eval_batch_size (int) –

    默认值是:1。每个GPU/TPU/MPS/NPU核心/CPU的验证集批次大小。

  • eval_strategy (Union[IntervalStrategy, str]) –

    默认值是:steps。要使用的验证评估策略。

  • eval_steps (Optional[float]) –

    默认值是:500。每X个步骤运行一次验证评估。应该是整数或范围在[0,1)的浮点数。如果小于1,将被解释为总训练步骤的比例。

Examples:

>>> from lazyllm import finetune
>>> trainer = finetune.llamafactory('internlm2-chat-7b', 'path/to/target')
<lazyllm.llm.finetune type=LlamafactoryFinetune>
Source code in lazyllm/components/finetune/llamafactory.py
class LlamafactoryFinetune(LazyLLMFinetuneBase):
    """此类是 ``LazyLLMFinetuneBase`` 的子类,基于 [LLaMA-Factory](https://github.com/hiyouga/LLaMA-Factory) 框架提供的训练能力,用于对大语言模型(或视觉语言模型)进行训练。

Args:
    base_model: 用于进行训练的基模型路径。支持本地路径,若路径不存在则尝试从配置的模型路径中查找。
    target_path: 训练完成后,模型权重保存的目标路径。
    merge_path (str, optional): 模型合并LoRA权重后的保存路径,默认为None。
        如果未指定,将在 ``target_path`` 下自动创建两个目录:
        - "lazyllm_lora"(用于存放LoRA训练权重)
        - "lazyllm_merge"(用于存放合并后的模型权重)
    config_path (str, optional): 训练配置的 YAML 文件路径,默认None。
        如果未指定,则使用默认配置文件 ``llama_factory/sft.yaml``。
        配置文件支持覆盖默认训练参数。
    export_config_path (str, optional): LoRA权重合并导出配置的 YAML 文件路径,默认None。
        如果未指定,则使用默认配置文件 ``llama_factory/lora_export.yaml``。
    lora_r (int, optional): LoRA的秩(rank),若提供则覆盖配置中的 ``lora_rank``。
    modules_to_save (str, optional): 额外需要保存的模型模块名称列表,格式类似于Python列表字符串,如 "[module1,module2]"。
    lora_target_modules (str, optional): 目标LoRA微调的模块名称列表,格式同上。
    launcher (lazyllm.launcher, optional): 微调任务的启动器,默认为单卡同步远程启动器 ``launchers.remote(ngpus=1, sync=True)``。
    **kw: 关键字参数,用于动态覆盖默认训练配置中的参数。

此类的关键字参数及其默认值如下:

Keyword Args:
    stage (typing.Literal['pt', 'sft', 'rm', 'ppo', 'dpo', 'kto']): 默认值是:``sft``。将在训练中执行的阶段。
    do_train (bool): 默认值是:``True``。是否运行训练。
    finetuning_type (typing.Literal['lora', 'freeze', 'full']): 默认值是:``lora``。要使用的微调方法。
    lora_target (str): 默认值是:``all``。要应用LoRA的目标模块的名称。使用逗号分隔多个模块。使用`all`指定所有线性模块。
    template (typing.Optional[str]): 默认值是:``None``。用于构建训练和推理提示的模板。
    cutoff_len (int): 默认值是:``1024``。数据集中token化后输入的截止长度。
    max_samples (typing.Optional[int]): 默认值是:``1000``。出于调试目的,截断每个数据集的示例数量。
    overwrite_cache (bool): 默认值是:``True``。覆盖缓存的训练和评估集。
    preprocessing_num_workers (typing.Optional[int]): 默认值是:``16``。用于预处理的进程数。
    dataset_dir (str): 默认值是:``lazyllm_temp_dir``。包含数据集的文件夹的路径。如果没有明确指定,LazyLLM将在当前工作目录的 ``.temp`` 文件夹中生成一个 ``dataset_info.json`` 文件,供LLaMA-Factory使用。
    logging_steps (float): 默认值是:``10``。每X个更新步骤记录一次日志。应该是整数或范围在 ``[0,1)`` 的浮点数。如果小于1,将被解释为总训练步骤的比例。
    save_steps (float): 默认值是:``500``。每X个更新步骤保存一次检查点。应该是整数或范围在 ``[0,1)`` 的浮点数。如果小于1,将被解释为总训练步骤的比例。
    plot_loss (bool): 默认值是:``True``。是否保存训练损失曲线。
    overwrite_output_dir (bool): 默认值是:``True``。覆盖输出目录的内容。
    per_device_train_batch_size (int): 默认值是:``1``。每个GPU/TPU/MPS/NPU核心/CPU的训练批次的大小。
    gradient_accumulation_steps (int): 默认值是:``8``。在执行反向传播及参数更新前,要累积的更新步骤数。
    learning_rate (float): 默认值是:``1e-04``。AdamW的初始学习率。
    num_train_epochs (float): 默认值是:``3.0``。要执行的总训练周期数。
    lr_scheduler_type (typing.Union[transformers.trainer_utils.SchedulerType, str]): 默认值是:``cosine``。要使用的调度器类型。
    warmup_ratio (float): 默认值是:``0.1``。在总步骤的 ``warmup_ratio`` 分之一阶段内进行线性预热。
    fp16 (bool): 默认值是:``True``。是否使用fp16(混合)精度,而不是32位。
    ddp_timeout (typing.Optional[int]): 默认值是:``180000000``。覆盖分布式训练的默认超时时间(值应以秒为单位给出)。
    report_to (typing.Union[NoneType, str, typing.List[str]]): 默认值是:``tensorboard``。要将结果和日志报告到的集成列表。
    val_size (float): 默认值是:``0.1``。验证集的大小,应该是整数或范围在`[0,1)`的浮点数。
    per_device_eval_batch_size (int): 默认值是:``1``。每个GPU/TPU/MPS/NPU核心/CPU的验证集批次大小。
    eval_strategy (typing.Union[transformers.trainer_utils.IntervalStrategy, str]): 默认值是:``steps``。要使用的验证评估策略。
    eval_steps (typing.Optional[float]): 默认值是:``500``。每X个步骤运行一次验证评估。应该是整数或范围在`[0,1)`的浮点数。如果小于1,将被解释为总训练步骤的比例。


Examples:
    >>> from lazyllm import finetune
    >>> trainer = finetune.llamafactory('internlm2-chat-7b', 'path/to/target')
    <lazyllm.llm.finetune type=LlamafactoryFinetune>
    """
    auto_map = {
        'gradient_step': 'gradient_accumulation_steps',
        'micro_batch_size': 'per_device_train_batch_size',
    }

    def __init__(self,
                 base_model,
                 target_path,
                 merge_path=None,
                 config_path=None,
                 export_config_path=None,
                 lora_r=None,
                 modules_to_save=None,
                 lora_target_modules=None,
                 launcher=launchers.remote(ngpus=1, sync=True),  # noqa B008
                 **kw
                 ):
        if not os.path.exists(base_model):
            defatult_path = os.path.join(lazyllm.config['model_path'], base_model)
            if os.path.exists(defatult_path):
                base_model = defatult_path
        if not merge_path:
            save_path = os.path.join(lazyllm.config['train_target_root'], target_path)
            target_path, merge_path = os.path.join(save_path, 'lazyllm_lora'), os.path.join(save_path, 'lazyllm_merge')
            os.system(f'mkdir -p {target_path} {merge_path}')
        super().__init__(
            base_model,
            target_path,
            launcher=launcher,
        )
        self.merge_path = merge_path
        self.temp_yaml_file = None
        self.temp_export_yaml_file = None
        self.config_path = config_path
        self.export_config_path = export_config_path
        self.config_folder_path = os.path.dirname(os.path.abspath(__file__))

        default_config_path = os.path.join(self.config_folder_path, 'llama_factory', 'sft.yaml')
        self.template_dict = ArgsDict(self._load_yaml(default_config_path))

        if self.config_path:
            self.template_dict.update(self._load_yaml(self.config_path))

        if lora_r:
            self.template_dict['lora_rank'] = lora_r
        if modules_to_save:
            self.template_dict['additional_target'] = modules_to_save.strip('[]')
        if lora_target_modules:
            self.template_dict['lora_target'] = lora_target_modules.strip('[]')
        self.template_dict['model_name_or_path'] = base_model
        self.template_dict['output_dir'] = target_path
        self.template_dict['template'] = self._get_template_name(base_model)
        self.template_dict.check_and_update(kw)

        default_export_config_path = os.path.join(self.config_folder_path, 'llama_factory', 'lora_export.yaml')
        self.export_dict = ArgsDict(self._load_yaml(default_export_config_path))

        if self.export_config_path:
            self.export_dict.update(self._load_yaml(self.export_config_path))

        self.export_dict['model_name_or_path'] = base_model
        self.export_dict['adapter_name_or_path'] = target_path
        self.export_dict['export_dir'] = merge_path
        self.export_dict['template'] = self.template_dict['template']

        self.temp_folder = os.path.join(lazyllm.config['temp_dir'], 'llamafactory_config', str(uuid.uuid4())[:10])
        if not os.path.exists(self.temp_folder):
            os.makedirs(self.temp_folder)
        self.log_file_path = None

    def _get_template_name(self, base_model):
        base_name = os.path.basename(base_model).lower()
        key_value = match_longest_prefix(base_name)
        if key_value:
            return key_value
        else:
            raise RuntimeError(f'Cannot find prfix of base_model({base_model}) '
                               f'in DEFAULT_TEMPLATE of LLaMA_Factory: {llamafactory_mapping_dict}')

    def _load_yaml(self, config_path):
        with open(config_path, 'r') as file:
            config_dict = yaml.safe_load(file)
        return config_dict

    def _build_temp_yaml(self, updated_template_str, prefix='train_'):
        fd, temp_yaml_file = tempfile.mkstemp(prefix=prefix, suffix='.yaml', dir=self.temp_folder)
        with os.fdopen(fd, 'w') as temp_file:
            temp_file.write(updated_template_str)
        return temp_yaml_file

    def _build_temp_dataset_info(self, datapaths):
        if isinstance(datapaths, str):
            datapaths = [datapaths]
        elif isinstance(datapaths, list) and all(isinstance(item, str) for item in datapaths):
            pass
        else:
            raise TypeError(f'datapaths({datapaths}) should be str or list of str.')
        temp_dataset_dict = dict()
        for datapath in datapaths:
            datapath = os.path.join(lazyllm.config['data_path'], datapath)
            assert os.path.isfile(datapath)
            file_name, _ = os.path.splitext(os.path.basename(datapath))
            temp_dataset_dict[file_name] = {'file_name': datapath}
            formatting = 'alpaca'
            try:
                with open(datapath, 'r', encoding='utf-8') as file:
                    data = json.load(file)
                if 'messages' in data[0]:
                    formatting = 'sharegpt'
                media_types = []
                for media in ['images', 'videos', 'audios']:
                    if media in data[0]:
                        media_types.append(media)
                if media_types:
                    columns = {item: item for item in media_types}
                    columns.update({'messages': 'messages'})
                    temp_dataset_dict[file_name].update({
                        'tags': {
                            'role_tag': 'role',
                            'content_tag': 'content',
                            'user_tag': 'user',
                            'assistant_tag': 'assistant'
                        },
                        'columns': columns
                    })
            except Exception:
                pass
            temp_dataset_dict[file_name].update({'formatting': formatting})
        self.temp_dataset_info_path = os.path.join(self.temp_folder, 'dataset_info.json')
        with open(self.temp_dataset_info_path, 'w') as json_file:
            json.dump(temp_dataset_dict, json_file, indent=4)
        return self.temp_dataset_info_path, ','.join(temp_dataset_dict.keys())

    def _rm_temp_yaml(self):
        if self.temp_yaml_file:
            if os.path.exists(self.temp_yaml_file):
                os.remove(self.temp_yaml_file)
            self.temp_yaml_file = None

    def cmd(self, trainset, valset=None) -> str:
        """生成LLaMA-Factory微调命令序列,包括训练和模型合并命令。

Args:
    trainset (str): 训练数据集路径(支持相对lazyllm.config['data_path']的路径)
    valset (str, optional): 验证数据集路径(当前实现中未直接使用)

**Returns:**

- str: 完整的shell命令字符串,包含:
    - 训练命令(自动配置参数)
    - 日志重定向(保存到目标路径)
    - 可选的模型合并命令(当配置LoRA时)

注意事项:
    - 自动生成带时间戳的训练日志文件
    - 临时文件会在使用后自动清理
    - 支持多种数据格式(alpaca/sharegpt等)
    - 多模态数据(图像/视频/音频)会自动检测处理
"""
        thirdparty.check_packages(['datasets', 'deepspeed', 'numpy', 'peft', 'torch', 'transformers', 'trl'])
        # train config update
        if 'dataset_dir' in self.template_dict and self.template_dict['dataset_dir'] == 'lazyllm_temp_dir':
            _, datasets = self._build_temp_dataset_info(trainset)
            self.template_dict['dataset_dir'] = self.temp_folder
        else:
            datasets = trainset
        self.template_dict['dataset'] = datasets

        # save config update
        if self.template_dict['finetuning_type'] == 'lora':
            updated_export_str = yaml.dump(dict(self.export_dict), default_flow_style=False)
            self.temp_export_yaml_file = self._build_temp_yaml(updated_export_str, prefix='merge_')

        updated_template_str = yaml.dump(dict(self.template_dict), default_flow_style=False)
        self.temp_yaml_file = self._build_temp_yaml(updated_template_str)

        formatted_date = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
        random_value = random.randint(1000, 9999)
        self.log_file_path = f'{self.target_path}/train_log_{formatted_date}_{random_value}.log'

        cmds = f'export DISABLE_VERSION_CHECK=1 && llamafactory-cli train {self.temp_yaml_file}'
        cmds += f' 2>&1 | tee {self.log_file_path}'
        if self.temp_export_yaml_file:
            cmds += f' && llamafactory-cli export {self.temp_export_yaml_file}'
        return cmds

cmd(trainset, valset=None)

生成LLaMA-Factory微调命令序列,包括训练和模型合并命令。

Parameters:

  • trainset (str) –

    训练数据集路径(支持相对lazyllm.config['data_path']的路径)

  • valset (str, default: None ) –

    验证数据集路径(当前实现中未直接使用)

Returns:

  • str: 完整的shell命令字符串,包含:
    • 训练命令(自动配置参数)
    • 日志重定向(保存到目标路径)
    • 可选的模型合并命令(当配置LoRA时)
注意事项
  • 自动生成带时间戳的训练日志文件
  • 临时文件会在使用后自动清理
  • 支持多种数据格式(alpaca/sharegpt等)
  • 多模态数据(图像/视频/音频)会自动检测处理
Source code in lazyllm/components/finetune/llamafactory.py
    def cmd(self, trainset, valset=None) -> str:
        """生成LLaMA-Factory微调命令序列,包括训练和模型合并命令。

Args:
    trainset (str): 训练数据集路径(支持相对lazyllm.config['data_path']的路径)
    valset (str, optional): 验证数据集路径(当前实现中未直接使用)

**Returns:**

- str: 完整的shell命令字符串,包含:
    - 训练命令(自动配置参数)
    - 日志重定向(保存到目标路径)
    - 可选的模型合并命令(当配置LoRA时)

注意事项:
    - 自动生成带时间戳的训练日志文件
    - 临时文件会在使用后自动清理
    - 支持多种数据格式(alpaca/sharegpt等)
    - 多模态数据(图像/视频/音频)会自动检测处理
"""
        thirdparty.check_packages(['datasets', 'deepspeed', 'numpy', 'peft', 'torch', 'transformers', 'trl'])
        # train config update
        if 'dataset_dir' in self.template_dict and self.template_dict['dataset_dir'] == 'lazyllm_temp_dir':
            _, datasets = self._build_temp_dataset_info(trainset)
            self.template_dict['dataset_dir'] = self.temp_folder
        else:
            datasets = trainset
        self.template_dict['dataset'] = datasets

        # save config update
        if self.template_dict['finetuning_type'] == 'lora':
            updated_export_str = yaml.dump(dict(self.export_dict), default_flow_style=False)
            self.temp_export_yaml_file = self._build_temp_yaml(updated_export_str, prefix='merge_')

        updated_template_str = yaml.dump(dict(self.template_dict), default_flow_style=False)
        self.temp_yaml_file = self._build_temp_yaml(updated_template_str)

        formatted_date = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
        random_value = random.randint(1000, 9999)
        self.log_file_path = f'{self.target_path}/train_log_{formatted_date}_{random_value}.log'

        cmds = f'export DISABLE_VERSION_CHECK=1 && llamafactory-cli train {self.temp_yaml_file}'
        cmds += f' 2>&1 | tee {self.log_file_path}'
        if self.temp_export_yaml_file:
            cmds += f' && llamafactory-cli export {self.temp_export_yaml_file}'
        return cmds

lazyllm.components.deploy.LazyLLMDeployBase

Bases: ComponentBase

此类是 ComponentBase 的一个子类,提供了LazyLLM部署的基础功能。它支持多种媒体类型的编码转换,并提供了结果提取和流式处理的配置选项。

Parameters:

  • launcher (LauncherBase, default: remote() ) –

    用于部署的启动器实例,默认为远程启动器(launchers.remote())。

注意事项
  • 继承此类时需要实现具体的部署逻辑
  • 可以通过重写extract_result方法来自定义结果提取逻辑

Examples:

>>> import lazyllm
>>> from lazyllm.components.deploy.base import LazyLLMDeployBase
>>> class MyDeployer(LazyLLMDeployBase):
...     def __call__(self, inputs):
...         return processed_result
        def extract_result(output, inputs):
...         return output.json()['result']
>>> deployer = MyDeployer()
>>> result = deployer.extract_result(raw_output, input_data)
Source code in lazyllm/components/deploy/base.py
class LazyLLMDeployBase(ComponentBase):
    """此类是 ``ComponentBase`` 的一个子类,提供了LazyLLM部署的基础功能。它支持多种媒体类型的编码转换,并提供了结果提取和流式处理的配置选项。

Args:
    launcher (LauncherBase): 用于部署的启动器实例,默认为远程启动器(``launchers.remote()``)。

注意事项: 
    - 继承此类时需要实现具体的部署逻辑
    - 可以通过重写extract_result方法来自定义结果提取逻辑


Examples:
    >>> import lazyllm
    >>> from lazyllm.components.deploy.base import LazyLLMDeployBase
    >>> class MyDeployer(LazyLLMDeployBase):
    ...     def __call__(self, inputs):
    ...         return processed_result
            def extract_result(output, inputs):
    ...         return output.json()['result']
    >>> deployer = MyDeployer()
    >>> result = deployer.extract_result(raw_output, input_data)
    """
    keys_name_handle = None
    message_format = None
    default_headers = {'Content-Type': 'application/json'}
    stream_url_suffix = ''
    stream_parse_parameters = {}

    encoder_map = dict(image=_image_to_base64, audio=_audio_to_base64, ocr_files=ocr_to_base64)

    @staticmethod
    def extract_result(output, inputs):
        """从模型输出中提取最终结果,默认实现直接返回原始输出,子类可重写此方法实现自定义结果提取逻辑。

Args:
    output: 模型原始输出
    inputs: 原始输入数据,可用于结果后处理

**Returns:**

- 处理后的最终结果
"""
        return output

    def __init__(self, *, launcher=launchers.remote()):  # noqa B008
        super().__init__(launcher=launcher)

extract_result(output, inputs) staticmethod

从模型输出中提取最终结果,默认实现直接返回原始输出,子类可重写此方法实现自定义结果提取逻辑。

Parameters:

  • output

    模型原始输出

  • inputs

    原始输入数据,可用于结果后处理

Returns:

  • 处理后的最终结果
Source code in lazyllm/components/deploy/base.py
    @staticmethod
    def extract_result(output, inputs):
        """从模型输出中提取最终结果,默认实现直接返回原始输出,子类可重写此方法实现自定义结果提取逻辑。

Args:
    output: 模型原始输出
    inputs: 原始输入数据,可用于结果后处理

**Returns:**

- 处理后的最终结果
"""
        return output

lazyllm.components.deploy.LazyLLMDeployBase.extract_result(output, inputs) staticmethod

从模型输出中提取最终结果,默认实现直接返回原始输出,子类可重写此方法实现自定义结果提取逻辑。

Parameters:

  • output

    模型原始输出

  • inputs

    原始输入数据,可用于结果后处理

Returns:

  • 处理后的最终结果
Source code in lazyllm/components/deploy/base.py
    @staticmethod
    def extract_result(output, inputs):
        """从模型输出中提取最终结果,默认实现直接返回原始输出,子类可重写此方法实现自定义结果提取逻辑。

Args:
    output: 模型原始输出
    inputs: 原始输入数据,可用于结果后处理

**Returns:**

- 处理后的最终结果
"""
        return output

lazyllm.components.finetune.FlagembeddingFinetune

Bases: LazyLLMFinetuneBase

该类是 LazyLLMFinetuneBase 的子类,基于 FlagEmbedding 框架提供的训练能力,用于训练嵌入和重排模型。

Parameters:

  • base_model (str) –

    用于训练的基础模型。必须是基础模型的路径。

  • target_path (str) –

    训练后模型权重保存的路径。

  • launcher (launcher, default: remote(ngpus=1, sync=True) ) –

    微调的启动器,默认为 launchers.remote(ngpus=1, sync=True)

  • kw

    用于更新默认训练参数的关键字参数。

该类嵌入模型的关键字参数及其默认值如下:

Other Parameters:

  • train_group_size (int) –

    默认为:8。训练组的大小。用于控制每个训练集中的负样本数量。

  • query_max_len (int) –

    默认为:512。经过分词后,段落的最大总输入序列长度。超过此长度的序列将被截断,较短的序列将被填充。

  • passage_max_len (int) –

    默认为:512。经过分词后,段落的最大总输入序列长度。超过此长度的序列将被截断,较短的序列将被填充。

  • pad_to_multiple_of (int) –

    默认为:8。如果设置,将序列填充为提供值的倍数。

  • query_instruction_for_retrieval (str) –

    默认为:Represent this sentence for searching relevant passages:。查询query的指令。

  • query_instruction_format (str) –

    默认为:{}{}。查询指令格式。

  • learning_rate (float) –

    默认为:1e-5。学习率。

  • num_train_epochs (int) –

    默认为:1。要执行的总训练周期数。

  • per_device_train_batch_size (int) –

    默认为:2。训练批量大小。

  • gradient_accumulation_steps (int) –

    默认为:1。在执行反向/更新传递之前要累积的更新步骤数。

  • dataloader_drop_last (bool) –

    默认为:True。如果数据集大小不能被批量大小整除,则丢弃最后一个不完整的批量,即 DataLoader 只返回完整的批量。

  • warmup_ratio (float) –

    默认为:0.1。线性调度器的预热比率。

  • weight_decay (float) –

    默认为:0.01。AdamW 中的权重衰减。

  • deepspeed (str) –

    默认为:``。DeepSpeed 配置文件的路径,默认使用 LazyLLM 代码仓库中的预置文件:ds_stage0.json``。

  • logging_steps (int) –

    默认为:1。更新日志的频率。

  • save_steps (int) –

    默认为:1000。保存频率。

  • temperature (float) –

    默认为:0.02。用于相似度评分的温度。

  • sentence_pooling_method (str) –

    默认为:cls。池化方法。可用选项:'cls', 'mean', 'last_token'。

  • normalize_embeddings (bool) –

    默认为:True。是否归一化嵌入。

  • kd_loss_type (str) –

    默认为:kl_div。知识蒸馏的损失类型。可用选项:'kl_div', 'm3_kd_loss'。

  • overwrite_output_dir (bool) –

    默认为:True。用于允许程序覆盖现有的输出目录。

  • fp16 (bool) –

    默认为:True。是否使用 fp16(混合)精度而不是 32 位。

  • gradient_checkpointing (bool) –

    默认为:True。是否启用梯度检查点。

  • negatives_cross_device (bool) –

    默认为:True。是否在设备间共享负样本。

该类重排模型的关键字参数及其默认值如下:

Other Parameters:

  • train_group_size (int) –

    默认为:8。训练组的大小。用于控制每个训练集中的负样本数量。

  • query_max_len (int) –

    默认为:256。经过分词后,段落的最大总输入序列长度。超过此长度的序列将被截断,较短的序列将被填充。

  • passage_max_len (int) –

    默认为:256。经过分词后,段落的最大总输入序列长度。超过此长度的序列将被截断,较短的序列将被填充。

  • pad_to_multiple_of (int) –

    默认为:8。如果设置,将序列填充为提供值的倍数。

  • learning_rate (float) –

    默认为:6e-5。学习率。

  • num_train_epochs (int) –

    默认为:1。要执行的总训练周期数。

  • per_device_train_batch_size (int) –

    默认为:2。训练批量大小。

  • gradient_accumulation_steps (int) –

    默认为:1。在执行反向/更新传递之前要累积的更新步骤数。

  • dataloader_drop_last (bool) –

    默认为:True。如果数据集大小不能被批量大小整除,则丢弃最后一个不完整的批量,即 DataLoader 只返回完整的批量。

  • warmup_ratio (float) –

    默认为:0.1。线性调度器的预热比率。

  • weight_decay (float) –

    默认为:0.01。AdamW 中的权重衰减。

  • deepspeed (str) –

    默认为:``。DeepSpeed 配置文件的路径,默认使用 LazyLLM 代码仓库中的预置文件:ds_stage0.json``。

  • logging_steps (int) –

    默认为:1。更新日志的频率。

  • save_steps (int) –

    默认为:1000。保存频率。

  • overwrite_output_dir (bool) –

    默认为:True。用于允许程序覆盖现有的输出目录。

  • fp16 (bool) –

    默认为:True。是否使用 fp16(混合)精度而不是 32 位。

  • gradient_checkpointing (bool) –

    默认为:True。是否启用梯度检查点。

Examples:

>>> from lazyllm import finetune
>>> finetune.FlagembeddingFinetune('bge-m3', 'path/to/target')
<lazyllm.llm.finetune type=FlagembeddingFinetune>
Source code in lazyllm/components/finetune/flagembedding.py
class FlagembeddingFinetune(LazyLLMFinetuneBase):
    """该类是 ``LazyLLMFinetuneBase`` 的子类,基于 [FlagEmbedding](https://github.com/FlagOpen/FlagEmbedding) 框架提供的训练能力,用于训练嵌入和重排模型。

Args:
    base_model (str): 用于训练的基础模型。必须是基础模型的路径。
    target_path (str): 训练后模型权重保存的路径。
    launcher (lazyllm.launcher): 微调的启动器,默认为 ``launchers.remote(ngpus=1, sync=True)``。
    kw: 用于更新默认训练参数的关键字参数。

该类嵌入模型的关键字参数及其默认值如下:

Keyword Args:
    train_group_size (int): 默认为:``8``。训练组的大小。用于控制每个训练集中的负样本数量。
    query_max_len (int): 默认为:``512``。经过分词后,段落的最大总输入序列长度。超过此长度的序列将被截断,较短的序列将被填充。
    passage_max_len (int): 默认为:``512``。经过分词后,段落的最大总输入序列长度。超过此长度的序列将被截断,较短的序列将被填充。
    pad_to_multiple_of (int): 默认为:``8``。如果设置,将序列填充为提供值的倍数。
    query_instruction_for_retrieval (str): 默认为:``Represent this sentence for searching relevant passages: ``。查询query的指令。
    query_instruction_format (str): 默认为:``{}{}``。查询指令格式。
    learning_rate (float): 默认为:``1e-5``。学习率。
    num_train_epochs (int): 默认为:``1``。要执行的总训练周期数。
    per_device_train_batch_size (int): 默认为:``2``。训练批量大小。
    gradient_accumulation_steps (int): 默认为:``1``。在执行反向/更新传递之前要累积的更新步骤数。
    dataloader_drop_last (bool): 默认为:``True``。如果数据集大小不能被批量大小整除,则丢弃最后一个不完整的批量,即 DataLoader 只返回完整的批量。
    warmup_ratio (float): 默认为:``0.1``。线性调度器的预热比率。
    weight_decay (float): 默认为:``0.01``。AdamW 中的权重衰减。
    deepspeed (str): 默认为:````。DeepSpeed 配置文件的路径,默认使用 LazyLLM 代码仓库中的预置文件:``ds_stage0.json``。
    logging_steps (int): 默认为:``1``。更新日志的频率。
    save_steps (int): 默认为:``1000``。保存频率。
    temperature (float): 默认为:``0.02``。用于相似度评分的温度。
    sentence_pooling_method (str): 默认为:``cls``。池化方法。可用选项:'cls', 'mean', 'last_token'。
    normalize_embeddings (bool): 默认为:``True``。是否归一化嵌入。
    kd_loss_type (str): 默认为:``kl_div``。知识蒸馏的损失类型。可用选项:'kl_div', 'm3_kd_loss'。
    overwrite_output_dir (bool): 默认为:``True``。用于允许程序覆盖现有的输出目录。
    fp16 (bool): 默认为:``True``。是否使用 fp16(混合)精度而不是 32 位。
    gradient_checkpointing (bool): 默认为:``True``。是否启用梯度检查点。
    negatives_cross_device (bool): 默认为:``True``。是否在设备间共享负样本。

该类重排模型的关键字参数及其默认值如下:

Keyword Args:
    train_group_size (int): 默认为:``8``。训练组的大小。用于控制每个训练集中的负样本数量。
    query_max_len (int): 默认为:``256``。经过分词后,段落的最大总输入序列长度。超过此长度的序列将被截断,较短的序列将被填充。
    passage_max_len (int): 默认为:``256``。经过分词后,段落的最大总输入序列长度。超过此长度的序列将被截断,较短的序列将被填充。
    pad_to_multiple_of (int): 默认为:``8``。如果设置,将序列填充为提供值的倍数。
    learning_rate (float): 默认为:``6e-5``。学习率。
    num_train_epochs (int): 默认为:``1``。要执行的总训练周期数。
    per_device_train_batch_size (int): 默认为:``2``。训练批量大小。
    gradient_accumulation_steps (int): 默认为:``1``。在执行反向/更新传递之前要累积的更新步骤数。
    dataloader_drop_last (bool): 默认为:``True``。如果数据集大小不能被批量大小整除,则丢弃最后一个不完整的批量,即 DataLoader 只返回完整的批量。
    warmup_ratio (float): 默认为:``0.1``。线性调度器的预热比率。
    weight_decay (float): 默认为:``0.01``。AdamW 中的权重衰减。
    deepspeed (str): 默认为:````。DeepSpeed 配置文件的路径,默认使用 LazyLLM 代码仓库中的预置文件:``ds_stage0.json``。
    logging_steps (int): 默认为:``1``。更新日志的频率。
    save_steps (int): 默认为:``1000``。保存频率。
    overwrite_output_dir (bool): 默认为:``True``。用于允许程序覆盖现有的输出目录。
    fp16 (bool): 默认为:``True``。是否使用 fp16(混合)精度而不是 32 位。
    gradient_checkpointing (bool): 默认为:``True``。是否启用梯度检查点。


Examples:
    >>> from lazyllm import finetune
    >>> finetune.FlagembeddingFinetune('bge-m3', 'path/to/target')
    <lazyllm.llm.finetune type=FlagembeddingFinetune>
    """
    defatult_embed_kw = ArgsDict({
        'train_group_size': 8,
        'query_max_len': 512,
        'passage_max_len': 512,
        'pad_to_multiple_of': 8,
        'query_instruction_for_retrieval': 'Represent this sentence for searching relevant passages: ',
        'query_instruction_format': '{}{}',
        'learning_rate': 1e-5,
        'num_train_epochs': 1,
        'per_device_train_batch_size': 2,
        'gradient_accumulation_steps': 1,
        'dataloader_drop_last': True,
        'warmup_ratio': 0.1,
        'weight_decay': 0.01,
        'deepspeed': '',
        'logging_steps': 1,
        'save_steps': 1000,
        'temperature': 0.02,
        'sentence_pooling_method': 'cls',
        'normalize_embeddings': True,
        'kd_loss_type': 'kl_div',
        'overwrite_output_dir': True,
        'fp16': True,
        'gradient_checkpointing': True,
        'negatives_cross_device': True
    })
    defatult_rerank_kw = ArgsDict({
        'train_group_size': 8,
        'query_max_len': 256,
        'passage_max_len': 256,
        'pad_to_multiple_of': 8,
        'learning_rate': 6e-5,
        'num_train_epochs': 1,
        'per_device_train_batch_size': 2,
        'gradient_accumulation_steps': 1,
        'dataloader_drop_last': True,
        'warmup_ratio': 0.1,
        'weight_decay': 0.01,
        'deepspeed': '',
        'logging_steps': 1,
        'save_steps': 1000,
        'overwrite_output_dir': True,
        'fp16': True,
        'gradient_checkpointing': True
    })
    store_true_embed_kw = {'overwrite_output_dir', 'fp16', 'gradient_checkpointing', 'negatives_cross_device'}
    store_true_rerank_kw = {'overwrite_output_dir', 'fp16', 'gradient_checkpointing'}

    def __init__(
        self,
        base_model,
        target_path,
        launcher=launchers.remote(ngpus=1, sync=True),  # noqa B008
        **kw
    ):
        model_type = ModelManager.get_model_type(base_model.split('/')[-1])
        if model_type not in ('embed', 'rerank'):
            raise RuntimeError(f'Not supported {model_type} type to finetune.')
        if not os.path.exists(base_model):
            defatult_path = os.path.join(lazyllm.config['model_path'], base_model)
            if os.path.exists(defatult_path):
                base_model = defatult_path
        save_path = os.path.join(lazyllm.config['train_target_root'], target_path)
        target_path = os.path.join(save_path, model_type)
        os.system(f'mkdir -p {target_path}')
        super().__init__(
            base_model,
            target_path,
            launcher=launcher,
        )
        if model_type == 'reranker':
            self.kw = copy.deepcopy(self.defatult_rerank_kw)
            self.store_true_kw = copy.deepcopy(self.store_true_rerank_kw)
            self.module_run_path = 'FlagEmbedding.finetune.reranker.encoder_only.base'
        else:
            self.kw = copy.deepcopy(self.defatult_embed_kw)
            self.store_true_kw = copy.deepcopy(self.store_true_embed_kw)
            self.module_run_path = 'FlagEmbedding.finetune.embedder.encoder_only.base'
        self.kw.check_and_update(kw)
        if not self.kw['deepspeed']:
            folder_path = os.path.dirname(os.path.abspath(__file__))
            deepspeed_config_path = os.path.join(folder_path, 'flag_embedding', 'ds_stage0.json')
            self.kw['deepspeed'] = deepspeed_config_path
        self.nproc_per_node = launcher.ngpus

    def cmd(self, trainset, valset=None) -> str:
        thirdparty.check_packages(['flagembedding'])
        self.kw['train_data'] = trainset

        formatted_date = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
        self.log_file_path = f'{self.target_path}/train_log_{formatted_date}_{random.randint(1000, 9999)}.log'
        cache_path = os.path.join(os.path.expanduser(lazyllm.config['home']), 'fintune', 'embeding')
        cache_model_path = os.path.join(cache_path, 'model')
        cache_data_path = os.path.join(cache_path, 'data')
        os.system(f'mkdir -p {cache_model_path} {cache_data_path}')

        cmds = (f'export WANDB_MODE=disabled && torchrun --nproc_per_node {self.nproc_per_node} '
                f'-m {self.module_run_path} '
                f'--model_name_or_path {self.base_model} '
                f'--output_dir {self.target_path} '
                f'--cache_dir {cache_model_path} '
                f'--cache_path {cache_data_path} '
            )
        for key in self.store_true_kw:
            cmds += f'--{key} ' if self.kw.pop(key) else ''
        cmds += self.kw.parse_kwargs()
        cmds += f' 2>&1 | tee {self.log_file_path}'
        return cmds

lazyllm.components.auto.AutoFinetune

Bases: LazyLLMFinetuneBase

此类是 LazyLLMFinetuneBase 的子类,可根据输入的参数自动选择合适的微调框架和参数,以对大语言模型进行微调。

具体而言,基于输入的:base_model 的模型参数、ctx_lenbatch_sizelora_rlauncher 中GPU的类型以及卡数,该类可以自动选择出合适的微调框架(如: AlpacaloraFinetuneCollieFinetune)及所需的参数。

Parameters:

  • base_model (str) –

    用于进行微调的基模型。要求是基模型的路径。

  • source (config[model_source]) –

    指定模型的下载源。可通过设置环境变量 LAZYLLM_MODEL_SOURCE 来配置,目前仅支持 huggingfacemodelscope 。若不设置,lazyllm不会启动自动模型下载。

  • target_path (str) –

    微调后模型保存LoRA权重的路径。

  • merge_path (str) –

    模型合并LoRA权重后的路径,默认为 None。如果未指定,则会在 target_path 下创建 "lazyllm_lora" 和 "lazyllm_merge" 目录,分别作为 target_pathmerge_path

  • ctx_len (int) –

    输入微调模型的token最大长度,默认为 1024

  • batch_size (int) –

    批处理大小,默认为 32

  • lora_r (int) –

    LoRA 的秩,默认为 8;该数值决定添加参数的量,数值越小参数量越小。

  • launcher (launcher, default: remote() ) –

    微调的启动器,默认为 launchers.remote(ngpus=1)

  • kw

    关键字参数,用于更新默认的训练参数。注意这里能够指定的关键字参数取决于 LazyLLM 推测出的框架,因此建议谨慎设置。

Examples:

>>> from lazyllm import finetune
>>> finetune.auto("internlm2-chat-7b", 'path/to/target')
<lazyllm.llm.finetune type=AlpacaloraFinetune>
Source code in lazyllm/components/auto/autofinetune.py
class AutoFinetune(LazyLLMFinetuneBase):
    """此类是 ``LazyLLMFinetuneBase`` 的子类,可根据输入的参数自动选择合适的微调框架和参数,以对大语言模型进行微调。

具体而言,基于输入的:``base_model`` 的模型参数、``ctx_len``、``batch_size``、``lora_r``、``launcher`` 中GPU的类型以及卡数,该类可以自动选择出合适的微调框架(如: ``AlpacaloraFinetune`` 或 ``CollieFinetune``)及所需的参数。

Args:
    base_model (str): 用于进行微调的基模型。要求是基模型的路径。
    source (lazyllm.config['model_source']): 指定模型的下载源。可通过设置环境变量 ``LAZYLLM_MODEL_SOURCE`` 来配置,目前仅支持 ``huggingface`` 或 ``modelscope`` 。若不设置,lazyllm不会启动自动模型下载。
    target_path (str): 微调后模型保存LoRA权重的路径。
    merge_path (str): 模型合并LoRA权重后的路径,默认为 ``None``。如果未指定,则会在 ``target_path`` 下创建 "lazyllm_lora" 和 "lazyllm_merge" 目录,分别作为 ``target_path`` 和  ``merge_path`` 。
    ctx_len (int): 输入微调模型的token最大长度,默认为 ``1024``。
    batch_size (int): 批处理大小,默认为 ``32``。
    lora_r (int): LoRA 的秩,默认为 ``8``;该数值决定添加参数的量,数值越小参数量越小。
    launcher (lazyllm.launcher): 微调的启动器,默认为 ``launchers.remote(ngpus=1)``。
    kw: 关键字参数,用于更新默认的训练参数。注意这里能够指定的关键字参数取决于 LazyLLM 推测出的框架,因此建议谨慎设置。


Examples:
    >>> from lazyllm import finetune
    >>> finetune.auto("internlm2-chat-7b", 'path/to/target')
    <lazyllm.llm.finetune type=AlpacaloraFinetune>
    """
    def __new__(cls, base_model, target_path, source=lazyllm.config['model_source'], merge_path=None, ctx_len=1024,
                batch_size=32, lora_r=8, launcher=launchers.remote(ngpus=1), **kw):  # noqa B008
        base_model = ModelManager(source).download(base_model) or ''
        model_name = get_model_name(base_model)
        model_type = ModelManager.get_model_type(model_name)
        if model_type in ['embed', 'tts', 'vlm', 'stt', 'sd']:
            raise RuntimeError(f'Fine-tuning of the {model_type} model is not currently supported.')
        map_name, _ = model_map(model_name)
        base_name = model_name.split('-')[0].split('_')[0].lower()
        candidates = get_configer().query_finetune(lazyllm.config['gpu_type'], launcher.ngpus,
                                                   map_name, ctx_len, batch_size, lora_r)
        configs = get_configs(base_name)

        for k, v in configs.items():
            if k not in kw: kw[k] = v

        for c in candidates:
            if check_requirements(requirements[c.framework.lower()]):
                finetune_cls = getattr(finetune, c.framework.lower())
                for key, value in finetune_cls.auto_map.items():
                    if value:
                        kw[value] = getattr(c, key)
                if finetune_cls.__name__ == 'LlamafactoryFinetune':
                    return finetune_cls(base_model, target_path, lora_r=lora_r, launcher=launcher, **kw)
                return finetune_cls(base_model, target_path, merge_path, cp_files='tokeniz*',
                                    batch_size=batch_size, lora_r=lora_r, launcher=launcher, **kw)
        raise RuntimeError(f'No valid framework found, candidates are {[c.framework.lower() for c in candidates]}')

lazyllm.components.finetune.base.DummyFinetune

Bases: LazyLLMFinetuneBase

DummyFinetune 是 LazyLLMFinetuneBase 的子类,用于占位实现微调逻辑。 此类主要用于演示或测试目的,因为它不执行任何实际的微调操作。

Parameters:

  • base_model

    字符串,指定基础模型的名称,默认为 'base'。

  • target_path

    字符串,指定微调输出的目标路径,默认为 'target'。

  • launcher

    启动器实例,用于执行命令。默认为 [launchers.remote()][lazyllm.launchers.remote]。

  • **kw

    其他关键字参数,这些参数会被保存以供后续使用。

Returns:

  • 一个字符串,表示一个占位命令。该字符串包括初始化时传递的参数。

Examples:

>>> from lazyllm.components import DummyFinetune
>>> from lazyllm import launchers
>>> # 创建一个 DummyFinetune 实例
>>> finetuner = DummyFinetune(base_model='example-base', target_path='example-target', launcher=launchers.local(), custom_arg='custom_value')
>>> # 调用 cmd 方法生成占位命令
>>> command = finetuner.cmd('--example-arg', key='value')
>>> print(command)
... echo 'dummy finetune!, and init-args is {'custom_arg': 'custom_value'}'
Source code in lazyllm/components/finetune/base.py
class DummyFinetune(LazyLLMFinetuneBase):
    """DummyFinetune 是 [LazyLLMFinetuneBase][lazyllm.components.LazyLLMFinetuneBase] 的子类,用于占位实现微调逻辑。
此类主要用于演示或测试目的,因为它不执行任何实际的微调操作。

Args:
    base_model: 字符串,指定基础模型的名称,默认为 'base'。
    target_path: 字符串,指定微调输出的目标路径,默认为 'target'。
    launcher: 启动器实例,用于执行命令。默认为 [launchers.remote()][lazyllm.launchers.remote]。
    **kw: 其他关键字参数,这些参数会被保存以供后续使用。

Returns:
    一个字符串,表示一个占位命令。该字符串包括初始化时传递的参数。


Examples:
    >>> from lazyllm.components import DummyFinetune
    >>> from lazyllm import launchers
    >>> # 创建一个 DummyFinetune 实例
    >>> finetuner = DummyFinetune(base_model='example-base', target_path='example-target', launcher=launchers.local(), custom_arg='custom_value')
    >>> # 调用 cmd 方法生成占位命令
    >>> command = finetuner.cmd('--example-arg', key='value')
    >>> print(command)
    ... echo 'dummy finetune!, and init-args is {'custom_arg': 'custom_value'}'
    """
    def __init__(self, base_model='base', target_path='target', *, launcher=launchers.remote(), **kw):  # noqa B008
        super().__init__(base_model, target_path, launcher=launchers.empty)
        self.kw = kw

    def cmd(self, *args, **kw) -> str:
        """`cmd` 方法生成一个用于微调的占位命令字符串。此方法主要用于测试或演示目的。

Args:
    *args: 要包含在命令中的位置参数(在本实现中未使用)。
    **kw: 要包含在命令中的关键字参数(在本实现中未使用)。

Returns:
    一个字符串,表示一个占位命令。该字符串包括初始化时传递的关键字参数 (`**kw`),存储在 `self.kw` 中。

Example:
    如果类初始化时使用 `custom_arg='value'`,调用 `cmd` 方法将返回:
    `"echo 'dummy finetune!, and init-args is {'custom_arg': 'value'}'"`


Examples:
    >>> from lazyllm.components import DummyFinetune
    >>> from lazyllm import launchers
    >>> # 创建一个 DummyFinetune 实例,并传递初始化参数
    >>> finetuner = DummyFinetune(base_model='example-base', target_path='example-target', launcher=launchers.local(), custom_arg='value')
    >>> # 调用 cmd 方法生成占位命令
    >>> command = finetuner.cmd()
    >>> # 打印生成的占位命令
    >>> print(command)
    ... echo 'dummy finetune!, and init-args is {'custom_arg': 'value'}'
    """
        return f'echo \'dummy finetune!, and init-args is {self.kw}\''

cmd(*args, **kw)

cmd 方法生成一个用于微调的占位命令字符串。此方法主要用于测试或演示目的。

Parameters:

  • *args

    要包含在命令中的位置参数(在本实现中未使用)。

  • **kw

    要包含在命令中的关键字参数(在本实现中未使用)。

Returns:

  • str

    一个字符串,表示一个占位命令。该字符串包括初始化时传递的关键字参数 (**kw),存储在 self.kw 中。

Example

如果类初始化时使用 custom_arg='value',调用 cmd 方法将返回: "echo 'dummy finetune!, and init-args is {'custom_arg': 'value'}'"

Examples:

>>> from lazyllm.components import DummyFinetune
>>> from lazyllm import launchers
>>> # 创建一个 DummyFinetune 实例,并传递初始化参数
>>> finetuner = DummyFinetune(base_model='example-base', target_path='example-target', launcher=launchers.local(), custom_arg='value')
>>> # 调用 cmd 方法生成占位命令
>>> command = finetuner.cmd()
>>> # 打印生成的占位命令
>>> print(command)
... echo 'dummy finetune!, and init-args is {'custom_arg': 'value'}'
Source code in lazyllm/components/finetune/base.py
    def cmd(self, *args, **kw) -> str:
        """`cmd` 方法生成一个用于微调的占位命令字符串。此方法主要用于测试或演示目的。

Args:
    *args: 要包含在命令中的位置参数(在本实现中未使用)。
    **kw: 要包含在命令中的关键字参数(在本实现中未使用)。

Returns:
    一个字符串,表示一个占位命令。该字符串包括初始化时传递的关键字参数 (`**kw`),存储在 `self.kw` 中。

Example:
    如果类初始化时使用 `custom_arg='value'`,调用 `cmd` 方法将返回:
    `"echo 'dummy finetune!, and init-args is {'custom_arg': 'value'}'"`


Examples:
    >>> from lazyllm.components import DummyFinetune
    >>> from lazyllm import launchers
    >>> # 创建一个 DummyFinetune 实例,并传递初始化参数
    >>> finetuner = DummyFinetune(base_model='example-base', target_path='example-target', launcher=launchers.local(), custom_arg='value')
    >>> # 调用 cmd 方法生成占位命令
    >>> command = finetuner.cmd()
    >>> # 打印生成的占位命令
    >>> print(command)
    ... echo 'dummy finetune!, and init-args is {'custom_arg': 'value'}'
    """
        return f'echo \'dummy finetune!, and init-args is {self.kw}\''

lazyllm.components.finetune.LazyLLMFinetuneBase

Bases: ComponentBase

LazyLLM微调基础组件类,继承自ComponentBase。

提供大语言模型微调的基础功能,支持远程启动器配置和模型路径管理。

Parameters:

  • base_model (str) –

    基础模型路径或标识

  • target_path (str) –

    微调后模型输出路径

  • launcher (Launcher, default: remote() ) –

    任务启动器,默认为远程启动器

Source code in lazyllm/components/finetune/base.py
class LazyLLMFinetuneBase(ComponentBase):
    """LazyLLM微调基础组件类,继承自ComponentBase。

提供大语言模型微调的基础功能,支持远程启动器配置和模型路径管理。

Args:
    base_model (str): 基础模型路径或标识
    target_path (str): 微调后模型输出路径
    launcher (Launcher, optional): 任务启动器,默认为远程启动器
"""
    __reg_overwrite__ = 'cmd'

    def __init__(self, base_model, target_path, *, launcher=launchers.remote()):  # noqa B008
        super().__init__(launcher=launcher)
        self.base_model = base_model
        self.target_path = target_path
        self.merge_path = None

    def __call__(self, *args, **kw):
        super().__call__(*args, **kw)
        if self.merge_path:
            return self.merge_path
        else:
            return self.target_path

lazyllm.components.auto.configure.core.configuration.AutoConfig

Bases: object

自动配置类,用于管理和查询微调和部署的配置参数。

Parameters:

  • finetune_file (str) –

    微调配置文件路径,CSV格式。

  • deploy_file (str) –

    部署配置文件路径,CSV格式。

Source code in lazyllm/components/auto/configure/core/configuration.py
class AutoConfig(object):
    """自动配置类,用于管理和查询微调和部署的配置参数。

Args:
    finetune_file (str): 微调配置文件路径,CSV格式。
    deploy_file (str): 部署配置文件路径,CSV格式。
"""
    def __init__(self, finetune_file, deploy_file):
        with open(finetune_file) as file:
            reader = csv.reader(file)
            self._finetune = Configurations(FINETUNE_RULE_SET).parse_header(next(reader)).parse_values(reader)
        with open(deploy_file) as file:
            reader = csv.reader(file)
            self._deploy = Configurations(DEPLOY_RULE_SET).parse_header(next(reader)).parse_values(reader)

    def _query(self, *, clazz: type[OutputConfiguration], **kw) -> List[OutputConfiguration]:
        cf = self._finetune if clazz == TrainingConfiguration else self._deploy
        configurations = [clazz.from_dict(arguments) for arguments in cf.lookup({k.upper(): v for k, v in kw.items()})]
        configurations.sort(key=lambda x: x.tgs, reverse=True)
        return configurations

    def query_finetune(self, gpu_type: str, gpu_num: int, model_name: str,
                       ctx_len: int, batch_size: int, lora_r: int):
        """查询微调配置参数。

Args:
    gpu_type (str): GPU类型。
    gpu_num (int): GPU数量。
    model_name (str): 模型名称。
    ctx_len (int): 上下文长度。
    batch_size (int): 批处理大小。
    lora_r (int): LoRA秩。

**Returns:**

- List[TrainingConfiguration]: 返回按TGS(训练吞吐量得分)降序排序的训练配置列表。
"""
        return self._query(clazz=TrainingConfiguration, gpu_type=gpu_type, gpu_num=gpu_num, model_name=model_name,
                           ctx_len=ctx_len, batch_size=batch_size, lora_r=lora_r)

    def query_deploy(self, gpu_type: str, gpu_num: int, model_name: str, max_token_num):
        """查询部署配置参数。

Args:
    gpu_type (str): GPU类型。
    gpu_num (int): GPU数量。
    model_name (str): 模型名称。
    max_token_num (int): 最大token数量。

**Returns:**

- List[DeployConfiguration]: 返回按TGS(推理吞吐量得分)降序排序的部署配置列表。
"""
        return self._query(clazz=DeployConfiguration, gpu_type=gpu_type, gpu_num=gpu_num,
                           model_name=model_name, max_token_num=max_token_num)

query_finetune(gpu_type, gpu_num, model_name, ctx_len, batch_size, lora_r)

查询微调配置参数。

Parameters:

  • gpu_type (str) –

    GPU类型。

  • gpu_num (int) –

    GPU数量。

  • model_name (str) –

    模型名称。

  • ctx_len (int) –

    上下文长度。

  • batch_size (int) –

    批处理大小。

  • lora_r (int) –

    LoRA秩。

Returns:

  • List[TrainingConfiguration]: 返回按TGS(训练吞吐量得分)降序排序的训练配置列表。
Source code in lazyllm/components/auto/configure/core/configuration.py
    def query_finetune(self, gpu_type: str, gpu_num: int, model_name: str,
                       ctx_len: int, batch_size: int, lora_r: int):
        """查询微调配置参数。

Args:
    gpu_type (str): GPU类型。
    gpu_num (int): GPU数量。
    model_name (str): 模型名称。
    ctx_len (int): 上下文长度。
    batch_size (int): 批处理大小。
    lora_r (int): LoRA秩。

**Returns:**

- List[TrainingConfiguration]: 返回按TGS(训练吞吐量得分)降序排序的训练配置列表。
"""
        return self._query(clazz=TrainingConfiguration, gpu_type=gpu_type, gpu_num=gpu_num, model_name=model_name,
                           ctx_len=ctx_len, batch_size=batch_size, lora_r=lora_r)

query_deploy(gpu_type, gpu_num, model_name, max_token_num)

查询部署配置参数。

Parameters:

  • gpu_type (str) –

    GPU类型。

  • gpu_num (int) –

    GPU数量。

  • model_name (str) –

    模型名称。

  • max_token_num (int) –

    最大token数量。

Returns:

  • List[DeployConfiguration]: 返回按TGS(推理吞吐量得分)降序排序的部署配置列表。
Source code in lazyllm/components/auto/configure/core/configuration.py
    def query_deploy(self, gpu_type: str, gpu_num: int, model_name: str, max_token_num):
        """查询部署配置参数。

Args:
    gpu_type (str): GPU类型。
    gpu_num (int): GPU数量。
    model_name (str): 模型名称。
    max_token_num (int): 最大token数量。

**Returns:**

- List[DeployConfiguration]: 返回按TGS(推理吞吐量得分)降序排序的部署配置列表。
"""
        return self._query(clazz=DeployConfiguration, gpu_type=gpu_type, gpu_num=gpu_num,
                           model_name=model_name, max_token_num=max_token_num)

Deploy

lazyllm.components.deploy.Lightllm

Bases: LazyLLMDeployBase

此类是 LazyLLMDeployBase 的子类,基于 LightLLM 框架提供的推理能力,用于对大语言模型进行推理。

Parameters:

  • trust_remote_code (bool, default: True ) –

    是否信任远程代码,默认为True

  • launcher (Launcher, default: remote(ngpus=1) ) –

    任务启动器,默认为单GPU远程启动器

  • log_path (str, default: None ) –

    日志文件路径,默认为None

  • **kw

    其他LightLLM服务器配置参数

此类的关键字参数及其默认值如下:

Other Parameters:

  • tp (int) –

    张量并行参数,默认为 1

  • max_total_token_num (int) –

    最大总token数,默认为 64000

  • eos_id (int) –

    结束符ID,默认为 2

  • port (int) –

    服务的端口号,默认为 None。此情况下LazyLLM会自动生成随机端口号。

  • host (str) –

    服务的IP地址,默认为 0.0.0.0

  • nccl_port (int) –

    NCCL 端口,默认为 None。此情况下LazyLLM会自动生成随机端口号。

  • tokenizer_mode (str) –

    tokenizer的加载模式,默认为 auto

  • running_max_req_size (int) –

    推理引擎最大的并行请求数, 默认为 256

  • data_type (str) –

    模型权重的数据类型,默认为 float16

  • max_req_total_len (int) –

    请求的最大总长度,默认为 64000

  • max_req_input_len (int) –

    输入的最大长度,默认为 4096

  • long_truncation_mode (str) –

    长文本的截断模式,默认为 head

Examples:

>>> from lazyllm import deploy
>>> infer = deploy.lightllm()
Source code in lazyllm/components/deploy/lightllm.py
class Lightllm(LazyLLMDeployBase):
    """此类是 ``LazyLLMDeployBase`` 的子类,基于 [LightLLM](https://github.com/ModelTC/lightllm) 框架提供的推理能力,用于对大语言模型进行推理。

Args:
    trust_remote_code (bool, optional): 是否信任远程代码,默认为True
    launcher (Launcher, optional): 任务启动器,默认为单GPU远程启动器
    log_path (str, optional): 日志文件路径,默认为None
    **kw: 其他LightLLM服务器配置参数
此类的关键字参数及其默认值如下:

Keyword Args: 
    tp (int): 张量并行参数,默认为 ``1``。
    max_total_token_num (int): 最大总token数,默认为 ``64000``。
    eos_id (int): 结束符ID,默认为 ``2``。
    port (int): 服务的端口号,默认为 ``None``。此情况下LazyLLM会自动生成随机端口号。
    host (str): 服务的IP地址,默认为 ``0.0.0.0``。
    nccl_port (int): NCCL 端口,默认为 ``None``。此情况下LazyLLM会自动生成随机端口号。
    tokenizer_mode (str): tokenizer的加载模式,默认为 ``auto``。
    running_max_req_size (int): 推理引擎最大的并行请求数, 默认为 ``256``。
    data_type (str): 模型权重的数据类型,默认为 ``float16``。
    max_req_total_len (int): 请求的最大总长度,默认为 ``64000``。
    max_req_input_len (int): 输入的最大长度,默认为 ``4096``。
    long_truncation_mode (str): 长文本的截断模式,默认为 ``head``。


Examples:
    >>> from lazyllm import deploy
    >>> infer = deploy.lightllm()
    """
    keys_name_handle = {
        'inputs': 'inputs',
        'stop': 'stop_sequences'
    }
    default_headers = {'Content-Type': 'application/json'}
    message_format = {
        'inputs': 'Who are you ?',
        'parameters': {
            'do_sample': False,
            'presence_penalty': 0.0,
            'frequency_penalty': 0.0,
            'repetition_penalty': 1.0,
            'temperature': 1.0,
            'top_p': 1,
            'top_k': -1,  # -1 is for all
            'ignore_eos': False,
            'max_new_tokens': 8192,
            'stop_sequences': None,
        }
    }
    auto_map = {}
    stream_url_suffix = '_stream'
    stream_parse_parameters = {'delimiter': b'\n\n'}

    def __init__(self, trust_remote_code=True, launcher=launchers.remote(ngpus=1), log_path=None, # noqa B008
                 openai_api: Optional[bool] = None, **kw):
        super().__init__(launcher=launcher)
        self.kw = ArgsDict({
            'tp': 1,
            'max_total_token_num': 64000,
            'eos_id': 2,
            'port': None,
            'host': '0.0.0.0',
            'nccl_port': None,
            'tokenizer_mode': 'auto',
            'running_max_req_size': 256,
            'data_type': 'float16',
            'max_req_total_len': 64000,
            'max_req_input_len': 4096,
            'long_truncation_mode': 'head',
        })
        self.options_keys = kw.pop('options_keys', [])
        if trust_remote_code and 'trust_remote_code' not in self.options_keys:
            self.options_keys.append('trust_remote_code')
        self.kw.check_and_update(kw)
        self.random_port = False if 'port' in kw and kw['port'] else True
        self.random_nccl_port = False if 'nccl_port' in kw and kw['nccl_port'] else True
        self.temp_folder = make_log_dir(log_path, 'lightllm') if log_path else None

    def cmd(self, finetuned_model=None, base_model=None):
        """该方法用于生成启动LightLLM服务的命令。

Args:
    finetuned_model (str): 微调后的模型路径。
    base_model (str): 基础模型路径,当finetuned_model无效时使用。

**Returns:**

- LazyLLMCMD: 一个包含启动命令的LazyLLMCMD对象。
"""
        if not os.path.exists(finetuned_model) or \
            not any(filename.endswith('.bin') or filename.endswith('.safetensors')
                    for filename in os.listdir(finetuned_model)):
            if not finetuned_model:
                LOG.warning(f'Note! That finetuned_model({finetuned_model}) is an invalid path, '
                            f'base_model({base_model}) will be used')
            finetuned_model = base_model

        def impl():
            if self.random_port:
                self.kw['port'] = random.randint(30000, 40000)
            if self.random_nccl_port:
                self.kw['nccl_port'] = random.randint(20000, 30000)
            cmd = f'python -m lightllm.server.api_server --model_dir {finetuned_model} '
            cmd += self.kw.parse_kwargs()
            cmd += ' ' + parse_options_keys(self.options_keys)
            if self.temp_folder: cmd += f' 2>&1 | tee {get_log_path(self.temp_folder)}'
            return cmd

        return LazyLLMCMD(cmd=impl, return_value=self.geturl, checkf=verify_fastapi_func)

    def geturl(self, job=None):
        """获取LightLLM服务的URL地址。

Args:
    job (optional): 任务对象,默认为None,此时使用self.job。

**Returns:**

- str: 服务的URL地址,格式为"http://{ip}:{port}/generate"。
"""
        if job is None:
            job = self.job
        if lazyllm.config['mode'] == lazyllm.Mode.Display:
            return 'http://{ip}:{port}/generate'
        else:
            return f'http://{job.get_jobip()}:{self.kw["port"]}/generate'

    @staticmethod
    def extract_result(x, inputs):
        """从服务响应中提取生成的文本结果。

Args:
    x (str): 服务返回的响应文本。
    inputs (str): 输入文本。

**Returns:**

- str: 提取出的生成文本。

异常:
    Exception: 当解析JSON响应失败时抛出异常。
"""
        try:
            if x.startswith('data:'): return json.loads(x[len('data:'):])['token']['text']
            else: return json.loads(x)['generated_text'][0]
        except Exception as e:
            LOG.warning(f'JSONDecodeError on load {x}')
            raise e

cmd(finetuned_model=None, base_model=None)

该方法用于生成启动LightLLM服务的命令。

Parameters:

  • finetuned_model (str, default: None ) –

    微调后的模型路径。

  • base_model (str, default: None ) –

    基础模型路径,当finetuned_model无效时使用。

Returns:

  • LazyLLMCMD: 一个包含启动命令的LazyLLMCMD对象。
Source code in lazyllm/components/deploy/lightllm.py
    def cmd(self, finetuned_model=None, base_model=None):
        """该方法用于生成启动LightLLM服务的命令。

Args:
    finetuned_model (str): 微调后的模型路径。
    base_model (str): 基础模型路径,当finetuned_model无效时使用。

**Returns:**

- LazyLLMCMD: 一个包含启动命令的LazyLLMCMD对象。
"""
        if not os.path.exists(finetuned_model) or \
            not any(filename.endswith('.bin') or filename.endswith('.safetensors')
                    for filename in os.listdir(finetuned_model)):
            if not finetuned_model:
                LOG.warning(f'Note! That finetuned_model({finetuned_model}) is an invalid path, '
                            f'base_model({base_model}) will be used')
            finetuned_model = base_model

        def impl():
            if self.random_port:
                self.kw['port'] = random.randint(30000, 40000)
            if self.random_nccl_port:
                self.kw['nccl_port'] = random.randint(20000, 30000)
            cmd = f'python -m lightllm.server.api_server --model_dir {finetuned_model} '
            cmd += self.kw.parse_kwargs()
            cmd += ' ' + parse_options_keys(self.options_keys)
            if self.temp_folder: cmd += f' 2>&1 | tee {get_log_path(self.temp_folder)}'
            return cmd

        return LazyLLMCMD(cmd=impl, return_value=self.geturl, checkf=verify_fastapi_func)

geturl(job=None)

获取LightLLM服务的URL地址。

Parameters:

  • job (optional, default: None ) –

    任务对象,默认为None,此时使用self.job。

Returns:

  • str: 服务的URL地址,格式为"http://{ip}:{port}/generate"。
Source code in lazyllm/components/deploy/lightllm.py
    def geturl(self, job=None):
        """获取LightLLM服务的URL地址。

Args:
    job (optional): 任务对象,默认为None,此时使用self.job。

**Returns:**

- str: 服务的URL地址,格式为"http://{ip}:{port}/generate"。
"""
        if job is None:
            job = self.job
        if lazyllm.config['mode'] == lazyllm.Mode.Display:
            return 'http://{ip}:{port}/generate'
        else:
            return f'http://{job.get_jobip()}:{self.kw["port"]}/generate'

extract_result(x, inputs) staticmethod

从服务响应中提取生成的文本结果。

Parameters:

  • x (str) –

    服务返回的响应文本。

  • inputs (str) –

    输入文本。

Returns:

  • str: 提取出的生成文本。
异常

Exception: 当解析JSON响应失败时抛出异常。

Source code in lazyllm/components/deploy/lightllm.py
    @staticmethod
    def extract_result(x, inputs):
        """从服务响应中提取生成的文本结果。

Args:
    x (str): 服务返回的响应文本。
    inputs (str): 输入文本。

**Returns:**

- str: 提取出的生成文本。

异常:
    Exception: 当解析JSON响应失败时抛出异常。
"""
        try:
            if x.startswith('data:'): return json.loads(x[len('data:'):])['token']['text']
            else: return json.loads(x)['generated_text'][0]
        except Exception as e:
            LOG.warning(f'JSONDecodeError on load {x}')
            raise e

lazyllm.components.deploy.Vllm

Bases: LazyLLMDeployBase

此类是 LazyLLMDeployBase 的子类,基于 VLLM 框架提供的推理能力,用于大语言模型的部署与推理。

Parameters:

  • trust_remote_code (bool, default: True ) –

    是否允许加载来自远程服务器的模型代码,默认为 True

  • launcher (launcher, default: remote(ngpus=1) ) –

    模型启动器,默认为 launchers.remote(ngpus=1)

  • log_path (str, default: None ) –

    日志保存路径,若为 None 则不保存日志。

  • openai_api (bool, default: None ) –

    是否使用 OpenAI API 接口启动 VLLM 服务,默认为 False

  • kw

    关键字参数,用于更新默认的部署参数。除支持的关键字参数外,不允许传入额外参数。

此类支持的关键字参数及其默认值如下:

Other Parameters:

  • tensor-parallel-size (int) –

    张量并行大小,默认为 1

  • dtype (str) –

    模型权重和激活值的数据类型,默认为 auto。可选:halffloat16bfloat16floatfloat32

  • kv-cache-dtype (str) –

    KV 缓存的数据类型,默认为 auto。可选:fp8fp8_e5m2fp8_e4m3

  • device (str) –

    VLLM 支持的硬件类型,默认为 auto。可选:cudaneuroncpu

  • block-size (int) –

    token 块大小,默认为 16

  • port (int | str) –

    服务端口号,默认为 auto,即随机分配。

  • host (str) –

    服务绑定的 IP 地址,默认为 0.0.0.0

  • seed (int) –

    随机数种子,默认为 0

  • tokenizer_mode (str) –

    Tokenizer 加载模式,默认为 auto

  • max-num-seqs (int) –

    推理引擎支持的最大并行请求数,默认为 256

  • pipeline-parallel-size (int) –

    流水线并行大小,默认为 1

  • max-num-batched-tokens (int) –

    最大批处理 token 数,默认为 64000

Examples:

>>> from lazyllm import deploy
>>> infer = deploy.vllm()
Source code in lazyllm/components/deploy/vllm.py
class Vllm(LazyLLMDeployBase, metaclass=_VllmStreamParseParametersMeta):
    """此类是 ``LazyLLMDeployBase`` 的子类,基于 [VLLM](https://github.com/vllm-project/vllm) 框架提供的推理能力,用于大语言模型的部署与推理。

Args:
    trust_remote_code (bool): 是否允许加载来自远程服务器的模型代码,默认为 ``True``。
    launcher (lazyllm.launcher): 模型启动器,默认为 ``launchers.remote(ngpus=1)``。
    log_path (str): 日志保存路径,若为 ``None`` 则不保存日志。
    openai_api (bool): 是否使用 OpenAI API 接口启动 VLLM 服务,默认为 ``False``。
    kw: 关键字参数,用于更新默认的部署参数。除支持的关键字参数外,不允许传入额外参数。

此类支持的关键字参数及其默认值如下:

Keyword Args: 
    tensor-parallel-size (int): 张量并行大小,默认为 ``1``。
    dtype (str): 模型权重和激活值的数据类型,默认为 ``auto``。可选:``half``、``float16``、``bfloat16``、``float``、``float32``。
    kv-cache-dtype (str): KV 缓存的数据类型,默认为 ``auto``。可选:``fp8``、``fp8_e5m2``、``fp8_e4m3``。
    device (str): VLLM 支持的硬件类型,默认为 ``auto``。可选:``cuda``、``neuron``、``cpu``。
    block-size (int): token 块大小,默认为 ``16``。
    port (int | str): 服务端口号,默认为 ``auto``,即随机分配。
    host (str): 服务绑定的 IP 地址,默认为 ``0.0.0.0``。
    seed (int): 随机数种子,默认为 ``0``。
    tokenizer_mode (str): Tokenizer 加载模式,默认为 ``auto``。
    max-num-seqs (int): 推理引擎支持的最大并行请求数,默认为 ``256``。
    pipeline-parallel-size (int): 流水线并行大小,默认为 ``1``。
    max-num-batched-tokens (int): 最大批处理 token 数,默认为 ``64000``。


Examples:
    >>> from lazyllm import deploy
    >>> infer = deploy.vllm()
    """
    # keys_name_handle/default_headers/message_format will lose efficacy when openai_api is True
    keys_name_handle = {'inputs': 'prompt', 'stop': 'stop'}
    default_headers = {'Content-Type': 'application/json'}
    message_format = {
        'prompt': 'Who are you ?',
        'stream': False,
        'stop': ['<|im_end|>', '<|im_start|>', '</s>', '<|assistant|>', '<|user|>', '<|system|>', '<eos>'],
        'skip_special_tokens': False,
        'temperature': 0.6,
        'top_p': 0.8,
        'max_tokens': 4096
    }
    auto_map = {
        'tp': 'tensor_parallel_size'
    }  # from cli to vllm
    optional_keys = set([
        'max_model_len',
        'gpu_memory_utilization',
        'task',
        'dtype',
        'kv_cache_dtype',
        'tokenizer_mode',
        'block_size',
        'max_num_seqs',
        'pipeline_parallel_size',
        'tensor_parallel_size',
        'seed',
        'port',
        'max_num_batched_tokens',
        'tool_call_parser',
        'swap_space',
        'mm_processor_kwargs',
        'limit_mm_per_prompt',
        'hf_overrides'])

    # TODO(wangzhihong): change default value for `openai_api` argument to True
    def __init__(self, trust_remote_code: bool = True, launcher: LazyLLMLaunchersBase = launchers.remote(ngpus=1),  # noqa B008
                 log_path: str = None, openai_api: Optional[bool] = None, **kw):
        self.launcher_list, launcher = reallocate_launcher(launcher)
        super().__init__(launcher=launcher)
        self.kw = ArgsDict({
            'host': '0.0.0.0',
        })
        if openai_api is None: openai_api = lazyllm.config['openai_api']
        self._vllm_cmd = 'vllm.entrypoints.openai.api_server' if openai_api else 'vllm.entrypoints.api_server'
        self._openai_api = openai_api
        self.options_keys = kw.pop('options_keys', [])
        if trust_remote_code and 'trust_remote_code' not in self.options_keys:
            self.options_keys.append('trust_remote_code')
        self.kw.update(**{key: kw[key] for key in self.optional_keys if key in kw})
        self.kw.check_and_update(kw)
        self.random_port = False if 'port' in kw and kw['port'] and kw['port'] != 'auto' else True
        self.temp_folder = make_log_dir(log_path, 'vllm') if log_path else None
        if self.launcher_list:
            ray_launcher = [Distributed(launcher=launcher) for launcher in self.launcher_list]
            parall_launcher = [lazyllm.pipeline(sleep_moment, launcher) for launcher in ray_launcher[1:]]
            self._prepare_deploy = lazyllm.pipeline(
                ray_launcher[0], post_action=(lazyllm.parallel(*parall_launcher) if len(parall_launcher) else None))

    def cmd(self, finetuned_model=None, base_model=None, master_ip=None):
        """构造用于启动 vLLM 推理服务的命令。

该方法会自动检测模型路径是否有效,并根据当前配置参数动态生成可执行命令,支持多节点部署时自动加入 ray 启动命令。

Args:
    finetuned_model (str): 微调后的模型路径。
    base_model (str): 备用基础模型路径(当 finetuned_model 无效时启用)。
    master_ip (str): 分布式部署中的主节点 IP,仅在多节点时启用。

**Returns:**

- LazyLLMCMD: 可执行命令对象,包含启动指令、结果回调函数及健康检查方法。
"""
        if not os.path.exists(finetuned_model) or \
            not any(filename.endswith('.bin') or filename.endswith('.safetensors')
                    for filename in os.listdir(finetuned_model)):
            if not finetuned_model:
                LOG.warning(f'Note! That finetuned_model({finetuned_model}) is an invalid path, '
                            f'base_model({base_model}) will be used')
            finetuned_model = base_model

        def impl():
            if self.random_port:
                self.kw['port'] = random.randint(30000, 40000)

            cmd = ''
            if self.launcher_list:
                cmd += f'ray start --address="{master_ip}" && '
            cmd += f'{sys.executable} -m {self._vllm_cmd} --model {finetuned_model} '
            if self._openai_api: cmd += '--served-model-name lazyllm '
            cmd += self.kw.parse_kwargs()
            cmd += ' ' + parse_options_keys(self.options_keys)
            if self.temp_folder: cmd += f' 2>&1 | tee {get_log_path(self.temp_folder)}'
            return cmd

        return LazyLLMCMD(cmd=impl, return_value=self.geturl,
                          checkf=(verify_vllm_openai_func if self._openai_api else verify_fastapi_func))

    def geturl(self, job=None):
        """获取 vLLM 服务的推理地址。

根据运行模式(Display 模式或实际部署)返回相应的 URL,用于访问模型的生成接口。

Args:
    job (Job, optional): 部署任务对象。默认取当前模块绑定的 job。

**Returns:**

- str: 推理服务的 HTTP 地址。
"""
        if job is None:
            job = self.job
        if lazyllm.config['mode'] == lazyllm.Mode.Display:
            return 'http://{ip}:{port}/generate'
        else:
            return f'http://{job.get_jobip()}:{self.kw["port"]}' + (
                '/v1/' if self._openai_api else '/generate')

    @staticmethod
    def extract_result(x, inputs):
        """从 VLLM 接口返回的 JSON 字符串中提取推理结果。

Args:
    x (str): VLLM 服务返回的原始 JSON 字符串。
    inputs (Any): 输入参数(此处未使用,保留接口一致性)。

**Returns:**

- str: 模型生成的文本结果。
"""
        return json.loads(x)['text'][0]

cmd(finetuned_model=None, base_model=None, master_ip=None)

构造用于启动 vLLM 推理服务的命令。

该方法会自动检测模型路径是否有效,并根据当前配置参数动态生成可执行命令,支持多节点部署时自动加入 ray 启动命令。

Parameters:

  • finetuned_model (str, default: None ) –

    微调后的模型路径。

  • base_model (str, default: None ) –

    备用基础模型路径(当 finetuned_model 无效时启用)。

  • master_ip (str, default: None ) –

    分布式部署中的主节点 IP,仅在多节点时启用。

Returns:

  • LazyLLMCMD: 可执行命令对象,包含启动指令、结果回调函数及健康检查方法。
Source code in lazyllm/components/deploy/vllm.py
    def cmd(self, finetuned_model=None, base_model=None, master_ip=None):
        """构造用于启动 vLLM 推理服务的命令。

该方法会自动检测模型路径是否有效,并根据当前配置参数动态生成可执行命令,支持多节点部署时自动加入 ray 启动命令。

Args:
    finetuned_model (str): 微调后的模型路径。
    base_model (str): 备用基础模型路径(当 finetuned_model 无效时启用)。
    master_ip (str): 分布式部署中的主节点 IP,仅在多节点时启用。

**Returns:**

- LazyLLMCMD: 可执行命令对象,包含启动指令、结果回调函数及健康检查方法。
"""
        if not os.path.exists(finetuned_model) or \
            not any(filename.endswith('.bin') or filename.endswith('.safetensors')
                    for filename in os.listdir(finetuned_model)):
            if not finetuned_model:
                LOG.warning(f'Note! That finetuned_model({finetuned_model}) is an invalid path, '
                            f'base_model({base_model}) will be used')
            finetuned_model = base_model

        def impl():
            if self.random_port:
                self.kw['port'] = random.randint(30000, 40000)

            cmd = ''
            if self.launcher_list:
                cmd += f'ray start --address="{master_ip}" && '
            cmd += f'{sys.executable} -m {self._vllm_cmd} --model {finetuned_model} '
            if self._openai_api: cmd += '--served-model-name lazyllm '
            cmd += self.kw.parse_kwargs()
            cmd += ' ' + parse_options_keys(self.options_keys)
            if self.temp_folder: cmd += f' 2>&1 | tee {get_log_path(self.temp_folder)}'
            return cmd

        return LazyLLMCMD(cmd=impl, return_value=self.geturl,
                          checkf=(verify_vllm_openai_func if self._openai_api else verify_fastapi_func))

geturl(job=None)

获取 vLLM 服务的推理地址。

根据运行模式(Display 模式或实际部署)返回相应的 URL,用于访问模型的生成接口。

Parameters:

  • job (Job, default: None ) –

    部署任务对象。默认取当前模块绑定的 job。

Returns:

  • str: 推理服务的 HTTP 地址。
Source code in lazyllm/components/deploy/vllm.py
    def geturl(self, job=None):
        """获取 vLLM 服务的推理地址。

根据运行模式(Display 模式或实际部署)返回相应的 URL,用于访问模型的生成接口。

Args:
    job (Job, optional): 部署任务对象。默认取当前模块绑定的 job。

**Returns:**

- str: 推理服务的 HTTP 地址。
"""
        if job is None:
            job = self.job
        if lazyllm.config['mode'] == lazyllm.Mode.Display:
            return 'http://{ip}:{port}/generate'
        else:
            return f'http://{job.get_jobip()}:{self.kw["port"]}' + (
                '/v1/' if self._openai_api else '/generate')

extract_result(x, inputs) staticmethod

从 VLLM 接口返回的 JSON 字符串中提取推理结果。

Parameters:

  • x (str) –

    VLLM 服务返回的原始 JSON 字符串。

  • inputs (Any) –

    输入参数(此处未使用,保留接口一致性)。

Returns:

  • str: 模型生成的文本结果。
Source code in lazyllm/components/deploy/vllm.py
    @staticmethod
    def extract_result(x, inputs):
        """从 VLLM 接口返回的 JSON 字符串中提取推理结果。

Args:
    x (str): VLLM 服务返回的原始 JSON 字符串。
    inputs (Any): 输入参数(此处未使用,保留接口一致性)。

**Returns:**

- str: 模型生成的文本结果。
"""
        return json.loads(x)['text'][0]

lazyllm.components.deploy.LMDeploy

Bases: LazyLLMDeployBase

LMDeploy 类,继承自 LazyLLMDeployBase,基于 LMDeploy 框架,
用于启动并管理大语言模型的推理服务。

Parameters:

  • launcher (Optional[launcher], default: remote(ngpus=1) ) –

    服务启动器,默认使用 launchers.remote(ngpus=1)

  • trust_remote_code (bool, default: True ) –

    是否信任远程代码,默认为 True

  • log_path (Optional[str], default: None ) –

    日志输出路径,默认为 None

  • **kw

    关键字参数,用于更新默认的部署配置。除下列参数外,不允许传入额外参数。

Other Parameters:

  • tp (int) –

    张量并行参数,默认为 1

  • server-name (str) –

    服务监听的 IP 地址,默认为 0.0.0.0

  • server-port (Optional[int]) –

    服务端口号,默认为 None,此时会自动随机分配 30000–40000 区间的端口。

  • max-batch-size (int) –

    最大批处理大小,默认为 128

  • chat-template (Optional[str]) –

    对话模板文件路径。若模型不是视觉语言模型且未指定模板,将使用默认模板。

  • eager-mode (bool) –

    是否启用 eager 模式,受环境变量 LMDEPLOY_EAGER_MODE 控制,默认为 False

Examples:

>>> # Basic use:
>>> from lazyllm import deploy
>>> infer = deploy.LMDeploy()
>>>
>>> # MultiModal:
>>> import lazyllm
>>> from lazyllm import deploy, globals
>>> from lazyllm.components.formatter import encode_query_with_filepaths
>>> chat = lazyllm.TrainableModule('Mini-InternVL-Chat-2B-V1-5').deploy_method(deploy.LMDeploy)
>>> chat.update_server()
>>> inputs = encode_query_with_filepaths('What is it?', ['path/to/image'])
>>> res = chat(inputs)
Source code in lazyllm/components/deploy/lmdeploy.py
class LMDeploy(LazyLLMDeployBase):
    """``LMDeploy`` 类,继承自 ``LazyLLMDeployBase``,基于 [LMDeploy](https://github.com/InternLM/lmdeploy) 框架,  
用于启动并管理大语言模型的推理服务。

Args:
    launcher (Optional[lazyllm.launcher]): 服务启动器,默认使用 ``launchers.remote(ngpus=1)``。  
    trust_remote_code (bool): 是否信任远程代码,默认为 ``True``。  
    log_path (Optional[str]): 日志输出路径,默认为 ``None``。  
    **kw: 关键字参数,用于更新默认的部署配置。除下列参数外,不允许传入额外参数。  

Keyword Args:
    tp (int): 张量并行参数,默认为 ``1``。  
    server-name (str): 服务监听的 IP 地址,默认为 ``0.0.0.0``。  
    server-port (Optional[int]): 服务端口号,默认为 ``None``,此时会自动随机分配 30000–40000 区间的端口。  
    max-batch-size (int): 最大批处理大小,默认为 ``128``。  
    chat-template (Optional[str]): 对话模板文件路径。若模型不是视觉语言模型且未指定模板,将使用默认模板。  
    eager-mode (bool): 是否启用 eager 模式,受环境变量 ``LMDEPLOY_EAGER_MODE`` 控制,默认为 ``False``。  


Examples:
    >>> # Basic use:
    >>> from lazyllm import deploy
    >>> infer = deploy.LMDeploy()
    >>>
    >>> # MultiModal:
    >>> import lazyllm
    >>> from lazyllm import deploy, globals
    >>> from lazyllm.components.formatter import encode_query_with_filepaths
    >>> chat = lazyllm.TrainableModule('Mini-InternVL-Chat-2B-V1-5').deploy_method(deploy.LMDeploy)
    >>> chat.update_server()
    >>> inputs = encode_query_with_filepaths('What is it?', ['path/to/image'])
    >>> res = chat(inputs)
    """
    keys_name_handle = {
        'inputs': 'prompt',
        'stop': 'stop',
        'image': 'image_url',
    }
    default_headers = {'Content-Type': 'application/json'}
    message_format = {
        'prompt': 'Who are you ?',
        'image_url': None,
        'session_id': -1,
        'interactive_mode': False,
        'stream': False,
        'stop': None,
        'request_output_len': None,
        'top_p': 0.8,
        'top_k': 40,
        'temperature': 0.8,
        'repetition_penalty': 1,
        'max_new_tokens': 4096,
        'ignore_eos': False,
        'skip_special_tokens': True,
        'cancel': False,
        'adapter_name': None
    }
    auto_map = {
        'port': 'server-port',
        'host': 'server-name',
        'max_batch_size': 'max-batch-size',
        'chat_template': 'chat-template',
    }
    stream_parse_parameters = {'delimiter': b'\n'}

    def __init__(self, launcher=launchers.remote(ngpus=1), trust_remote_code=True, log_path=None, **kw):  # noqa B008
        super().__init__(launcher=launcher)
        self.kw = ArgsDict({
            'server-name': '0.0.0.0',
            'server-port': None,
            'tp': 1,
            'max-batch-size': 128,
            'chat-template': None,
        })
        self.options_keys = kw.pop('options_keys', [])
        self.kw.check_and_update(kw)
        self._trust_remote_code = trust_remote_code
        self.random_port = False if 'server-port' in kw and kw['server-port'] else True
        self.temp_folder = make_log_dir(log_path, 'lmdeploy') if log_path else None

    def cmd(self, finetuned_model=None, base_model=None):
        """该方法用于生成启动LMDeploy服务的命令。

Args:
    finetuned_model (str): 微调后的模型路径。
    base_model (str): 基础模型路径,当finetuned_model无效时使用。

**Returns:**

- LazyLLMCMD: 一个包含启动命令的LazyLLMCMD对象。
"""
        if not os.path.exists(finetuned_model) or \
            not any(filename.endswith('.bin') or filename.endswith('.safetensors')
                    for filename in os.listdir(finetuned_model)):
            if not finetuned_model:
                LOG.warning(f'Note! That finetuned_model({finetuned_model}) is an invalid path, '
                            f'base_model({base_model}) will be used')
            finetuned_model = base_model

        model_type = ModelManager.get_model_type(base_model or finetuned_model)
        if model_type == 'vlm':
            self.kw.pop('chat-template')
        else:
            if not self.kw['chat-template'] and 'vl' not in finetuned_model and 'lava' not in finetuned_model:
                self.kw['chat-template'] = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                                        'lmdeploy', 'chat_template.json')
            else:
                self.kw.pop('chat-template')

        def impl():
            if self.random_port:
                self.kw['server-port'] = random.randint(30000, 40000)
            cmd = f'lmdeploy serve api_server {finetuned_model} '

            if importlib.util.find_spec('torch_npu') is not None: cmd += '--device ascend '
            if config['lmdeploy_eager_mode']: cmd += '--eager-mode '
            cmd += self.kw.parse_kwargs()
            cmd += ' ' + parse_options_keys(self.options_keys)
            if self.temp_folder: cmd += f' 2>&1 | tee {get_log_path(self.temp_folder)}'
            return cmd

        return LazyLLMCMD(cmd=impl, return_value=self.geturl, checkf=verify_fastapi_func)

    def geturl(self, job=None):
        """获取LMDeploy服务的URL地址。

Args:
    job (optional): 任务对象,默认为None,此时使用self.job。

**Returns:**

- str: 服务的URL地址,格式为"http://{ip}:{port}/v1/chat/interactive"。
"""
        if job is None:
            job = self.job
        if lazyllm.config['mode'] == lazyllm.Mode.Display:
            return 'http://{ip}:{port}/v1/chat/interactive'
        else:
            return f'http://{job.get_jobip()}:{self.kw["server-port"]}/v1/chat/interactive'

    @staticmethod
    def extract_result(x, inputs):
        """解析模型推理结果,从返回的 JSON 字符串中提取文本输出。

Args:
    x (str): 模型返回的 JSON 格式字符串。  
    inputs (dict): 原始输入数据(此参数未被直接使用,保留作接口兼容)。  

**Returns:**

- str: 从响应中解析得到的文本结果。  
"""
        return json.loads(x)['text']

cmd(finetuned_model=None, base_model=None)

该方法用于生成启动LMDeploy服务的命令。

Parameters:

  • finetuned_model (str, default: None ) –

    微调后的模型路径。

  • base_model (str, default: None ) –

    基础模型路径,当finetuned_model无效时使用。

Returns:

  • LazyLLMCMD: 一个包含启动命令的LazyLLMCMD对象。
Source code in lazyllm/components/deploy/lmdeploy.py
    def cmd(self, finetuned_model=None, base_model=None):
        """该方法用于生成启动LMDeploy服务的命令。

Args:
    finetuned_model (str): 微调后的模型路径。
    base_model (str): 基础模型路径,当finetuned_model无效时使用。

**Returns:**

- LazyLLMCMD: 一个包含启动命令的LazyLLMCMD对象。
"""
        if not os.path.exists(finetuned_model) or \
            not any(filename.endswith('.bin') or filename.endswith('.safetensors')
                    for filename in os.listdir(finetuned_model)):
            if not finetuned_model:
                LOG.warning(f'Note! That finetuned_model({finetuned_model}) is an invalid path, '
                            f'base_model({base_model}) will be used')
            finetuned_model = base_model

        model_type = ModelManager.get_model_type(base_model or finetuned_model)
        if model_type == 'vlm':
            self.kw.pop('chat-template')
        else:
            if not self.kw['chat-template'] and 'vl' not in finetuned_model and 'lava' not in finetuned_model:
                self.kw['chat-template'] = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                                        'lmdeploy', 'chat_template.json')
            else:
                self.kw.pop('chat-template')

        def impl():
            if self.random_port:
                self.kw['server-port'] = random.randint(30000, 40000)
            cmd = f'lmdeploy serve api_server {finetuned_model} '

            if importlib.util.find_spec('torch_npu') is not None: cmd += '--device ascend '
            if config['lmdeploy_eager_mode']: cmd += '--eager-mode '
            cmd += self.kw.parse_kwargs()
            cmd += ' ' + parse_options_keys(self.options_keys)
            if self.temp_folder: cmd += f' 2>&1 | tee {get_log_path(self.temp_folder)}'
            return cmd

        return LazyLLMCMD(cmd=impl, return_value=self.geturl, checkf=verify_fastapi_func)

geturl(job=None)

获取LMDeploy服务的URL地址。

Parameters:

  • job (optional, default: None ) –

    任务对象,默认为None,此时使用self.job。

Returns:

  • str: 服务的URL地址,格式为"http://{ip}:{port}/v1/chat/interactive"。
Source code in lazyllm/components/deploy/lmdeploy.py
    def geturl(self, job=None):
        """获取LMDeploy服务的URL地址。

Args:
    job (optional): 任务对象,默认为None,此时使用self.job。

**Returns:**

- str: 服务的URL地址,格式为"http://{ip}:{port}/v1/chat/interactive"。
"""
        if job is None:
            job = self.job
        if lazyllm.config['mode'] == lazyllm.Mode.Display:
            return 'http://{ip}:{port}/v1/chat/interactive'
        else:
            return f'http://{job.get_jobip()}:{self.kw["server-port"]}/v1/chat/interactive'

extract_result(x, inputs) staticmethod

解析模型推理结果,从返回的 JSON 字符串中提取文本输出。

Parameters:

  • x (str) –

    模型返回的 JSON 格式字符串。

  • inputs (dict) –

    原始输入数据(此参数未被直接使用,保留作接口兼容)。

Returns:

  • str: 从响应中解析得到的文本结果。
Source code in lazyllm/components/deploy/lmdeploy.py
    @staticmethod
    def extract_result(x, inputs):
        """解析模型推理结果,从返回的 JSON 字符串中提取文本输出。

Args:
    x (str): 模型返回的 JSON 格式字符串。  
    inputs (dict): 原始输入数据(此参数未被直接使用,保留作接口兼容)。  

**Returns:**

- str: 从响应中解析得到的文本结果。  
"""
        return json.loads(x)['text']

lazyllm.components.deploy.base.DummyDeploy

Bases: LazyLLMDeployBase, Pipeline

DummyDeploy(launcher=launchers.remote(sync=False), , stream=False, *kw)

一个用于测试的模拟部署类,继承自 LazyLLMDeployBaseflows.Pipeline,实现了一个简单的流水线风格部署服务, 支持流式输出(可选)。

该类主要用于内部测试和示例用途。它接收符合 message_format 格式的输入,根据是否启用 stream 参数,返回 字符串或逐步输出的模拟响应。

Args: launcher: 部署器实例,默认值为 launchers.remote(sync=False)。 stream (bool): 是否以流式方式输出结果。 kw: 其他传递给父类的关键字参数。

Call Arguments

keys_name_handle (dict): 输入字段名的映射。

message_format (dict): 默认请求模板,包括输入内容与生成参数。

Source code in lazyllm/components/deploy/base.py
class DummyDeploy(LazyLLMDeployBase, flows.Pipeline):
    """DummyDeploy(launcher=launchers.remote(sync=False), *, stream=False, **kw)

一个用于测试的模拟部署类,继承自 `LazyLLMDeployBase` 和 `flows.Pipeline`,实现了一个简单的流水线风格部署服务,
支持流式输出(可选)。

该类主要用于内部测试和示例用途。它接收符合 `message_format` 格式的输入,根据是否启用 `stream` 参数,返回
字符串或逐步输出的模拟响应。

Args:
    launcher: 部署器实例,默认值为 `launchers.remote(sync=False)`。
    stream (bool): 是否以流式方式输出结果。
    kw: 其他传递给父类的关键字参数。

Call Arguments:
    keys_name_handle (dict): 输入字段名的映射。 

    message_format (dict): 默认请求模板,包括输入内容与生成参数。 

"""
    keys_name_handle = {'inputs': 'inputs'}
    message_format = {
        'inputs': '',
        'parameters': {
            'do_sample': False,
            'temperature': 0.1,
        }
    }

    def __init__(self, launcher=launchers.remote(sync=False), *, stream=False, **kw):  # noqa B008
        super().__init__(launcher=launcher)

        def func():

            def impl(x):
                LOG.info(f'input is {x["inputs"]}, parameters is {x["parameters"]}')
                return f'reply for {x["inputs"]}, and parameters is {x["parameters"]}'

            def impl_stream(x):
                for s in ['reply', ' for', f' {x["inputs"]}', ', and',
                          ' parameters', ' is', f' {x["parameters"]}']:
                    yield s
                    time.sleep(0.2)
            return impl_stream if stream else impl
        flows.Pipeline.__init__(self, func,
                                lazyllm.deploy.RelayServer(port=random.randint(30000, 40000), launcher=launcher))

    def __call__(self, *args):
        url = flows.Pipeline.__call__(self)
        LOG.info(f'dummy deploy url is : {url}')
        return url

    def __repr__(self):
        return flows.Pipeline.__repr__(self)

lazyllm.components.auto.AutoDeploy

Bases: LazyLLMDeployBase

此类是 LazyLLMDeployBase 的子类,可根据输入的参数自动选择合适的推理框架和参数,以对大语言模型进行推理。

具体而言,基于输入的:base_model 的模型参数、max_token_numlauncher 中GPU的类型以及卡数,该类可以自动选择出合适的推理框架(如: LightllmVllm)及所需的参数。

Parameters:

  • base_model (str) –

    用于进行微调的基模型,要求是基模型的路径或模型名。用于提供基模型信息。

  • source (config[model_source]) –

    指定模型的下载源。可通过设置环境变量 LAZYLLM_MODEL_SOURCE 来配置,目前仅支持 huggingfacemodelscope 。若不设置,lazyllm不会启动自动模型下载。

  • trust_remote_code (bool) –

    是否允许加载来自远程服务器的模型代码,默认为 True

  • launcher (launcher, default: remote() ) –

    微调的启动器,默认为 launchers.remote(ngpus=1)

  • stream (bool) –

    是否为流式响应,默认为 False

  • type (str) –

    类型参数,默认为 None,及llm类型,另外还支持embed类型。

  • max_token_num (int) –

    输入微调模型的token最大长度,默认为1024

  • launcher (launcher, default: remote() ) –

    微调的启动器,默认为 launchers.remote(ngpus=1)

  • kw

    关键字参数,用于更新默认的训练参数。注意这里能够指定的关键字参数取决于 LazyLLM 推测出的框架,因此建议谨慎设置。

Examples:

>>> from lazyllm import deploy
>>> deploy.auto('internlm2-chat-7b')
<lazyllm.llm.deploy type=Lightllm>
Source code in lazyllm/components/auto/autodeploy.py
class AutoDeploy(LazyLLMDeployBase):
    """此类是 ``LazyLLMDeployBase`` 的子类,可根据输入的参数自动选择合适的推理框架和参数,以对大语言模型进行推理。

具体而言,基于输入的:``base_model`` 的模型参数、``max_token_num``、``launcher`` 中GPU的类型以及卡数,该类可以自动选择出合适的推理框架(如: ``Lightllm`` 或 ``Vllm``)及所需的参数。

Args:
    base_model (str): 用于进行微调的基模型,要求是基模型的路径或模型名。用于提供基模型信息。
    source (lazyllm.config['model_source']): 指定模型的下载源。可通过设置环境变量 ``LAZYLLM_MODEL_SOURCE`` 来配置,目前仅支持 ``huggingface`` 或 ``modelscope`` 。若不设置,lazyllm不会启动自动模型下载。
    trust_remote_code (bool): 是否允许加载来自远程服务器的模型代码,默认为 ``True``。
    launcher (lazyllm.launcher): 微调的启动器,默认为 ``launchers.remote(ngpus=1)``。
    stream (bool): 是否为流式响应,默认为 ``False``。
    type (str): 类型参数,默认为 ``None``,及``llm``类型,另外还支持``embed``类型。
    max_token_num (int): 输入微调模型的token最大长度,默认为``1024``。
    launcher (lazyllm.launcher): 微调的启动器,默认为 ``launchers.remote(ngpus=1)``。
    kw: 关键字参数,用于更新默认的训练参数。注意这里能够指定的关键字参数取决于 LazyLLM 推测出的框架,因此建议谨慎设置。


Examples:
    >>> from lazyllm import deploy
    >>> deploy.auto('internlm2-chat-7b')
    <lazyllm.llm.deploy type=Lightllm> 
    """
    @staticmethod
    def _get_embed_deployer(launcher, type, kw):
        launcher = launcher or launchers.remote(ngpus=1)
        kw['model_type'] = type
        if lazyllm.config['default_embedding_engine'].lower() in ('transformers', 'flagembedding') \
            or kw.get('embed_type')=='sparse' or not check_requirements('infinity_emb'):
            return deploy.Rerank if type == 'rerank' else deploy.Embedding, launcher, kw
        else:
            return deploy.InfinityRerank if type == 'rerank' else deploy.Infinity, launcher, kw

    @classmethod
    def get_deployer(cls, base_model: str, source: Optional[str] = None, trust_remote_code: bool = True,
                     launcher: Optional[LazyLLMLaunchersBase] = None, type: Optional[str] = None,
                     log_path: Optional[str] = None, **kw):
        """根据模型类型获取对应的部署器类。

自动检测模型类型并返回最适合的部署器类、启动器和配置参数。

Args:
    base_model (str): 基础模型名称或路径。
    source (Optional[str], optional): 模型来源。
    trust_remote_code (bool, optional): 是否信任远程代码。
    launcher (Optional[LazyLLMLaunchersBase], optional): 启动器实例。
    type (Optional[str], optional): 模型类型。
    log_path (Optional[str], optional): 日志文件路径。
    **kw: 其他配置参数。
"""
        model_name = get_model_name(base_model)
        kw['log_path'], kw['trust_remote_code'] = log_path, trust_remote_code
        if not type:
            type = ModelManager.get_model_type(model_name)

        if type in ('embed', 'cross_modal_embed', 'rerank'):
            return AutoDeploy._get_embed_deployer(launcher, type, kw)
        elif type == 'sd':
            return StableDiffusionDeploy, launcher or launchers.remote(ngpus=1), kw
        elif type == 'stt':
            return SenseVoiceDeploy, launcher or launchers.remote(ngpus=1), kw
        elif type == 'tts':
            return TTSDeploy.get_deploy_cls(model_name), launcher or launchers.remote(ngpus=1), kw
        elif type == 'vlm':
            return deploy.LMDeploy, launcher or launchers.remote(ngpus=1), kw
        elif type == 'ocr':
            return OCRDeploy, launcher or launchers.remote(ngpus=1), kw

        if not launcher:
            match = re.search(r'(\d+)[bB]', model_name)
            size = int(match.group(1)) if match else 0
            size = (size * 2) if 'awq' not in model_name.lower() else (size / 1.5)
            ngpus = (1 << (math.ceil(size * 2 / config['gpu_memory']) - 1).bit_length())
            launcher = launchers.remote(ngpus = ngpus)

        for deploy_cls in ['vllm', 'lightllm', 'lmdeploy', 'mindie']:
            if check_cmd(deploy_cls) or check_requirements(requirements.get(deploy_cls)):
                deploy_cls = getattr(deploy, deploy_cls)
                return deploy_cls, launcher, kw
        return deploy.auto, launcher, kw

    def __new__(cls, base_model, source=lazyllm.config['model_source'], trust_remote_code=True,
                launcher=None, type=None, log_path=None, **kw):
        deploy_cls, launcher, kw = __class__.get_deployer(
            base_model=base_model, source=source, trust_remote_code=trust_remote_code,
            launcher=launcher, type=type, log_path=log_path, **kw)
        return deploy_cls(launcher=launcher, **kw)

get_deployer(base_model, source=None, trust_remote_code=True, launcher=None, type=None, log_path=None, **kw) classmethod

根据模型类型获取对应的部署器类。

自动检测模型类型并返回最适合的部署器类、启动器和配置参数。

Parameters:

  • base_model (str) –

    基础模型名称或路径。

  • source (Optional[str], default: None ) –

    模型来源。

  • trust_remote_code (bool, default: True ) –

    是否信任远程代码。

  • launcher (Optional[LazyLLMLaunchersBase], default: None ) –

    启动器实例。

  • type (Optional[str], default: None ) –

    模型类型。

  • log_path (Optional[str], default: None ) –

    日志文件路径。

  • **kw

    其他配置参数。

Source code in lazyllm/components/auto/autodeploy.py
    @classmethod
    def get_deployer(cls, base_model: str, source: Optional[str] = None, trust_remote_code: bool = True,
                     launcher: Optional[LazyLLMLaunchersBase] = None, type: Optional[str] = None,
                     log_path: Optional[str] = None, **kw):
        """根据模型类型获取对应的部署器类。

自动检测模型类型并返回最适合的部署器类、启动器和配置参数。

Args:
    base_model (str): 基础模型名称或路径。
    source (Optional[str], optional): 模型来源。
    trust_remote_code (bool, optional): 是否信任远程代码。
    launcher (Optional[LazyLLMLaunchersBase], optional): 启动器实例。
    type (Optional[str], optional): 模型类型。
    log_path (Optional[str], optional): 日志文件路径。
    **kw: 其他配置参数。
"""
        model_name = get_model_name(base_model)
        kw['log_path'], kw['trust_remote_code'] = log_path, trust_remote_code
        if not type:
            type = ModelManager.get_model_type(model_name)

        if type in ('embed', 'cross_modal_embed', 'rerank'):
            return AutoDeploy._get_embed_deployer(launcher, type, kw)
        elif type == 'sd':
            return StableDiffusionDeploy, launcher or launchers.remote(ngpus=1), kw
        elif type == 'stt':
            return SenseVoiceDeploy, launcher or launchers.remote(ngpus=1), kw
        elif type == 'tts':
            return TTSDeploy.get_deploy_cls(model_name), launcher or launchers.remote(ngpus=1), kw
        elif type == 'vlm':
            return deploy.LMDeploy, launcher or launchers.remote(ngpus=1), kw
        elif type == 'ocr':
            return OCRDeploy, launcher or launchers.remote(ngpus=1), kw

        if not launcher:
            match = re.search(r'(\d+)[bB]', model_name)
            size = int(match.group(1)) if match else 0
            size = (size * 2) if 'awq' not in model_name.lower() else (size / 1.5)
            ngpus = (1 << (math.ceil(size * 2 / config['gpu_memory']) - 1).bit_length())
            launcher = launchers.remote(ngpus = ngpus)

        for deploy_cls in ['vllm', 'lightllm', 'lmdeploy', 'mindie']:
            if check_cmd(deploy_cls) or check_requirements(requirements.get(deploy_cls)):
                deploy_cls = getattr(deploy, deploy_cls)
                return deploy_cls, launcher, kw
        return deploy.auto, launcher, kw

lazyllm.components.deploy.embed.AbstractEmbedding

Bases: ABC

抽象嵌入基类,为所有嵌入模型提供统一的接口和基础功能。此类定义了嵌入模型的标准接口,包括模型加载、调用和序列化等功能。

Parameters:

  • base_embed (str) –

    嵌入模型的基础路径或标识符,用于指定要加载的嵌入模型。

  • source (str, default: None ) –

    模型来源,默认为 None。如果未指定,将使用 LazyLLM 配置中的默认模型来源。

  • init (bool, default: False ) –

    是否在初始化时立即加载模型,默认为 False。如果为 True,将在对象创建时立即调用 load_embed() 方法。

Source code in lazyllm/components/deploy/embed.py
class AbstractEmbedding(ABC):
    """抽象嵌入基类,为所有嵌入模型提供统一的接口和基础功能。此类定义了嵌入模型的标准接口,包括模型加载、调用和序列化等功能。

Args:
    base_embed (str): 嵌入模型的基础路径或标识符,用于指定要加载的嵌入模型。
    source (str, optional): 模型来源,默认为 ``None``。如果未指定,将使用 LazyLLM 配置中的默认模型来源。
    init (bool): 是否在初始化时立即加载模型,默认为 ``False``。如果为 ``True``,将在对象创建时立即调用 ``load_embed()`` 方法。
"""
    def __init__(self, base_embed, source=None, init=False):
        from ..utils.downloader import ModelManager
        self._source = source or lazyllm.config['model_source']
        self._base_embed = ModelManager(self._source).download(base_embed) or ''
        self._embed = None
        self._init = lazyllm.once_flag()
        if init:
            lazyllm.call_once(self._init, self.load_embed)

    @abstractmethod
    def load_embed(self) -> None:
        """加载嵌入模型的抽象方法。此方法由子类实现,用于执行具体的模型加载逻辑。
"""
        pass

    @abstractmethod
    def _call(self, data: Dict[str, Union[str, List[str]]]) -> str:
        pass

    def __call__(self, data: Dict[str, Union[str, List[str]]]) -> str:
        lazyllm.call_once(self._init, self.load_embed)
        return self._call(data)

    def __reduce__(self):
        init = bool(os.getenv('LAZYLLM_ON_CLOUDPICKLE', None) == 'ON' or self._init)
        return self.__class__, (self._base_embed, self._source, init)

load_embed() abstractmethod

加载嵌入模型的抽象方法。此方法由子类实现,用于执行具体的模型加载逻辑。

Source code in lazyllm/components/deploy/embed.py
    @abstractmethod
    def load_embed(self) -> None:
        """加载嵌入模型的抽象方法。此方法由子类实现,用于执行具体的模型加载逻辑。
"""
        pass

lazyllm.components.deploy.EmbeddingDeploy

Bases: LazyLLMDeployBase

此类是 LazyLLMDeployBase 的子类,用于部署文本嵌入(Embedding)服务。支持稠密向量(dense)和稀疏向量(sparse)两种嵌入方式,可使用 HuggingFace 模型或 FlagEmbedding 模型。

Parameters:

  • launcher (Optional[launcher], default: None ) –

    启动器实例,默认为 None

  • model_type (Optional[str], default: 'embed' ) –

    模型类型,默认为 'embed'

  • log_path (Optional[str], default: None ) –

    日志文件路径,默认为 None

  • embed_type (Optional[str], default: 'dense' ) –

    嵌入类型,可选 'dense''sparse',默认为 'dense'

  • trust_remote_code (bool, default: True ) –

    是否信任远程代码,默认为 True

  • port (Optional[int], default: None ) –

    服务端口号,默认为 None,此情况下 LazyLLM 会自动生成随机端口号。

Call Arguments

finetuned_model (Optional[str]): 微调后的模型路径或名称。

base_model (Optional[str]): 基础模型路径或名称,当 finetuned_model 无效时会使用此模型。

Message Format

输入格式为包含 text(文本)和 images(图像列表)的字典。

  • text (str): 需要编码的文本内容

  • images (Union[str, List[str]]): 需要编码的图像列表,可选

Examples:

>>> from lazyllm import deploy
>>> embed_service = deploy.EmbeddingDeploy(embed_type='dense')
>>> embed_service('path/to/model')
Source code in lazyllm/components/deploy/embed.py
class EmbeddingDeploy(LazyLLMDeployBase):
    """此类是 ``LazyLLMDeployBase`` 的子类,用于部署文本嵌入(Embedding)服务。支持稠密向量(dense)和稀疏向量(sparse)两种嵌入方式,可使用 HuggingFace 模型或 FlagEmbedding 模型。

Args:
    launcher (Optional[lazyllm.launcher]): 启动器实例,默认为 ``None``。
    model_type (Optional[str]): 模型类型,默认为 ``'embed'``。
    log_path (Optional[str]): 日志文件路径,默认为 ``None``。
    embed_type (Optional[str]): 嵌入类型,可选 ``'dense'`` 或 ``'sparse'``,默认为 ``'dense'``。
    trust_remote_code (bool): 是否信任远程代码,默认为 ``True``。
    port (Optional[int]): 服务端口号,默认为 ``None``,此情况下 LazyLLM 会自动生成随机端口号。

Call Arguments:
    finetuned_model (Optional[str]): 微调后的模型路径或名称。\n
    base_model (Optional[str]): 基础模型路径或名称,当 finetuned_model 无效时会使用此模型。\n

Message Format:
    输入格式为包含 text(文本)和 images(图像列表)的字典。\n
    - text (str): 需要编码的文本内容 \n
    - images (Union[str, List[str]]): 需要编码的图像列表,可选 \n


Examples:
    >>> from lazyllm import deploy
    >>> embed_service = deploy.EmbeddingDeploy(embed_type='dense')
    >>> embed_service('path/to/model')
    """
    message_format = {
        'text': 'text',  # str,
        'images': []  # Union[str, List[str]]
    }
    keys_name_handle = {
        'inputs': 'text',
        'image': 'images'
    }
    default_headers = {'Content-Type': 'application/json'}

    def __init__(self, launcher: LazyLLMLaunchersBase = None, model_type: str = 'embed', log_path: Optional[str] = None,
                 embed_type: Optional[str] = 'dense', trust_remote_code: bool = True, port: Optional[int] = None, **kw):
        super().__init__(launcher=launcher)
        self._launcher = launcher
        self._port = port
        self._model_type = model_type
        self._log_path = log_path
        self._sparse_embed = True if embed_type == 'sparse' else False
        self._trust_remote_code = trust_remote_code
        self._port = port

    def _get_model_path(self, finetuned_model=None, base_model=None):
        if not os.path.exists(finetuned_model) or \
            not any(filename.endswith('.bin') or filename.endswith('.safetensors')
                    for filename in os.listdir(finetuned_model)):
            if not finetuned_model:
                LOG.warning(f'Note! That finetuned_model({finetuned_model}) is an invalid path, '
                            f'base_model({base_model}) will be used')
            finetuned_model = base_model
        return finetuned_model

    def __call__(self, finetuned_model=None, base_model=None):
        finetuned_model = self._get_model_path(finetuned_model, base_model)
        if self._sparse_embed or lazyllm.config['default_embedding_engine'] == 'flagEmbedding':
            return lazyllm.deploy.RelayServer(port=self._port, func=LazyFlagEmbedding(
                finetuned_model, sparse=self._sparse_embed),
                launcher=self._launcher, log_path=self._log_path, cls='embedding')()
        else:
            return lazyllm.deploy.RelayServer(port=self._port, func=HuggingFaceEmbedding(finetuned_model),
                                              launcher=self._launcher, log_path=self._log_path, cls='embedding')()

lazyllm.components.deploy.embed.RerankDeploy

Bases: EmbeddingDeploy

此类是 EmbeddingDeploy 的子类,用于部署重排序(Rerank)服务。支持使用HuggingFace模型进行文本重排序。

Parameters:

  • launcher (launcher, default: None ) –

    启动器,默认为 None

  • model_type (str, default: 'embed' ) –

    模型类型,默认为 'embed'

  • log_path (str, default: None ) –

    日志文件路径,默认为 None

  • trust_remote_code (bool, default: True ) –

    是否信任远程代码,默认为 True

  • port (int, default: None ) –

    服务端口号,默认为 None,此情况下LazyLLM会自动生成随机端口号。

Call Arguments

finetuned_model: 微调后的模型路径或模型名称。

base_model: 基础模型路径或模型名称,当finetuned_model无效时会使用此模型。

Message Format

输入格式为包含query(查询文本)、documents(候选文档列表)和top_n(返回的文档数量)的字典。

  • query: 查询文本

  • documents: 候选文档列表

  • top_n: 返回的文档数量,默认为1

Examples:

>>> from lazyllm import deploy
>>> rerank_service = deploy.embed.RerankDeploy()
>>> rerank_service('path/to/model')
>>> input_data = {
...     "query": "What is machine learning?",
...     "documents": [
...         "Machine learning is a branch of AI.",
...         "Machine learning uses data to improve.",
...         "Deep learning is a subset of machine learning."
...     ],
...     "top_n": 2
... }
>>> result = rerank_service(input_data)
Source code in lazyllm/components/deploy/embed.py
class RerankDeploy(EmbeddingDeploy):
    """此类是 ``EmbeddingDeploy`` 的子类,用于部署重排序(Rerank)服务。支持使用HuggingFace模型进行文本重排序。

Args:
    launcher (lazyllm.launcher): 启动器,默认为 ``None``。
    model_type (str): 模型类型,默认为 ``'embed'``。
    log_path (str): 日志文件路径,默认为 ``None``。
    trust_remote_code (bool): 是否信任远程代码,默认为 ``True``。
    port (int): 服务端口号,默认为 ``None``,此情况下LazyLLM会自动生成随机端口号。

Call Arguments:
    finetuned_model: 微调后的模型路径或模型名称。

    base_model: 基础模型路径或模型名称,当finetuned_model无效时会使用此模型。


Message Format:
    输入格式为包含query(查询文本)、documents(候选文档列表)和top_n(返回的文档数量)的字典。

    - query: 查询文本

    - documents: 候选文档列表

    - top_n: 返回的文档数量,默认为1



Examples:
    >>> from lazyllm import deploy
    >>> rerank_service = deploy.embed.RerankDeploy()
    >>> rerank_service('path/to/model')
    >>> input_data = {
    ...     "query": "What is machine learning?",
    ...     "documents": [
    ...         "Machine learning is a branch of AI.",
    ...         "Machine learning uses data to improve.",
    ...         "Deep learning is a subset of machine learning."
    ...     ],
    ...     "top_n": 2
    ... }
    >>> result = rerank_service(input_data)
    """
    message_format = {'query': 'query', 'documents': ['string'], 'top_n': 1}
    keys_name_handle = {'inputs': 'query', 'documents': 'documents', 'top_n': 'top_n'}
    default_headers = {'Content-Type': 'application/json'}

    def __call__(self, finetuned_model=None, base_model=None):
        finetuned_model = self._get_model_path(finetuned_model, base_model)
        return lazyllm.deploy.RelayServer(port=self._port, func=LazyHuggingFaceRerank(
            finetuned_model), launcher=self._launcher, log_path=self._log_path, cls='embedding')()

lazyllm.components.deploy.embed.LazyHuggingFaceRerank

Bases: object

基于 HuggingFace CrossEncoder 的重排序(Rerank)封装类。
用于根据查询与候选文档的相关性分数,对文档进行排序。
支持在初始化时下载并加载指定的重排序模型,并可选择延迟加载以提升启动性能。

Parameters:

  • base_rerank (str) –

    重排序模型名称或本地路径。支持 HuggingFace Hub 模型标识符或本地路径。

  • source (Optional[str], default: None ) –

    模型来源,支持 huggingfacemodelscope,默认为全局配置项 model_source

  • init (bool, default: False ) –

    是否在实例化时立即加载模型。若为 False,将在首次调用时延迟加载。

Source code in lazyllm/components/deploy/embed.py
class LazyHuggingFaceRerank(object):
    """基于 HuggingFace CrossEncoder 的重排序(Rerank)封装类。  
用于根据查询与候选文档的相关性分数,对文档进行排序。  
支持在初始化时下载并加载指定的重排序模型,并可选择延迟加载以提升启动性能。

Args:
    base_rerank (str): 重排序模型名称或本地路径。支持 HuggingFace Hub 模型标识符或本地路径。
    source (Optional[str]): 模型来源,支持 `huggingface` 和 `modelscope`,默认为全局配置项 `model_source`。
    init (bool): 是否在实例化时立即加载模型。若为 `False`,将在首次调用时延迟加载。
"""
    def __init__(self, base_rerank, source=None, init=False):
        from ..utils.downloader import ModelManager
        source = lazyllm.config['model_source'] if not source else source
        self.base_rerank = ModelManager(source).download(base_rerank) or ''
        self.reranker = None
        self.init_flag = lazyllm.once_flag()
        if init:
            lazyllm.call_once(self.init_flag, self.load_reranker)

    def load_reranker(self):
        """加载重排序模型。  

该方法会基于 `self.base_rerank` 初始化一个 `sentence_transformers.CrossEncoder` 实例,  
并赋值给类属性 `self.reranker`,用于后续的重排序任务。  
"""
        self.reranker = sentence_transformers.CrossEncoder(self.base_rerank)

    def __call__(self, inps):
        lazyllm.call_once(self.init_flag, self.load_reranker)
        query, documents, top_n = inps['query'], inps['documents'], inps['top_n']
        query_pairs = [(query, doc) for doc in documents]
        scores = self.reranker.predict(query_pairs)
        sorted_indices = [(index, scores[index]) for index in np.argsort(scores)[::-1]]
        if top_n > 0:
            sorted_indices = sorted_indices[:top_n]
        return sorted_indices

    @classmethod
    def rebuild(cls, base_rerank, init):
        """重建 `LazyHuggingFaceRerank` 实例的类方法。  
主要用于序列化(pickle/cloudpickle)时的反序列化过程,根据提供的参数重新实例化对象。

Args:
    base_rerank (str): 模型名称或路径。
    init (bool): 是否在重建时立即加载模型。

**Returns:**

- LazyHuggingFaceRerank: 重新构建的类实例。
"""
        return cls(base_rerank, init)

    def __reduce__(self):
        init = bool(os.getenv('LAZYLLM_ON_CLOUDPICKLE', None) == 'ON' or self.init_flag)
        return LazyHuggingFaceRerank.rebuild, (self.base_rerank, init)

load_reranker()

加载重排序模型。

该方法会基于 self.base_rerank 初始化一个 sentence_transformers.CrossEncoder 实例,
并赋值给类属性 self.reranker,用于后续的重排序任务。

Source code in lazyllm/components/deploy/embed.py
    def load_reranker(self):
        """加载重排序模型。  

该方法会基于 `self.base_rerank` 初始化一个 `sentence_transformers.CrossEncoder` 实例,  
并赋值给类属性 `self.reranker`,用于后续的重排序任务。  
"""
        self.reranker = sentence_transformers.CrossEncoder(self.base_rerank)

rebuild(base_rerank, init) classmethod

重建 LazyHuggingFaceRerank 实例的类方法。
主要用于序列化(pickle/cloudpickle)时的反序列化过程,根据提供的参数重新实例化对象。

Parameters:

  • base_rerank (str) –

    模型名称或路径。

  • init (bool) –

    是否在重建时立即加载模型。

Returns:

  • LazyHuggingFaceRerank: 重新构建的类实例。
Source code in lazyllm/components/deploy/embed.py
    @classmethod
    def rebuild(cls, base_rerank, init):
        """重建 `LazyHuggingFaceRerank` 实例的类方法。  
主要用于序列化(pickle/cloudpickle)时的反序列化过程,根据提供的参数重新实例化对象。

Args:
    base_rerank (str): 模型名称或路径。
    init (bool): 是否在重建时立即加载模型。

**Returns:**

- LazyHuggingFaceRerank: 重新构建的类实例。
"""
        return cls(base_rerank, init)

lazyllm.components.deploy.embed.HuggingFaceEmbedding

HuggingFace嵌入模型管理类,用于管理和注册不同的嵌入模型实现。

属性: _model_id_mapping (dict): 模型ID到具体实现类的映射字典。

Parameters:

  • base_embed (str) –

    基础嵌入模型的路径或名称。

  • source (Optional[str], default: None ) –

    模型来源,默认为None。

Source code in lazyllm/components/deploy/embed.py
class HuggingFaceEmbedding:
    """HuggingFace嵌入模型管理类,用于管理和注册不同的嵌入模型实现。

属性:
    _model_id_mapping (dict): 模型ID到具体实现类的映射字典。

Args:
    base_embed (str): 基础嵌入模型的路径或名称。
    source (Optional[str]): 模型来源,默认为None。
"""
    _model_id_mapping = {}

    @classmethod
    def get_emb_cls(cls, model_name: str):
        """获取模型对应的嵌入实现类。

Args:
    model_name (str): 模型名称或路径。

**Returns:**

- type: 返回对应的嵌入模型实现类,如果未找到则返回默认实现LazyHuggingFaceDefaultEmbedding。
"""
        model_id = model_name.split('/')[-1].lower()
        return cls._model_id_mapping.get(model_id, LazyHuggingFaceDefaultEmbedding)

    @classmethod
    def register(cls, model_ids: List[str]):
        """注册模型ID到特定实现类的装饰器。

Args:
    model_ids (List[str]): 要注册的模型ID列表。

**Returns:**

- Callable: 返回装饰器函数。
"""
        def decorator(target_class):
            for ele in model_ids:
                cls._model_id_mapping[ele.lower()] = target_class
            return target_class
        return decorator

    def __init__(self, base_embed, source=None):
        self._embed = self.__class__.get_emb_cls(base_embed)(base_embed, source)

    def load_embed(self):
        """加载嵌入模型。

该方法会调用内部嵌入实现类的load_embed方法来加载模型。
"""
        self._embed.load_embed()

    def __call__(self, *args, **kwargs):
        try:
            args[0]['images'] = [_base64_to_file(image) if _is_base64_with_mime(image) else image
                                 for image in args[0]['images']]
        except Exception as e:
            LOG.error(f'Error converting base64 to image: {e}')
        return self._embed(*args, **kwargs)

get_emb_cls(model_name) classmethod

获取模型对应的嵌入实现类。

Parameters:

  • model_name (str) –

    模型名称或路径。

Returns:

  • type: 返回对应的嵌入模型实现类,如果未找到则返回默认实现LazyHuggingFaceDefaultEmbedding。
Source code in lazyllm/components/deploy/embed.py
    @classmethod
    def get_emb_cls(cls, model_name: str):
        """获取模型对应的嵌入实现类。

Args:
    model_name (str): 模型名称或路径。

**Returns:**

- type: 返回对应的嵌入模型实现类,如果未找到则返回默认实现LazyHuggingFaceDefaultEmbedding。
"""
        model_id = model_name.split('/')[-1].lower()
        return cls._model_id_mapping.get(model_id, LazyHuggingFaceDefaultEmbedding)

register(model_ids) classmethod

注册模型ID到特定实现类的装饰器。

Parameters:

  • model_ids (List[str]) –

    要注册的模型ID列表。

Returns:

  • Callable: 返回装饰器函数。
Source code in lazyllm/components/deploy/embed.py
    @classmethod
    def register(cls, model_ids: List[str]):
        """注册模型ID到特定实现类的装饰器。

Args:
    model_ids (List[str]): 要注册的模型ID列表。

**Returns:**

- Callable: 返回装饰器函数。
"""
        def decorator(target_class):
            for ele in model_ids:
                cls._model_id_mapping[ele.lower()] = target_class
            return target_class
        return decorator

load_embed()

加载嵌入模型。

该方法会调用内部嵌入实现类的load_embed方法来加载模型。

Source code in lazyllm/components/deploy/embed.py
    def load_embed(self):
        """加载嵌入模型。

该方法会调用内部嵌入实现类的load_embed方法来加载模型。
"""
        self._embed.load_embed()

lazyllm.components.deploy.embed.LazyFlagEmbedding

Bases: object

支持懒加载的 FlagEmbedding 嵌入模块封装。

该类包装了 FlagEmbedding 的加载和调用逻辑,提供对稀疏和稠密嵌入的支持,并通过 lazyllm.once_flag() 机制实现懒加载。适用于嵌入模型的本地/远程下载、初始化与编码流程的封装,便于与 LazyLLM 系统集成。

Parameters:

  • base_embed (str) –

    嵌入模型名称或路径。

  • sparse (bool, default: False ) –

    是否使用稀疏嵌入模式,默认为 False。

  • source (str, default: None ) –

    模型下载源,若未提供则使用 lazyllm 全局配置。

  • init (bool, default: False ) –

    是否在初始化时立即加载模型,默认为 False。

Source code in lazyllm/components/deploy/embed.py
class LazyFlagEmbedding(object):
    """支持懒加载的 FlagEmbedding 嵌入模块封装。

该类包装了 FlagEmbedding 的加载和调用逻辑,提供对稀疏和稠密嵌入的支持,并通过 lazyllm.once_flag() 机制实现懒加载。适用于嵌入模型的本地/远程下载、初始化与编码流程的封装,便于与 LazyLLM 系统集成。

Args:
    base_embed (str): 嵌入模型名称或路径。
    sparse (bool): 是否使用稀疏嵌入模式,默认为 False。
    source (str, optional): 模型下载源,若未提供则使用 lazyllm 全局配置。
    init (bool): 是否在初始化时立即加载模型,默认为 False。
"""
    def __init__(self, base_embed, sparse=False, source=None, init=False):
        from ..utils.downloader import ModelManager
        source = lazyllm.config['model_source'] if not source else source
        self.base_embed = ModelManager(source).download(base_embed) or ''
        self.embed = None
        self.device = 'cpu'
        self.sparse = sparse
        self.init_flag = lazyllm.once_flag()
        if init:
            lazyllm.call_once(self.init_flag, self.load_embed)

    def load_embed(self):
        """加载嵌入模型并初始化到设备上。

该方法根据系统是否支持 CUDA 自动选择运行设备(GPU 或 CPU),并从本地或远程加载预训练的 FlagEmbedding 模型。
"""
        self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
        self.embed = fe.FlagAutoModel.from_finetuned(self.base_embed, use_fp16=False, devices=[self.device])

    def __call__(self, data: Dict[str, Union[str, List[str]]]):
        lazyllm.call_once(self.init_flag, self.load_embed)
        string, _ = data['text'], data['images']
        with torch.no_grad():
            model_output = self.embed.encode(string, return_sparse=self.sparse)
        if self.sparse:
            embeddings = model_output['lexical_weights']
            if isinstance(string, list):
                res = [dict(embedding) for embedding in embeddings]
            else:
                res = dict(embeddings)
        else:
            res = model_output['dense_vecs'].tolist()

        if type(string) is list and type(res) is dict:
            return json.dumps([res], default=lambda x: float(x))
        else:
            return json.dumps(res, default=lambda x: float(x))

    @classmethod
    def rebuild(cls, base_embed, sparse, init):
        """重建 LazyFlagEmbedding 实例的方法。

该类方法用于在序列化或跨进程传递时,重新构造带有初始化配置的 LazyFlagEmbedding 实例。

Args:
    base_embed (str): 嵌入模型的路径或模型名称。
    sparse (bool): 是否启用稀疏嵌入。
    init (bool): 是否在构造时立即加载模型。

**Returns:**

- LazyFlagEmbedding: 一个新的 LazyFlagEmbedding 实例。
"""
        return cls(base_embed, sparse, init=init)

    def __reduce__(self):
        init = bool(os.getenv('LAZYLLM_ON_CLOUDPICKLE', None) == 'ON' or self.init_flag)
        return LazyFlagEmbedding.rebuild, (self.base_embed, self.sparse, init)

load_embed()

加载嵌入模型并初始化到设备上。

该方法根据系统是否支持 CUDA 自动选择运行设备(GPU 或 CPU),并从本地或远程加载预训练的 FlagEmbedding 模型。

Source code in lazyllm/components/deploy/embed.py
    def load_embed(self):
        """加载嵌入模型并初始化到设备上。

该方法根据系统是否支持 CUDA 自动选择运行设备(GPU 或 CPU),并从本地或远程加载预训练的 FlagEmbedding 模型。
"""
        self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
        self.embed = fe.FlagAutoModel.from_finetuned(self.base_embed, use_fp16=False, devices=[self.device])

rebuild(base_embed, sparse, init) classmethod

重建 LazyFlagEmbedding 实例的方法。

该类方法用于在序列化或跨进程传递时,重新构造带有初始化配置的 LazyFlagEmbedding 实例。

Parameters:

  • base_embed (str) –

    嵌入模型的路径或模型名称。

  • sparse (bool) –

    是否启用稀疏嵌入。

  • init (bool) –

    是否在构造时立即加载模型。

Returns:

  • LazyFlagEmbedding: 一个新的 LazyFlagEmbedding 实例。
Source code in lazyllm/components/deploy/embed.py
    @classmethod
    def rebuild(cls, base_embed, sparse, init):
        """重建 LazyFlagEmbedding 实例的方法。

该类方法用于在序列化或跨进程传递时,重新构造带有初始化配置的 LazyFlagEmbedding 实例。

Args:
    base_embed (str): 嵌入模型的路径或模型名称。
    sparse (bool): 是否启用稀疏嵌入。
    init (bool): 是否在构造时立即加载模型。

**Returns:**

- LazyFlagEmbedding: 一个新的 LazyFlagEmbedding 实例。
"""
        return cls(base_embed, sparse, init=init)

lazyllm.components.deploy.Mindie

Bases: LazyLLMDeployBase

此类是 LazyLLMDeployBase 的一个子类, 用于部署和管理MindIE大模型推理服务。它封装了MindIE服务的配置生成、进程启动和API交互的全流程。

Parameters:

  • trust_remote_code (bool, default: True ) –

    是否信任远程代码(如HuggingFace模型)。默认为 True

  • launcher

    任务启动器实例,默认为 launchers.remote()

  • log_path (str, default: None ) –

    日志保存路径,若为 None 则不保存日志。

  • **kw

    其他配置参数

Other Parameters:

  • npuDeviceIds

    NPU设备ID列表(如 [[0,1]] 表示使用2张卡)

  • worldSize

    模型并行数量

  • port

    服务端口(设为 'auto' 时自动分配30000-40000的随机端口)

  • maxSeqLen

    最大序列长度

  • maxInputTokenLen

    单次输入最大token数

  • maxPrefillTokens

    预填充token上限

  • config

    自定义配置文件

Notes : 必须预先设置环境变量 LAZYLLM_MINDIE_HOME 指向MindIE安装目录, 若未指定 finetuned_model 或路径无效,会自动回退到 base_model

Examples:

>>> import lazyllm
>>> from lazyllm.components.deploy import Mindie            
>>> deployer = Mindie(
...     port=30000,
...     launcher=lazyllm.launchers.remote(),
...     max_seq_len=32000,
...     log_path="/path/to/logs"
... )
>>> cmd = deployer.cmd(
...     finetuned_model="/path/to/finetuned_model",
...     base_model="/path/to/base_model")
>>> print("Service URL:", cmd.geturl())
Source code in lazyllm/components/deploy/mindie.py
class Mindie(LazyLLMDeployBase):
    """此类是 ``LazyLLMDeployBase`` 的一个子类, 用于部署和管理MindIE大模型推理服务。它封装了MindIE服务的配置生成、进程启动和API交互的全流程。

Args:
    trust_remote_code (bool): 是否信任远程代码(如HuggingFace模型)。默认为 ``True``。
    launcher: 任务启动器实例,默认为 ``launchers.remote()``。
    log_path (str): 日志保存路径,若为 ``None`` 则不保存日志。
    **kw: 其他配置参数

Keyword Args: 
            npuDeviceIds: NPU设备ID列表(如 ``[[0,1]]`` 表示使用2张卡)
            worldSize: 模型并行数量
            port: 服务端口(设为 ``'auto'`` 时自动分配30000-40000的随机端口)
            maxSeqLen: 最大序列长度
            maxInputTokenLen: 单次输入最大token数
            maxPrefillTokens: 预填充token上限
            config: 自定义配置文件

Notes
                : 
   必须预先设置环境变量 ``LAZYLLM_MINDIE_HOME`` 指向MindIE安装目录, 若未指定 ``finetuned_model`` 或路径无效,会自动回退到 ``base_model``


Examples:
    >>> import lazyllm
    >>> from lazyllm.components.deploy import Mindie            
    >>> deployer = Mindie(
    ...     port=30000,
    ...     launcher=lazyllm.launchers.remote(),
    ...     max_seq_len=32000,
    ...     log_path="/path/to/logs"
    ... )
    >>> cmd = deployer.cmd(
    ...     finetuned_model="/path/to/finetuned_model",
    ...     base_model="/path/to/base_model")
    >>> print("Service URL:", cmd.geturl())

    """
    keys_name_handle = {
        'inputs': 'prompt',
    }
    default_headers = {'Content-Type': 'application/json'}
    message_format = {
        'prompt': 'Who are you ?',
        'stream': False,
        'max_tokens': 4096,
        'presence_penalty': 1.03,
        'frequency_penalty': 1.0,
        'temperature': 0.5,
        'top_p': 0.95
    }
    auto_map = {
        'port': int,
        'tp': ('world_size', int),
        'max_input_token_len': ('maxInputTokenLen', int),
        'max_prefill_tokens': ('maxPrefillTokens', int),
        'max_seq_len': ('maxSeqLen', int)
    }

    def __init__(self, trust_remote_code=True, launcher=launchers.remote(), log_path=None, **kw):  # noqa B008
        super().__init__(launcher=launcher)
        assert lazyllm.config['mindie_home'], 'Ensure you have installed MindIE and \
                                  "export LAZYLLM_MINDIE_HOME=/path/to/mindie/latest"'
        self.mindie_home = lazyllm.config['mindie_home']
        self.mindie_config_path = os.path.join(self.mindie_home, 'mindie-service/conf/config.json')
        self.backup_path = self.mindie_config_path + '.backup'
        self.custom_config = kw.pop('config', None)
        self.kw = ArgsDict({
            'npuDeviceIds': [[0]],
            'worldSize': 1,
            'port': 'auto',
            'host': '0.0.0.0',
            'maxSeqLen': 64000,
            'maxInputTokenLen': 4096,
            'maxPrefillTokens': 8192,
        })
        self.trust_remote_code = trust_remote_code
        self.options_keys = kw.pop('options_keys', [])
        assert len(self.options_keys) == 0, 'options_keys is not supported'
        self.kw.check_and_update(kw)
        self.kw['npuDeviceIds'] = [[i for i in range(self.kw.get('worldSize', 1))]]
        self.random_port = False if 'port' in kw and kw['port'] and kw['port'] != 'auto' else True
        self.temp_folder = make_log_dir(log_path, 'mindie') if log_path else None

        if self.custom_config:
            self.config_dict = (ArgsDict(self.load_config(self.custom_config))
                                if isinstance(self.custom_config, str) else ArgsDict(self.custom_config))
            self.kw['host'] = self.config_dict['ServerConfig']['ipAddress']
            self.kw['port'] = self.config_dict['ServerConfig']['port']
        else:
            default_config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'mindie', 'config.json')
            self.config_dict = ArgsDict(self.load_config(default_config_path))

    def __del__(self):
        if hasattr(self, 'backup_path') and os.path.isfile(self.backup_path):
            shutil.copy2(self.backup_path, self.mindie_config_path)

    def load_config(self, config_path):
        """加载并解析MindIE配置文件。

Args:
    config_path (str): JSON配置文件的路径

**Returns:**

- dict: 解析后的配置字典

注意事项:
    - 处理默认和自定义配置文件
    - 使用JSON格式配置
    - 修改前会创建原始配置的备份
"""
        with open(config_path, 'r') as file:
            config_dict = json.load(file)
        return config_dict

    def save_config(self):
        """保存当前配置到文件。

注意事项:
    - 自动创建现有配置的备份
    - 写入到标准MindIE配置位置
    - 使用带缩进的JSON格式
    - 部署时自动调用
"""
        if os.path.isfile(self.mindie_config_path):
            shutil.copy2(self.mindie_config_path, self.backup_path)

        with open(self.mindie_config_path, 'w') as file:
            json.dump(self.config_dict, file)

    def update_config(self):
        """使用当前设置更新配置字典。

注意事项:
    - 处理多个配置部分:
        - 模型部署参数
        - 服务器设置
        - 调度参数
"""
        backend_config = self.config_dict['BackendConfig']
        backend_config['npuDeviceIds'] = self.kw['npuDeviceIds']
        model_config = {
            'modelName': self.finetuned_model.split('/')[-1],
            'modelWeightPath': self.finetuned_model,
            'worldSize': self.kw['worldSize'],
            'trust_remote_code': self.trust_remote_code
        }
        backend_config['ModelDeployConfig']['ModelConfig'][0].update(model_config)
        backend_config['ModelDeployConfig']['maxSeqLen'] = self.kw['maxSeqLen']
        backend_config['ModelDeployConfig']['maxInputTokenLen'] = self.kw['maxInputTokenLen']
        backend_config['ScheduleConfig']['maxPrefillTokens'] = self.kw['maxPrefillTokens']
        self.config_dict['BackendConfig'] = backend_config
        if self.kw['host'] != '0.0.0.0':
            self.config_dict['ServerConfig']['ipAddress'] = self.kw['host']
        self.config_dict['ServerConfig']['port'] = self.kw['port']

    def cmd(self, finetuned_model=None, base_model=None, master_ip=None):
        """生成启动MindIE服务的命令。

Args:
    finetuned_model (str): 微调模型路径
    base_model (str): 基础模型路径(当微调模型无效时作为后备)
    master_ip (str): 主节点IP地址(当前未使用)

**Returns:**

- LazyLLMCMD: 启动服务的命令对象

注意事项:
    - 自动处理模型路径验证
    - 启动服务前更新配置
    - 支持配置随机端口分配
"""
        if self.custom_config is None:
            self.finetuned_model = finetuned_model
            if finetuned_model or base_model:
                if not os.path.exists(finetuned_model) or \
                    not any(filename.endswith('.bin') or filename.endswith('.safetensors')
                            for filename in os.listdir(finetuned_model)):
                    if not finetuned_model:
                        LOG.warning(f'Note! That finetuned_model({finetuned_model}) is an invalid path, '
                                    f'base_model({base_model}) will be used')
                    self.finetuned_model = base_model

            if self.random_port:
                self.kw['port'] = random.randint(30000, 40000)

            self.update_config()

        self.save_config()

        def impl():
            cmd = f'{os.path.join(self.mindie_home, "mindie-service/bin/mindieservice_daemon")}'
            if self.temp_folder: cmd += f' 2>&1 | tee {get_log_path(self.temp_folder)}'
            return cmd

        return LazyLLMCMD(cmd=impl, return_value=self.geturl, checkf=verify_fastapi_func)

    def geturl(self, job=None):
        """获取部署后的服务URL。

Args:
    job: 任务对象(可选,默认为self.job)

**Returns:**

- str: generate接口的URL

注意事项:
    - 根据显示模式返回不同格式
    - 包含配置中的端口号
"""
        if job is None:
            job = self.job
        if lazyllm.config['mode'] == lazyllm.Mode.Display:
            return f'http://{job.get_jobip()}:{self.kw["port"]}/generate'
        else:
            LOG.info(f'MindIE Server running on http://{job.get_jobip()}:{self.kw["port"]}')
            return f'http://{job.get_jobip()}:{self.kw["port"]}/generate'

    @staticmethod
    def extract_result(x, inputs):
        """从API响应中提取生成的文本。

Args:
    x: 原始API响应
    inputs: 原始输入(未使用)

**Returns:**

- str: 生成的文本

注意事项:
    - 解析JSON响应
    - 返回响应中的第一个文本条目
"""
        return json.loads(x)['text'][0]

cmd(finetuned_model=None, base_model=None, master_ip=None)

生成启动MindIE服务的命令。

Parameters:

  • finetuned_model (str, default: None ) –

    微调模型路径

  • base_model (str, default: None ) –

    基础模型路径(当微调模型无效时作为后备)

  • master_ip (str, default: None ) –

    主节点IP地址(当前未使用)

Returns:

  • LazyLLMCMD: 启动服务的命令对象
注意事项
  • 自动处理模型路径验证
  • 启动服务前更新配置
  • 支持配置随机端口分配
Source code in lazyllm/components/deploy/mindie.py
    def cmd(self, finetuned_model=None, base_model=None, master_ip=None):
        """生成启动MindIE服务的命令。

Args:
    finetuned_model (str): 微调模型路径
    base_model (str): 基础模型路径(当微调模型无效时作为后备)
    master_ip (str): 主节点IP地址(当前未使用)

**Returns:**

- LazyLLMCMD: 启动服务的命令对象

注意事项:
    - 自动处理模型路径验证
    - 启动服务前更新配置
    - 支持配置随机端口分配
"""
        if self.custom_config is None:
            self.finetuned_model = finetuned_model
            if finetuned_model or base_model:
                if not os.path.exists(finetuned_model) or \
                    not any(filename.endswith('.bin') or filename.endswith('.safetensors')
                            for filename in os.listdir(finetuned_model)):
                    if not finetuned_model:
                        LOG.warning(f'Note! That finetuned_model({finetuned_model}) is an invalid path, '
                                    f'base_model({base_model}) will be used')
                    self.finetuned_model = base_model

            if self.random_port:
                self.kw['port'] = random.randint(30000, 40000)

            self.update_config()

        self.save_config()

        def impl():
            cmd = f'{os.path.join(self.mindie_home, "mindie-service/bin/mindieservice_daemon")}'
            if self.temp_folder: cmd += f' 2>&1 | tee {get_log_path(self.temp_folder)}'
            return cmd

        return LazyLLMCMD(cmd=impl, return_value=self.geturl, checkf=verify_fastapi_func)

extract_result(x, inputs) staticmethod

从API响应中提取生成的文本。

Parameters:

  • x

    原始API响应

  • inputs

    原始输入(未使用)

Returns:

  • str: 生成的文本
注意事项
  • 解析JSON响应
  • 返回响应中的第一个文本条目
Source code in lazyllm/components/deploy/mindie.py
    @staticmethod
    def extract_result(x, inputs):
        """从API响应中提取生成的文本。

Args:
    x: 原始API响应
    inputs: 原始输入(未使用)

**Returns:**

- str: 生成的文本

注意事项:
    - 解析JSON响应
    - 返回响应中的第一个文本条目
"""
        return json.loads(x)['text'][0]

geturl(job=None)

获取部署后的服务URL。

Parameters:

  • job

    任务对象(可选,默认为self.job)

Returns:

  • str: generate接口的URL
注意事项
  • 根据显示模式返回不同格式
  • 包含配置中的端口号
Source code in lazyllm/components/deploy/mindie.py
    def geturl(self, job=None):
        """获取部署后的服务URL。

Args:
    job: 任务对象(可选,默认为self.job)

**Returns:**

- str: generate接口的URL

注意事项:
    - 根据显示模式返回不同格式
    - 包含配置中的端口号
"""
        if job is None:
            job = self.job
        if lazyllm.config['mode'] == lazyllm.Mode.Display:
            return f'http://{job.get_jobip()}:{self.kw["port"]}/generate'
        else:
            LOG.info(f'MindIE Server running on http://{job.get_jobip()}:{self.kw["port"]}')
            return f'http://{job.get_jobip()}:{self.kw["port"]}/generate'

load_config(config_path)

加载并解析MindIE配置文件。

Parameters:

  • config_path (str) –

    JSON配置文件的路径

Returns:

  • dict: 解析后的配置字典
注意事项
  • 处理默认和自定义配置文件
  • 使用JSON格式配置
  • 修改前会创建原始配置的备份
Source code in lazyllm/components/deploy/mindie.py
    def load_config(self, config_path):
        """加载并解析MindIE配置文件。

Args:
    config_path (str): JSON配置文件的路径

**Returns:**

- dict: 解析后的配置字典

注意事项:
    - 处理默认和自定义配置文件
    - 使用JSON格式配置
    - 修改前会创建原始配置的备份
"""
        with open(config_path, 'r') as file:
            config_dict = json.load(file)
        return config_dict

save_config()

保存当前配置到文件。

注意事项
  • 自动创建现有配置的备份
  • 写入到标准MindIE配置位置
  • 使用带缩进的JSON格式
  • 部署时自动调用
Source code in lazyllm/components/deploy/mindie.py
    def save_config(self):
        """保存当前配置到文件。

注意事项:
    - 自动创建现有配置的备份
    - 写入到标准MindIE配置位置
    - 使用带缩进的JSON格式
    - 部署时自动调用
"""
        if os.path.isfile(self.mindie_config_path):
            shutil.copy2(self.mindie_config_path, self.backup_path)

        with open(self.mindie_config_path, 'w') as file:
            json.dump(self.config_dict, file)

update_config()

使用当前设置更新配置字典。

注意事项
  • 处理多个配置部分:
    • 模型部署参数
    • 服务器设置
    • 调度参数
Source code in lazyllm/components/deploy/mindie.py
    def update_config(self):
        """使用当前设置更新配置字典。

注意事项:
    - 处理多个配置部分:
        - 模型部署参数
        - 服务器设置
        - 调度参数
"""
        backend_config = self.config_dict['BackendConfig']
        backend_config['npuDeviceIds'] = self.kw['npuDeviceIds']
        model_config = {
            'modelName': self.finetuned_model.split('/')[-1],
            'modelWeightPath': self.finetuned_model,
            'worldSize': self.kw['worldSize'],
            'trust_remote_code': self.trust_remote_code
        }
        backend_config['ModelDeployConfig']['ModelConfig'][0].update(model_config)
        backend_config['ModelDeployConfig']['maxSeqLen'] = self.kw['maxSeqLen']
        backend_config['ModelDeployConfig']['maxInputTokenLen'] = self.kw['maxInputTokenLen']
        backend_config['ScheduleConfig']['maxPrefillTokens'] = self.kw['maxPrefillTokens']
        self.config_dict['BackendConfig'] = backend_config
        if self.kw['host'] != '0.0.0.0':
            self.config_dict['ServerConfig']['ipAddress'] = self.kw['host']
        self.config_dict['ServerConfig']['port'] = self.kw['port']

lazyllm.components.deploy.OCRDeploy

Bases: LazyLLMDeployBase

OCRDeploy 是 LazyLLMDeployBase 的子类,用于部署 OCR(光学字符识别)模型。 此类支持额外的配置,例如日志记录、远程代码信任以及端口自定义。

属性:

keys_name_handle: 一个字典,用于将输入键映射到相应的处理键。例如:
    - "inputs": 处理一般输入。
    - "ocr_files": 同样映射到 "inputs"。
message_format: 一个字典,指定模型期望的消息格式。例如:
    - {"inputs": "/path/to/pdf"} 表示模型需要一个 PDF 文件路径作为输入。
default_headers: 一个字典,指定 API 请求的默认头部。默认为:
    - {"Content-Type": "application/json"}

Parameters:

  • launcher

    启动器实例,用于部署模型。默认为 None

  • log_path

    字符串,指定日志保存的路径。默认为 None

  • trust_remote_code

    布尔值,指示是否信任远程代码执行。默认为 True

  • port

    整数,指定部署服务器的端口号。默认为 None

Returns:

  • OCRDeploy实例,可通过调用方式启动服务

Examples:

>>> from lazyllm.components import OCRDeploy
>>> from lazyllm import launchers
>>> # 创建一个 OCRDeploy 实例
>>> deployer = OCRDeploy(launcher=launchers.local(), log_path='./logs', port=8080)
>>> # 使用微调的 OCR 模型部署服务器
>>> server = deployer(finetuned_model='ocr-model')
>>> # 打印部署服务器信息
>>> print(server)
... <RelayServer instance ready to handle OCR requests>
Source code in lazyllm/components/deploy/ocr/pp_ocr.py
class OCRDeploy(LazyLLMDeployBase):
    """OCRDeploy 是 [LazyLLMDeployBase][lazyllm.components.LazyLLMDeployBase] 的子类,用于部署 OCR(光学字符识别)模型。
此类支持额外的配置,例如日志记录、远程代码信任以及端口自定义。

属性:

    keys_name_handle: 一个字典,用于将输入键映射到相应的处理键。例如:
        - "inputs": 处理一般输入。
        - "ocr_files": 同样映射到 "inputs"。
    message_format: 一个字典,指定模型期望的消息格式。例如:
        - {"inputs": "/path/to/pdf"} 表示模型需要一个 PDF 文件路径作为输入。
    default_headers: 一个字典,指定 API 请求的默认头部。默认为:
        - {"Content-Type": "application/json"}

Args:
    launcher: 启动器实例,用于部署模型。默认为 `None`。
    log_path: 字符串,指定日志保存的路径。默认为 `None`。
    trust_remote_code: 布尔值,指示是否信任远程代码执行。默认为 `True`。
    port: 整数,指定部署服务器的端口号。默认为 `None`。

Returns:
    OCRDeploy实例,可通过调用方式启动服务


Examples:
    >>> from lazyllm.components import OCRDeploy
    >>> from lazyllm import launchers
    >>> # 创建一个 OCRDeploy 实例
    >>> deployer = OCRDeploy(launcher=launchers.local(), log_path='./logs', port=8080)
    >>> # 使用微调的 OCR 模型部署服务器
    >>> server = deployer(finetuned_model='ocr-model')
    >>> # 打印部署服务器信息
    >>> print(server)
    ... <RelayServer instance ready to handle OCR requests>
    """
    keys_name_handle = {
        'inputs': 'inputs',
        'ocr_files': 'inputs',
    }
    message_format = {'inputs': '/path/to/pdf'}
    default_headers = {'Content-Type': 'application/json'}

    def __init__(self, launcher=None, log_path=None, trust_remote_code=True, port=None, **kw):
        super().__init__(launcher=launcher)
        self._log_path = log_path
        self._trust_remote_code = trust_remote_code
        self._port = port

    def __call__(self, finetuned_model=None, base_model=None):
        if not finetuned_model:
            finetuned_model = base_model
        return lazyllm.deploy.RelayServer(
            port=self._port, func=_OCR(finetuned_model), launcher=self._launcher, log_path=self._log_path, cls='ocr')()

lazyllm.components.deploy.Infinity

Bases: LazyLLMDeployBase

此类是 LazyLLMDeployBase 的子类,基于 Infinity 框架提供的高性能文本嵌入、重排序和CLIP等能力。

Parameters:

  • launcher (launcher, default: remote(ngpus=1) ) –

    Infinity 的启动器,默认为 launchers.remote(ngpus=1)

  • kw

    关键字参数,用于更新默认的训练参数。请注意,除了以下列出的关键字参数外,这里不能传入额外的关键字参数。

此类的关键字参数及其默认值如下:

Other Parameters:

  • launcher (Launcher) –

    启动器配置,默认为remote(ngpus=1)。

  • model_type (str) –

    模型类型,默认为'embed'。

  • log_path (str) –

    日志文件路径,默认为None。

  • **kw

    额外的配置参数,包括host、port、batch-size等。

Examples:

>>> import lazyllm
>>> from lazyllm import deploy
>>> deploy.Infinity()
<lazyllm.llm.deploy type=Infinity>
Source code in lazyllm/components/deploy/infinity.py
class Infinity(LazyLLMDeployBase):
    """此类是 ``LazyLLMDeployBase`` 的子类,基于 [Infinity](https://github.com/michaelfeil/infinity) 框架提供的高性能文本嵌入、重排序和CLIP等能力。

Args:
    launcher (lazyllm.launcher): Infinity 的启动器,默认为 ``launchers.remote(ngpus=1)``。
    kw: 关键字参数,用于更新默认的训练参数。请注意,除了以下列出的关键字参数外,这里不能传入额外的关键字参数。

此类的关键字参数及其默认值如下:

Keyword Args: 
    launcher (Launcher, optional): 启动器配置,默认为remote(ngpus=1)。
    model_type (str, optional): 模型类型,默认为'embed'。
    log_path (str, optional): 日志文件路径,默认为None。
    **kw: 额外的配置参数,包括host、port、batch-size等。



Examples:
    >>> import lazyllm
    >>> from lazyllm import deploy
    >>> deploy.Infinity()
    <lazyllm.llm.deploy type=Infinity>
    """
    keys_name_handle = {
        'inputs': 'input',
    }
    message_format = {
        'input': 'who are you ?',
    }
    default_headers = {'Content-Type': 'application/json'}
    target_name = 'embeddings'

    def __init__(self, launcher=launchers.remote(ngpus=1), model_type='embed', log_path=None, **kw):  # noqa B008
        super().__init__(launcher=launcher)
        self.kw = ArgsDict({
            'host': '0.0.0.0',
            'port': None,
            'batch-size': 256,
        })
        self._model_type = model_type
        kw.pop('stream', '')
        self.options_keys = kw.pop('options_keys', [])
        self.kw.check_and_update(kw)
        self.random_port = False if 'port' in kw and kw['port'] else True
        self.temp_folder = make_log_dir(log_path, 'lmdeploy') if log_path else None

    def cmd(self, finetuned_model=None, base_model=None):
        if not os.path.exists(finetuned_model) or \
            not any(filename.endswith('.bin') or filename.endswith('.safetensors')
                    for filename in os.listdir(finetuned_model)):
            if not finetuned_model:
                LOG.warning(f'Note! That finetuned_model({finetuned_model}) is an invalid path, '
                            f'base_model({base_model}) will be used')
            finetuned_model = base_model

        def impl():
            if self.random_port:
                self.kw['port'] = random.randint(30000, 40000)
            cmd = f'infinity_emb v2 --model-id {finetuned_model} '
            if isinstance(self._launcher, launchers.EmptyLauncher) and self._launcher.ngpus:
                available_gpus = self._launcher._get_idle_gpus()
                required_count = self._launcher.ngpus
                if required_count <= len(available_gpus):
                    gpu_ids = ','.join(map(str, available_gpus[:required_count]))
                    cmd += f'--device-id={gpu_ids} '
                else:
                    raise RuntimeError(
                        f'Insufficient GPUs available (required: {required_count}, '
                        f'available: {len(available_gpus)})'
                    )
            cmd += self.kw.parse_kwargs()
            cmd += ' ' + parse_options_keys(self.options_keys)
            if self.temp_folder: cmd += f' 2>&1 | tee {get_log_path(self.temp_folder)}'
            return cmd

        return LazyLLMCMD(cmd=impl, return_value=self.geturl, checkf=verify_fastapi_func)

    def geturl(self, job=None):
        """获取Infinity服务的URL地址。根据部署模式和作业状态,返回对应的API访问URL地址。

Args:
    job (Optional[Any]): 作业对象,如果为None则使用当前实例的job属性。
"""
        if job is None:
            job = self.job
        if lazyllm.config['mode'] == lazyllm.Mode.Display:
            return f'http://<ip>:<port>/{self.target_name}'
        else:
            return f'http://{job.get_jobip()}:{self.kw["port"]}/{self.target_name}'

    @staticmethod
    def extract_result(x, inputs):
        """从Infinity API响应中提取结果数据。
解析Infinity服务的JSON响应,根据返回的对象类型提取嵌入向量或重排序结果。

Args:
    x (str): API返回的JSON字符串响应。
    inputs (Dict): 原始输入数据,用于确定返回结果的格式。
"""
        try:
            res_object = json.loads(x)
        except Exception as e:
            LOG.warning(f'JSONDecodeError on load {x}')
            raise e
        assert 'object' in res_object
        object_type = res_object['object']
        if object_type == 'list':  # for infinity >= 0.0.64
            object_type = res_object['data'][0]['object']
        if object_type == 'embedding':
            res_list = [item['embedding'] for item in res_object['data']]
            if len(res_list) == 1 and type(inputs['input']) is str:
                res_list = res_list[0]
            return json.dumps(res_list)
        elif object_type == 'rerank':
            return [(x['index'], x['relevance_score']) for x in res_object['results']]

extract_result(x, inputs) staticmethod

从Infinity API响应中提取结果数据。 解析Infinity服务的JSON响应,根据返回的对象类型提取嵌入向量或重排序结果。

Parameters:

  • x (str) –

    API返回的JSON字符串响应。

  • inputs (Dict) –

    原始输入数据,用于确定返回结果的格式。

Source code in lazyllm/components/deploy/infinity.py
    @staticmethod
    def extract_result(x, inputs):
        """从Infinity API响应中提取结果数据。
解析Infinity服务的JSON响应,根据返回的对象类型提取嵌入向量或重排序结果。

Args:
    x (str): API返回的JSON字符串响应。
    inputs (Dict): 原始输入数据,用于确定返回结果的格式。
"""
        try:
            res_object = json.loads(x)
        except Exception as e:
            LOG.warning(f'JSONDecodeError on load {x}')
            raise e
        assert 'object' in res_object
        object_type = res_object['object']
        if object_type == 'list':  # for infinity >= 0.0.64
            object_type = res_object['data'][0]['object']
        if object_type == 'embedding':
            res_list = [item['embedding'] for item in res_object['data']]
            if len(res_list) == 1 and type(inputs['input']) is str:
                res_list = res_list[0]
            return json.dumps(res_list)
        elif object_type == 'rerank':
            return [(x['index'], x['relevance_score']) for x in res_object['results']]

geturl(job=None)

获取Infinity服务的URL地址。根据部署模式和作业状态,返回对应的API访问URL地址。

Parameters:

  • job (Optional[Any], default: None ) –

    作业对象,如果为None则使用当前实例的job属性。

Source code in lazyllm/components/deploy/infinity.py
    def geturl(self, job=None):
        """获取Infinity服务的URL地址。根据部署模式和作业状态,返回对应的API访问URL地址。

Args:
    job (Optional[Any]): 作业对象,如果为None则使用当前实例的job属性。
"""
        if job is None:
            job = self.job
        if lazyllm.config['mode'] == lazyllm.Mode.Display:
            return f'http://<ip>:<port>/{self.target_name}'
        else:
            return f'http://{job.get_jobip()}:{self.kw["port"]}/{self.target_name}'

lazyllm.components.deploy.relay.base.RelayServer

Bases: LazyLLMDeployBase

Source code in lazyllm/components/deploy/relay/base.py
class RelayServer(LazyLLMDeployBase):
    keys_name_handle = None
    default_headers = {'Content-Type': 'application/json'}
    message_format = None

    def __init__(self, port=None, *, func=None, pre_func=None, post_func=None, pythonpath=None,
                 log_path=None, cls=None, launcher=launchers.remote(sync=False), num_replicas: int = 1):  # noqa B008
        # func must dump in __call__ to wait for dependancies.
        self._func = func
        self._pre = dump_obj(pre_func)
        self._post = dump_obj(post_func)
        self._port, self._real_port = port, None
        self._pythonpath = pythonpath
        self._num_replicas = num_replicas
        super().__init__(launcher=launcher)
        self.temp_folder = make_log_dir(log_path, cls or 'relay') if log_path else None

    def cmd(self, func=None):
        FastapiApp.update()
        self._func = dump_obj(func or self._func)
        folder_path = os.path.dirname(os.path.abspath(__file__))
        run_file_path = os.path.join(folder_path, 'server.py')

        def impl():
            self._real_port = self._port if self._port else random.randint(30000, 40000)
            cmd = f'{sys.executable} {run_file_path} --open_port={self._real_port} --function="{self._func}" '
            if self._pre:
                cmd += f'--before_function="{self._pre}" '
            if self._post:
                cmd += f'--after_function="{self._post}" '
            if self._pythonpath:
                cmd += f'--pythonpath="{self._pythonpath}" '
            if self._num_replicas > 1 and config['use_ray']:
                cmd += f'--num_replicas={self._num_replicas}'
            if self.temp_folder: cmd += f' 2>&1 | tee {get_log_path(self.temp_folder)}'
            return cmd

        return LazyLLMCMD(cmd=impl, return_value=self.geturl,
                          checkf=verify_ray_func if config['use_ray'] else verify_fastapi_func,
                          no_displays=['function', 'before_function', 'after_function'])

    def geturl(self, job=None):
        if job is None:
            job = self.job
        return f'http://{job.get_jobip()}:{self._real_port}/generate'

lazyllm.components.deploy.OCRDeploy

Bases: LazyLLMDeployBase

OCRDeploy 是 LazyLLMDeployBase 的子类,用于部署 OCR(光学字符识别)模型。 此类支持额外的配置,例如日志记录、远程代码信任以及端口自定义。

属性:

keys_name_handle: 一个字典,用于将输入键映射到相应的处理键。例如:
    - "inputs": 处理一般输入。
    - "ocr_files": 同样映射到 "inputs"。
message_format: 一个字典,指定模型期望的消息格式。例如:
    - {"inputs": "/path/to/pdf"} 表示模型需要一个 PDF 文件路径作为输入。
default_headers: 一个字典,指定 API 请求的默认头部。默认为:
    - {"Content-Type": "application/json"}

Parameters:

  • launcher

    启动器实例,用于部署模型。默认为 None

  • log_path

    字符串,指定日志保存的路径。默认为 None

  • trust_remote_code

    布尔值,指示是否信任远程代码执行。默认为 True

  • port

    整数,指定部署服务器的端口号。默认为 None

Returns:

  • OCRDeploy实例,可通过调用方式启动服务

Examples:

>>> from lazyllm.components import OCRDeploy
>>> from lazyllm import launchers
>>> # 创建一个 OCRDeploy 实例
>>> deployer = OCRDeploy(launcher=launchers.local(), log_path='./logs', port=8080)
>>> # 使用微调的 OCR 模型部署服务器
>>> server = deployer(finetuned_model='ocr-model')
>>> # 打印部署服务器信息
>>> print(server)
... <RelayServer instance ready to handle OCR requests>
Source code in lazyllm/components/deploy/ocr/pp_ocr.py
class OCRDeploy(LazyLLMDeployBase):
    """OCRDeploy 是 [LazyLLMDeployBase][lazyllm.components.LazyLLMDeployBase] 的子类,用于部署 OCR(光学字符识别)模型。
此类支持额外的配置,例如日志记录、远程代码信任以及端口自定义。

属性:

    keys_name_handle: 一个字典,用于将输入键映射到相应的处理键。例如:
        - "inputs": 处理一般输入。
        - "ocr_files": 同样映射到 "inputs"。
    message_format: 一个字典,指定模型期望的消息格式。例如:
        - {"inputs": "/path/to/pdf"} 表示模型需要一个 PDF 文件路径作为输入。
    default_headers: 一个字典,指定 API 请求的默认头部。默认为:
        - {"Content-Type": "application/json"}

Args:
    launcher: 启动器实例,用于部署模型。默认为 `None`。
    log_path: 字符串,指定日志保存的路径。默认为 `None`。
    trust_remote_code: 布尔值,指示是否信任远程代码执行。默认为 `True`。
    port: 整数,指定部署服务器的端口号。默认为 `None`。

Returns:
    OCRDeploy实例,可通过调用方式启动服务


Examples:
    >>> from lazyllm.components import OCRDeploy
    >>> from lazyllm import launchers
    >>> # 创建一个 OCRDeploy 实例
    >>> deployer = OCRDeploy(launcher=launchers.local(), log_path='./logs', port=8080)
    >>> # 使用微调的 OCR 模型部署服务器
    >>> server = deployer(finetuned_model='ocr-model')
    >>> # 打印部署服务器信息
    >>> print(server)
    ... <RelayServer instance ready to handle OCR requests>
    """
    keys_name_handle = {
        'inputs': 'inputs',
        'ocr_files': 'inputs',
    }
    message_format = {'inputs': '/path/to/pdf'}
    default_headers = {'Content-Type': 'application/json'}

    def __init__(self, launcher=None, log_path=None, trust_remote_code=True, port=None, **kw):
        super().__init__(launcher=launcher)
        self._log_path = log_path
        self._trust_remote_code = trust_remote_code
        self._port = port

    def __call__(self, finetuned_model=None, base_model=None):
        if not finetuned_model:
            finetuned_model = base_model
        return lazyllm.deploy.RelayServer(
            port=self._port, func=_OCR(finetuned_model), launcher=self._launcher, log_path=self._log_path, cls='ocr')()

lazyllm.components.deploy.text_to_speech.utils.TTSBase

Bases: LazyLLMDeployBase

TTS(文本转语音)服务的基类。

提供文本转语音服务的部署基础框架,支持模型加载和RelayServer部署。

Parameters:

  • launcher (LazyLLMLaunchersBase, default: None ) –

    任务启动器

  • log_path (str, default: None ) –

    日志文件路径

  • port (int, default: None ) –

    服务端口号

Source code in lazyllm/components/deploy/text_to_speech/utils.py
class TTSBase(LazyLLMDeployBase):
    """TTS(文本转语音)服务的基类。

提供文本转语音服务的部署基础框架,支持模型加载和RelayServer部署。

Args:
    launcher (LazyLLMLaunchersBase, optional): 任务启动器
    log_path (str, optional): 日志文件路径
    port (int, optional): 服务端口号
"""
    func = None

    def __init__(self, launcher: LazyLLMLaunchersBase = None,
                 log_path: Optional[str] = None, port: Optional[int] = None, **kw):
        super().__init__(launcher=launcher)
        self._log_path = log_path
        self._port = port

    def __call__(self, finetuned_model=None, base_model=None):
        if not finetuned_model:
            finetuned_model = base_model
        elif not os.path.exists(finetuned_model) or \
            not any(file.endswith(('.bin', '.safetensors'))
                    for _, _, filenames in os.walk(finetuned_model) for file in filenames):
            LOG.warning(f'Note! That finetuned_model({finetuned_model}) is an invalid path, '
                        f'base_model({base_model}) will be used')
            finetuned_model = base_model
        return lazyllm.deploy.RelayServer(port=self._port, func=self.__class__.func(finetuned_model),
                                          launcher=self._launcher, log_path=self._log_path, cls='tts')()

lazyllm.components.deploy.relay.base.FastapiApp

Bases: object

Source code in lazyllm/components/deploy/relay/base.py
class FastapiApp(object):
    __relay_services__ = []

    @staticmethod
    def _server(method, path, **kw):
        def impl(f):
            FastapiApp.__relay_services__.append([f, method, path, kw])
            return f
        return impl

    @staticmethod
    def get(path, **kw):
        return FastapiApp._server('get', path, **kw)

    @staticmethod
    def post(path, **kw):
        return FastapiApp._server('post', path, **kw)

    @staticmethod
    def list(path, **kw):
        return FastapiApp._server('list', path, **kw)

    @staticmethod
    def delete(path, **kw):
        return FastapiApp._server('delete', path, **kw)

    @staticmethod
    def update():
        for f, method, path, kw in FastapiApp.__relay_services__:
            cls = inspect._findclass(f)
            if '__relay_services__' not in cls.__dict__:
                cls.__relay_services__ = dict()
            cls.__relay_services__[method, path] = ([f.__name__, kw])
        FastapiApp.__relay_services__.clear()

Prompter

lazyllm.components.prompter.LazyLLMPrompterBase

LazyLLM提示词基类,用于管理和生成模型提示词。

Parameters:

  • show (bool, default: False ) –

    是否显示生成的提示词,默认为False。

  • tools (Optional[List], default: None ) –

    可用工具列表,默认为None。

  • history (Optional[List], default: None ) –

    对话历史记录,默认为None。

Attributes:

  • ISA (str) –

    指令分隔符起始标记 "<!lazyllm-spliter!>"。

  • ISE (str) –

    指令分隔符结束标记 "</!lazyllm-spliter!>"。

Configuration Items
  • system: 系统角色设定

  • sos/eos: 会话开始/结束标记

  • soh/eoh: 人类输入开始/结束标记

  • soa/eoa: AI回复开始/结束标记

  • soe/eoe: 工具执行结果开始/结束标记

  • tool_start_token/tool_end_token: 工具调用开始/结束标记

  • tool_args_token: 工具参数标记

Source code in lazyllm/components/prompter/builtinPrompt.py
class LazyLLMPrompterBase(metaclass=LazyLLMRegisterMetaClass):
    """LazyLLM提示词基类,用于管理和生成模型提示词。

Args:
    show (bool): 是否显示生成的提示词,默认为False。
    tools (Optional[List]): 可用工具列表,默认为None。
    history (Optional[List]): 对话历史记录,默认为None。

Attributes:
    ISA (str): 指令分隔符起始标记 "<!lazyllm-spliter!>"。

    ISE (str): 指令分隔符结束标记 "</!lazyllm-spliter!>"。


Configuration Items:
    - system: 系统角色设定

    - sos/eos: 会话开始/结束标记

    - soh/eoh: 人类输入开始/结束标记

    - soa/eoa: AI回复开始/结束标记

    - soe/eoe: 工具执行结果开始/结束标记

    - tool_start_token/tool_end_token: 工具调用开始/结束标记

    - tool_args_token: 工具参数标记

"""
    ISA = '<!lazyllm-spliter!>'
    ISE = '</!lazyllm-spliter!>'

    def __init__(self, show=False, tools=None, history=None):
        self._set_model_configs(system='You are an AI-Agent developed by LazyLLM.', sos='',
                                soh='', soa='', eos='', eoh='', eoa='')
        self._show = show
        self._tools = tools
        self._pre_hook = None
        self._history = history or []

    def _init_prompt(self, template: str, instruction_template: str, split: Union[None, str] = None):
        self._template = template
        self._instruction_template = instruction_template
        if split:
            assert not hasattr(self, '_split')
            self._split = split

    @staticmethod
    def _get_extro_key_template(extra_keys, prefix='Here are some extra messages you can referred to:\n\n'):
        if extra_keys:
            if isinstance(extra_keys, str): extra_keys = [extra_keys]
            assert isinstance(extra_keys, (tuple, list)), 'Only str, tuple[str], list[str] are supported'
            return prefix + ''.join([f'### {k}:\n{{{k}}}\n\n' for k in extra_keys])
        return ''

    def _handle_tool_call_instruction(self):
        tool_dict = {}
        for key in ['tool_start_token', 'tool_args_token', 'tool_end_token']:
            if getattr(self, f'_{key}', None) and key in self._instruction_template:
                tool_dict[key] = getattr(self, f'_{key}')
        return reduce(lambda s, kv: s.replace(f'{{{kv[0]}}}', kv[1]), tool_dict.items(), self._instruction_template)

    def _set_model_configs(self, system: str = None, sos: Union[None, str] = None, soh: Union[None, str] = None,
                           soa: Union[None, str] = None, eos: Union[None, str] = None,
                           eoh: Union[None, str] = None, eoa: Union[None, str] = None,
                           soe: Union[None, str] = None, eoe: Union[None, str] = None,
                           separator: Union[None, str] = None, plugin: Union[None, str] = None,
                           interpreter: Union[None, str] = None, stop_words: Union[None, List[str]] = None,
                           tool_start_token: Union[None, str] = None, tool_end_token: Union[None, str] = None,
                           tool_args_token: Union[None, str] = None):

        local = locals()
        for name in ['system', 'sos', 'soh', 'soa', 'eos', 'eoh', 'eoa', 'soe', 'eoe', 'tool_start_token',
                     'tool_end_token', 'tool_args_token']:
            if local[name] is not None: setattr(self, f'_{name}', local[name])

        if getattr(self, '_instruction_template', None):
            self._instruction_template = self._handle_tool_call_instruction()

    def _get_tools(self, tools, *, return_dict):
        if self._tools:
            assert tools is None
            tools = self._tools

        return tools if return_dict else '### Function-call Tools. \n\n' + json.dumps(tools) + '\n\n' if tools else ''

    def _get_histories(self, history, *, return_dict):  # noqa: C901
        if not self._history and not history: return ''
        if return_dict:
            content = []
            for item in self._history + (history or []):
                if isinstance(item, list):
                    assert len(item) <= 2, 'history item length cannot be greater than 2'
                    if len(item) > 0: content.append({'role': 'user', 'content': item[0]})
                    if len(item) > 1: content.append({'role': 'assistant', 'content': item[1]})
                elif isinstance(item, dict):
                    content.append(item)
                else:
                    LOG.error(f'history: {history}')
                    raise ValueError('history must be a list of list or dict')
            return content
        else:
            ret = ''.join([f'{self._soh}{h}{self._eoh}{self._soa}{a}{self._eoa}' for h, a in self._history])
            if not history: return ret
            if isinstance(history[0], list):
                return ret + ''.join([f'{self._soh}{h}{self._eoh}{self._soa}{a}{self._eoa}' for h, a in history])
            elif isinstance(history[0], dict):
                for item in history:
                    if item['role'] == 'user':
                        ret += f'{self._soh}{item["content"]}{self._eoh}'
                    elif item['role'] == 'assistant':
                        ret += f'{self._soa}'
                        ret += f'{item.get("content", "")}'
                        for idx in range(len(item.get('tool_calls', []))):
                            tool = item['tool_calls'][idx]['function']
                            if getattr(self, '_tool_args_token', None):
                                tool = tool['name'] + self._tool_args_token + \
                                    json.dumps(tool['arguments'], ensure_ascii=False)
                            ret += (f'{getattr(self, "_tool_start_token", "")}' + '\n'
                                    f'{tool}'
                                    f'{getattr(self, "_tool_end_token", "")}' + '\n')
                        ret += f'{self._eoa}'
                    elif item['role'] == 'tool':
                        try:
                            content = json.loads(item['content'].strip())
                        except Exception:
                            content = item['content']
                        ret += f'{getattr(self, "_soe", "")}{content}{getattr(self, "_eoe", "")}'

                return ret
            else:
                raise NotImplementedError('Cannot transform json history to {type(history[0])} now')

    def _get_instruction_and_input(self, input):
        prompt_keys = list(set(re.findall(r'\{(\w+)\}', self._instruction_template)))
        if isinstance(input, (str, int)):
            if len(prompt_keys) == 1:
                return self._instruction_template.format(**{prompt_keys[0]: input}), ''
            else:
                assert len(prompt_keys) == 0
                return self._instruction_template, input
        assert isinstance(input, dict), f'expected types are str, int and dict, bug get {type(input)}(`{input})`'
        kwargs = {k: input.pop(k) for k in prompt_keys}
        assert len(input) <= 1, f'Unexpected keys found in input: {list(input.keys())}'
        return (reduce(lambda s, kv: s.replace(f'{{{kv[0]}}}', kv[1]),
                       kwargs.items(),
                       self._instruction_template)
                if len(kwargs) > 0 else self._instruction_template,
                list(input.values())[0] if input else '')

    def _check_values(self, instruction, input, history, tools): pass

    # Used for TrainableModule(local deployed)
    def _generate_prompt_impl(self, instruction, input, user, history, tools, label):
        is_tool = False
        if isinstance(input, dict):
            input = input.get('content', '')
            is_tool = input.get('role') == 'tool'
        elif isinstance(input, list):
            is_tool = any(item.get('role') == 'tool' for item in input)
            input = '\n'.join([item.get('content', '') for item in input])
        params = dict(system=self._system, instruction=instruction, input=input, user=user, history=history, tools=tools,
                      sos=self._sos, eos=self._eos, soh=self._soh, eoh=self._eoh, soa=self._soa, eoa=self._eoa)
        if is_tool:
            params['soh'] = getattr(self, '_soe', self._soh)
            params['eoh'] = getattr(self, '_eoe', self._eoh)
        return self._template.format(**params) + (label if label else '')

    # Used for OnlineChatModule
    def _generate_prompt_dict_impl(self, instruction, input, user, history, tools, label):
        if not history: history = []
        if isinstance(input, str):
            history.append({'role': 'user', 'content': input})
        elif isinstance(input, dict):
            history.append(input)
        elif isinstance(input, list) and all(isinstance(ele, dict) for ele in input):
            history.extend(input)
        elif isinstance(input, tuple) and len(input) == 1:
            # Note tuple size 1 with one single string is not expected
            history.append({'role': 'user', 'content': input[0]})
        else:
            raise TypeError('input must be a string or a dict')

        if user:
            history[-1]['content'] = user + history[-1]['content']

        history.insert(0, {'role': 'system',
                           'content': self._system + '\n' + instruction if instruction else self._system})

        return dict(messages=history, tools=tools) if tools else dict(messages=history)

    def pre_hook(self, func: Optional[Callable] = None):
        """设置预处理钩子函数,供外部在生成提示词前对输入数据进行自定义处理。

Args:
    func (Optional[Callable]): 一个可调用对象,作为预处理钩子函数,接收并处理输入数据。

**Returns:**

- LazyLLMPrompterBase: 返回自身实例,方便链式调用。
"""
        self._pre_hook = func
        return self

    def _split_instruction(self, instruction: str):
        system_instruction = instruction
        user_instruction = ''
        if LazyLLMPrompterBase.ISA in instruction and LazyLLMPrompterBase.ISE in instruction:
            # The instruction includes system prompts and/or user prompts
            pattern = re.compile(r'%s(.*)%s' % (LazyLLMPrompterBase.ISA, LazyLLMPrompterBase.ISE), re.DOTALL)
            ret = re.split(pattern, instruction)
            system_instruction = ret[0]
            user_instruction = ret[1]

        return system_instruction, user_instruction

    def generate_prompt(self, input: Union[str, List, Dict[str, str], None] = None,
                        history: List[Union[List[str], Dict[str, Any]]] = None,
                        tools: Union[List[Dict[str, Any]], None] = None,
                        label: Union[str, None] = None,
                        *, show: bool = False, return_dict: bool = False) -> Union[str, Dict]:
        """根据用户输入,生成对应的Prompt.

Args:
    input (Option[str | Dict]):  Prompter的输入,如果是dict,会填充到instruction的槽位中;如果是str,则会作为输入。
    history (Option[List[List | Dict]]): 历史对话,可以为 ``[[u, s], [u, s]]`` 或 openai的history格式,默认为None。
    tools (Option[List[Dict]]: 可以使用的工具合集,大模型用作FunctionCall时使用,默认为None
    label (Option[str]): 标签,训练或微调时使用,默认为None
    show (bool): 标志是否打印生成的Prompt,默认为False
    return_dict (bool): 标志是否返回dict,一般情况下使用 ``OnlineChatModule`` 时会设置为True。如果返回dict,则仅填充 ``instruction``。默认为False
"""
        input = copy.deepcopy(input)
        if self._pre_hook:
            input, history, tools, label = self._pre_hook(input, history, tools, label)
        instruction, input = self._get_instruction_and_input(input)
        history = self._get_histories(history, return_dict=return_dict)
        tools = self._get_tools(tools, return_dict=return_dict)
        self._check_values(instruction, input, history, tools)
        instruction, user_instruction = self._split_instruction(instruction)
        func = self._generate_prompt_dict_impl if return_dict else self._generate_prompt_impl
        result = func(instruction, input, user_instruction, history, tools, label)
        if self._show or show: LOG.info(result)
        return result

    def get_response(self, output: str, input: Union[str, None] = None) -> str:
        """用作对Prompt的截断,只保留有价值的输出

Args:
     output (str): 大模型的输出
     input (Option[[str]): 大模型的输入,若指定此参数,会将输出中包含输入的部分全部截断,默认为None
"""
        if input and output.startswith(input):
            return output[len(input):]
        return output if getattr(self, '_split', None) is None else output.split(self._split)[-1]

generate_prompt(input=None, history=None, tools=None, label=None, *, show=False, return_dict=False)

根据用户输入,生成对应的Prompt.

Parameters:

  • input (Option[str | Dict], default: None ) –

    Prompter的输入,如果是dict,会填充到instruction的槽位中;如果是str,则会作为输入。

  • history (Option[List[List | Dict]], default: None ) –

    历史对话,可以为 [[u, s], [u, s]] 或 openai的history格式,默认为None。

  • tools (Option[List[Dict]]

    可以使用的工具合集,大模型用作FunctionCall时使用,默认为None

  • label (Option[str], default: None ) –

    标签,训练或微调时使用,默认为None

  • show (bool, default: False ) –

    标志是否打印生成的Prompt,默认为False

  • return_dict (bool, default: False ) –

    标志是否返回dict,一般情况下使用 OnlineChatModule 时会设置为True。如果返回dict,则仅填充 instruction。默认为False

Source code in lazyllm/components/prompter/builtinPrompt.py
    def generate_prompt(self, input: Union[str, List, Dict[str, str], None] = None,
                        history: List[Union[List[str], Dict[str, Any]]] = None,
                        tools: Union[List[Dict[str, Any]], None] = None,
                        label: Union[str, None] = None,
                        *, show: bool = False, return_dict: bool = False) -> Union[str, Dict]:
        """根据用户输入,生成对应的Prompt.

Args:
    input (Option[str | Dict]):  Prompter的输入,如果是dict,会填充到instruction的槽位中;如果是str,则会作为输入。
    history (Option[List[List | Dict]]): 历史对话,可以为 ``[[u, s], [u, s]]`` 或 openai的history格式,默认为None。
    tools (Option[List[Dict]]: 可以使用的工具合集,大模型用作FunctionCall时使用,默认为None
    label (Option[str]): 标签,训练或微调时使用,默认为None
    show (bool): 标志是否打印生成的Prompt,默认为False
    return_dict (bool): 标志是否返回dict,一般情况下使用 ``OnlineChatModule`` 时会设置为True。如果返回dict,则仅填充 ``instruction``。默认为False
"""
        input = copy.deepcopy(input)
        if self._pre_hook:
            input, history, tools, label = self._pre_hook(input, history, tools, label)
        instruction, input = self._get_instruction_and_input(input)
        history = self._get_histories(history, return_dict=return_dict)
        tools = self._get_tools(tools, return_dict=return_dict)
        self._check_values(instruction, input, history, tools)
        instruction, user_instruction = self._split_instruction(instruction)
        func = self._generate_prompt_dict_impl if return_dict else self._generate_prompt_impl
        result = func(instruction, input, user_instruction, history, tools, label)
        if self._show or show: LOG.info(result)
        return result

get_response(output, input=None)

用作对Prompt的截断,只保留有价值的输出

Parameters:

  • output (str) –

    大模型的输出

  • input (Option[[str], default: None ) –

    大模型的输入,若指定此参数,会将输出中包含输入的部分全部截断,默认为None

Source code in lazyllm/components/prompter/builtinPrompt.py
    def get_response(self, output: str, input: Union[str, None] = None) -> str:
        """用作对Prompt的截断,只保留有价值的输出

Args:
     output (str): 大模型的输出
     input (Option[[str]): 大模型的输入,若指定此参数,会将输出中包含输入的部分全部截断,默认为None
"""
        if input and output.startswith(input):
            return output[len(input):]
        return output if getattr(self, '_split', None) is None else output.split(self._split)[-1]

pre_hook(func=None)

设置预处理钩子函数,供外部在生成提示词前对输入数据进行自定义处理。

Parameters:

  • func (Optional[Callable], default: None ) –

    一个可调用对象,作为预处理钩子函数,接收并处理输入数据。

Returns:

  • LazyLLMPrompterBase: 返回自身实例,方便链式调用。
Source code in lazyllm/components/prompter/builtinPrompt.py
    def pre_hook(self, func: Optional[Callable] = None):
        """设置预处理钩子函数,供外部在生成提示词前对输入数据进行自定义处理。

Args:
    func (Optional[Callable]): 一个可调用对象,作为预处理钩子函数,接收并处理输入数据。

**Returns:**

- LazyLLMPrompterBase: 返回自身实例,方便链式调用。
"""
        self._pre_hook = func
        return self

lazyllm.components.prompter.EmptyPrompter

Bases: LazyLLMPrompterBase

继承自 LazyLLMPrompterBase 的空提示生成器,用于直接返回原始输入。

该类不会对输入进行任何处理,适用于无需格式化的调试、测试或占位场景。

Examples:

>>> from lazyllm.components.prompter import EmptyPrompter
>>> prompter = EmptyPrompter()
>>> prompter.generate_prompt("Hello LazyLLM")
'Hello LazyLLM'
>>> prompter.generate_prompt({"query": "Tell me a joke"})
{'query': 'Tell me a joke'}
>>> # Even with additional parameters, the input is returned unchanged
>>> prompter.generate_prompt("No-op", history=[["Hi", "Hello"]], tools=[{"name": "search"}], label="debug")
'No-op'
Source code in lazyllm/components/prompter/builtinPrompt.py
class EmptyPrompter(LazyLLMPrompterBase):
    """继承自 `LazyLLMPrompterBase` 的空提示生成器,用于直接返回原始输入。

该类不会对输入进行任何处理,适用于无需格式化的调试、测试或占位场景。


Examples:
    >>> from lazyllm.components.prompter import EmptyPrompter
    >>> prompter = EmptyPrompter()
    >>> prompter.generate_prompt("Hello LazyLLM")
    'Hello LazyLLM'
    >>> prompter.generate_prompt({"query": "Tell me a joke"})
    {'query': 'Tell me a joke'}
    >>> # Even with additional parameters, the input is returned unchanged
    >>> prompter.generate_prompt("No-op", history=[["Hi", "Hello"]], tools=[{"name": "search"}], label="debug")
    'No-op'
    """

    def generate_prompt(self, input, history=None, tools=None, label=None, show=False, return_dict=False):
        """直接返回输入的Prompt实现,继承自 `LazyLLMPrompterBase`。

该方法不会对输入做任何格式化操作,适用于调试、测试或占位场景。

Args:
    input (Any): 任意输入,作为Prompt返回。
    history (Option[List[List | Dict]]): 历史对话,可忽略,默认None。
    tools (Option[List[Dict]]): 工具参数,可忽略,默认None。
    label (Option[str]): 标签,可忽略,默认None。
    show (bool): 是否打印返回内容,默认为False。
"""
        if return_dict:
            return {'messages': [{'role': 'user', 'content': input}]}
        if self._show or show: LOG.info(input)
        return input

generate_prompt(input, history=None, tools=None, label=None, show=False, return_dict=False)

直接返回输入的Prompt实现,继承自 LazyLLMPrompterBase

该方法不会对输入做任何格式化操作,适用于调试、测试或占位场景。

Parameters:

  • input (Any) –

    任意输入,作为Prompt返回。

  • history (Option[List[List | Dict]], default: None ) –

    历史对话,可忽略,默认None。

  • tools (Option[List[Dict]], default: None ) –

    工具参数,可忽略,默认None。

  • label (Option[str], default: None ) –

    标签,可忽略,默认None。

  • show (bool, default: False ) –

    是否打印返回内容,默认为False。

Source code in lazyllm/components/prompter/builtinPrompt.py
    def generate_prompt(self, input, history=None, tools=None, label=None, show=False, return_dict=False):
        """直接返回输入的Prompt实现,继承自 `LazyLLMPrompterBase`。

该方法不会对输入做任何格式化操作,适用于调试、测试或占位场景。

Args:
    input (Any): 任意输入,作为Prompt返回。
    history (Option[List[List | Dict]]): 历史对话,可忽略,默认None。
    tools (Option[List[Dict]]): 工具参数,可忽略,默认None。
    label (Option[str]): 标签,可忽略,默认None。
    show (bool): 是否打印返回内容,默认为False。
"""
        if return_dict:
            return {'messages': [{'role': 'user', 'content': input}]}
        if self._show or show: LOG.info(input)
        return input

lazyllm.components.Prompter

Bases: object

用于生成模型输入的Prompt类,支持模板、历史对话拼接与响应抽取。

该类支持从字典、模板名称或文件中加载prompt配置,支持历史对话结构拼接(用于Chat类任务), 可灵活处理有/无history结构的prompt输入,适配非字典类型输入。

Parameters:

  • prompt (Optional[str], default: None ) –

    模板Prompt字符串,支持格式化字段。

  • response_split (Optional[str], default: None ) –

    对模型响应进行切分的分隔符,仅用于抽取模型回答。

  • chat_prompt (Optional[str], default: None ) –

    多轮对话使用的Prompt模板,必须包含history字段。

  • history_symbol (str, default: 'llm_chat_history' ) –

    表示历史对话字段的名称,默认为'llm_chat_history'。

  • eoa (Optional[str], default: None ) –

    对话中 assistant/user 分隔符。

  • eoh (Optional[str], default: None ) –

    多轮history中 user-assistant 分隔符。

  • show (bool, default: False ) –

    是否打印最终生成的Prompt,默认False。

Examples:

>>> from lazyllm import Prompter
>>> p = Prompter(prompt="Answer the following: {question}")
>>> p.generate_prompt("What is AI?")
'Answer the following: What is AI?'
>>> p.generate_prompt({"question": "Define machine learning"})
'Answer the following: Define machine learning'
>>> p = Prompter(
...     prompt="Instruction: {instruction}",
...     chat_prompt="Instruction: {instruction}\nHistory:\n{llm_chat_history}",
...     history_symbol="llm_chat_history",
...     eoa="</s>",
...     eoh="|"
... )
>>> p.generate_prompt(
...     input={"instruction": "Translate this."},
...     history=[["hello", "你好"], ["how are you", "你好吗"]]
... )
'Instruction: Translate this.\nHistory:\nhello|你好</s>how are you|你好吗'
>>> prompt_conf = {
...     "prompt": "Task: {task}",
...     "response_split": "---"
... }
>>> p = Prompter.from_dict(prompt_conf)
>>> p.generate_prompt("Summarize this article.")
'Task: Summarize this article.'
>>> full_output = "Task: Summarize this article.---This is the summary."
>>> p.get_response(full_output)
'This is the summary.'
Source code in lazyllm/components/prompter/prompter.py
class Prompter(object):
    """用于生成模型输入的Prompt类,支持模板、历史对话拼接与响应抽取。

该类支持从字典、模板名称或文件中加载prompt配置,支持历史对话结构拼接(用于Chat类任务),
可灵活处理有/无history结构的prompt输入,适配非字典类型输入。

Args:
    prompt (Optional[str]): 模板Prompt字符串,支持格式化字段。
    response_split (Optional[str]): 对模型响应进行切分的分隔符,仅用于抽取模型回答。
    chat_prompt (Optional[str]): 多轮对话使用的Prompt模板,必须包含history字段。
    history_symbol (str): 表示历史对话字段的名称,默认为'llm_chat_history'。
    eoa (Optional[str]): 对话中 assistant/user 分隔符。
    eoh (Optional[str]): 多轮history中 user-assistant 分隔符。
    show (bool): 是否打印最终生成的Prompt,默认False。


Examples:
    >>> from lazyllm import Prompter

    >>> p = Prompter(prompt="Answer the following: {question}")
    >>> p.generate_prompt("What is AI?")
    'Answer the following: What is AI?'

    >>> p.generate_prompt({"question": "Define machine learning"})
    'Answer the following: Define machine learning'

    >>> p = Prompter(
    ...     prompt="Instruction: {instruction}",
    ...     chat_prompt="Instruction: {instruction}\\nHistory:\\n{llm_chat_history}",
    ...     history_symbol="llm_chat_history",
    ...     eoa="</s>",
    ...     eoh="|"
    ... )
    >>> p.generate_prompt(
    ...     input={"instruction": "Translate this."},
    ...     history=[["hello", "你好"], ["how are you", "你好吗"]]
    ... )
    'Instruction: Translate this.\\nHistory:\\nhello|你好</s>how are you|你好吗'

    >>> prompt_conf = {
    ...     "prompt": "Task: {task}",
    ...     "response_split": "---"
    ... }
    >>> p = Prompter.from_dict(prompt_conf)
    >>> p.generate_prompt("Summarize this article.")
    'Task: Summarize this article.'

    >>> full_output = "Task: Summarize this article.---This is the summary."
    >>> p.get_response(full_output)
    'This is the summary.'
    """
    def __init__(self, prompt=None, response_split=None, *, chat_prompt=None,
                 history_symbol='llm_chat_history', eoa=None, eoh=None, show=False):
        self._prompt, self._response_split = prompt, response_split
        self._chat_prompt = chat_prompt
        self._history_symbol, self._eoa, self._eoh = history_symbol, eoa, eoh
        self._show = show
        self._prompt_keys = list(set(re.findall(r'\{(\w+)\}', self._prompt))) if prompt else []
        if chat_prompt is not None:
            chat_keys = set(re.findall(r'\{(\w+)\}', self._chat_prompt))
            assert set(self._prompt_keys).issubset(chat_keys)
            assert chat_keys - set(self._prompt_keys) == set([self._history_symbol])
            self.use_history = True
        else:
            self.use_history = history_symbol in self._prompt_keys
            if self.use_history:
                self._prompt_keys.pop(self._prompt_keys.index(history_symbol))
                self._chat_prompt = self._prompt

    @classmethod
    def from_dict(cls, prompt, *, show=False):
        """通过字典配置初始化一个 Prompter 实例。

Args:
    prompt (Dict): 包含 prompt 相关字段的配置字典,需包含 `prompt` 键,其他为可选。
    show (bool): 是否显示生成的 prompt,默认为 False。

**Returns:**

- Prompter: 返回一个初始化的 Prompter 实例。
"""
        assert isinstance(prompt, dict)
        return cls(**prompt, show=show)

    @classmethod
    def from_template(cls, template_name, *, show=False):
        """根据模板名称加载 prompt 配置并初始化 Prompter 实例。

Args:
    template_name (str): 模板名称,必须在 `templates` 中存在。
    show (bool): 是否显示生成的 prompt,默认为 False。

**Returns:**

- Prompter: 返回一个初始化的 Prompter 实例。
"""
        return cls.from_dict(templates[template_name], show=show)

    @classmethod
    def from_file(cls, fname, *, show=False):
        """从 JSON 文件中读取配置并初始化 Prompter 实例。

Args:
    fname (str): JSON 配置文件路径。
    show (bool): 是否显示生成的 prompt,默认为 False。

Returns:
    Prompter: 返回一个初始化的 Prompter 实例。
"""
        with open(fname) as fp:
            return cls.from_dict(json.load(fp), show=show)

    @classmethod
    def empty(cls):
        """创建一个空的 Prompter 实例。

Returns:
    Prompter: 返回一个无 prompt 配置的 Prompter 实例。
"""
        return cls()

    def _is_empty(self):
        return self._prompt is None

    def generate_prompt(self, input, history=None, tools=None, label=None, show=False):
        """根据输入和可选的历史记录生成最终 Prompt。

Args:
    input (Union[str, Dict]): 用户输入。可以是字符串或包含多字段的字典。
    history (Optional[List[List[str]]]): 多轮对话历史,例如 [['u1', 'a1'], ['u2', 'a2']]。
    tools (Optional[Any]): 目前未支持工具调用,此字段必须为 None。
    label (Optional[str]): 附加在 prompt 末尾的标签,通常用于训练。
    show (bool): 是否显示生成的 prompt,默认 False。

Returns:
    str: 格式化后的 prompt 字符串。
"""
        if not self._is_empty():
            assert tools is None
            # datasets.formatting.formatting.LazyDict is used in transformers
            if not isinstance(input, collections.abc.Mapping):
                assert len(self._prompt_keys) == 1, (
                    f'invalid prompt `{self._prompt}` for <{type(input)}> input `{input}`')
                input = {self._prompt_keys[0]: input}
            try:
                if self.use_history and isinstance(history, list) and len(history) > 0:
                    assert isinstance(history[0], list), 'history must be list of list'
                    input[self._history_symbol] = self._eoa.join([self._eoh.join(h) for h in history])
                    input = self._chat_prompt.format(**input)
                else:
                    if self.use_history: input[self._history_symbol] = ''
                    input = self._prompt.format(**input)
            except Exception:
                raise RuntimeError(f'Generate prompt failed, and prompt is {self._prompt}; chat-prompt'
                                   f' is {self._chat_prompt}; input is {input}; history is {history}')
            if label: input += label
        if self._show or show: LOG.info(input)
        return input

    def get_response(self, response, input=None):
        """从 LLM 返回结果中提取模型的回答内容。

Args:
    response (str): 模型完整响应文本。
    input (Optional[str]): 如果模型输出以输入开头,将会自动去除输入部分。

Returns:
    str: 提取后的模型响应内容。
"""
        if input and response.startswith(input):
            return response[len(input):]
        return response if self._response_split is None else response.split(self._response_split)[-1]

from_dict(prompt, *, show=False) classmethod

通过字典配置初始化一个 Prompter 实例。

Parameters:

  • prompt (Dict) –

    包含 prompt 相关字段的配置字典,需包含 prompt 键,其他为可选。

  • show (bool, default: False ) –

    是否显示生成的 prompt,默认为 False。

Returns:

  • Prompter: 返回一个初始化的 Prompter 实例。
Source code in lazyllm/components/prompter/prompter.py
    @classmethod
    def from_dict(cls, prompt, *, show=False):
        """通过字典配置初始化一个 Prompter 实例。

Args:
    prompt (Dict): 包含 prompt 相关字段的配置字典,需包含 `prompt` 键,其他为可选。
    show (bool): 是否显示生成的 prompt,默认为 False。

**Returns:**

- Prompter: 返回一个初始化的 Prompter 实例。
"""
        assert isinstance(prompt, dict)
        return cls(**prompt, show=show)

from_template(template_name, *, show=False) classmethod

根据模板名称加载 prompt 配置并初始化 Prompter 实例。

Parameters:

  • template_name (str) –

    模板名称,必须在 templates 中存在。

  • show (bool, default: False ) –

    是否显示生成的 prompt,默认为 False。

Returns:

  • Prompter: 返回一个初始化的 Prompter 实例。
Source code in lazyllm/components/prompter/prompter.py
    @classmethod
    def from_template(cls, template_name, *, show=False):
        """根据模板名称加载 prompt 配置并初始化 Prompter 实例。

Args:
    template_name (str): 模板名称,必须在 `templates` 中存在。
    show (bool): 是否显示生成的 prompt,默认为 False。

**Returns:**

- Prompter: 返回一个初始化的 Prompter 实例。
"""
        return cls.from_dict(templates[template_name], show=show)

from_file(fname, *, show=False) classmethod

从 JSON 文件中读取配置并初始化 Prompter 实例。

Parameters:

  • fname (str) –

    JSON 配置文件路径。

  • show (bool, default: False ) –

    是否显示生成的 prompt,默认为 False。

Returns:

  • Prompter

    返回一个初始化的 Prompter 实例。

Source code in lazyllm/components/prompter/prompter.py
    @classmethod
    def from_file(cls, fname, *, show=False):
        """从 JSON 文件中读取配置并初始化 Prompter 实例。

Args:
    fname (str): JSON 配置文件路径。
    show (bool): 是否显示生成的 prompt,默认为 False。

Returns:
    Prompter: 返回一个初始化的 Prompter 实例。
"""
        with open(fname) as fp:
            return cls.from_dict(json.load(fp), show=show)

empty() classmethod

创建一个空的 Prompter 实例。

Returns:

  • Prompter

    返回一个无 prompt 配置的 Prompter 实例。

Source code in lazyllm/components/prompter/prompter.py
    @classmethod
    def empty(cls):
        """创建一个空的 Prompter 实例。

Returns:
    Prompter: 返回一个无 prompt 配置的 Prompter 实例。
"""
        return cls()

generate_prompt(input, history=None, tools=None, label=None, show=False)

根据输入和可选的历史记录生成最终 Prompt。

Parameters:

  • input (Union[str, Dict]) –

    用户输入。可以是字符串或包含多字段的字典。

  • history (Optional[List[List[str]]], default: None ) –

    多轮对话历史,例如 [['u1', 'a1'], ['u2', 'a2']]。

  • tools (Optional[Any], default: None ) –

    目前未支持工具调用,此字段必须为 None。

  • label (Optional[str], default: None ) –

    附加在 prompt 末尾的标签,通常用于训练。

  • show (bool, default: False ) –

    是否显示生成的 prompt,默认 False。

Returns:

  • str

    格式化后的 prompt 字符串。

Source code in lazyllm/components/prompter/prompter.py
    def generate_prompt(self, input, history=None, tools=None, label=None, show=False):
        """根据输入和可选的历史记录生成最终 Prompt。

Args:
    input (Union[str, Dict]): 用户输入。可以是字符串或包含多字段的字典。
    history (Optional[List[List[str]]]): 多轮对话历史,例如 [['u1', 'a1'], ['u2', 'a2']]。
    tools (Optional[Any]): 目前未支持工具调用,此字段必须为 None。
    label (Optional[str]): 附加在 prompt 末尾的标签,通常用于训练。
    show (bool): 是否显示生成的 prompt,默认 False。

Returns:
    str: 格式化后的 prompt 字符串。
"""
        if not self._is_empty():
            assert tools is None
            # datasets.formatting.formatting.LazyDict is used in transformers
            if not isinstance(input, collections.abc.Mapping):
                assert len(self._prompt_keys) == 1, (
                    f'invalid prompt `{self._prompt}` for <{type(input)}> input `{input}`')
                input = {self._prompt_keys[0]: input}
            try:
                if self.use_history and isinstance(history, list) and len(history) > 0:
                    assert isinstance(history[0], list), 'history must be list of list'
                    input[self._history_symbol] = self._eoa.join([self._eoh.join(h) for h in history])
                    input = self._chat_prompt.format(**input)
                else:
                    if self.use_history: input[self._history_symbol] = ''
                    input = self._prompt.format(**input)
            except Exception:
                raise RuntimeError(f'Generate prompt failed, and prompt is {self._prompt}; chat-prompt'
                                   f' is {self._chat_prompt}; input is {input}; history is {history}')
            if label: input += label
        if self._show or show: LOG.info(input)
        return input

get_response(response, input=None)

从 LLM 返回结果中提取模型的回答内容。

Parameters:

  • response (str) –

    模型完整响应文本。

  • input (Optional[str], default: None ) –

    如果模型输出以输入开头,将会自动去除输入部分。

Returns:

  • str

    提取后的模型响应内容。

Source code in lazyllm/components/prompter/prompter.py
    def get_response(self, response, input=None):
        """从 LLM 返回结果中提取模型的回答内容。

Args:
    response (str): 模型完整响应文本。
    input (Optional[str]): 如果模型输出以输入开头,将会自动去除输入部分。

Returns:
    str: 提取后的模型响应内容。
"""
        if input and response.startswith(input):
            return response[len(input):]
        return response if self._response_split is None else response.split(self._response_split)[-1]

lazyllm.components.AlpacaPrompter

Bases: LazyLLMPrompterBase

Alpaca格式的Prompter,支持工具调用,不支持历史对话。

Parameters:

  • instruction (Option[str], default: None ) –

    大模型的任务指令,至少带一个可填充的槽位(如 {instruction})。或者使用字典指定 systemuser 的指令。

  • extra_keys (Option[List], default: None ) –

    额外的字段,用户的输入会填充这些字段。

  • show (bool, default: False ) –

    标志是否打印生成的Prompt,默认为False

  • tools (Option[list], default: None ) –

    大模型可以使用的工具集合,默认为None

Examples:

>>> from lazyllm import AlpacaPrompter
>>> p = AlpacaPrompter('hello world {instruction}')
>>> p.generate_prompt('this is my input')
'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n ### Instruction:\nhello world this is my input\n\n\n### Response:\n'
>>> p.generate_prompt('this is my input', return_dict=True)
{'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n ### Instruction:\nhello world this is my input\n\n'}, {'role': 'user', 'content': ''}]}
>>>
>>> p = AlpacaPrompter('hello world {instruction}, {input}', extra_keys=['knowledge'])
>>> p.generate_prompt(dict(instruction='hello world', input='my input', knowledge='lazyllm'))
'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n ### Instruction:\nhello world hello world, my input\n\nHere are some extra messages you can referred to:\n\n### knowledge:\nlazyllm\n\n\n### Response:\n'
>>> p.generate_prompt(dict(instruction='hello world', input='my input', knowledge='lazyllm'), return_dict=True)
{'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n ### Instruction:\nhello world hello world, my input\n\nHere are some extra messages you can referred to:\n\n### knowledge:\nlazyllm\n\n'}, {'role': 'user', 'content': ''}]}
>>>
>>> p = AlpacaPrompter(dict(system="hello world", user="this is user instruction {input}"))
>>> p.generate_prompt(dict(input="my input"))
'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n ### Instruction:\nhello word\n\n\n\nthis is user instruction my input### Response:\n'
>>> p.generate_prompt(dict(input="my input"), return_dict=True)
{'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\n\n ### Instruction:\nhello world'}, {'role': 'user', 'content': 'this is user instruction my input'}]}
Source code in lazyllm/components/prompter/alpacaPrompter.py
class AlpacaPrompter(LazyLLMPrompterBase):
    """Alpaca格式的Prompter,支持工具调用,不支持历史对话。

Args:
    instruction (Option[str]): 大模型的任务指令,至少带一个可填充的槽位(如 ``{instruction}``)。或者使用字典指定 ``system`` 和 ``user`` 的指令。
    extra_keys (Option[List]): 额外的字段,用户的输入会填充这些字段。
    show (bool): 标志是否打印生成的Prompt,默认为False
    tools (Option[list]): 大模型可以使用的工具集合,默认为None


Examples:
    >>> from lazyllm import AlpacaPrompter
    >>> p = AlpacaPrompter('hello world {instruction}')
    >>> p.generate_prompt('this is my input')
    'You are an AI-Agent developed by LazyLLM.\\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\\n\\n ### Instruction:\\nhello world this is my input\\n\\n\\n### Response:\\n'
    >>> p.generate_prompt('this is my input', return_dict=True)
    {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\\n\\n ### Instruction:\\nhello world this is my input\\n\\n'}, {'role': 'user', 'content': ''}]}
    >>>
    >>> p = AlpacaPrompter('hello world {instruction}, {input}', extra_keys=['knowledge'])
    >>> p.generate_prompt(dict(instruction='hello world', input='my input', knowledge='lazyllm'))
    'You are an AI-Agent developed by LazyLLM.\\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\\n\\n ### Instruction:\\nhello world hello world, my input\\n\\nHere are some extra messages you can referred to:\\n\\n### knowledge:\\nlazyllm\\n\\n\\n### Response:\\n'
    >>> p.generate_prompt(dict(instruction='hello world', input='my input', knowledge='lazyllm'), return_dict=True)
    {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\\n\\n ### Instruction:\\nhello world hello world, my input\\n\\nHere are some extra messages you can referred to:\\n\\n### knowledge:\\nlazyllm\\n\\n'}, {'role': 'user', 'content': ''}]}
    >>>
    >>> p = AlpacaPrompter(dict(system="hello world", user="this is user instruction {input}"))
    >>> p.generate_prompt(dict(input="my input"))
    'You are an AI-Agent developed by LazyLLM.\\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\\n\\n ### Instruction:\\nhello word\\n\\n\\n\\nthis is user instruction my input### Response:\\n'
    >>> p.generate_prompt(dict(input="my input"), return_dict=True)
    {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\nBelow is an instruction that describes a task, paired with extra messages such as input that provides further context if possible. Write a response that appropriately completes the request.\\n\\n ### Instruction:\\nhello world'}, {'role': 'user', 'content': 'this is user instruction my input'}]}
    """
    def __init__(self, instruction: Union[None, str, Dict[str, str]] = None, extra_keys: Union[None, List[str]] = None,
                 show: bool = False, tools: Optional[List] = None):
        super(__class__, self).__init__(show, tools=tools)
        if isinstance(instruction, dict):
            splice_struction = instruction.get('system', '') + \
                AlpacaPrompter.ISA + instruction.get('user', '') + AlpacaPrompter.ISE
            instruction = splice_struction
        instruction_template = ('Below is an instruction that describes a task, paired with extra messages such as '
                                'input that provides further context if possible. Write a response that appropriately '
                                f'completes the request.\n\n### Instruction:\n{instruction if instruction else ""}'
                                '\n\n' + LazyLLMPrompterBase._get_extro_key_template(extra_keys))
        self._init_prompt('{system}\n{instruction}\n{tools}\n{user}### Response:\n',
                          instruction_template,
                          '### Response:\n')

    def _check_values(self, instruction, input, history, tools):
        assert not history, f'Chat history is not supported in {__class__}.'
        assert not input, 'All keys should in instruction or extra-keys'

generate_prompt(input=None, history=None, tools=None, label=None, *, show=False, return_dict=False)

根据用户输入,生成对应的Prompt.

Parameters:

  • input (Option[str | Dict], default: None ) –

    Prompter的输入,如果是dict,会填充到instruction的槽位中;如果是str,则会作为输入。

  • history (Option[List[List | Dict]], default: None ) –

    历史对话,可以为 [[u, s], [u, s]] 或 openai的history格式,默认为None。

  • tools (Option[List[Dict]]

    可以使用的工具合集,大模型用作FunctionCall时使用,默认为None

  • label (Option[str], default: None ) –

    标签,训练或微调时使用,默认为None

  • show (bool, default: False ) –

    标志是否打印生成的Prompt,默认为False

  • return_dict (bool, default: False ) –

    标志是否返回dict,一般情况下使用 OnlineChatModule 时会设置为True。如果返回dict,则仅填充 instruction。默认为False

Source code in lazyllm/components/prompter/builtinPrompt.py
    def generate_prompt(self, input: Union[str, List, Dict[str, str], None] = None,
                        history: List[Union[List[str], Dict[str, Any]]] = None,
                        tools: Union[List[Dict[str, Any]], None] = None,
                        label: Union[str, None] = None,
                        *, show: bool = False, return_dict: bool = False) -> Union[str, Dict]:
        """根据用户输入,生成对应的Prompt.

Args:
    input (Option[str | Dict]):  Prompter的输入,如果是dict,会填充到instruction的槽位中;如果是str,则会作为输入。
    history (Option[List[List | Dict]]): 历史对话,可以为 ``[[u, s], [u, s]]`` 或 openai的history格式,默认为None。
    tools (Option[List[Dict]]: 可以使用的工具合集,大模型用作FunctionCall时使用,默认为None
    label (Option[str]): 标签,训练或微调时使用,默认为None
    show (bool): 标志是否打印生成的Prompt,默认为False
    return_dict (bool): 标志是否返回dict,一般情况下使用 ``OnlineChatModule`` 时会设置为True。如果返回dict,则仅填充 ``instruction``。默认为False
"""
        input = copy.deepcopy(input)
        if self._pre_hook:
            input, history, tools, label = self._pre_hook(input, history, tools, label)
        instruction, input = self._get_instruction_and_input(input)
        history = self._get_histories(history, return_dict=return_dict)
        tools = self._get_tools(tools, return_dict=return_dict)
        self._check_values(instruction, input, history, tools)
        instruction, user_instruction = self._split_instruction(instruction)
        func = self._generate_prompt_dict_impl if return_dict else self._generate_prompt_impl
        result = func(instruction, input, user_instruction, history, tools, label)
        if self._show or show: LOG.info(result)
        return result

get_response(output, input=None)

用作对Prompt的截断,只保留有价值的输出

Parameters:

  • output (str) –

    大模型的输出

  • input (Option[[str], default: None ) –

    大模型的输入,若指定此参数,会将输出中包含输入的部分全部截断,默认为None

Source code in lazyllm/components/prompter/builtinPrompt.py
    def get_response(self, output: str, input: Union[str, None] = None) -> str:
        """用作对Prompt的截断,只保留有价值的输出

Args:
     output (str): 大模型的输出
     input (Option[[str]): 大模型的输入,若指定此参数,会将输出中包含输入的部分全部截断,默认为None
"""
        if input and output.startswith(input):
            return output[len(input):]
        return output if getattr(self, '_split', None) is None else output.split(self._split)[-1]

lazyllm.components.ChatPrompter

Bases: LazyLLMPrompterBase

用于多轮对话的大模型Prompt构造器,继承自 LazyLLMPrompterBase

支持工具调用、历史对话与自定义指令模版。支持传入 system/user 拆分的指令结构,自动合并为统一模板。支持额外字段注入和打印提示信息。

Parameters:

  • instruction (Option[str | Dict[str, str]], default: None ) –

    Prompt模板指令,可为字符串或包含 systemuser 的字典。若为字典,将自动拼接并注入特殊标记分隔符。

  • extra_keys (Option[List[str]], default: None ) –

    额外的字段列表,用户输入中的内容会被插入对应槽位,用于丰富上下文。

  • show (bool, default: False ) –

    是否打印生成的Prompt,默认False。

  • tools (Option[List], default: None ) –

    可选的工具列表,用于FunctionCall任务,默认None。

  • history (Option[List[List[str]]], default: None ) –

    可选的历史对话,用于对话记忆,格式为[[user, assistant], ...],默认None。

Examples:

>>> from lazyllm import ChatPrompter
  • Simple instruction string
>>> p = ChatPrompter('hello world')
>>> p.generate_prompt('this is my input')
'You are an AI-Agent developed by LazyLLM.hello world\nthis is my input\n'
>>> p.generate_prompt('this is my input', return_dict=True)
{'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\nhello world'}, {'role': 'user', 'content': 'this is my input'}]}
  • Using extra_keys
>>> p = ChatPrompter('hello world {instruction}', extra_keys=['knowledge'])
>>> p.generate_prompt({
...     'instruction': 'this is my ins',
...     'input': 'this is my inp',
...     'knowledge': 'LazyLLM-Knowledge'
... })
'You are an AI-Agent developed by LazyLLM.hello world this is my ins\nHere are some extra messages you can referred to:\n\n### knowledge:\nLazyLLM-Knowledge\nthis is my inp\n'
  • With conversation history
>>> p.generate_prompt({
...     'instruction': 'this is my ins',
...     'input': 'this is my inp',
...     'knowledge': 'LazyLLM-Knowledge'
... }, history=[['s1', 'e1'], ['s2', 'e2']])
'You are an AI-Agent developed by LazyLLM.hello world this is my ins\nHere are some extra messages you can referred to:\n\n### knowledge:\nLazyLLM-Knowledge\ns1|e1\ns2|e2\nthis is my inp\n'
  • Using dict format for system/user instructions
>>> p = ChatPrompter(dict(system="hello world", user="this is user instruction {input}"))
>>> p.generate_prompt({'input': "my input", 'query': "this is user query"})
'You are an AI-Agent developed by LazyLLM.hello world\nthis is user instruction my input this is user query\n'
>>> p.generate_prompt({'input': "my input", 'query': "this is user query"}, return_dict=True)
{'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\nhello world'}, {'role': 'user', 'content': 'this is user instruction my input this is user query'}]}
Source code in lazyllm/components/prompter/chatPrompter.py
class ChatPrompter(LazyLLMPrompterBase):
    """用于多轮对话的大模型Prompt构造器,继承自 `LazyLLMPrompterBase`。

支持工具调用、历史对话与自定义指令模版。支持传入 system/user 拆分的指令结构,自动合并为统一模板。支持额外字段注入和打印提示信息。

Args:
    instruction (Option[str | Dict[str, str]]): Prompt模板指令,可为字符串或包含 `system` 和 `user` 的字典。若为字典,将自动拼接并注入特殊标记分隔符。
    extra_keys (Option[List[str]]): 额外的字段列表,用户输入中的内容会被插入对应槽位,用于丰富上下文。
    show (bool): 是否打印生成的Prompt,默认False。
    tools (Option[List]): 可选的工具列表,用于FunctionCall任务,默认None。
    history (Option[List[List[str]]]): 可选的历史对话,用于对话记忆,格式为[[user, assistant], ...],默认None。


Examples:
    >>> from lazyllm import ChatPrompter

    - Simple instruction string
    >>> p = ChatPrompter('hello world')
    >>> p.generate_prompt('this is my input')
    'You are an AI-Agent developed by LazyLLM.hello world\\nthis is my input\\n'

    >>> p.generate_prompt('this is my input', return_dict=True)
    {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\nhello world'}, {'role': 'user', 'content': 'this is my input'}]}

    - Using extra_keys
    >>> p = ChatPrompter('hello world {instruction}', extra_keys=['knowledge'])
    >>> p.generate_prompt({
    ...     'instruction': 'this is my ins',
    ...     'input': 'this is my inp',
    ...     'knowledge': 'LazyLLM-Knowledge'
    ... })
    'You are an AI-Agent developed by LazyLLM.hello world this is my ins\\nHere are some extra messages you can referred to:\\n\\n### knowledge:\\nLazyLLM-Knowledge\\nthis is my inp\\n'

    - With conversation history
    >>> p.generate_prompt({
    ...     'instruction': 'this is my ins',
    ...     'input': 'this is my inp',
    ...     'knowledge': 'LazyLLM-Knowledge'
    ... }, history=[['s1', 'e1'], ['s2', 'e2']])
    'You are an AI-Agent developed by LazyLLM.hello world this is my ins\\nHere are some extra messages you can referred to:\\n\\n### knowledge:\\nLazyLLM-Knowledge\\ns1|e1\\ns2|e2\\nthis is my inp\\n'

    - Using dict format for system/user instructions
    >>> p = ChatPrompter(dict(system="hello world", user="this is user instruction {input}"))
    >>> p.generate_prompt({'input': "my input", 'query': "this is user query"})
    'You are an AI-Agent developed by LazyLLM.hello world\\nthis is user instruction my input this is user query\\n'

    >>> p.generate_prompt({'input': "my input", 'query': "this is user query"}, return_dict=True)
    {'messages': [{'role': 'system', 'content': 'You are an AI-Agent developed by LazyLLM.\\nhello world'}, {'role': 'user', 'content': 'this is user instruction my input this is user query'}]}
    """
    def __init__(self, instruction: Union[None, str, Dict[str, str]] = None, extra_keys: Union[None, List[str]] = None,
                 show: bool = False, tools: Optional[List] = None, history: Optional[List[List[str]]] = None):
        super(__class__, self).__init__(show, tools=tools, history=history)
        if isinstance(instruction, dict):
            splice_instruction = instruction.get('system', '') + \
                ChatPrompter.ISA + instruction.get('user', '') + ChatPrompter.ISE
            instruction = splice_instruction
        instruction_template = f'{instruction}\n{{extra_keys}}\n'.replace(
            '{extra_keys}', LazyLLMPrompterBase._get_extro_key_template(extra_keys)) if instruction else ''
        self._init_prompt('{sos}{system}{instruction}{tools}{eos}\n\n{history}\n{soh}\n{user}{input}\n{eoh}{soa}\n',
                          instruction_template)

    @property
    def _split(self): return f'{self._soa}\n' if self._soa else None

generate_prompt(input=None, history=None, tools=None, label=None, *, show=False, return_dict=False)

根据用户输入,生成对应的Prompt.

Parameters:

  • input (Option[str | Dict], default: None ) –

    Prompter的输入,如果是dict,会填充到instruction的槽位中;如果是str,则会作为输入。

  • history (Option[List[List | Dict]], default: None ) –

    历史对话,可以为 [[u, s], [u, s]] 或 openai的history格式,默认为None。

  • tools (Option[List[Dict]]

    可以使用的工具合集,大模型用作FunctionCall时使用,默认为None

  • label (Option[str], default: None ) –

    标签,训练或微调时使用,默认为None

  • show (bool, default: False ) –

    标志是否打印生成的Prompt,默认为False

  • return_dict (bool, default: False ) –

    标志是否返回dict,一般情况下使用 OnlineChatModule 时会设置为True。如果返回dict,则仅填充 instruction。默认为False

Source code in lazyllm/components/prompter/builtinPrompt.py
    def generate_prompt(self, input: Union[str, List, Dict[str, str], None] = None,
                        history: List[Union[List[str], Dict[str, Any]]] = None,
                        tools: Union[List[Dict[str, Any]], None] = None,
                        label: Union[str, None] = None,
                        *, show: bool = False, return_dict: bool = False) -> Union[str, Dict]:
        """根据用户输入,生成对应的Prompt.

Args:
    input (Option[str | Dict]):  Prompter的输入,如果是dict,会填充到instruction的槽位中;如果是str,则会作为输入。
    history (Option[List[List | Dict]]): 历史对话,可以为 ``[[u, s], [u, s]]`` 或 openai的history格式,默认为None。
    tools (Option[List[Dict]]: 可以使用的工具合集,大模型用作FunctionCall时使用,默认为None
    label (Option[str]): 标签,训练或微调时使用,默认为None
    show (bool): 标志是否打印生成的Prompt,默认为False
    return_dict (bool): 标志是否返回dict,一般情况下使用 ``OnlineChatModule`` 时会设置为True。如果返回dict,则仅填充 ``instruction``。默认为False
"""
        input = copy.deepcopy(input)
        if self._pre_hook:
            input, history, tools, label = self._pre_hook(input, history, tools, label)
        instruction, input = self._get_instruction_and_input(input)
        history = self._get_histories(history, return_dict=return_dict)
        tools = self._get_tools(tools, return_dict=return_dict)
        self._check_values(instruction, input, history, tools)
        instruction, user_instruction = self._split_instruction(instruction)
        func = self._generate_prompt_dict_impl if return_dict else self._generate_prompt_impl
        result = func(instruction, input, user_instruction, history, tools, label)
        if self._show or show: LOG.info(result)
        return result

get_response(output, input=None)

用作对Prompt的截断,只保留有价值的输出

Parameters:

  • output (str) –

    大模型的输出

  • input (Option[[str], default: None ) –

    大模型的输入,若指定此参数,会将输出中包含输入的部分全部截断,默认为None

Source code in lazyllm/components/prompter/builtinPrompt.py
    def get_response(self, output: str, input: Union[str, None] = None) -> str:
        """用作对Prompt的截断,只保留有价值的输出

Args:
     output (str): 大模型的输出
     input (Option[[str]): 大模型的输入,若指定此参数,会将输出中包含输入的部分全部截断,默认为None
"""
        if input and output.startswith(input):
            return output[len(input):]
        return output if getattr(self, '_split', None) is None else output.split(self._split)[-1]

MultiModal

Text to Image

lazyllm.components.StableDiffusionDeploy

Bases: LazyLLMDeployBase

Stable Diffusion 模型部署类。该类用于将SD模型部署到指定服务器上,以便可以通过网络进行调用。

Parameters:

  • launcher (Optional[LazyLLMLaunchersBase], default: None ) –

    启动器实例。默认为 None

  • log_path (Optional[str], default: None ) –

    日志文件路径。默认为 None

  • trust_remote_code (bool, default: True ) –

    是否信任远程代码。默认为 True

  • port (Optional[int], default: None ) –

    服务端口号。默认为 None

Examples:

>>> from lazyllm import launchers, UrlModule
>>> from lazyllm.components import StableDiffusionDeploy
>>> deployer = StableDiffusionDeploy(launchers.remote())
>>> url = deployer(base_model='stable-diffusion-3-medium')
>>> model = UrlModule(url=url)
>>> res = model('a tiny cat.')
>>> print(res)
... <lazyllm-query>{"query": "", "files": ["path/to/sd3/image_xxx.png"]}
Source code in lazyllm/components/deploy/stable_diffusion/stable_diffusion3.py
class StableDiffusionDeploy(LazyLLMDeployBase):
    """Stable Diffusion 模型部署类。该类用于将SD模型部署到指定服务器上,以便可以通过网络进行调用。

Args:
    launcher (Optional[LazyLLMLaunchersBase], optional): 启动器实例。默认为 ``None``
    log_path (Optional[str], optional): 日志文件路径。默认为 ``None``
    trust_remote_code (bool, optional): 是否信任远程代码。默认为 ``True``
    port (Optional[int], optional): 服务端口号。默认为 ``None``



Examples:
    >>> from lazyllm import launchers, UrlModule
    >>> from lazyllm.components import StableDiffusionDeploy
    >>> deployer = StableDiffusionDeploy(launchers.remote())
    >>> url = deployer(base_model='stable-diffusion-3-medium')
    >>> model = UrlModule(url=url)
    >>> res = model('a tiny cat.')
    >>> print(res)
    ... <lazyllm-query>{"query": "", "files": ["path/to/sd3/image_xxx.png"]}
    """
    message_format = None
    keys_name_handle = None
    default_headers = {'Content-Type': 'application/json'}

    def __init__(self, launcher: Optional[LazyLLMLaunchersBase] = None,
                 log_path: Optional[str] = None, trust_remote_code: bool = True, port: Optional[int] = None, **kw):
        super().__init__(launcher=launcher)
        self._log_path = log_path
        self._trust_remote_code = trust_remote_code
        self._port = port

    def __call__(self, finetuned_model=None, base_model=None):
        if not finetuned_model:
            finetuned_model = base_model
        elif not os.path.exists(finetuned_model) or \
            not any(file.endswith(('.bin', '.safetensors'))
                    for _, _, filenames in os.walk(finetuned_model) for file in filenames):
            LOG.warning(f'Note! That finetuned_model({finetuned_model}) is an invalid path, '
                        f'base_model({base_model}) will be used')
            finetuned_model = base_model
        return lazyllm.deploy.RelayServer(port=self._port, func=_StableDiffusion3(finetuned_model),
                                          launcher=self._launcher, log_path=self._log_path, cls='stable_diffusion')()

Visual Question Answering

Reference LMDeploy, which supports the Visual Question Answering model.

Text to Sound

lazyllm.components.TTSDeploy

Source code in lazyllm/components/deploy/text_to_speech/__init__.py
class TTSDeploy:

    def __new__(cls, name, **kwarg):
        return cls.get_deploy_cls(name)(**kwarg)

    @classmethod
    def get_deploy_cls(cls, name):
        name = name.lower()
        if name == 'bark':
            return BarkDeploy
        elif name in ('chattts', 'chattts-new'):
            return ChatTTSDeploy
        elif name.startswith('musicgen'):
            return MusicGenDeploy
        else:
            raise RuntimeError(f'Not support model: {name}')

lazyllm.components.ChatTTSDeploy

Bases: TTSBase

ChatTTS 模型部署类。

Other Parameters:

  • keys_name_handle (dict) –

    键名映射字典,用于处理内部和外部API接口之间的参数名称转换。 默认为 {'inputs': 'inputs'}

  • message_format (dict) –

    请求负载结构,包含三个主要部分:

    • inputs (str): 要合成为语音的原始文本内容。

    • refinetext (dict): 文本细化和风格化参数,控制语音表达:

      • prompt (str): 语音风格控制标签,例如:"[oral_2][laugh_0][break_6]"

      • top_P (float): 核采样参数,用于解码策略(默认值:0.7)

      • top_K (int): Top-K 采样参数(默认值:20)

      • temperature (float): 采样温度,控制随机性(默认值:0.7)

      • repetition_penalty (float): 重复惩罚,避免冗余生成(默认值:1.0)

      • max_new_token (int): 最大生成token数(默认值:384)

      • min_new_token (int): 最小生成token数(默认值:0)

      • show_tqdm (bool): 是否在生成过程中显示进度条(默认值:True)

      • ensure_non_empty (bool): 确保生成非空结果(默认值:True)

    • infercode (dict): 推理和编码参数,影响音频质量:

      • prompt (str): 语速控制标签,例如:"[speed_5]"

      • spk_emb (可选): 说话人嵌入向量,用于指定音色特征(默认值:None)

      • temperature (float): 音频生成的采样温度(默认值:0.3)

      • repetition_penalty (float): 重复惩罚系数(默认值:1.05)

      • max_new_token (int): 音频生成的最大token数(默认值:2048)

Examples:

>>> from lazyllm import launchers, UrlModule
>>> from lazyllm.components import ChatTTSDeploy
>>> deployer = ChatTTSDeploy(launchers.remote())
>>> url = deployer(base_model='ChatTTS')
>>> model = UrlModule(url=url)
>>> res = model('Hello World!')
>>> print(res)
... <lazyllm-query>{"query": "", "files": ["path/to/chattts/sound_xxx.wav"]}
Source code in lazyllm/components/deploy/text_to_speech/chattts.py
class ChatTTSDeploy(TTSBase):
    """ChatTTS 模型部署类。

Keyword Args: 
    keys_name_handle (dict): 键名映射字典,用于处理内部和外部API接口之间的参数名称转换。
                            默认为 `{'inputs': 'inputs'}`。

    message_format (dict): 请求负载结构,包含三个主要部分:

        - `inputs` (str): 要合成为语音的原始文本内容。

        - `refinetext` (dict): 文本细化和风格化参数,控制语音表达:

            * `prompt` (str): 语音风格控制标签,例如:"[oral_2][laugh_0][break_6]"

            * `top_P` (float): 核采样参数,用于解码策略(默认值:0.7)

            * `top_K` (int): Top-K 采样参数(默认值:20)

            * `temperature` (float): 采样温度,控制随机性(默认值:0.7)

            * `repetition_penalty` (float): 重复惩罚,避免冗余生成(默认值:1.0)

            * `max_new_token` (int): 最大生成token数(默认值:384)

            * `min_new_token` (int): 最小生成token数(默认值:0)

            * `show_tqdm` (bool): 是否在生成过程中显示进度条(默认值:True)

            * `ensure_non_empty` (bool): 确保生成非空结果(默认值:True)

        - `infercode` (dict): 推理和编码参数,影响音频质量:

            * `prompt` (str): 语速控制标签,例如:"[speed_5]"

            * `spk_emb` (可选): 说话人嵌入向量,用于指定音色特征(默认值:None)

            * `temperature` (float): 音频生成的采样温度(默认值:0.3)

            * `repetition_penalty` (float): 重复惩罚系数(默认值:1.05)

            * `max_new_token` (int): 音频生成的最大token数(默认值:2048)



Examples:
    >>> from lazyllm import launchers, UrlModule
    >>> from lazyllm.components import ChatTTSDeploy
    >>> deployer = ChatTTSDeploy(launchers.remote())
    >>> url = deployer(base_model='ChatTTS')
    >>> model = UrlModule(url=url)
    >>> res = model('Hello World!')
    >>> print(res)
    ... <lazyllm-query>{"query": "", "files": ["path/to/chattts/sound_xxx.wav"]}
    """
    keys_name_handle = {
        'inputs': 'inputs',
    }
    message_format = {
        'inputs': 'Who are you ?',
        'refinetext': {
            'prompt': '[oral_2][laugh_0][break_6]',
            'top_P': 0.7,
            'top_K': 20,
            'temperature': 0.7,
            'repetition_penalty': 1.0,
            'max_new_token': 384,
            'min_new_token': 0,
            'show_tqdm': True,
            'ensure_non_empty': True,
        },
        'infercode': {
            'prompt': '[speed_5]',
            'spk_emb': None,
            'temperature': 0.3,
            'repetition_penalty': 1.05,
            'max_new_token': 2048,
        }

    }
    default_headers = {'Content-Type': 'application/json'}
    func = _ChatTTSModule

lazyllm.components.BarkDeploy

Bases: TTSBase

Bark 模型部署类。该类用于将Bark模型部署到指定服务器上,以便可以通过网络进行调用。

__init__(self, launcher=None) 构造函数,初始化部署类。

Parameters:

  • launcher (launcher, default: None ) –

    用于启动远程服务的启动器实例。

__call__(self, finetuned_model=None, base_model=None) 部署模型,并返回远程服务地址。

Parameters:

  • finetuned_model (str) –

    如果提供,则使用该模型进行部署;如果未提供或路径无效,则使用 base_model

  • base_model (str) –

    默认模型,如果 finetuned_model 无效,则使用该模型进行部署。

  • 返回值 (str) –

    远程服务的URL地址。

Notes
  • 推理的输入:字符串。待生成音频的对应文字。
  • 推理的返回值:从生成的文件路径编码的字符串, 编码标志以 ""开头,后面跟序列化后的字典, 字典中 files键存放了一个列表,元素是生成的音频文件路径。
  • 支持的模型为:bark

Examples:

>>> from lazyllm import launchers, UrlModule
>>> from lazyllm.components import BarkDeploy
>>> deployer = BarkDeploy(launchers.remote())
>>> url = deployer(base_model='bark')
>>> model = UrlModule(url=url)
>>> res = model('Hello World!')
>>> print(res)
... <lazyllm-query>{"query": "", "files": ["path/to/bark/sound_xxx.wav"]}
Source code in lazyllm/components/deploy/text_to_speech/bark.py
class BarkDeploy(TTSBase):
    """Bark 模型部署类。该类用于将Bark模型部署到指定服务器上,以便可以通过网络进行调用。

`__init__(self, launcher=None)`
构造函数,初始化部署类。

Args:
    launcher(lazyllm.launcher): 用于启动远程服务的启动器实例。

`__call__(self, finetuned_model=None, base_model=None)`
部署模型,并返回远程服务地址。

Args: 
    finetuned_model (str): 如果提供,则使用该模型进行部署;如果未提供或路径无效,则使用 `base_model`。
    base_model (str): 默认模型,如果 `finetuned_model` 无效,则使用该模型进行部署。
    返回值 (str): 远程服务的URL地址。

Notes:
    - 推理的输入:字符串。待生成音频的对应文字。
    - 推理的返回值:从生成的文件路径编码的字符串, 编码标志以 "<lazyllm-query>"开头,后面跟序列化后的字典, 字典中 `files`键存放了一个列表,元素是生成的音频文件路径。
    - 支持的模型为:[bark](https://huggingface.co/suno/bark)


Examples:
    >>> from lazyllm import launchers, UrlModule
    >>> from lazyllm.components import BarkDeploy
    >>> deployer = BarkDeploy(launchers.remote())
    >>> url = deployer(base_model='bark')
    >>> model = UrlModule(url=url)
    >>> res = model('Hello World!')
    >>> print(res)
    ... <lazyllm-query>{"query": "", "files": ["path/to/bark/sound_xxx.wav"]}
    """
    keys_name_handle = {
        'inputs': 'inputs',
    }
    message_format = {
        'inputs': 'Who are you ?',
        'voice_preset': None,
    }
    default_headers = {'Content-Type': 'application/json'}

    func = _Bark

lazyllm.components.MusicGenDeploy

Bases: TTSBase

MusicGen 模型部署类。该类用于将MusicGen模型部署到指定服务器上,以便可以通过网络进行调用。

__init__(self, launcher=None) 构造函数,初始化部署类。

Parameters:

  • launcher (launcher, default: None ) –

    用于启动远程服务的启动器实例。

__call__(self, finetuned_model=None, base_model=None) 部署模型,并返回远程服务地址。

Parameters:

  • finetuned_model (str) –

    如果提供,则使用该模型进行部署;如果未提供或路径无效,则使用 base_model

  • base_model (str) –

    默认模型,如果 finetuned_model 无效,则使用该模型进行部署。

  • 返回值 (str) –

    远程服务的URL地址。

Notes
  • 推理的输入:字符串。待生成音频的对应文字。
  • 推理的返回值:从生成的文件路径编码的字符串, 编码标志以 ""开头,后面跟序列化后的字典, 字典中 files键存放了一个列表,元素是生成的音频文件路径。
  • 支持的模型为:musicgen-small

Examples:

>>> from lazyllm import launchers, UrlModule
>>> from lazyllm.components import MusicGenDeploy
>>> deployer = MusicGenDeploy(launchers.remote())
>>> url = deployer(base_model='musicgen-small')
>>> model = UrlModule(url=url)
>>> model('Symphony with flute as the main melody')
... <lazyllm-query>{"query": "", "files": ["path/to/musicgen/sound_xxx.wav"]}
Source code in lazyllm/components/deploy/text_to_speech/musicgen.py
class MusicGenDeploy(TTSBase):
    """MusicGen 模型部署类。该类用于将MusicGen模型部署到指定服务器上,以便可以通过网络进行调用。

`__init__(self, launcher=None)`
构造函数,初始化部署类。

Args:
    launcher(lazyllm.launcher): 用于启动远程服务的启动器实例。

`__call__(self, finetuned_model=None, base_model=None)`
部署模型,并返回远程服务地址。

Args: 
    finetuned_model (str): 如果提供,则使用该模型进行部署;如果未提供或路径无效,则使用 `base_model`。
    base_model (str): 默认模型,如果 `finetuned_model` 无效,则使用该模型进行部署。
    返回值 (str): 远程服务的URL地址。

Notes:
    - 推理的输入:字符串。待生成音频的对应文字。
    - 推理的返回值:从生成的文件路径编码的字符串, 编码标志以 "<lazyllm-query>"开头,后面跟序列化后的字典, 字典中 `files`键存放了一个列表,元素是生成的音频文件路径。
    - 支持的模型为:[musicgen-small](https://huggingface.co/facebook/musicgen-small)


Examples:
    >>> from lazyllm import launchers, UrlModule
    >>> from lazyllm.components import MusicGenDeploy
    >>> deployer = MusicGenDeploy(launchers.remote())
    >>> url = deployer(base_model='musicgen-small')
    >>> model = UrlModule(url=url)
    >>> model('Symphony with flute as the main melody')
    ... <lazyllm-query>{"query": "", "files": ["path/to/musicgen/sound_xxx.wav"]}
    """
    message_format = None
    keys_name_handle = None
    default_headers = {'Content-Type': 'application/json'}
    func = _MusicGen

Speech to Text

lazyllm.components.SenseVoiceDeploy

Bases: LazyLLMDeployBase

SenseVoice 模型部署类。该类用于将SenseVoice模型部署到指定服务器上,以便可以通过网络进行调用。

__init__(self, launcher=None) 构造函数,初始化部署类。

Parameters:

  • launcher (Optional[LazyLLMLaunchersBase], default: None ) –

    Launcher instance, defaults to None.

  • log_path (Optional[str], default: None ) –

    Log file path, defaults to None.

  • trust_remote_code (bool, default: True ) –

    Whether to trust remote code, defaults to True.

  • port (Optional[int], default: None ) –

    Service port number, defaults to None.

Notes
  • 推理的输入:字符串。音频路径或者链接。
  • 推理的返回值:字符串。识别出的内容。
  • 支持的模型为:SenseVoiceSmall

Examples:

>>> import os
>>> import lazyllm
>>> from lazyllm import launchers, UrlModule
>>> from lazyllm.components import SenseVoiceDeploy
>>> deployer = SenseVoiceDeploy(launchers.remote())
>>> url = deployer(base_model='SenseVoiceSmall')
>>> model = UrlModule(url=url)
>>> model('path/to/audio') # support format: .mp3, .wav
... xxxxxxxxxxxxxxxx
Source code in lazyllm/components/deploy/speech_to_text/sense_voice.py
class SenseVoiceDeploy(LazyLLMDeployBase):
    """SenseVoice 模型部署类。该类用于将SenseVoice模型部署到指定服务器上,以便可以通过网络进行调用。

`__init__(self, launcher=None)`
构造函数,初始化部署类。

Args:
    launcher (Optional[LazyLLMLaunchersBase]): Launcher instance, defaults to None.
    log_path (Optional[str]): Log file path, defaults to None.
    trust_remote_code (bool): Whether to trust remote code, defaults to True.
    port (Optional[int]): Service port number, defaults to None.

Notes:
    - 推理的输入:字符串。音频路径或者链接。
    - 推理的返回值:字符串。识别出的内容。
    - 支持的模型为:[SenseVoiceSmall](https://huggingface.co/FunAudioLLM/SenseVoiceSmall)


Examples:
    >>> import os
    >>> import lazyllm
    >>> from lazyllm import launchers, UrlModule
    >>> from lazyllm.components import SenseVoiceDeploy
    >>> deployer = SenseVoiceDeploy(launchers.remote())
    >>> url = deployer(base_model='SenseVoiceSmall')
    >>> model = UrlModule(url=url)
    >>> model('path/to/audio') # support format: .mp3, .wav
    ... xxxxxxxxxxxxxxxx
    """
    keys_name_handle = {
        'inputs': 'inputs',
        'audio': 'audio',
    }
    message_format = {
        'inputs': 'Who are you ?',
        'audio': None,
    }
    default_headers = {'Content-Type': 'application/json'}

    def __init__(self, launcher: Optional[LazyLLMLaunchersBase] = None,
                 log_path: Optional[str] = None, trust_remote_code: bool = True, port: Optional[int] = None, **kw):
        super().__init__(launcher=launcher)
        self._log_path = log_path
        self._trust_remote_code = trust_remote_code
        self._port = port

    def __call__(self, finetuned_model=None, base_model=None):
        if not finetuned_model:
            finetuned_model = base_model
        elif not os.path.exists(finetuned_model) or \
            not any(file.endswith(('.pt', '.bin', '.safetensors'))
                    for _, _, filenames in os.walk(finetuned_model) for file in filenames):
            LOG.warning(f'Note! That finetuned_model({finetuned_model}) is an invalid path, '
                        f'base_model({base_model}) will be used')
            finetuned_model = base_model
        return lazyllm.deploy.RelayServer(port=self._port, func=SenseVoice(finetuned_model), launcher=self._launcher,
                                          log_path=self._log_path, cls='sensevoice')()

lazyllm.components.deploy.speech_to_text.sense_voice.SenseVoice

Bases: object

SenseVoice 类,封装了基于 FunASR 的语音转文本模型加载与调用逻辑。
支持懒加载、自动模型下载,输入可为字符串路径、URL 或包含音频的字典。

Parameters:

  • base_path (str) –

    模型路径或标识符,将通过 ModelManager 下载到本地。

  • source (Optional[str], default: None ) –

    模型来源,若未指定则使用 lazyllm.config['model_source']

  • init (bool, default: False ) –

    是否在初始化时立即加载模型,默认为 False

Attributes:

  • base_path (str) –

    下载或解析后的模型路径。

  • model (Optional[AutoModel]) –

    FunASR 语音识别模型实例,初始化后可用。

  • init_flag

    用于懒加载的标志,确保模型只加载一次。

Source code in lazyllm/components/deploy/speech_to_text/sense_voice.py
class SenseVoice(object):
    """SenseVoice 类,封装了基于 FunASR 的语音转文本模型加载与调用逻辑。  
支持懒加载、自动模型下载,输入可为字符串路径、URL 或包含音频的字典。  

Args:
    base_path (str): 模型路径或标识符,将通过 ModelManager 下载到本地。  
    source (Optional[str]): 模型来源,若未指定则使用 ``lazyllm.config['model_source']``。  
    init (bool): 是否在初始化时立即加载模型,默认为 ``False``。  

Attributes:
    base_path (str): 下载或解析后的模型路径。  
    model (Optional[funasr.AutoModel]): FunASR 语音识别模型实例,初始化后可用。  
    init_flag: 用于懒加载的标志,确保模型只加载一次。  
"""
    def __init__(self, base_path, source=None, init=False):
        source = lazyllm.config['model_source'] if not source else source
        self.base_path = ModelManager(source).download(base_path) or ''
        self.model = None
        self.init_flag = lazyllm.once_flag()
        if init:
            lazyllm.call_once(self.init_flag, self.load_stt)

    def load_stt(self):
        """初始化并加载 FunASR 语音转文本模型,如果存在 `torch_npu` 则支持华为 NPU 加速。

使用 `fsmn-vad` 进行语音活动检测(VAD),支持长语音段。
单段语音最大持续时间为 30 秒。
默认推理设备为 `cuda:0`(GPU)。

加载的模型将保存在 `self.model` 中,用于后续音频转写。

注意:
- 如果当前环境中存在 `torch_npu`,函数会导入以支持昇腾 NPU 加速。
"""
        if importlib.util.find_spec('torch_npu') is not None:
            import torch_npu  # noqa F401
            from torch_npu.contrib import transfer_to_npu  # noqa F401

        self.model = funasr.AutoModel(
            model=self.base_path,
            trust_remote_code=False,
            vad_model='fsmn-vad',
            vad_kwargs={'max_single_segment_time': 30000},
            device='cuda:0',
        )

    def __call__(self, string):
        lazyllm.call_once(self.init_flag, self.load_stt)
        if isinstance(string, dict):
            if string['audio']:
                string = string['audio'][-1] if isinstance(string['audio'], list) else string['audio']
            else:
                string = string['inputs']
        assert isinstance(string, str)
        string = string.strip()
        try:
            string = _base64_to_file(string) if _is_base64_with_mime(string) else string
        except Exception as e:
            LOG.error(f'Error processing base64 encoding: {e}')
            return f'Error processing base64 encoding {e}'
        if not string.endswith(supported_formats):
            return f'Only {", ".join(supported_formats)} formats in the form of file paths or URLs are supported.'
        if not is_valid_path(string) and not is_valid_url(string):
            return f'This {string} is not a valid URL or file path. Please check.'
        res = self.model.generate(
            input=string,
            cache={},
            language='auto',  # 'zn', 'en', 'yue', 'ja', 'ko', 'nospeech'
            use_itn=True,
            batch_size_s=60,
            merge_vad=True,
            merge_length_s=15,
        )
        text = funasr.utils.postprocess_utils.rich_transcription_postprocess(res[0]['text'])
        return text

    @classmethod
    def rebuild(cls, base_path, init):
        """类方法,用于在反序列化过程中重新构建 `SenseVoice` 实例(例如使用 `cloudpickle`)。  

Args:
    base_path (str): 语音识别模型路径。  
    init (bool): 实例化时是否立即初始化并加载模型。

**Returns:**

- SenseVoice: 返回一个新的 `SenseVoice` 实例,用于支持序列化/多进程兼容。
"""
        return cls(base_path, init=init)

    def __reduce__(self):
        init = bool(os.getenv('LAZYLLM_ON_CLOUDPICKLE', None) == 'ON' or self.init_flag)
        return SenseVoice.rebuild, (self.base_path, init)
load_stt()

初始化并加载 FunASR 语音转文本模型,如果存在 torch_npu 则支持华为 NPU 加速。

使用 fsmn-vad 进行语音活动检测(VAD),支持长语音段。 单段语音最大持续时间为 30 秒。 默认推理设备为 cuda:0(GPU)。

加载的模型将保存在 self.model 中,用于后续音频转写。

注意: - 如果当前环境中存在 torch_npu,函数会导入以支持昇腾 NPU 加速。

Source code in lazyllm/components/deploy/speech_to_text/sense_voice.py
    def load_stt(self):
        """初始化并加载 FunASR 语音转文本模型,如果存在 `torch_npu` 则支持华为 NPU 加速。

使用 `fsmn-vad` 进行语音活动检测(VAD),支持长语音段。
单段语音最大持续时间为 30 秒。
默认推理设备为 `cuda:0`(GPU)。

加载的模型将保存在 `self.model` 中,用于后续音频转写。

注意:
- 如果当前环境中存在 `torch_npu`,函数会导入以支持昇腾 NPU 加速。
"""
        if importlib.util.find_spec('torch_npu') is not None:
            import torch_npu  # noqa F401
            from torch_npu.contrib import transfer_to_npu  # noqa F401

        self.model = funasr.AutoModel(
            model=self.base_path,
            trust_remote_code=False,
            vad_model='fsmn-vad',
            vad_kwargs={'max_single_segment_time': 30000},
            device='cuda:0',
        )
rebuild(base_path, init) classmethod

类方法,用于在反序列化过程中重新构建 SenseVoice 实例(例如使用 cloudpickle)。

Parameters:

  • base_path (str) –

    语音识别模型路径。

  • init (bool) –

    实例化时是否立即初始化并加载模型。

Returns:

  • SenseVoice: 返回一个新的 SenseVoice 实例,用于支持序列化/多进程兼容。
Source code in lazyllm/components/deploy/speech_to_text/sense_voice.py
    @classmethod
    def rebuild(cls, base_path, init):
        """类方法,用于在反序列化过程中重新构建 `SenseVoice` 实例(例如使用 `cloudpickle`)。  

Args:
    base_path (str): 语音识别模型路径。  
    init (bool): 实例化时是否立即初始化并加载模型。

**Returns:**

- SenseVoice: 返回一个新的 `SenseVoice` 实例,用于支持序列化/多进程兼容。
"""
        return cls(base_path, init=init)

ModelManager

lazyllm.components.ModelManager

ModelManager 是 LazyLLM 提供的模型管理与下载工具类,支持本地搜索和 Huggingface/Modelscope 下载。

Parameters:

  • model_source (Optional[str]) –

    模型下载源,仅支持 huggingfacemodelscope。 未提供时使用 LAZYLLM_MODEL_SOURCE,若未设置则默认 modelscope

  • token (Optional[str], default: config['model_source_token'] ) –

    下载私有模型的访问令牌。未提供时使用 LAZYLLM_MODEL_SOURCE_TOKEN。

  • model_path (Optional[str], default: config['model_path'] ) –

    冒号分隔的本地绝对路径列表,用于下载前搜索模型。未提供时使用 LAZYLLM_MODEL_PATH。

  • cache_dir (Optional[str], default: config['model_cache_dir'] ) –

    本地缓存目录,用于存放下载的模型。未提供时使用 LAZYLLM_MODEL_CACHE_DIR,默认 ~/.lazyllm/model

Static Methods

get_model_type(model: str) -> str 返回指定模型类型,如 llmchat,未识别返回 llm。 get_model_prompt_keys(model: str) -> dict 返回模型的 prompt key 映射字典。 validate_model_path(model_path: str) -> bool 检查目录下是否存在有效模型文件(扩展名: .pt, .bin, .safetensors)。

Instance Methods

download(model: Optional[str] = '', call_back: Optional[Callable] = None) -> str | bool 下载指定模型。流程: 1. 在 model_path 列出的本地目录搜索; 2. 未找到则在 cache_dir 下搜索; 3. 仍未找到则从 model_source 下载并存放 cache_dir。

Args:
    model (Optional[str]): 目标模型名称,可使用简略名称或下载源完整名称。
    call_back (Optional[Callable]): 下载进度回调函数,可选。

Examples:

>>> from lazyllm.components import ModelManager
>>> downloader = ModelManager(model_source='modelscope')
>>> downloader.download('chatglm3-6b')
Source code in lazyllm/components/utils/downloader/model_downloader.py
class ModelManager():
    """ModelManager 是 LazyLLM 提供的模型管理与下载工具类,支持本地搜索和 Huggingface/Modelscope 下载。  

Args:
    model_source (Optional[str]): 模型下载源,仅支持 ``huggingface`` 或 ``modelscope``。
        未提供时使用 LAZYLLM_MODEL_SOURCE,若未设置则默认 ``modelscope``。
    token (Optional[str]): 下载私有模型的访问令牌。未提供时使用 LAZYLLM_MODEL_SOURCE_TOKEN。
    model_path (Optional[str]): 冒号分隔的本地绝对路径列表,用于下载前搜索模型。未提供时使用 LAZYLLM_MODEL_PATH。
    cache_dir (Optional[str]): 本地缓存目录,用于存放下载的模型。未提供时使用 LAZYLLM_MODEL_CACHE_DIR,默认 ``~/.lazyllm/model``。

Static Methods:
    get_model_type(model: str) -> str
        返回指定模型类型,如 ``llm``、``chat``,未识别返回 ``llm``。
    get_model_prompt_keys(model: str) -> dict
        返回模型的 prompt key 映射字典。
    validate_model_path(model_path: str) -> bool
        检查目录下是否存在有效模型文件(扩展名: ``.pt``, ``.bin``, ``.safetensors``)。

Instance Methods:
    download(model: Optional[str] = '', call_back: Optional[Callable] = None) -> str | bool
        下载指定模型。流程:
        1. 在 model_path 列出的本地目录搜索;
        2. 未找到则在 cache_dir 下搜索;
        3. 仍未找到则从 model_source 下载并存放 cache_dir。

        Args:
            model (Optional[str]): 目标模型名称,可使用简略名称或下载源完整名称。
            call_back (Optional[Callable]): 下载进度回调函数,可选。


Examples:
    >>> from lazyllm.components import ModelManager
    >>> downloader = ModelManager(model_source='modelscope')
    >>> downloader.download('chatglm3-6b')
    """
    def __init__(self, model_source, token=lazyllm.config['model_source_token'],
                 cache_dir=lazyllm.config['model_cache_dir'], model_path=lazyllm.config['model_path']):
        self.model_source = model_source or lazyllm.config['model_source']
        self.token = token or None
        self.cache_dir = cache_dir
        self.model_paths = model_path.split(':') if len(model_path) > 0 else []
        if self.model_source == 'huggingface':
            self.hub_downloader = _HuggingfaceDownloader(token=self.token)
        else:
            self.hub_downloader = _ModelscopeDownloader(token=self.token)
            if self.model_source != 'modelscope':
                lazyllm.LOG.error('Only support Huggingface and Modelscope currently. '
                                  f'Unsupported model source: {self.model_source}. Forcing use of Modelscope.')

    @staticmethod
    @functools.lru_cache
    def get_model_type(model) -> str:
        """根据模型名称获取模型类型(如 LLM、VLM 等)。

Args:
    model (str): 模型名称或路径,必须为非空字符串。

**Returns:**

- str: 模型类型,如果无法匹配则返回 ``llm``。
"""
        assert isinstance(model, str) and len(model) > 0, f'model name should be a non-empty string, get {model}'
        __class__._try_add_mapping(model)
        for name, info in model_name_mapping.items():
            if 'type' not in info: continue

            model_name_set = {name.casefold()}
            for source in info['source']:
                model_name_set.add(info['source'][source].split('/')[-1].casefold())

            if model.split(os.sep)[-1].casefold() in model_name_set:
                return info['type']
        return 'llm'

    @staticmethod
    @functools.lru_cache
    def _get_model_name(model) -> str:
        search_string = os.path.basename(model)
        __class__._try_add_mapping(search_string)
        for model_name, sources in model_name_mapping.items():
            if model_name.lower() == search_string.lower() or any(
                    os.path.basename(source_file).lower() == search_string.lower()
                    for source_file in sources['source'].values()):
                return model_name
        return ''

    @staticmethod
    @functools.lru_cache
    def get_model_prompt_keys(model) -> dict:
        """获取指定模型的 prompt key 映射字典,用于推理时构建输入。  

Args:
    model (str): 模型名称或路径。

**Returns:**

- dict: 模型对应的 prompt key 映射,如果不存在则返回空字典
"""
        model_name = __class__._get_model_name(model)
        __class__._try_add_mapping(model_name)
        if model_name and 'prompt_keys' in model_name_mapping[model_name.lower()]:
            return model_name_mapping[model_name.lower()]['prompt_keys']
        else:
            return dict()

    @staticmethod
    def validate_model_path(model_path):
        """检查指定路径下是否存在有效的模型文件(.pt, .bin, .safetensors)。  

Args:
    model_path (str): 模型目录路径。

**Returns:**

- bool: 如果目录中存在模型文件返回 True,否则返回 False
"""
        extensions = {'.pt', '.bin', '.safetensors'}
        for _, _, files in os.walk(model_path):
            for file in files:
                if any(file.endswith(ext) for ext in extensions):
                    return True
        return False

    @staticmethod
    def _try_add_mapping(model):
        model_base = os.path.basename(model)
        model = model_base.lower()
        if model in model_name_mapping.keys():
            return
        matched_model_prefix = next((key for key in model_provider if model.startswith(key)), None)
        if matched_model_prefix:
            matching_keys = [key for key in model_groups.keys() if key in model]
            if matching_keys:
                matched_groups = max(matching_keys, key=len)
                model_name_mapping[model] = {
                    'prompt_keys': model_groups[matched_groups]['prompt_keys'],
                    'source': {k: v + '/' + model_base for k, v in model_provider[matched_model_prefix].items()}
                }

    def download(self, model='', call_back=None):
        """下载指定名称的模型,如果本地已有则直接返回本地路径;  
支持 Huggingface 和 Modelscope 平台的自动下载,并会在缓存目录创建符号链接以便统一管理。  

Args:
    model (str, optional): 模型名称或路径,默认为空字符串,表示不下载。
    call_back (Optional[Callable], optional): 下载进度回调函数,接受当前下载状态等参数。  

**Returns:**

- str | bool: 模型在本地的完整路径,如果下载失败返回 False
"""
        assert isinstance(model, str), 'model name should be a string.'
        if len(model) == 0 or model[0] in (os.sep, '.', '~') or os.path.isabs(model): return model
        if (model_at_path := self._model_exists_at_path(model)): return model_at_path
        if self.model_source == '' or self.model_source not in ('huggingface', 'modelscope'):
            lazyllm.LOG.error('model automatic downloads only support Huggingface and Modelscope currently.')
            return model

        self._try_add_mapping(model)
        if model_name_mapping.get(model.lower(), {}).get('download_by_other'): return model

        if model.lower() in model_name_mapping.keys() and \
                self.model_source in model_name_mapping[model.lower()]['source'].keys():
            full_model_dir = os.path.join(self.cache_dir, model)

            mapped_model_name = model_name_mapping[model.lower()]['source'][self.model_source]
            model_save_dir = self._do_download(mapped_model_name, call_back)
            if model_save_dir:
                # The code safely creates a symbolic link by removing any existing target.
                if os.path.exists(full_model_dir):
                    os.remove(full_model_dir)
                if os.path.islink(full_model_dir):
                    os.unlink(full_model_dir)
                os.symlink(model_save_dir, full_model_dir, target_is_directory=True)
                return full_model_dir
            return model_save_dir  # return False
        else:
            model_name_for_download = model

            if '/' not in model_name_for_download:
                # Try to figure out a possible model provider
                matched_model_prefix = next((key for key in model_provider if model.lower().startswith(key)), None)
                if matched_model_prefix and self.model_source in model_provider[matched_model_prefix]:
                    model_name_for_download = model_provider[matched_model_prefix][self.model_source] + '/' + model

            model_save_dir = self._do_download(model_name_for_download, call_back)
            return model_save_dir

    def _validate_token(self):
        return self.hub_downloader.verify_hub_token()

    def _validate_model_id(self, model_id):
        return self.hub_downloader._verify_model_id(model_id)

    def _model_exists_at_path(self, model_name):
        if len(self.model_paths) == 0:
            return None
        model_dirs = []

        # For short model name, get all possible names from the mapping.
        if model_name.lower() in model_name_mapping.keys():
            for source in ('huggingface', 'modelscope'):
                if source in model_name_mapping[model_name.lower()]['source'].keys():
                    model_dirs.append(model_name_mapping[model_name.lower()]['source'][source].replace('/', os.sep))
        model_dirs.append(model_name.replace('/', os.sep))

        for model_path in self.model_paths:
            if len(model_path) == 0: continue
            if model_path[0] != os.sep:
                lazyllm.LOG.warning(f'skipping path {model_path} as only absolute paths is accepted.')
                continue
            for model_dir in model_dirs:
                full_model_dir = os.path.join(model_path, model_dir)
                if self._is_model_valid(full_model_dir):
                    return full_model_dir
        return None

    def _is_model_valid(self, model_dir):
        if not os.path.isdir(model_dir):
            return False
        return any((True for _ in os.scandir(model_dir)))

    def _do_download(self, model='', call_back=None):
        model_dir = model.replace('/', os.sep)
        full_model_dir = os.path.join(self.cache_dir, self.model_source, model_dir)

        try:
            return self.hub_downloader.download(model, full_model_dir, call_back)
        # Use `BaseException` to capture `KeyboardInterrupt` and normal `Exceptioin`.
        except BaseException as e:  # noqa B036
            lazyllm.LOG.warning(f'Download encountered an error: {e}')
            if not self.token and 'Permission denied' not in str(e):
                lazyllm.LOG.warning('Token is empty, which may prevent private models from being downloaded, '
                                    'as indicated by "the model does not exist." Please set the token with the '
                                    'environment variable LAZYLLM_MODEL_SOURCE_TOKEN to download private models.')
            if os.path.isdir(full_model_dir):
                shutil.rmtree(full_model_dir)
                lazyllm.LOG.warning(f'{full_model_dir} removed due to exceptions.')
        return False

get_model_type(model) cached staticmethod

根据模型名称获取模型类型(如 LLM、VLM 等)。

Parameters:

  • model (str) –

    模型名称或路径,必须为非空字符串。

Returns:

  • str: 模型类型,如果无法匹配则返回 llm
Source code in lazyllm/components/utils/downloader/model_downloader.py
    @staticmethod
    @functools.lru_cache
    def get_model_type(model) -> str:
        """根据模型名称获取模型类型(如 LLM、VLM 等)。

Args:
    model (str): 模型名称或路径,必须为非空字符串。

**Returns:**

- str: 模型类型,如果无法匹配则返回 ``llm``。
"""
        assert isinstance(model, str) and len(model) > 0, f'model name should be a non-empty string, get {model}'
        __class__._try_add_mapping(model)
        for name, info in model_name_mapping.items():
            if 'type' not in info: continue

            model_name_set = {name.casefold()}
            for source in info['source']:
                model_name_set.add(info['source'][source].split('/')[-1].casefold())

            if model.split(os.sep)[-1].casefold() in model_name_set:
                return info['type']
        return 'llm'

get_model_prompt_keys(model) cached staticmethod

获取指定模型的 prompt key 映射字典,用于推理时构建输入。

Parameters:

  • model (str) –

    模型名称或路径。

Returns:

  • dict: 模型对应的 prompt key 映射,如果不存在则返回空字典
Source code in lazyllm/components/utils/downloader/model_downloader.py
    @staticmethod
    @functools.lru_cache
    def get_model_prompt_keys(model) -> dict:
        """获取指定模型的 prompt key 映射字典,用于推理时构建输入。  

Args:
    model (str): 模型名称或路径。

**Returns:**

- dict: 模型对应的 prompt key 映射,如果不存在则返回空字典
"""
        model_name = __class__._get_model_name(model)
        __class__._try_add_mapping(model_name)
        if model_name and 'prompt_keys' in model_name_mapping[model_name.lower()]:
            return model_name_mapping[model_name.lower()]['prompt_keys']
        else:
            return dict()

validate_model_path(model_path) staticmethod

检查指定路径下是否存在有效的模型文件(.pt, .bin, .safetensors)。

Parameters:

  • model_path (str) –

    模型目录路径。

Returns:

  • bool: 如果目录中存在模型文件返回 True,否则返回 False
Source code in lazyllm/components/utils/downloader/model_downloader.py
    @staticmethod
    def validate_model_path(model_path):
        """检查指定路径下是否存在有效的模型文件(.pt, .bin, .safetensors)。  

Args:
    model_path (str): 模型目录路径。

**Returns:**

- bool: 如果目录中存在模型文件返回 True,否则返回 False
"""
        extensions = {'.pt', '.bin', '.safetensors'}
        for _, _, files in os.walk(model_path):
            for file in files:
                if any(file.endswith(ext) for ext in extensions):
                    return True
        return False

download(model='', call_back=None)

下载指定名称的模型,如果本地已有则直接返回本地路径;
支持 Huggingface 和 Modelscope 平台的自动下载,并会在缓存目录创建符号链接以便统一管理。

Parameters:

  • model (str, default: '' ) –

    模型名称或路径,默认为空字符串,表示不下载。

  • call_back (Optional[Callable], default: None ) –

    下载进度回调函数,接受当前下载状态等参数。

Returns:

  • str | bool: 模型在本地的完整路径,如果下载失败返回 False
Source code in lazyllm/components/utils/downloader/model_downloader.py
    def download(self, model='', call_back=None):
        """下载指定名称的模型,如果本地已有则直接返回本地路径;  
支持 Huggingface 和 Modelscope 平台的自动下载,并会在缓存目录创建符号链接以便统一管理。  

Args:
    model (str, optional): 模型名称或路径,默认为空字符串,表示不下载。
    call_back (Optional[Callable], optional): 下载进度回调函数,接受当前下载状态等参数。  

**Returns:**

- str | bool: 模型在本地的完整路径,如果下载失败返回 False
"""
        assert isinstance(model, str), 'model name should be a string.'
        if len(model) == 0 or model[0] in (os.sep, '.', '~') or os.path.isabs(model): return model
        if (model_at_path := self._model_exists_at_path(model)): return model_at_path
        if self.model_source == '' or self.model_source not in ('huggingface', 'modelscope'):
            lazyllm.LOG.error('model automatic downloads only support Huggingface and Modelscope currently.')
            return model

        self._try_add_mapping(model)
        if model_name_mapping.get(model.lower(), {}).get('download_by_other'): return model

        if model.lower() in model_name_mapping.keys() and \
                self.model_source in model_name_mapping[model.lower()]['source'].keys():
            full_model_dir = os.path.join(self.cache_dir, model)

            mapped_model_name = model_name_mapping[model.lower()]['source'][self.model_source]
            model_save_dir = self._do_download(mapped_model_name, call_back)
            if model_save_dir:
                # The code safely creates a symbolic link by removing any existing target.
                if os.path.exists(full_model_dir):
                    os.remove(full_model_dir)
                if os.path.islink(full_model_dir):
                    os.unlink(full_model_dir)
                os.symlink(model_save_dir, full_model_dir, target_is_directory=True)
                return full_model_dir
            return model_save_dir  # return False
        else:
            model_name_for_download = model

            if '/' not in model_name_for_download:
                # Try to figure out a possible model provider
                matched_model_prefix = next((key for key in model_provider if model.lower().startswith(key)), None)
                if matched_model_prefix and self.model_source in model_provider[matched_model_prefix]:
                    model_name_for_download = model_provider[matched_model_prefix][self.model_source] + '/' + model

            model_save_dir = self._do_download(model_name_for_download, call_back)
            return model_save_dir

Formatter

lazyllm.components.formatter.LazyLLMFormatterBase

此类是格式化器的基类,格式化器是模型输出结果的格式化器,用户可以自定义格式化器,也可以使用LazyLLM提供的格式化器。

Examples:

>>> from lazyllm.components.formatter import LazyLLMFormatterBase
>>> class MyFormatter(LazyLLMFormatterBase):
...     def __init__(self, formatter: str = None):
...         self._formatter = formatter
...         if self._formatter:
...             self._parse_formatter()
...         else:
...             self._slices = None
...     def _parse_formatter(self):
...         slice_str = self._formatter.strip()[1:-1]
...         slices = []
...         parts = slice_str.split(":")
...         start = int(parts[0]) if parts[0] else None
...         end = int(parts[1]) if len(parts) > 1 and parts[1] else None
...         step = int(parts[2]) if len(parts) > 2 and parts[2] else None
...         slices.append(slice(start, end, step))
...         self._slices = slices
...     def _load(self, data):
...         return [int(x) for x in data.strip('[]').split(',')]
...     def _parse_py_data_by_formatter(self, data):
...         if self._slices is not None:
...             result = []
...             for s in self._slices:
...                 if isinstance(s, slice):
...                     result.extend(data[s])
...                 else:
...                     result.append(data[int(s)])
...             return result
...         else:
...             return data
...
>>> fmt = MyFormatter("[1:3]")
>>> res = fmt.format("[1,2,3,4,5]")
>>> print(res)
[2, 3]
Source code in lazyllm/components/formatter/formatterbase.py
class LazyLLMFormatterBase(metaclass=LazyLLMRegisterMetaClass):
    """此类是格式化器的基类,格式化器是模型输出结果的格式化器,用户可以自定义格式化器,也可以使用LazyLLM提供的格式化器。


Examples:
    >>> from lazyllm.components.formatter import LazyLLMFormatterBase
    >>> class MyFormatter(LazyLLMFormatterBase):
    ...     def __init__(self, formatter: str = None):
    ...         self._formatter = formatter
    ...         if self._formatter:
    ...             self._parse_formatter()
    ...         else:
    ...             self._slices = None
    ...     def _parse_formatter(self):
    ...         slice_str = self._formatter.strip()[1:-1]
    ...         slices = []
    ...         parts = slice_str.split(":")
    ...         start = int(parts[0]) if parts[0] else None
    ...         end = int(parts[1]) if len(parts) > 1 and parts[1] else None
    ...         step = int(parts[2]) if len(parts) > 2 and parts[2] else None
    ...         slices.append(slice(start, end, step))
    ...         self._slices = slices
    ...     def _load(self, data):
    ...         return [int(x) for x in data.strip('[]').split(',')]
    ...     def _parse_py_data_by_formatter(self, data):
    ...         if self._slices is not None:
    ...             result = []
    ...             for s in self._slices:
    ...                 if isinstance(s, slice):
    ...                     result.extend(data[s])
    ...                 else:
    ...                     result.append(data[int(s)])
    ...             return result
    ...         else:
    ...             return data
    ...
    >>> fmt = MyFormatter("[1:3]")
    >>> res = fmt.format("[1,2,3,4,5]")
    >>> print(res)
    [2, 3]
    """
    def _load(self, msg: str):
        return msg

    def _parse_py_data_by_formatter(self, py_data):
        raise NotImplementedError('This data parse function is not implemented.')

    def format(self, msg):
        """格式化输入消息。

Args:
    msg: 输入消息,可以是字符串或其他格式

**Returns:**

- 格式化后的数据,具体类型由子类实现决定
"""
        if isinstance(msg, str): msg = self._load(msg)
        return self._parse_py_data_by_formatter(msg)

    def __call__(self, *msg):
        return self.format(msg[0] if len(msg) == 1 else package(msg))

    def __or__(self, other):
        if not isinstance(other, LazyLLMFormatterBase):
            return NotImplemented
        return PipelineFormatter(other.__ror__(self))

    def __ror__(self, f: Callable) -> Pipeline:
        if isinstance(f, Pipeline):
            if not f._capture:
                _ = Finalizer(lambda: setattr(f, '_capture', True), lambda: setattr(f, '_capture', False))
            f._add(str(uuid.uuid4().hex) if len(f._item_names) else None, self)
            return f
        return Pipeline(f, self)

format(msg)

格式化输入消息。

Parameters:

  • msg

    输入消息,可以是字符串或其他格式

Returns:

  • 格式化后的数据,具体类型由子类实现决定
Source code in lazyllm/components/formatter/formatterbase.py
    def format(self, msg):
        """格式化输入消息。

Args:
    msg: 输入消息,可以是字符串或其他格式

**Returns:**

- 格式化后的数据,具体类型由子类实现决定
"""
        if isinstance(msg, str): msg = self._load(msg)
        return self._parse_py_data_by_formatter(msg)

lazyllm.components.formatter.formatterbase.JsonLikeFormatter

Bases: LazyLLMFormatterBase

该类用于以类 JSON 的格式提取嵌套结构(如 dict、list、tuple)中的子字段内容。

其功能通过格式化字符串 formatter 来控制,格式类似于数组/字典的索引切片表达式。例如:

  • [0] 表示取第 0 个元素
  • [0][{key}] 表示取第 0 个元素并获取其中 key 字段
  • [0,1][{a,b}] 表示同时提取第 0 和第 1 个对象的 a 和 b 字段
  • [::2] 表示步长为 2 的切片
  • *[0][{x}] 表示以包装格式返回处理后的数据(用于进一步结构化)

Parameters:

  • formatter (str, default: None ) –

    控制提取规则的格式字符串。若为 None,则返回原始数据。

Examples:

>>> from lazyllm.components.formatter.formatterbase import JsonLikeFormatter
>>> formatter = JsonLikeFormatter("[{a,b}]")
Source code in lazyllm/components/formatter/formatterbase.py
class JsonLikeFormatter(LazyLLMFormatterBase):
    """该类用于以类 JSON 的格式提取嵌套结构(如 dict、list、tuple)中的子字段内容。

其功能通过格式化字符串 `formatter` 来控制,格式类似于数组/字典的索引切片表达式。例如:

- `[0]` 表示取第 0 个元素
- `[0][{key}]` 表示取第 0 个元素并获取其中 key 字段
- `[0,1][{a,b}]` 表示同时提取第 0 和第 1 个对象的 a 和 b 字段
- `[::2]` 表示步长为 2 的切片
- `*[0][{x}]` 表示以包装格式返回处理后的数据(用于进一步结构化)

Args:
    formatter (str, optional): 控制提取规则的格式字符串。若为 None,则返回原始数据。


Examples:
    >>> from lazyllm.components.formatter.formatterbase import JsonLikeFormatter
    >>> formatter = JsonLikeFormatter("[{a,b}]")
    """
    class _ListIdxes(tuple): pass
    class _DictKeys(tuple): pass

    def __init__(self, formatter: Optional[str] = None):
        if formatter and formatter.startswith('*['):
            self._return_package = True
            self._formatter = formatter.strip('*')
        else:
            self._return_package = False
            self._formatter = formatter

        if self._formatter:
            assert '*' not in self._formatter, '`*` can only be used before `[` in the beginning'
            self._formatter = self._formatter.strip().replace('{', '[{').replace('}', '}]')
            self._parse_formatter()
        else:
            self._slices = None

    def _parse_formatter(self):
        # Remove the surrounding brackets
        assert self._formatter.startswith('[') and self._formatter.endswith(']')
        slice_str = self._formatter.strip()[1:-1]
        dimensions = slice_str.split('][')
        slices = []

        for dim in dimensions:
            if '{' in dim:
                slices.append(__class__._DictKeys(d.strip() for d in dim[1:-1].split(',') if d.strip()))
            elif ':' in dim:
                assert ',' not in dim, '[a, b:c] is not supported'
                parts = dim.split(':')
                start = int(parts[0]) if _is_number(parts[0]) else None
                end = int(parts[1]) if len(parts) > 1 and _is_number(parts[1]) else None
                step = int(parts[2]) if len(parts) > 2 and _is_number(parts[2]) else None
                slices.append(slice(start, end, step))
            elif ',' in dim:
                slices.append(__class__._ListIdxes(d.strip() for d in dim.split(',') if d.strip()))
            else:
                slices.append(dim.strip())
        self._slices = slices

    def _parse_py_data_by_formatter(self, data, *, slices=None):  # noqa C901
        def _impl(data, slice):
            if isinstance(data, (tuple, list)) and isinstance(slice, str):
                return data[int(slice)]
            if isinstance(slice, __class__._ListIdxes):
                if isinstance(data, dict): return [data[k] for k in slice]
                elif isinstance(data, (tuple, list)): return type(data)(data[int(k)] for k in slice)
                else: raise RuntimeError('Only tuple/list/dict is supported for [a,b,c]')
            if isinstance(slice, __class__._DictKeys):
                assert isinstance(data, dict)
                if len(slice) == 1 and slice[0] == ':': return data
                return {k: data[k] for k in slice}
            return data[slice]

        if slices is None: slices = self._slices
        if not slices: return data
        curr_slice = slices[0]
        if isinstance(curr_slice, slice):
            if isinstance(data, dict):
                assert curr_slice.start is None and curr_slice.stop is None and curr_slice.step is None, (
                    'Only {:} and [:] is supported in dict slice')
                curr_slice = __class__._ListIdxes(data.keys())
            elif isinstance(data, (tuple, list)):
                return type(data)(self._parse_py_data_by_formatter(d, slices=slices[1:])
                                  for d in _impl(data, curr_slice))
        if isinstance(curr_slice, __class__._DictKeys):
            return {k: self._parse_py_data_by_formatter(v, slices=slices[1:])
                    for k, v in _impl(data, curr_slice).items()}
        elif isinstance(curr_slice, __class__._ListIdxes):
            tp = package if self._return_package else list if isinstance(data, dict) else type(data)
            return tp(self._parse_py_data_by_formatter(r, slices=slices[1:]) for r in _impl(data, curr_slice))
        else: return self._parse_py_data_by_formatter(_impl(data, curr_slice), slices=slices[1:])

lazyllm.components.formatter.formatterbase.PythonFormatter

Bases: JsonLikeFormatter

预留格式化器类,用于支持 Python 风格的数据提取语法,待开发。

当前继承自 JsonLikeFormatter,无额外功能。

Source code in lazyllm/components/formatter/formatterbase.py
class PythonFormatter(JsonLikeFormatter):
    """预留格式化器类,用于支持 Python 风格的数据提取语法,待开发。

当前继承自 JsonLikeFormatter,无额外功能。
"""
    pass

lazyllm.components.formatter.FileFormatter

Bases: LazyLLMFormatterBase

用于处理带文档上下文的查询字符串格式转换的格式化器。

支持三种模式:

  • "decode":将结构化查询字符串解码为包含 query 和 files 的字典。
  • "encode":将包含 query 和 files 的字典编码为结构化查询字符串。
  • "merge":将多个结构化查询字符串合并为一个整体查询。

Parameters:

  • formatter (str, default: 'decode' ) –

    指定操作模式,可为 "decode"、"encode" 或 "merge"(默认为 "decode")。

Examples:

>>> from lazyllm.components.formatter import FileFormatter
>>> # Decode mode
>>> fmt = FileFormatter('decode')
Source code in lazyllm/components/formatter/formatterbase.py
class FileFormatter(LazyLLMFormatterBase):
    """用于处理带文档上下文的查询字符串格式转换的格式化器。

支持三种模式:

- "decode":将结构化查询字符串解码为包含 query 和 files 的字典。
- "encode":将包含 query 和 files 的字典编码为结构化查询字符串。
- "merge":将多个结构化查询字符串合并为一个整体查询。

Args:
    formatter (str): 指定操作模式,可为 "decode"、"encode" 或 "merge"(默认为 "decode")。


Examples:
    >>> from lazyllm.components.formatter import FileFormatter

    >>> # Decode mode
    >>> fmt = FileFormatter('decode')
    """

    def __init__(self, formatter: str = 'decode'):
        self._mode = formatter.strip().lower()
        assert self._mode in ('decode', 'encode', 'merge')

    def _parse_py_data_by_formatter(self, py_data):
        if self._mode == 'merge':
            if isinstance(py_data, str):
                return py_data
            assert isinstance(py_data, package)
            return lazyllm_merge_query(*py_data)

        if isinstance(py_data, package):
            res = []
            for i_data in py_data:
                res.append(self._parse_py_data_by_formatter(i_data))
            return package(res)
        elif isinstance(py_data, (str, dict)):
            return self._decode_one_data(py_data)
        else:
            return py_data

    def _decode_one_data(self, py_data):
        if self._mode == 'decode':
            if isinstance(py_data, str):
                return decode_query_with_filepaths(py_data)
            else:
                return py_data
        else:
            if isinstance(py_data, dict) and 'query' in py_data and 'files' in py_data:
                return encode_query_with_filepaths(**py_data)
            else:
                return py_data

lazyllm.components.formatter.YamlFormatter

Bases: JsonLikeFormatter

用于从 YAML 格式的字符串中提取结构化信息的格式化器。

继承自 JsonLikeFormatter,通过内部方法将字符串解析为 Python 对象后使用类 JSON 的方式提取字段。

适合用于处理包含嵌套结构的 YAML 文本,并结合格式化表达式获取目标数据。

Examples:

>>> from lazyllm.components.formatter import YamlFormatter
>>> formatter = YamlFormatter("{name,age}")
>>> msg = """ 
... name: Alice
... age: 30
... city: London
... """
>>> formatter(msg)
{'name': 'Alice', 'age': 30}
Source code in lazyllm/components/formatter/yamlformatter.py
class YamlFormatter(JsonLikeFormatter):
    """用于从 YAML 格式的字符串中提取结构化信息的格式化器。

继承自 JsonLikeFormatter,通过内部方法将字符串解析为 Python 对象后使用类 JSON 的方式提取字段。

适合用于处理包含嵌套结构的 YAML 文本,并结合格式化表达式获取目标数据。



Examples:
    >>> from lazyllm.components.formatter import YamlFormatter
    >>> formatter = YamlFormatter("{name,age}")
    >>> msg = \"\"\" 
    ... name: Alice
    ... age: 30
    ... city: London
    ... \"\"\"
    >>> formatter(msg)
    {'name': 'Alice', 'age': 30}
    """
    def _load(self, msg: str):
        try:
            return yaml.load(msg, Loader=yaml.SafeLoader)
        except Exception as e:
            lazyllm.LOG.info(f'Error: {e}')
            return ''

lazyllm.components.formatter.encode_query_with_filepaths(query=None, files=None)

将查询文本和文件路径编码为带有文档上下文的结构化字符串格式。

当指定文件路径时,该函数会将查询内容与文件路径打包成 JSON 格式,并在前缀 __lazyllm_docs__ 的基础上编码返回。否则仅返回原始查询文本。

Parameters:

  • query (str, default: None ) –

    用户查询字符串,默认为空字符串。

  • files (str or List[str], default: None ) –

    与查询相关的文档路径,可为单个字符串或字符串列表。

Returns:

  • str: 编码后的结构化查询字符串,或原始查询。

Raises:

  • AssertionError

    如果 files 不是字符串或字符串列表,或列表中元素类型错误。

Examples:

>>> from lazyllm.components.formatter import encode_query_with_filepaths
>>> # Encode a query along with associated documentation files
>>> encode_query_with_filepaths("Generate questions based on the document", files=["a.md"])
'<lazyllm-query>{"query": "Generate questions based on the document", "files": ["a.md"]}'
Source code in lazyllm/components/formatter/formatterbase.py
def encode_query_with_filepaths(query: str = None, files: Union[str, List[str]] = None) -> str:
    """将查询文本和文件路径编码为带有文档上下文的结构化字符串格式。

当指定文件路径时,该函数会将查询内容与文件路径打包成 JSON 格式,并在前缀 ``__lazyllm_docs__`` 的基础上编码返回。否则仅返回原始查询文本。

Args:
    query (str): 用户查询字符串,默认为空字符串。
    files (str or List[str]): 与查询相关的文档路径,可为单个字符串或字符串列表。

**Returns:**

- str: 编码后的结构化查询字符串,或原始查询。

Raises:
    AssertionError: 如果 `files` 不是字符串或字符串列表,或列表中元素类型错误。


Examples:
    >>> from lazyllm.components.formatter import encode_query_with_filepaths

    >>> # Encode a query along with associated documentation files
    >>> encode_query_with_filepaths("Generate questions based on the document", files=["a.md"])
    '<lazyllm-query>{"query": "Generate questions based on the document", "files": ["a.md"]}'
    """
    query = query if query else ''
    if files:
        if isinstance(files, str): files = [files]
        assert isinstance(files, list), 'files must be a list.'
        assert all(isinstance(item, str) for item in files), 'All items in files must be strings'
        return LAZYLLM_QUERY_PREFIX + json.dumps({'query': query, 'files': files})
    else:
        return query

lazyllm.components.formatter.decode_query_with_filepaths(query_files)

将结构化查询字符串解析为包含原始查询和文件路径的字典格式。

当输入字符串以特殊前缀 __lazyllm_docs__ 开头时,函数会尝试从中提取 JSON 格式的查询信息;否则将原样返回字符串内容。

Parameters:

  • query_files (str) –

    编码后的查询字符串,可能包含文档路径和查询内容。

Returns:

  • Union[dict, str]: 若为结构化格式则返回包含 'query' 和 'files' 的字典,否则返回原始查询字符串。

Raises:

  • AssertionError

    如果输入参数不是字符串类型。

  • ValueError

    如果字符串为结构化格式但解析 JSON 失败。

Examples:

>>> from lazyllm.components.formatter import decode_query_with_filepaths
>>> # Decode a structured query with files
>>> decode_query_with_filepaths('<lazyllm-query>{"query": "Summarize the content", "files": ["doc.md"]}')
{'query': 'Summarize the content', 'files': ['doc.md']}
>>> # Decode a plain string without files
>>> decode_query_with_filepaths("This is just a simple question")
'This is just a simple question'
Source code in lazyllm/components/formatter/formatterbase.py
def decode_query_with_filepaths(query_files: str) -> Union[dict, str]:
    """将结构化查询字符串解析为包含原始查询和文件路径的字典格式。

当输入字符串以特殊前缀 ``__lazyllm_docs__`` 开头时,函数会尝试从中提取 JSON 格式的查询信息;否则将原样返回字符串内容。

Args:
    query_files (str): 编码后的查询字符串,可能包含文档路径和查询内容。

**Returns:**

- Union[dict, str]: 若为结构化格式则返回包含 'query' 和 'files' 的字典,否则返回原始查询字符串。

Raises:
    AssertionError: 如果输入参数不是字符串类型。
    ValueError: 如果字符串为结构化格式但解析 JSON 失败。


Examples:
    >>> from lazyllm.components.formatter import decode_query_with_filepaths

    >>> # Decode a structured query with files
    >>> decode_query_with_filepaths('<lazyllm-query>{"query": "Summarize the content", "files": ["doc.md"]}')
    {'query': 'Summarize the content', 'files': ['doc.md']}

    >>> # Decode a plain string without files
    >>> decode_query_with_filepaths("This is just a simple question")
    'This is just a simple question'
    """
    assert isinstance(query_files, str), 'query_files must be a str.'
    query_files = query_files.strip()
    if query_files.startswith(LAZYLLM_QUERY_PREFIX):
        try:
            obj = json.loads(query_files[len(LAZYLLM_QUERY_PREFIX):])
            return obj
        except json.JSONDecodeError as e:
            raise ValueError(f'JSON parsing failed: {e}')
    else:
        return query_files

lazyllm.components.formatter.lazyllm_merge_query(*args)

将多个查询字符串(可能包含文档路径)合并为一个统一的结构化查询字符串。

每个输入参数可以是普通查询字符串或由 encode_query_with_filepaths 编码后的结构化字符串。函数会自动解码、拼接查询文本,并合并所有涉及的文档路径,最终重新编码为统一的查询格式。

Parameters:

  • *args (str, default: () ) –

    多个查询字符串。每个字符串可以是普通文本或已编码的带文件路径的结构化查询。

Returns:

  • str: 合并后的结构化查询字符串,包含统一的查询内容与文件路径。

Examples:

>>> from lazyllm.components.formatter import encode_query_with_filepaths, lazyllm_merge_query
>>> # Merge two structured queries with English content and associated files
>>> q1 = encode_query_with_filepaths("Please summarize document one", files=["doc1.md"])
>>> q2 = encode_query_with_filepaths("Add details from document two", files=["doc2.md"])
>>> lazyllm_merge_query(q1, q2)
'<lazyllm-query>{"query": "Please summarize document oneAdd details from document two", "files": ["doc1.md", "doc2.md"]}'
>>> # Merge plain English text queries without documents
>>> lazyllm_merge_query("What is AI?", "Explain deep learning.")
'What is AI?Explain deep learning.'
Source code in lazyllm/components/formatter/formatterbase.py
def lazyllm_merge_query(*args: str) -> str:
    """将多个查询字符串(可能包含文档路径)合并为一个统一的结构化查询字符串。

每个输入参数可以是普通查询字符串或由 ``encode_query_with_filepaths`` 编码后的结构化字符串。函数会自动解码、拼接查询文本,并合并所有涉及的文档路径,最终重新编码为统一的查询格式。

Args:
    *args (str): 多个查询字符串。每个字符串可以是普通文本或已编码的带文件路径的结构化查询。

**Returns:**

- str: 合并后的结构化查询字符串,包含统一的查询内容与文件路径。


Examples:
    >>> from lazyllm.components.formatter import encode_query_with_filepaths, lazyllm_merge_query

    >>> # Merge two structured queries with English content and associated files
    >>> q1 = encode_query_with_filepaths("Please summarize document one", files=["doc1.md"])
    >>> q2 = encode_query_with_filepaths("Add details from document two", files=["doc2.md"])
    >>> lazyllm_merge_query(q1, q2)
    '<lazyllm-query>{"query": "Please summarize document oneAdd details from document two", "files": ["doc1.md", "doc2.md"]}'

    >>> # Merge plain English text queries without documents
    >>> lazyllm_merge_query("What is AI?", "Explain deep learning.")
    'What is AI?Explain deep learning.'
    """
    if len(args) == 1:
        return args[0]
    for item in args:
        assert isinstance(item, str), 'Merge object must be str!'
    querys = ''
    files = []
    for item in args:
        decode = decode_query_with_filepaths(item)
        if isinstance(decode, dict):
            querys += decode['query']
            files.extend(decode['files'])
        else:
            querys += decode
    return encode_query_with_filepaths(querys, files)

lazyllm.components.JsonFormatter

Bases: JsonLikeFormatter

此类是JSON格式化器,即用户希望模型输出的内容格式为JSON,还可以通过索引方式对输出内容中的某个字段进行选择。

Examples:

>>> import lazyllm
>>> from lazyllm.components import JsonFormatter
>>> toc_prompt='''
... You are now an intelligent assistant. Your task is to understand the user's input and convert the outline into a list of nested dictionaries. Each dictionary contains a `title` and a `describe`, where the `title` should clearly indicate the level using Markdown format, and the `describe` is a description and writing guide for that section.
... 
... Please generate the corresponding list of nested dictionaries based on the following user input:
... 
... Example output:
... [
...     {
...         "title": "# Level 1 Title",
...         "describe": "Please provide a detailed description of the content under this title, offering background information and core viewpoints."
...     },
...     {
...         "title": "## Level 2 Title",
...         "describe": "Please provide a detailed description of the content under this title, giving specific details and examples to support the viewpoints of the Level 1 title."
...     },
...     {
...         "title": "### Level 3 Title",
...         "describe": "Please provide a detailed description of the content under this title, deeply analyzing and providing more details and data support."
...     }
... ]
... User input is as follows:
... '''
>>> query = "Please help me write an article about the application of artificial intelligence in the medical field."
>>> m = lazyllm.TrainableModule("internlm2-chat-20b").prompt(toc_prompt).start()
>>> ret = m(query, max_new_tokens=2048)
>>> print(f"ret: {ret!r}")  # the model output without specifying a formatter
'Based on your user input, here is the corresponding list of nested dictionaries:
[
    {
        "title": "# Application of Artificial Intelligence in the Medical Field",
        "describe": "Please provide a detailed description of the application of artificial intelligence in the medical field, including its benefits, challenges, and future prospects."
    },
    {
        "title": "## AI in Medical Diagnosis",
        "describe": "Please provide a detailed description of how artificial intelligence is used in medical diagnosis, including specific examples of AI-based diagnostic tools and their impact on patient outcomes."
    },
    {
        "title": "### AI in Medical Imaging",
        "describe": "Please provide a detailed description of how artificial intelligence is used in medical imaging, including the advantages of AI-based image analysis and its applications in various medical specialties."
    },
    {
        "title": "### AI in Drug Discovery and Development",
        "describe": "Please provide a detailed description of how artificial intelligence is used in drug discovery and development, including the role of AI in identifying potential drug candidates and streamlining the drug development process."
    },
    {
        "title": "## AI in Medical Research",
        "describe": "Please provide a detailed description of how artificial intelligence is used in medical research, including its applications in genomics, epidemiology, and clinical trials."
    },
    {
        "title": "### AI in Genomics and Precision Medicine",
        "describe": "Please provide a detailed description of how artificial intelligence is used in genomics and precision medicine, including the role of AI in analyzing large-scale genomic data and tailoring treatments to individual patients."
    },
    {
        "title": "### AI in Epidemiology and Public Health",
        "describe": "Please provide a detailed description of how artificial intelligence is used in epidemiology and public health, including its applications in disease surveillance, outbreak prediction, and resource allocation."
    },
    {
        "title": "### AI in Clinical Trials",
        "describe": "Please provide a detailed description of how artificial intelligence is used in clinical trials, including its role in patient recruitment, trial design, and data analysis."
    },
    {
        "title": "## AI in Medical Practice",
        "describe": "Please provide a detailed description of how artificial intelligence is used in medical practice, including its applications in patient monitoring, personalized medicine, and telemedicine."
    },
    {
        "title": "### AI in Patient Monitoring",
        "describe": "Please provide a detailed description of how artificial intelligence is used in patient monitoring, including its role in real-time monitoring of vital signs and early detection of health issues."
    },
    {
        "title": "### AI in Personalized Medicine",
        "describe": "Please provide a detailed description of how artificial intelligence is used in personalized medicine, including its role in analyzing patient data to tailor treatments and predict outcomes."
    },
    {
        "title": "### AI in Telemedicine",
        "describe": "Please provide a detailed description of how artificial intelligence is used in telemedicine, including its applications in remote consultations, virtual diagnoses, and digital health records."
    },
    {
        "title": "## AI in Medical Ethics and Policy",
        "describe": "Please provide a detailed description of the ethical and policy considerations surrounding the use of artificial intelligence in the medical field, including issues related to data privacy, bias, and accountability."
    }
]'
>>> m = lazyllm.TrainableModule("internlm2-chat-20b").formatter(JsonFormatter("[:][title]")).prompt(toc_prompt).start()
>>> ret = m(query, max_new_tokens=2048)
>>> print(f"ret: {ret}")  # the model output of the specified formaater
['# Application of Artificial Intelligence in the Medical Field', '## AI in Medical Diagnosis', '### AI in Medical Imaging', '### AI in Drug Discovery and Development', '## AI in Medical Research', '### AI in Genomics and Precision Medicine', '### AI in Epidemiology and Public Health', '### AI in Clinical Trials', '## AI in Medical Practice', '### AI in Patient Monitoring', '### AI in Personalized Medicine', '### AI in Telemedicine', '## AI in Medical Ethics and Policy']
Source code in lazyllm/components/formatter/jsonformatter.py
class JsonFormatter(JsonLikeFormatter):
    """此类是JSON格式化器,即用户希望模型输出的内容格式为JSON,还可以通过索引方式对输出内容中的某个字段进行选择。


Examples:
    >>> import lazyllm
    >>> from lazyllm.components import JsonFormatter
    >>> toc_prompt='''
    ... You are now an intelligent assistant. Your task is to understand the user's input and convert the outline into a list of nested dictionaries. Each dictionary contains a `title` and a `describe`, where the `title` should clearly indicate the level using Markdown format, and the `describe` is a description and writing guide for that section.
    ... 
    ... Please generate the corresponding list of nested dictionaries based on the following user input:
    ... 
    ... Example output:
    ... [
    ...     {
    ...         "title": "# Level 1 Title",
    ...         "describe": "Please provide a detailed description of the content under this title, offering background information and core viewpoints."
    ...     },
    ...     {
    ...         "title": "## Level 2 Title",
    ...         "describe": "Please provide a detailed description of the content under this title, giving specific details and examples to support the viewpoints of the Level 1 title."
    ...     },
    ...     {
    ...         "title": "### Level 3 Title",
    ...         "describe": "Please provide a detailed description of the content under this title, deeply analyzing and providing more details and data support."
    ...     }
    ... ]
    ... User input is as follows:
    ... '''
    >>> query = "Please help me write an article about the application of artificial intelligence in the medical field."
    >>> m = lazyllm.TrainableModule("internlm2-chat-20b").prompt(toc_prompt).start()
    >>> ret = m(query, max_new_tokens=2048)
    >>> print(f"ret: {ret!r}")  # the model output without specifying a formatter
    'Based on your user input, here is the corresponding list of nested dictionaries:
    [
        {
            "title": "# Application of Artificial Intelligence in the Medical Field",
            "describe": "Please provide a detailed description of the application of artificial intelligence in the medical field, including its benefits, challenges, and future prospects."
        },
        {
            "title": "## AI in Medical Diagnosis",
            "describe": "Please provide a detailed description of how artificial intelligence is used in medical diagnosis, including specific examples of AI-based diagnostic tools and their impact on patient outcomes."
        },
        {
            "title": "### AI in Medical Imaging",
            "describe": "Please provide a detailed description of how artificial intelligence is used in medical imaging, including the advantages of AI-based image analysis and its applications in various medical specialties."
        },
        {
            "title": "### AI in Drug Discovery and Development",
            "describe": "Please provide a detailed description of how artificial intelligence is used in drug discovery and development, including the role of AI in identifying potential drug candidates and streamlining the drug development process."
        },
        {
            "title": "## AI in Medical Research",
            "describe": "Please provide a detailed description of how artificial intelligence is used in medical research, including its applications in genomics, epidemiology, and clinical trials."
        },
        {
            "title": "### AI in Genomics and Precision Medicine",
            "describe": "Please provide a detailed description of how artificial intelligence is used in genomics and precision medicine, including the role of AI in analyzing large-scale genomic data and tailoring treatments to individual patients."
        },
        {
            "title": "### AI in Epidemiology and Public Health",
            "describe": "Please provide a detailed description of how artificial intelligence is used in epidemiology and public health, including its applications in disease surveillance, outbreak prediction, and resource allocation."
        },
        {
            "title": "### AI in Clinical Trials",
            "describe": "Please provide a detailed description of how artificial intelligence is used in clinical trials, including its role in patient recruitment, trial design, and data analysis."
        },
        {
            "title": "## AI in Medical Practice",
            "describe": "Please provide a detailed description of how artificial intelligence is used in medical practice, including its applications in patient monitoring, personalized medicine, and telemedicine."
        },
        {
            "title": "### AI in Patient Monitoring",
            "describe": "Please provide a detailed description of how artificial intelligence is used in patient monitoring, including its role in real-time monitoring of vital signs and early detection of health issues."
        },
        {
            "title": "### AI in Personalized Medicine",
            "describe": "Please provide a detailed description of how artificial intelligence is used in personalized medicine, including its role in analyzing patient data to tailor treatments and predict outcomes."
        },
        {
            "title": "### AI in Telemedicine",
            "describe": "Please provide a detailed description of how artificial intelligence is used in telemedicine, including its applications in remote consultations, virtual diagnoses, and digital health records."
        },
        {
            "title": "## AI in Medical Ethics and Policy",
            "describe": "Please provide a detailed description of the ethical and policy considerations surrounding the use of artificial intelligence in the medical field, including issues related to data privacy, bias, and accountability."
        }
    ]'
    >>> m = lazyllm.TrainableModule("internlm2-chat-20b").formatter(JsonFormatter("[:][title]")).prompt(toc_prompt).start()
    >>> ret = m(query, max_new_tokens=2048)
    >>> print(f"ret: {ret}")  # the model output of the specified formaater
    ['# Application of Artificial Intelligence in the Medical Field', '## AI in Medical Diagnosis', '### AI in Medical Imaging', '### AI in Drug Discovery and Development', '## AI in Medical Research', '### AI in Genomics and Precision Medicine', '### AI in Epidemiology and Public Health', '### AI in Clinical Trials', '## AI in Medical Practice', '### AI in Patient Monitoring', '### AI in Personalized Medicine', '### AI in Telemedicine', '## AI in Medical Ethics and Policy']
    """
    def _extract_json_from_string(self, mixed_str: str):
        json_objects = []
        brace_level = 0
        current_json = ''
        in_string = False

        for char in mixed_str:
            if char == '"' and (len(current_json) == 0 or current_json[-1] != '\\'):
                in_string = not in_string

            if not in_string:
                if char in '{[':
                    if brace_level == 0:
                        current_json = ''
                    brace_level += 1
                elif char in '}]':
                    brace_level -= 1

            if brace_level > 0 or (brace_level == 0 and char in '}]'):
                current_json += char

            if brace_level == 0 and current_json:
                try:
                    json.loads(current_json)
                    json_objects.append(current_json)
                    current_json = ''
                except json.JSONDecodeError:
                    continue

        return json_objects

    def _load(self, msg: str):
        # Convert str to json format
        assert msg.count('{') == msg.count('}'), f'{msg} is not a valid json string.'
        try:
            json_strs = self._extract_json_from_string(msg)
            if len(json_strs) == 0:
                raise TypeError(f'{msg} is not a valid json string.')
            res = []
            for json_str in json_strs:
                res.append(json.loads(json_str))
            return res if len(res) > 1 else res[0]
        except Exception as e:
            lazyllm.LOG.info(f'Error: {e}')
            return ''

lazyllm.components.EmptyFormatter

Bases: LazyLLMFormatterBase

此类是空的格式化器,即用户希望对模型的输出不做格式化,用户可以对模型指定该格式化器,也可以不指定(模型默认的格式化器就是空格式化器)

Examples:

>>> import lazyllm
>>> from lazyllm.components import EmptyFormatter
>>> toc_prompt='''
... You are now an intelligent assistant. Your task is to understand the user's input and convert the outline into a list of nested dictionaries. Each dictionary contains a `title` and a `describe`, where the `title` should clearly indicate the level using Markdown format, and the `describe` is a description and writing guide for that section.
... 
... Please generate the corresponding list of nested dictionaries based on the following user input:
... 
... Example output:
... [
...     {
...         "title": "# Level 1 Title",
...         "describe": "Please provide a detailed description of the content under this title, offering background information and core viewpoints."
...     },
...     {
...         "title": "## Level 2 Title",
...         "describe": "Please provide a detailed description of the content under this title, giving specific details and examples to support the viewpoints of the Level 1 title."
...     },
...     {
...         "title": "### Level 3 Title",
...         "describe": "Please provide a detailed description of the content under this title, deeply analyzing and providing more details and data support."
...     }
... ]
... User input is as follows:
... '''
>>> query = "Please help me write an article about the application of artificial intelligence in the medical field."
>>> m = lazyllm.TrainableModule("internlm2-chat-20b").prompt(toc_prompt).start()  # the model output without specifying a formatter
>>> ret = m(query, max_new_tokens=2048)
>>> print(f"ret: {ret!r}")
'Based on your user input, here is the corresponding list of nested dictionaries:
[
    {
        "title": "# Application of Artificial Intelligence in the Medical Field",
        "describe": "Please provide a detailed description of the application of artificial intelligence in the medical field, including its benefits, challenges, and future prospects."
    },
    {
        "title": "## AI in Medical Diagnosis",
        "describe": "Please provide a detailed description of how artificial intelligence is used in medical diagnosis, including specific examples of AI-based diagnostic tools and their impact on patient outcomes."
    },
    {
        "title": "### AI in Medical Imaging",
        "describe": "Please provide a detailed description of how artificial intelligence is used in medical imaging, including the advantages of AI-based image analysis and its applications in various medical specialties."
    },
    {
        "title": "### AI in Drug Discovery and Development",
        "describe": "Please provide a detailed description of how artificial intelligence is used in drug discovery and development, including the role of AI in identifying potential drug candidates and streamlining the drug development process."
    },
    {
        "title": "## AI in Medical Research",
        "describe": "Please provide a detailed description of how artificial intelligence is used in medical research, including its applications in genomics, epidemiology, and clinical trials."
    },
    {
        "title": "### AI in Genomics and Precision Medicine",
        "describe": "Please provide a detailed description of how artificial intelligence is used in genomics and precision medicine, including the role of AI in analyzing large-scale genomic data and tailoring treatments to individual patients."
    },
    {
        "title": "### AI in Epidemiology and Public Health",
        "describe": "Please provide a detailed description of how artificial intelligence is used in epidemiology and public health, including its applications in disease surveillance, outbreak prediction, and resource allocation."
    },
    {
        "title": "### AI in Clinical Trials",
        "describe": "Please provide a detailed description of how artificial intelligence is used in clinical trials, including its role in patient recruitment, trial design, and data analysis."
    },
    {
        "title": "## AI in Medical Practice",
        "describe": "Please provide a detailed description of how artificial intelligence is used in medical practice, including its applications in patient monitoring, personalized medicine, and telemedicine."
    },
    {
        "title": "### AI in Patient Monitoring",
        "describe": "Please provide a detailed description of how artificial intelligence is used in patient monitoring, including its role in real-time monitoring of vital signs and early detection of health issues."
    },
    {
        "title": "### AI in Personalized Medicine",
        "describe": "Please provide a detailed description of how artificial intelligence is used in personalized medicine, including its role in analyzing patient data to tailor treatments and predict outcomes."
    },
    {
        "title": "### AI in Telemedicine",
        "describe": "Please provide a detailed description of how artificial intelligence is used in telemedicine, including its applications in remote consultations, virtual diagnoses, and digital health records."
    },
    {
        "title": "## AI in Medical Ethics and Policy",
        "describe": "Please provide a detailed description of the ethical and policy considerations surrounding the use of artificial intelligence in the medical field, including issues related to data privacy, bias, and accountability."
    }
]'
>>> m = lazyllm.TrainableModule("internlm2-chat-20b").formatter(EmptyFormatter()).prompt(toc_prompt).start()  # the model output of the specified formatter
>>> ret = m(query, max_new_tokens=2048)
>>> print(f"ret: {ret!r}")
'Based on your user input, here is the corresponding list of nested dictionaries:
[
    {
        "title": "# Application of Artificial Intelligence in the Medical Field",
        "describe": "Please provide a detailed description of the application of artificial intelligence in the medical field, including its benefits, challenges, and future prospects."
    },
    {
        "title": "## AI in Medical Diagnosis",
        "describe": "Please provide a detailed description of how artificial intelligence is used in medical diagnosis, including specific examples of AI-based diagnostic tools and their impact on patient outcomes."
    },
    {
        "title": "### AI in Medical Imaging",
        "describe": "Please provide a detailed description of how artificial intelligence is used in medical imaging, including the advantages of AI-based image analysis and its applications in various medical specialties."
    },
    {
        "title": "### AI in Drug Discovery and Development",
        "describe": "Please provide a detailed description of how artificial intelligence is used in drug discovery and development, including the role of AI in identifying potential drug candidates and streamlining the drug development process."
    },
    {
        "title": "## AI in Medical Research",
        "describe": "Please provide a detailed description of how artificial intelligence is used in medical research, including its applications in genomics, epidemiology, and clinical trials."
    },
    {
        "title": "### AI in Genomics and Precision Medicine",
        "describe": "Please provide a detailed description of how artificial intelligence is used in genomics and precision medicine, including the role of AI in analyzing large-scale genomic data and tailoring treatments to individual patients."
    },
    {
        "title": "### AI in Epidemiology and Public Health",
        "describe": "Please provide a detailed description of how artificial intelligence is used in epidemiology and public health, including its applications in disease surveillance, outbreak prediction, and resource allocation."
    },
    {
        "title": "### AI in Clinical Trials",
        "describe": "Please provide a detailed description of how artificial intelligence is used in clinical trials, including its role in patient recruitment, trial design, and data analysis."
    },
    {
        "title": "## AI in Medical Practice",
        "describe": "Please provide a detailed description of how artificial intelligence is used in medical practice, including its applications in patient monitoring, personalized medicine, and telemedicine."
    },
    {
        "title": "### AI in Patient Monitoring",
        "describe": "Please provide a detailed description of how artificial intelligence is used in patient monitoring, including its role in real-time monitoring of vital signs and early detection of health issues."
    },
    {
        "title": "### AI in Personalized Medicine",
        "describe": "Please provide a detailed description of how artificial intelligence is used in personalized medicine, including its role in analyzing patient data to tailor treatments and predict outcomes."
    },
    {
        "title": "### AI in Telemedicine",
        "describe": "Please provide a detailed description of how artificial intelligence is used in telemedicine, including its applications in remote consultations, virtual diagnoses, and digital health records."
    },
    {
        "title": "## AI in Medical Ethics and Policy",
        "describe": "Please provide a detailed description of the ethical and policy considerations surrounding the use of artificial intelligence in the medical field, including issues related to data privacy, bias, and accountability."
    }
]'
Source code in lazyllm/components/formatter/formatterbase.py
class EmptyFormatter(LazyLLMFormatterBase):
    """此类是空的格式化器,即用户希望对模型的输出不做格式化,用户可以对模型指定该格式化器,也可以不指定(模型默认的格式化器就是空格式化器)


Examples:
    >>> import lazyllm
    >>> from lazyllm.components import EmptyFormatter
    >>> toc_prompt='''
    ... You are now an intelligent assistant. Your task is to understand the user's input and convert the outline into a list of nested dictionaries. Each dictionary contains a `title` and a `describe`, where the `title` should clearly indicate the level using Markdown format, and the `describe` is a description and writing guide for that section.
    ... 
    ... Please generate the corresponding list of nested dictionaries based on the following user input:
    ... 
    ... Example output:
    ... [
    ...     {
    ...         "title": "# Level 1 Title",
    ...         "describe": "Please provide a detailed description of the content under this title, offering background information and core viewpoints."
    ...     },
    ...     {
    ...         "title": "## Level 2 Title",
    ...         "describe": "Please provide a detailed description of the content under this title, giving specific details and examples to support the viewpoints of the Level 1 title."
    ...     },
    ...     {
    ...         "title": "### Level 3 Title",
    ...         "describe": "Please provide a detailed description of the content under this title, deeply analyzing and providing more details and data support."
    ...     }
    ... ]
    ... User input is as follows:
    ... '''
    >>> query = "Please help me write an article about the application of artificial intelligence in the medical field."
    >>> m = lazyllm.TrainableModule("internlm2-chat-20b").prompt(toc_prompt).start()  # the model output without specifying a formatter
    >>> ret = m(query, max_new_tokens=2048)
    >>> print(f"ret: {ret!r}")
    'Based on your user input, here is the corresponding list of nested dictionaries:
    [
        {
            "title": "# Application of Artificial Intelligence in the Medical Field",
            "describe": "Please provide a detailed description of the application of artificial intelligence in the medical field, including its benefits, challenges, and future prospects."
        },
        {
            "title": "## AI in Medical Diagnosis",
            "describe": "Please provide a detailed description of how artificial intelligence is used in medical diagnosis, including specific examples of AI-based diagnostic tools and their impact on patient outcomes."
        },
        {
            "title": "### AI in Medical Imaging",
            "describe": "Please provide a detailed description of how artificial intelligence is used in medical imaging, including the advantages of AI-based image analysis and its applications in various medical specialties."
        },
        {
            "title": "### AI in Drug Discovery and Development",
            "describe": "Please provide a detailed description of how artificial intelligence is used in drug discovery and development, including the role of AI in identifying potential drug candidates and streamlining the drug development process."
        },
        {
            "title": "## AI in Medical Research",
            "describe": "Please provide a detailed description of how artificial intelligence is used in medical research, including its applications in genomics, epidemiology, and clinical trials."
        },
        {
            "title": "### AI in Genomics and Precision Medicine",
            "describe": "Please provide a detailed description of how artificial intelligence is used in genomics and precision medicine, including the role of AI in analyzing large-scale genomic data and tailoring treatments to individual patients."
        },
        {
            "title": "### AI in Epidemiology and Public Health",
            "describe": "Please provide a detailed description of how artificial intelligence is used in epidemiology and public health, including its applications in disease surveillance, outbreak prediction, and resource allocation."
        },
        {
            "title": "### AI in Clinical Trials",
            "describe": "Please provide a detailed description of how artificial intelligence is used in clinical trials, including its role in patient recruitment, trial design, and data analysis."
        },
        {
            "title": "## AI in Medical Practice",
            "describe": "Please provide a detailed description of how artificial intelligence is used in medical practice, including its applications in patient monitoring, personalized medicine, and telemedicine."
        },
        {
            "title": "### AI in Patient Monitoring",
            "describe": "Please provide a detailed description of how artificial intelligence is used in patient monitoring, including its role in real-time monitoring of vital signs and early detection of health issues."
        },
        {
            "title": "### AI in Personalized Medicine",
            "describe": "Please provide a detailed description of how artificial intelligence is used in personalized medicine, including its role in analyzing patient data to tailor treatments and predict outcomes."
        },
        {
            "title": "### AI in Telemedicine",
            "describe": "Please provide a detailed description of how artificial intelligence is used in telemedicine, including its applications in remote consultations, virtual diagnoses, and digital health records."
        },
        {
            "title": "## AI in Medical Ethics and Policy",
            "describe": "Please provide a detailed description of the ethical and policy considerations surrounding the use of artificial intelligence in the medical field, including issues related to data privacy, bias, and accountability."
        }
    ]'
    >>> m = lazyllm.TrainableModule("internlm2-chat-20b").formatter(EmptyFormatter()).prompt(toc_prompt).start()  # the model output of the specified formatter
    >>> ret = m(query, max_new_tokens=2048)
    >>> print(f"ret: {ret!r}")
    'Based on your user input, here is the corresponding list of nested dictionaries:
    [
        {
            "title": "# Application of Artificial Intelligence in the Medical Field",
            "describe": "Please provide a detailed description of the application of artificial intelligence in the medical field, including its benefits, challenges, and future prospects."
        },
        {
            "title": "## AI in Medical Diagnosis",
            "describe": "Please provide a detailed description of how artificial intelligence is used in medical diagnosis, including specific examples of AI-based diagnostic tools and their impact on patient outcomes."
        },
        {
            "title": "### AI in Medical Imaging",
            "describe": "Please provide a detailed description of how artificial intelligence is used in medical imaging, including the advantages of AI-based image analysis and its applications in various medical specialties."
        },
        {
            "title": "### AI in Drug Discovery and Development",
            "describe": "Please provide a detailed description of how artificial intelligence is used in drug discovery and development, including the role of AI in identifying potential drug candidates and streamlining the drug development process."
        },
        {
            "title": "## AI in Medical Research",
            "describe": "Please provide a detailed description of how artificial intelligence is used in medical research, including its applications in genomics, epidemiology, and clinical trials."
        },
        {
            "title": "### AI in Genomics and Precision Medicine",
            "describe": "Please provide a detailed description of how artificial intelligence is used in genomics and precision medicine, including the role of AI in analyzing large-scale genomic data and tailoring treatments to individual patients."
        },
        {
            "title": "### AI in Epidemiology and Public Health",
            "describe": "Please provide a detailed description of how artificial intelligence is used in epidemiology and public health, including its applications in disease surveillance, outbreak prediction, and resource allocation."
        },
        {
            "title": "### AI in Clinical Trials",
            "describe": "Please provide a detailed description of how artificial intelligence is used in clinical trials, including its role in patient recruitment, trial design, and data analysis."
        },
        {
            "title": "## AI in Medical Practice",
            "describe": "Please provide a detailed description of how artificial intelligence is used in medical practice, including its applications in patient monitoring, personalized medicine, and telemedicine."
        },
        {
            "title": "### AI in Patient Monitoring",
            "describe": "Please provide a detailed description of how artificial intelligence is used in patient monitoring, including its role in real-time monitoring of vital signs and early detection of health issues."
        },
        {
            "title": "### AI in Personalized Medicine",
            "describe": "Please provide a detailed description of how artificial intelligence is used in personalized medicine, including its role in analyzing patient data to tailor treatments and predict outcomes."
        },
        {
            "title": "### AI in Telemedicine",
            "describe": "Please provide a detailed description of how artificial intelligence is used in telemedicine, including its applications in remote consultations, virtual diagnoses, and digital health records."
        },
        {
            "title": "## AI in Medical Ethics and Policy",
            "describe": "Please provide a detailed description of the ethical and policy considerations surrounding the use of artificial intelligence in the medical field, including issues related to data privacy, bias, and accountability."
        }
    ]'
    """
    def _parse_py_data_by_formatter(self, msg: str):
        return msg

lazyllm.components.formatter.formatterbase.PipelineFormatter

Bases: LazyLLMFormatterBase

流水线格式化器,用于将数据处理流水线封装为格式化器。

该类将Pipeline实例包装为格式化器,支持通过管道操作符组合多个格式化器。

Parameters:

  • formatter (Pipeline) –

    要封装的流水线实例

Source code in lazyllm/components/formatter/formatterbase.py
class PipelineFormatter(LazyLLMFormatterBase):
    """流水线格式化器,用于将数据处理流水线封装为格式化器。

该类将Pipeline实例包装为格式化器,支持通过管道操作符组合多个格式化器。

Args:
    formatter (Pipeline): 要封装的流水线实例
"""
    def __init__(self, formatter: Pipeline):
        self._formatter = formatter

    def _parse_py_data_by_formatter(self, py_data):
        return self._formatter(py_data)

    def __or__(self, other):
        if isinstance(other, LazyLLMFormatterBase):
            if isinstance(other, PipelineFormatter): other = other._formatter
            return PipelineFormatter(self._formatter | other)
        return NotImplemented

ComponentBase

lazyllm.components.core.ComponentBase

Bases: object

组件基类,提供统一的接口与基础实现,便于创建不同类型的组件。
组件通过指定的 Launcher 来执行任务,支持自定义任务执行逻辑。

Parameters:

  • launcher (LazyLLMLaunchersBase or type, default: empty() ) –

    组件使用的启动器实例或启动器类,默认为空启动器(empty)。

Examples:

>>> from lazyllm.components.core import ComponentBase
>>> class MyComponent(ComponentBase):
...     def apply(self, x):
...         return x * 2
>>> comp = MyComponent()
>>> comp.name = "ExampleComponent"
>>> print(comp.name)
ExampleComponent
>>> result = comp(10)
>>> print(result)
20
>>> print(comp.apply(5))
10
Source code in lazyllm/components/core.py
class ComponentBase(object, metaclass=LazyLLMRegisterMetaClass):
    """组件基类,提供统一的接口与基础实现,便于创建不同类型的组件。  
组件通过指定的 Launcher 来执行任务,支持自定义任务执行逻辑。

Args:
    launcher (LazyLLMLaunchersBase or type, optional): 组件使用的启动器实例或启动器类,默认为空启动器(empty)。


Examples:
    >>> from lazyllm.components.core import ComponentBase
    >>> class MyComponent(ComponentBase):
    ...     def apply(self, x):
    ...         return x * 2
    >>> comp = MyComponent()
    >>> comp.name = "ExampleComponent"
    >>> print(comp.name)
    ExampleComponent
    >>> result = comp(10)
    >>> print(result)
    20
    >>> print(comp.apply(5))
    10
    """
    def __init__(self, *, launcher=launchers.empty()):  # noqa B008
        self._llm_name = None
        self.job = ReadOnlyWrapper()
        if isinstance(launcher, LazyLLMLaunchersBase):
            self._launcher = launcher
        elif isinstance(launcher, type) and issubclass(launcher, LazyLLMLaunchersBase):
            self._launcher = launcher()
        else:
            raise RuntimeError('Invalid launcher given:', launcher)

    def apply():
        """组件执行的核心方法,需由子类实现。  
定义组件的具体业务逻辑或任务执行步骤。  

**注意:**  
调用组件时,如果子类重写了此方法,则会调用此方法执行任务。  
"""
        raise NotImplementedError('please implement function \'apply\'')

    def cmd(self, *args, **kw) -> Union[str, tuple, list]:
        """生成组件的执行命令,需由子类实现。  
返回的命令可以是字符串、元组或列表,表示具体执行任务的指令。  

**注意:**  
调用组件时,如果未重写 `apply` 方法,将通过此命令生成任务并由启动器执行。  
"""
        raise NotImplementedError('please implement function \'cmd\'')

    @property
    def name(self): return self._llm_name
    @name.setter
    def name(self, name): self._llm_name = name

    @property
    def launcher(self): return self._launcher

    def _get_job_with_cmd(self, *args, **kw):
        cmd = self.cmd(*args, **kw)
        cmd = cmd if isinstance(cmd, LazyLLMCMD) else LazyLLMCMD(cmd)
        return self._launcher.makejob(cmd=cmd)

    def _overwrote(self, f):
        return getattr(self.__class__, f) is not getattr(__class__, f) or \
            getattr(self.__class__, '__reg_overwrite__', None) == f

    def __call__(self, *args, **kw):
        if self._overwrote('apply'):
            assert not self._overwrote('cmd'), (
                'Cannot overwrite \'cmd\' and \'apply\' in the same class')
            assert isinstance(self._launcher, launchers.Empty), 'Please use EmptyLauncher instead.'
            return self._launcher.launch(self.apply, *args, **kw)
        else:
            job = self._get_job_with_cmd(*args, **kw)
            self.job.set(job)
            return self._launcher.launch(job)

    def __repr__(self):
        return lazyllm.make_repr('lazyllm.llm.' + self.__class__._lazy_llm_group,
                                 self.__class__.__name__, name=self.name)

apply()

组件执行的核心方法,需由子类实现。
定义组件的具体业务逻辑或任务执行步骤。

注意:
调用组件时,如果子类重写了此方法,则会调用此方法执行任务。

Source code in lazyllm/components/core.py
    def apply():
        """组件执行的核心方法,需由子类实现。  
定义组件的具体业务逻辑或任务执行步骤。  

**注意:**  
调用组件时,如果子类重写了此方法,则会调用此方法执行任务。  
"""
        raise NotImplementedError('please implement function \'apply\'')

cmd(*args, **kw)

生成组件的执行命令,需由子类实现。
返回的命令可以是字符串、元组或列表,表示具体执行任务的指令。

注意:
调用组件时,如果未重写 apply 方法,将通过此命令生成任务并由启动器执行。

Source code in lazyllm/components/core.py
    def cmd(self, *args, **kw) -> Union[str, tuple, list]:
        """生成组件的执行命令,需由子类实现。  
返回的命令可以是字符串、元组或列表,表示具体执行任务的指令。  

**注意:**  
调用组件时,如果未重写 `apply` 方法,将通过此命令生成任务并由启动器执行。  
"""
        raise NotImplementedError('please implement function \'cmd\'')

lazyllm.components.deploy.ray.Distributed

Bases: LazyLLMDeployBase

分布式部署类,继承自LazyLLMDeployBase。

提供基于Ray框架的分布式模型部署功能,支持多节点集群部署。

Parameters:

  • launcher

    启动器配置,默认为远程启动器(ngpus=1)

  • port (int, default: None ) –

    服务端口号,默认为随机端口(30000-40000)

Attributes:

  • finetuned_model

    微调后的模型路径

  • base_model

    基础模型路径

  • master_ip

    主节点IP地址

Methods:

  • cmd

    生成部署命令

  • geturl

    获取部署服务的URL地址

Source code in lazyllm/components/deploy/ray.py
class Distributed(LazyLLMDeployBase):
    """分布式部署类,继承自LazyLLMDeployBase。

提供基于Ray框架的分布式模型部署功能,支持多节点集群部署。

Args:
    launcher: 启动器配置,默认为远程启动器(ngpus=1)
    port (int, optional): 服务端口号,默认为随机端口(30000-40000)

Attributes:
    finetuned_model: 微调后的模型路径
    base_model: 基础模型路径
    master_ip: 主节点IP地址

Methods:
    cmd(finetuned_model, base_model, master_ip): 生成部署命令
    geturl(job): 获取部署服务的URL地址
"""

    def __init__(self, launcher=launchers.remote(ngpus=1), port=None):  # noqa B008
        super().__init__(launcher=launcher)
        self.port = port or random.randint(30000, 40000)
        self.finetuned_model = None
        self.base_model = None
        self.master_ip = None

    def cmd(self, finetuned_model=None, base_model=None, master_ip=None):
        """生成Ray分布式部署命令。

根据是否为主节点生成相应的Ray启动命令,支持头节点和工作节点两种模式。

Args:
    finetuned_model: 微调后的模型路径
    base_model: 基础模型路径
    master_ip: 主节点IP地址,如果为空则作为头节点启动

Returns:
    LazyLLMCMD: 包含部署命令的对象
"""
        self.finetuned_model = finetuned_model
        self.base_model = base_model
        self.master_ip = master_ip
        if not self.master_ip:
            cmd = f'ray start --block --head --port={self.port} && sleep 365d'
        else:
            cmd = f'ray start --address={self.master_ip} && sleep 365d'
        return LazyLLMCMD(cmd=cmd, return_value=self.geturl)

    def geturl(self, job=None):
        """获取分布式部署服务的URL地址。

根据部署模式返回相应的服务地址信息,支持显示模式和实际部署模式。

Args:
    job: 任务对象,默认为当前任务

Returns:
    Package: 包含模型路径和服务地址的打包对象
"""
        time.sleep(5)
        if job is None:
            job = self.job
        if lazyllm.config['mode'] == lazyllm.Mode.Display:
            return lazyllm.package(self.finetuned_model, self.base_model, None)
        else:
            if self.master_ip:
                return lazyllm.package(self.finetuned_model, self.base_model, self.master_ip)
            return lazyllm.package(self.finetuned_model, self.base_model, f'{job.get_jobip()}:{self.port}')

cmd(finetuned_model=None, base_model=None, master_ip=None)

生成Ray分布式部署命令。

根据是否为主节点生成相应的Ray启动命令,支持头节点和工作节点两种模式。

Parameters:

  • finetuned_model

    微调后的模型路径

  • base_model

    基础模型路径

  • master_ip

    主节点IP地址,如果为空则作为头节点启动

Returns:

  • LazyLLMCMD

    包含部署命令的对象

Source code in lazyllm/components/deploy/ray.py
    def cmd(self, finetuned_model=None, base_model=None, master_ip=None):
        """生成Ray分布式部署命令。

根据是否为主节点生成相应的Ray启动命令,支持头节点和工作节点两种模式。

Args:
    finetuned_model: 微调后的模型路径
    base_model: 基础模型路径
    master_ip: 主节点IP地址,如果为空则作为头节点启动

Returns:
    LazyLLMCMD: 包含部署命令的对象
"""
        self.finetuned_model = finetuned_model
        self.base_model = base_model
        self.master_ip = master_ip
        if not self.master_ip:
            cmd = f'ray start --block --head --port={self.port} && sleep 365d'
        else:
            cmd = f'ray start --address={self.master_ip} && sleep 365d'
        return LazyLLMCMD(cmd=cmd, return_value=self.geturl)