Implementación de razonamiento y planificación en Python

Esta sección presenta la capacidad de inteligencia central de los Agentes de IA, es decir, la capacidad de razonamiento y planificación.

A diferencia del modo tradicional de ejecución de instrucciones, un Agente con capacidad de razonamiento puede llevar a cabo procesos de pensamiento complejos.

Es capaz de descomponer tareas complejas en pasos ejecutables y tomar decisiones basándose en el contexto.


framework ReAct

ReAct (Reasoning + Acting) es un marco que combina el razonamiento con la acción.

En el modo ReAct, el Agente alterna entre razonamiento y acción, formando un ciclo cerrado.

El razonamiento guía las acciones, y los resultados de estas retroalimentan el proceso de razonamiento, en un ciclo continuo.

ReAct simula el proceso humano de resolución de problemas: pensar antes de actuar, observar los resultados después de actuar y luego continuar razonando con base en la nueva información.

Principio de funcionamiento

La idea central de ReAct puede resumirse como un ciclo de tres fases:

Primer paso, fase de razonamiento. El Agente genera el pensamiento de acción para el siguiente paso basándose en el contexto actual.

Segundo paso, fase de acción. El Agente ejecuta la herramienta o acción seleccionada.

Tercer paso, fase de observación. El agente recibe el resultado de la acción, actualiza el contexto y regresa al primer paso para continuar el razonamiento.

Implementación de código

A continuación se muestra una implementación simplificada de un Agente ReAct:

Implementación básica del agente ReAct

class ReActAgent:
    """
Implementación del Agent en el marco ReAct
Mecanismo central: razonamiento -> acción -> observación -> razonamiento (bucle)
    """

   
    def __init__(self, llm, tools, max_iterations=5):
        # Instancia de LLM, utilizada para inferencia y generación
        self.llm = llm
        # Lista de herramientas disponibles
        self.tools = tools
        # Número máximo de iteraciones para evitar bucles infinitos
        self.max_iterations = max_iterations
   
    def run(self, task):
        """
Ejecutar el bucle ReAct
:param task: Descripción de la tarea del usuario.
:return: Resultado de la ejecución
        """

        # Inicializar el contexto, incluyendo la tarea y la información histórica
        context = {
            "task": task,
            "steps": [],      # Registro de pasos ejecutados
            "observations": []  # Registro de observaciones
        }
       
        for i in range(self.max_iterations):
            # Etapa 1: Razonamiento - Generar la siguiente acción basada en el contexto actual
            reasoning = self.llm.reason(context)
           
            # Determinar si es necesario ejecutar la herramienta o devolver la respuesta directamente
            if reasoning.needs_action:
                # Seleccionar la herramienta a utilizar
                action = reasoning.select_tool(self.tools)
                # Ejecutar la herramienta y obtener las observaciones
                observation = action.execute(reasoning.tool_input)
                # Agregar las observaciones al contexto
                context["observations"].append(observation)
            else:
                # No se necesita acción, devolver directamente la respuesta obtenida por razonamiento.
                return reasoning.answer
       
        # Se alcanzó el número máximo de iteraciones sin completar
        return Se alcanzó el límite máximo de iteraciones

Escenarios de aplicación típicos

El modo ReAct es especialmente adecuado para los siguientes escenarios:

Tareas que requieren explorar el entorno y recopilar información antes de poder completarse.

Escenario de búsqueda inteligente: el agente necesita primero buscar información y luego razonar y resumir con base en los resultados de la búsqueda.

Preguntas y respuestas conversacionales: el Agente necesita aclarar requisitos y obtener información mediante diálogos de múltiples turnos.

Resolución de problemas complejos: el problema no puede resolverse en un solo paso y requiere múltiples pasos intermedios.

Nota: la ventaja del modo ReAct radica en su flexibilidad, ya que puede ajustar dinámicamente las acciones posteriores según el resultado de cada paso. Pero esto también significa que la ruta de ejecución puede ser inestable, y resulta adecuado para tareas que requieren exploración.


cadena de pensamiento (Chain of Thought, CoT)

La cadena de pensamiento es una técnica que impulsa al modelo a mostrar el proceso de razonamiento paso a paso.

CoT no hace que el modelo dé la respuesta directamente, sino que lo guía para que primero muestre los pasos de razonamiento y luego llegue a la conclusión final.

¿Por qué es necesaria la cadena de pensamiento?

Hacer que el modelo genere la respuesta directamente presenta varios problemas:

Los pasos intermedios del razonamiento complejo tienden a omitirse o saltarse fácilmente.

Es difícil localizar dónde ocurrió el error.

El usuario no puede comprender el proceso de pensamiento del modelo.

La cadena de pensamiento resuelve estos problemas al exigir que el modelo muestre el proceso de razonamiento.

Zero-shot CoT

Zero-shot CoT es un método que puede estimular la capacidad de razonamiento paso a paso sin necesidad de ejemplos.

Solo es necesario añadir al final del prompt una frase de activación como "pensemos paso a paso".

Ejemplo de Zero-shot CoT

# Plantilla de prompt para Zero-shot CoT
prompt = """
Problema: Xiaoming tiene 5 manzanas, Xiaohong le dio 3, Xiaoming se comió 2, ¿cuántas quedan?
Pensemos paso a paso:
"""


# Llamar al modelo de lenguaje
response = llm.generate(prompt)

# Ejemplo de salida del modelo:
# Primer paso: calcular el total de manzanas que recibió Xiao Ming
# Xiaoming tenía 5 manzanas, Xiaohong le dio 3.
# 5 + 3 = 8
#
# Segundo paso: calcular la cantidad después de comer
# Xiaoming se comió 2
# 8 - 2 = 6 unidades
#
# Conclusión: quedan 6 manzanas

Few-shot CoT

El Few-shot CoT, al proporcionar ejemplos con procesos de razonamiento detallados, ayuda al modelo a aprender patrones de razonamiento específicos.

Cuando el Zero-shot CoT no da buenos resultados, se puede probar con Few-shot CoT.

Ejemplo de Few-shot CoT

# Plantilla de prompt de Few-shot CoT
prompt = """
Ejemplo 1:
Problema: Xiaozhang tiene 10 yuanes, compró 3 libros, cada uno a 2 yuanes, ¿cuánto le queda?
Pensemos paso a paso:
- Xiao Zhang tenía originalmente 10 yuanes
- Cada libro cuesta 2 yuanes, se compran 3 libros, el gasto es 3 × 2 = 6 yuanes
- 10 - 6 = 4 yuan
Respuesta: quedan 4 yuanes

Ejemplo 2:
Problema: un gato atrapa 2 ratones por hora, ¿cuántos atrapa en 8 horas?
Pensemos paso a paso:
- Atrapa 2 ratones por hora
- En 8 horas capturó 8 × 2 = 16
Respuesta: atrapé 16

Pregunta: {user_question}
Pensemos paso a paso:
"""


response = llm.generate(prompt)

Ventajas de la cadena de pensamiento

La técnica de la cadena de pensamiento aporta tres valores fundamentales:

Trazabilidad: descompone el razonamiento complejo en pasos intermedios trazables, lo que facilita la comprensión del proceso de razonamiento.

Explicabilidad: mejora la explicabilidad del modelo y permite a los usuarios saber de dónde proviene la respuesta.

Mejora de la precisión: aumenta significativamente la precisión en tareas de razonamiento complejo, especialmente en tareas matemáticas y lógicas.


Tree of Thoughts(ToT)

El árbol de pensamiento es una extensión de la cadena de pensamiento; ya no se limita al razonamiento lineal.

ToT explora múltiples caminos posibles en cada nodo de razonamiento, formando una estructura de árbol.

Esto permite al Agente realizar exploración de múltiples rutas, retroceder y evaluar globalmente.

Diferencias con la cadena de pensamiento

CoT adopta un razonamiento lineal, donde cada paso depende de la conclusión del paso anterior; es adecuado para problemas con una ruta clara.

ToT adopta un razonamiento espacial, considerando simultáneamente múltiples ramas posibles; es adecuado para problemas que requieren exploración y planificación.

Implementación de código

Implementación básica del agente ToT

class ToTAgent:
    """
Implementación del agente Tree of Thoughts
Mecanismo central: generar múltiples ramas candidatas en cada nodo, evaluarlas y seleccionar la mejor para continuar
    """

   
    def __init__(self, llm, max_depth=4, beam_size=3):
        # Instancia de LLM
        self.llm = llm
        # Profundidad máxima de búsqueda
        self.max_depth = max_depth
        # Número de nodos candidatos retenidos por capa (beam width)
        self.beam_size = beam_size
   
    def solve(self, problem):
        """
Usar el marco ToT para resolver el problema
:param problem: descripción del problema
:return: la solución óptima
        """

        # Crear el nodo raíz, conteniendo la pregunta como estado inicial
        root = ThoughtNode(problem, depth=0)
        # Inicializar la lista de nodos frontera (nodos a expandir).
        frontier = [root]
       
        # Expandir por capas
        for depth in range(self.max_depth):
            # Almacenar todos los nodos candidatos
            all_candidates = []
           
            # Recorrer todos los nodos frontera
            for node in frontier:
                # Generar múltiples candidatos para el siguiente paso del nodo actual
                candidates = self.llm.generate_thoughts(
                    node.content,    # Contenido del nodo actual
                    n=self.beam_size  # Generar cantidad
                )
                # Crear un nuevo nodo y agregarlo a la lista de candidatos
                for cand in candidates:
                    all_candidates.append(
                        ThoughtNode(cand, depth + 1, parent=node)
                    )
           
            # Evaluar todos los nodos candidatos
            evaluated = self.evaluator.rank(all_candidates)
           
            # Seleccionar los beam_size nodos óptimos como frontera de la siguiente ronda
            frontier = evaluated[:self.beam_size]
           
            # Verificar si se encontró una solución
            if self.is_solution(frontier):
                break
       
        # Retroceder para encontrar la solución óptima
        return self.backtrack_best(frontier)

Escenarios de aplicación

ToT es especialmente adecuado para escenarios que requieren tomar decisiones o planificar:

Escritura creativa: genera múltiples direcciones de desarrollo para una historia, evalúa y selecciona la mejor.

Planificación estratégica: evaluar los resultados potenciales de múltiples opciones de acción.

Decisiones complejas: problemas de decisión que requieren considerar múltiples posibilidades.


Planificación de tareas y MCTS

La búsqueda en árbol de Monte Carlo (Monte Carlo Tree Search, MCTS) es un algoritmo de búsqueda heurística para problemas de decisión complejos.

MCTS tiene una amplia aplicación en la planificación de agentes, especialmente adecuado para IA de juegos y planificación de tareas complejas.

Idea central

MCTS evalúa el valor potencial de cada nodo de decisión mediante la simulación de juegos aleatorios.

No necesita evaluar todas las rutas posibles, sino que guía la dirección de la búsqueda mediante muestreo y estadísticas.

Los cuatro pasos del MCTS

Primer paso, selección (Selection): comienza desde el nodo raíz y selecciona recursivamente el mejor nodo hijo hasta alcanzar un nodo hoja.

Al seleccionar, se utiliza la fórmula UCB (Upper Confidence Bound) para equilibrar la exploración y la explotación.

Segundo paso, expansión (Expansion): se añaden uno o más nodos hijos al nodo hoja.

Tercer paso, simulación (Simulation): desde el nuevo nodo, se simula aleatoriamente el juego hasta el final.

Cuarto paso, retropropagación (Backpropagation): actualizar la información estadística de todos los nodos en la trayectoria simulada.

Implementación de código

Implementación del planificador MCTS

import math

class MCTSNode:
    """
Nodo del árbol MCTS
Almacena el estado del nodo, los datos estadísticos y las relaciones de nodos hijos
    """

   
    def __init__(self, state, parent=None, action=None):
        # Estado actual
        self.state = state
        Referencia al nodo padre
        self.parent = parent
        # Acción para llegar a este nodo desde el nodo padre
        self.action = action
        Lista de nodos hijos
        self.children = []
        # Número de visitas de este nodo
        self.visit_count = 0
        # Valor de recompensa acumulada de este nodo
        self.reward = 0.0
   
    def is_fully_expanded(self):
        """Comprobar si se han expandido todos los posibles nodos hijos"""
        return len(self.children) > 0
   
    def is_terminal(self):
        """Comprueba si es un nodo terminal (juego terminado o objetivo alcanzado)"""
        return self.state.is_terminal()
   
    def uct_child(self):
        """
Seleccionar el subnodo óptimo utilizando la fórmula UCT
        UCT = reward/visits + C * sqrt(ln(parent_visits)/visits)
C es la constante de exploración, normalmente establecida en sqrt(2)
        """

        # Constante de exploración, equilibrando exploración y explotación
        C = math.sqrt(2)
       
        return max(
            self.children,
            key=lambda c: c.reward / c.visit_count +
                         C * math.sqrt(math.log(self.visit_count) / c.visit_count)
        )


class MCTSPlanner:
    """
Planificador MCTS
Usar la búsqueda de árbol de Monte Carlo para generar la planificación de acciones para el agente.
    """

   
    def __init__(self, simulation_limit=1000, exploration_constant=1.41):
        # Número máximo de simulaciones
        self.simulation_limit = simulation_limit
        # Explorar constantes
        self.exploration_constant = exploration_constant
   
    def plan(self, initial_state):
        """
Planificar desde el estado inicial
:param initial_state: estado inicial
:return: acción óptima
        """

        Crear nodo raíz
        root = MCTSNode(initial_state)
       
        # Ejecutar múltiples simulaciones
        for _ in range(self.simulation_limit):
            # 1. Selección: desde el nodo raíz, selecciona hacia abajo el mejor nodo hijo hasta el nodo hoja
            node = self._selection(root)
           
            # 2. Expansión: si no es un nodo terminal, expandir un nuevo nodo
            if not node.is_terminal():
                node = self._expansion(node)
           
            # 3. Simulación: desde un nuevo nodo, simular aleatoriamente hasta la terminación
            reward = self._simulation(node)
           
            # 4. Retropropagación: actualizar las estadísticas de todos los nodos en la ruta
            self._backpropagation(node, reward)
       
        # Devuelve la acción correspondiente al nodo hijo óptimo del nodo raíz
        return root.best_child().action
   
    def _selection(self, node):
        """Fase de selección: seleccionar el mejor subnodo"""
        while node.is_fully_expanded() and not node.is_terminal():
            node = node.uct_child()
        return node
   
    def _expansion(self, node):
        """Fase de expansión: añadir nuevo nodo hijo"""
        # Generar todas las acciones posibles
        possible_actions = node.state.get_possible_actions()
        # Crear un nodo hijo para cada acción
        for action in possible_actions:
            new_state = node.state.apply_action(action)
            child = MCTSNode(new_state, parent=node, action=action)
            node.children.append(child)
        # Devolver un nodo hijo aleatorio (también se puede usar una estrategia determinista)
        return node.children[0]
   
    def _simulation(self, node):
        """Fase de simulación: simulación aleatoria hasta el final del juego"""
        state = node.state
        while not state.is_terminal():
            # Selección aleatoria de acciones
            actions = state.get_possible_actions()
            action = random.choice(actions)
            state = state.apply_action(action)
        # Devolver la recompensa final
        return state.get_reward()
   
    def _backpropagation(self, node, reward):
        """Retropropagación: actualizar las estadísticas"""
        while node is not None:
            node.visit_count += 1
            node.reward += reward
            node = node.parent

Nota: MCTS tiene un costo computacional alto; es adecuado para escenarios que requieren planificación profunda pero con condiciones de terminación claras. Para tareas con altos requisitos de tiempo real, puede ser necesario limitar el número de simulaciones o usar otros métodos.


Reflexion (autorreflexión)

Reflexion es una técnica que dota al Agente de capacidad de autorreflexión.

Al añadir un mecanismo de reflexión al Agente, este puede analizar las causas del error después de un fallo, ajustar la estrategia e intentarlo de nuevo.

Idea central

El agente no solo ejecuta acciones, sino que también observa los resultados y reflexiona: ¿por qué fallé? ¿cómo debería mejorar la próxima vez?

Esta capacidad es crucial para el aprendizaje continuo y la automejora.

Implementación de código

Implementación del Agente Reflexion

class ReflexionAgent:
    """
Agente con capacidad de autorreflexión
Mecanismo central: Ejecutar -> Evaluar -> Reflexionar -> Reintentar
    """

   
    def __init__(self, actor, reviewer, max_retries=3):
        # Ejecutor: responsable de ejecutar tareas específicas
        self.actor = actor
        # Evaluador: responsable de evaluar los resultados de la ejecución
        self.reviewer = reviewer
        # Número máximo de reintentos
        self.max_retries = max_retries
   
    def run(self, task):
        """
Ejecutar una tarea con autorreflexión
:param task: descripción de la tarea
:return: Resultado de la ejecución
        """

        # Mantener el historial de ejecución
        history = []
       
        for attempt in range(self.max_retries):
            # Fase 1: Intentar ejecutar la tarea
            result = self.actor.execute(task, history)
           
            # Registrar este intento
            history.append({
                "attempt": attempt,
                "result": result
            })
           
            # Fase 2: Revisar resultados
            feedback = self.reviewer.evaluate(task, result)
           
            # Fase 3: Verificar si se logró
            if feedback.is_success:
                return result
           
            # Fase 4: Reflexionar sobre las causas del fracaso
            # Generar una nueva indicación de estrategia para guiar el próximo intento
            reflection = self.reviewer.reflect(
                task,           # Tarea original
                result,         # Resultado fallido
                feedback        # Comentarios de revisión
            )
           
            # Agregar el resultado de la reflexión al historial para referencia en el próximo intento
            history.append({
                "type": "reflection",
                "content": reflection
            })
       
        # Si todos los reintentos fallan, devolver el historial
        return history


class Reviewer:
    """Evaluador: evalúa los resultados de la ejecución y genera reflexiones"""
   
    def evaluate(self, task, result):
        """
Evaluar el resultado de ejecución
:return: el objeto que contiene si fue exitoso y la retroalimentación detallada.
        """

        # Comprobar si el resultado cumple con los requisitos de la tarea
        is_success = self.check_success(task, result)
       
        if is_success:
            return EvaluationResult(is_success=True)
        else:
            # Generar análisis de la causa del fallo
            failure_reasons = self.analyze_failures(task, result)
            return EvaluationResult(
                is_success=False,
                reasons=failure_reasons
            )
   
    def reflect(self, task, result, feedback):
        """
Generar contenido de reflexión
Ayudar al Actor a entender las causas del fallo y mejorar la estrategia
        """

        prompt = f"""
Tarea: {task}
Resultado de ejecución: {result}
Motivo del fallo: {feedback.reasons}

Analice las causas del fallo y proporcione sugerencias de mejora.
Notas importantes:
1. ¿Qué salió mal?
2. ¿Cómo debería evitarse la próxima vez?
3. ¿Qué estrategia se debe cambiar?
"""

        return self.llm.generate(prompt)

Escenarios de aplicación

Reflexion es especialmente adecuado para los siguientes escenarios:

Tareas que requieren mejora continua, como sistemas de diálogo, generación de código, etc.

Escenarios donde el costo del error es alto pero el costo de reintentar es bajo.

Situaciones en las que se necesita aprender de los fracasos.


Estrategia de descomposición de tareas

Las tareas complejas generalmente deben descomponerse en subtareas manejables.

La descomposición efectiva de tareas es la base de la capacidad de planificación.

Descomposición recursiva de tareas

Descomponer la tarea recursivamente en subtareas más pequeñas hasta que puedan ejecutarse directamente.

Descomposición recursiva de tareas

def decompose(task, is_executable_fn, decompose_fn):
    """
Descomponer tareas recursivamente
:param task: La tarea a descomponer.
:param is_executable_fn: función que determina si la tarea se puede ejecutar directamente
:param decompose_fn: función que descompone la tarea
:return: lista de tareas ejecutables
    """

    # Si la tarea puede ejecutarse directamente, retornar directamente
    if is_executable_fn(task):
        return [task]
   
    # Descomponer la tarea en subtareas
    subtasks = decompose_fn(task)
   
    # Descomponer recursivamente cada subtarea
    result = []
    for subtask in subtasks:
        # Llamar recursivamente a la función de descomposición para las subtareas
        result.extend(
            decompose(subtask, is_executable_fn, decompose_fn)
        )
   
    return result


# Ejemplo: determinar si la tarea es ejecutable
def is_code_complete(task):
    Comprobar si la tarea puede ejecutar código directamente
    return task.get("type") == "code" and len(task.get("dependencies", [])) == 0


# Ejemplo: descomponer tareas complejas
def decompose_programming_task(task):
    """Descomponer la tarea de programación"""
    if "write_function" in task["type"]:
        return [
            {"type": "understand_requirements", "task": task["spec"]},
            {"type": "write_code", "spec": task["spec"]},
            {"type": "write_tests", "function": task["function_name"]},
            {"type": "verify_tests", "function": task["function_name"]}
        ]
    return [task]

Descomposición paralela de tareas

Identificar subtareas independientes que puedan ejecutarse en paralelo para mejorar la eficiencia.

Esta es una estrategia clave para acelerar la ejecución de tareas.

Descomposición jerárquica de tareas

Dividir las tareas en diferentes niveles de abstracción; las tareas de alto nivel invocan a las de bajo nivel, formando un árbol jerárquico de tareas.

Adecuado para sistemas complejos que requieren múltiples niveles de abstracción.


Modo Plan-and-Execute

Plan-and-Execute es un patrón arquitectónico que separa la planificación de la ejecución.

El Agente primero planifica completamente todo el flujo de la tarea y luego ejecuta según el plan.

Diferencias con ReAct

ReAct razona y ejecuta simultáneamente; es más flexible pero la ruta puede ser inestable.

Plan-and-Execute planifica primero y ejecuta después; es más estable pero carece de capacidad de ajuste dinámico.

Implementación de código

Implementación del agente Plan-and-Execute

class PlanAndExecuteAgent:
    """
Agente de la arquitectura Plan-and-Execute
Mecanismo central: primero planificar completamente y luego ejecutar según el plan
    """

   
    def __init__(self, planner, executor):
        # Planificador: responsable de elaborar el plan de ejecución
        self.planner = planner
        # Ejecutor: responsable de ejecutar los pasos específicos
        self.executor = executor
   
    def run(self, task):
        """
Ejecutar tareas
Se divide en fase de planificación y fase de ejecución
        """

        # ==================== Fase de planificación ====================
        # Generar el plan de ejecución completo de una sola vez
        plan = self.planner.create_plan(task)
       
        # ==================== Fase de ejecución ====================
        results = []
       
        # Ejecutar en el orden planificado
        for step in plan.steps:
            # Ejecutar el paso actual
            result = self.executor.execute(step)
            results.append(result)
           
            # Verificar si se necesita replanificar
            # Por ejemplo: el resultado de la ejecución no coincide con lo esperado, o se produce una situación inesperada
            if self.needs_replan(results):
                # Replanificar basándose en los resultados actuales
                plan = self.planner.replan(task, results)
       
        # Integrar todos los resultados
        return self.summarize(results)
   
    def needs_replan(self, results):
        """
Determinar si es necesario replanificar
Verificar si el resultado de la ejecución cumple con lo esperado
        """

        # Obtener el último resultado
        last_result = results[-1]
       
        # Si el resultado no cumple claramente lo esperado, se necesita replanificar.
        if last_result.is_unexpected():
            return True
       
        # Si el resultado provoca que los pasos siguientes no se puedan ejecutar, es necesario replanificar
        if last_result.blocks_future():
            return True
       
        return False


class Planner:
    """Planificador: generar el plan de ejecución de la tarea"""
   
    def create_plan(self, task):
        """Crear el plan de ejecución inicial"""
        prompt = f"""
Tarea: {task}

Por favor, elabore un plan de ejecución detallado, incluyendo:
1. El orden de los pasos a ejecutar
2. La operación específica de cada paso
3. Dependencias entre pasos

Formato de salida:
Paso 1: [Descripción de la operación]
Paso 2: [Descripción de la operación]
...
"""

        plan_text = self.llm.generate(prompt)
        return Plan.parse(plan_text)
   
    def replan(self, task, results):
        """Replanificar basado en los resultados de ejecución"""
        # Analizar los resultados completados
        completed = [r for r in results if r.is_success]
        failed = [r for r in results if not r.is_success]
       
        # Generar el plan ajustado
        prompt = f"""
Tarea original: {task}
Pasos completados: {completed}
Paso fallido: {failed}

Por favor, elabore el plan de ejecución ajustado:
"""

        plan_text = self.llm.generate(prompt)
        return Plan.parse(plan_text)


class Executor:
    """Ejecutor: ejecuta los pasos concretos del plan."""
   
    def execute(self, step):
        """Ejecutar un solo paso"""
        # Seleccionar el método de ejecución según el tipo de paso
        if step.type == "tool_call":
            return self.execute_tool_call(step)
        elif step.type == "code":
            return self.execute_code(step)
        elif step.type == "query":
            return self.execute_query(step)
       
        return Result(success=False, error="Unknown step type")

Nota: el patrón Plan-and-Execute es adecuado para escenarios donde la estructura de la tarea es relativamente estable y puede planificarse con antelación. Para entornos que requieren flexibilidad, el modo ReAct puede ser más adecuado.


Resumen del capítulo

Este capítulo presenta las capacidades centrales de razonamiento y planificación de los Agentes de IA.

ReActEl marco, mediante el ciclo de razonamiento y acción, permite al Agente ajustar su estrategia mientras ejecuta.

Cadena de pensamiento (CoT)Al mostrar el proceso de razonamiento paso a paso, se mejora la precisión en la ejecución de tareas complejas.

Árbol de pensamiento (ToT)Extiende la cadena de pensamiento, soportando exploración de múltiples rutas y retroceso.

MCTSEs un algoritmo de búsqueda heurística, adecuado para problemas complejos de decisión y planificación.

ReflexionDota al Agente de capacidad de autorreflexión para aprender de los fracasos y mejorar.

Estrategia de descomposición de tareasEs la base de la capacidad de planificación, incluyendo descomposición recursiva, descomposición paralela y descomposición jerárquica.

Plan-and-ExecuteAdopta el modo de planificar primero y ejecutar después, adecuado para tareas con estructura estable.

Estas técnicas pueden usarse individualmente o combinarse para construir sistemas de Agentes más potentes.

Otras extensiones