@@ -286,8 +286,6 @@ def __init__(
286286 # We also register the kb as a parameter that can be passed to actions.
287287 self .runtime .register_action_param ("kb" , self .kb )
288288
289- # detect actions that need isolated LLM instances and create them
290- self ._create_isolated_llms_for_actions ()
291289 # Reference to the general ExplainInfo object.
292290 self .explain_info = None
293291
@@ -511,147 +509,6 @@ def _init_llms(self):
511509
512510 self .runtime .register_action_param ("llms" , llms )
513511
514- def _create_isolated_llms_for_actions (self ):
515- """Create isolated LLM copies for all actions that accept 'llm' parameter."""
516- if not self .llm :
517- log .debug ("No main LLM available for creating isolated copies" )
518- return
519-
520- try :
521- actions_needing_llms = self ._detect_llm_requiring_actions ()
522- log .info (
523- "%d actions requiring isolated LLMs: %s" ,
524- len (actions_needing_llms ),
525- list (actions_needing_llms ),
526- )
527-
528- created_count = 0
529-
530- configured_actions_names = []
531- try :
532- if self .config .flows :
533- get_action_details = partial (
534- get_action_details_from_flow_id , flows = self .config .flows
535- )
536- for flow_id in self .config .rails .input .flows :
537- action_name , _ = get_action_details (flow_id )
538- configured_actions_names .append (action_name )
539- for flow_id in self .config .rails .output .flows :
540- action_name , _ = get_action_details (flow_id )
541- configured_actions_names .append (action_name )
542- else :
543- # for configurations without flow definitions, use all actions that need LLMs
544- log .info (
545- "No flow definitions found, creating isolated LLMs for all actions requiring them"
546- )
547- configured_actions_names = list (actions_needing_llms )
548- except Exception as e :
549- # if flow matching fails, fall back to all actions that need LLMs
550- log .info (
551- "Flow matching failed (%s), creating isolated LLMs for all actions requiring them" ,
552- e ,
553- )
554- configured_actions_names = list (actions_needing_llms )
555-
556- for action_name in configured_actions_names :
557- if action_name not in actions_needing_llms :
558- continue
559- if f"{ action_name } _llm" not in self .runtime .registered_action_params :
560- isolated_llm = self ._create_action_llm_copy (self .llm , action_name )
561- if isolated_llm :
562- self .runtime .register_action_param (
563- f"{ action_name } _llm" , isolated_llm
564- )
565- created_count += 1
566- log .debug ("Created isolated LLM for action: %s" , action_name )
567- else :
568- log .debug (
569- "Action %s already has dedicated LLM, skipping isolation" ,
570- action_name ,
571- )
572-
573- log .info ("Created %d isolated LLM instances for actions" , created_count )
574-
575- except Exception as e :
576- log .warning ("Failed to create isolated LLMs for actions: %s" , e )
577-
578- def _detect_llm_requiring_actions (self ):
579- """Auto-detect actions that have 'llm' parameter."""
580- import inspect
581-
582- actions_needing_llms = set ()
583-
584- if (
585- not hasattr (self .runtime , "action_dispatcher" )
586- or not self .runtime .action_dispatcher
587- ):
588- log .debug ("Action dispatcher not available" )
589- return actions_needing_llms
590-
591- for (
592- action_name ,
593- action_info ,
594- ) in self .runtime .action_dispatcher .registered_actions .items ():
595- action_func = self ._get_action_function (action_info )
596- if not action_func :
597- continue
598-
599- try :
600- sig = inspect .signature (action_func )
601- if "llm" in sig .parameters :
602- actions_needing_llms .add (action_name )
603- log .debug ("Action %s has 'llm' parameter" , action_name )
604-
605- except Exception as e :
606- log .debug ("Could not inspect action %s: %s" , action_name , e )
607-
608- return actions_needing_llms
609-
610- def _get_action_function (self , action_info ):
611- """Extract the actual function from action info."""
612- return action_info if callable (action_info ) else None
613-
614- def _create_action_llm_copy (
615- self , main_llm : Union [BaseLLM , BaseChatModel ], action_name : str
616- ) -> Optional [Union [BaseLLM , BaseChatModel ]]:
617- """Create an isolated copy of main LLM for a specific action."""
618- import copy
619-
620- try :
621- # shallow copy to preserve HTTP clients, credentials, etc.
622- # but create new instance to avoid shared state
623- isolated_llm = copy .copy (main_llm )
624-
625- # isolate model_kwargs to prevent shared mutable state
626- if (
627- hasattr (isolated_llm , "model_kwargs" )
628- and isolated_llm .model_kwargs is not None
629- ):
630- isolated_llm .model_kwargs = isolated_llm .model_kwargs .copy ()
631-
632- log .debug (
633- "Successfully created isolated LLM copy for action: %s" , action_name
634- )
635- return isolated_llm
636-
637- except Exception as e :
638- error_msg = (
639- "Failed to create isolated LLM instance for action '%s'. "
640- "This is required to prevent parameter contamination between different actions. "
641- "\n \n Possible solutions:"
642- "\n 1. If using a custom LLM class, ensure it supports copy.copy() operation"
643- "\n 2. Check that your LLM configuration doesn't contain non-copyable objects"
644- "\n 3. Consider using a dedicated LLM configuration for action '%s'"
645- "\n \n Original error: %s"
646- "\n \n To use a dedicated LLM for this action, add to your config:"
647- "\n models:"
648- "\n - type: %s"
649- "\n engine: <your_engine>"
650- "\n model: <your_model>"
651- ) % (action_name , action_name , e , action_name )
652- log .error (error_msg )
653- raise RuntimeError (error_msg )
654-
655512 def _get_embeddings_search_provider_instance (
656513 self , esp_config : Optional [EmbeddingSearchProvider ] = None
657514 ) -> EmbeddingsIndex :
0 commit comments