---
name: comfyui_inject_multi_lora
kind: function
lang: py
domain: ml
version: "1.0.0"
purity: pure
signature: "def comfyui_inject_multi_lora(workflow: dict, loras: list[dict]) -> dict"
description: "Encadena N nodos LoraLoader en un workflow ComfyUI ya construido (API format) reusando comfyui_inject_lora una vez por LoRA. Cada lora = {name, strength_model, strength_clip}. La salida MODEL/CLIP de cada LoraLoader alimenta al siguiente: el primer elemento queda cerca del checkpoint y el ultimo cerca del KSampler. Respeta el orden de la lista. Pura: no muta el dict de entrada."
tags: [comfyui, comfyui-skill, ml, lora, stable-diffusion, workflow]
uses_functions: [comfyui_inject_lora_py_ml]
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
params:
  - name: workflow
    desc: "dict en API format (ej. salida de comfyui_build_txt2img_workflow). No se muta; se devuelve una copia."
  - name: loras
    desc: "Lista de dicts aplicados en orden. Cada dict: name (str, obligatorio, archivo .safetensors en models/loras/), strength_model (float, default 1.0, fuerza sobre el UNet), strength_clip (float, default 1.0, fuerza sobre el CLIP). Lista vacia => copia sin cambios."
output: "copia del workflow con N LoraLoader insertados y encadenados (checkpoint -> loras[0] -> loras[1] -> ... -> KSampler/CLIPTextEncode). Los node_id crecen en el orden de la lista."
tested: true
tests: ["encadena N LoRAs (cuenta correcta de LoraLoader)", "orden y cadena validos (loras[0] toma model del checkpoint, KSampler toma model del ultimo)", "respeta pesos por posicion", "no muta el dict de entrada (pureza)", "lista vacia devuelve copia sin loras", "lora sin name o no-dict lanza ValueError", "determinismo"]
test_file_path: "python/functions/ml/tests/test_comfyui_inject_multi_lora.py"
file_path: "python/functions/ml/comfyui_inject_multi_lora.py"
---

## Ejemplo

```python
import sys, os
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
from ml.comfyui_build_txt2img_workflow import comfyui_build_txt2img_workflow
from ml.comfyui_inject_multi_lora import comfyui_inject_multi_lora

base = comfyui_build_txt2img_workflow("IMG_dreamshaper_8.safetensors", "a robot, 3D Render Style")
wf = comfyui_inject_multi_lora(base, [
    {"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
    {"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5, "strength_clip": 0.5},
])
# Cadena: checkpoint -> 3d_render (0.9) -> detail_tweaker (0.5/0.5) -> KSampler/CLIPTextEncode
```

## Cuando usarla

Cuando quieras apilar **varios LoRAs de estilo/detalle** sobre un workflow
txt2img/img2img sin llamar `comfyui_inject_lora` a mano N veces. Pasa la lista y
la funcion encadena en orden. Util para combinar estilo + ajuste fino (ej. un
LoRA de estilo 3D + un detail_tweaker) en una sola llamada.

## Gotchas

- Pura: no muta el `workflow` de entrada y NO valida que cada `name` exista en el
  servidor. Valida con `comfyui_validate_workflow` antes de submit.
- **El orden importa**: `[estilo, detalle]` produce una cadena distinta a
  `[detalle, estilo]`. El primer elemento queda mas cerca del checkpoint y el
  ultimo mas cerca del KSampler (es el que el sampler "ve" mas directo).
- Cada LoRA acumula coste de VRAM. En 8GB con SD1.5 caben varios; con SDXL vigila
  la memoria y reduce resolucion si hay OOM.
- Hereda los gotchas de `comfyui_inject_lora`: asume slots MODEL=0/CLIP=1 y detecta
  la fuente por el KSampler.model. Si el workflow no tiene KSampler, propaga el
  ValueError de `comfyui_inject_lora`.
