paint-brush
Cómo evaluar eficazmente sus solicitudes RAG + LLMpor@vndee
1,521 lecturas
1,521 lecturas

Cómo evaluar eficazmente sus solicitudes RAG + LLM

por Duy Huynh17m2023/12/27
Read on Terminal Reader

Demasiado Largo; Para Leer

¿Alguna vez te has preguntado cómo algunas de las aplicaciones actuales parecen casi mágicamente inteligentes? Una gran parte de esa magia proviene de algo llamado RAG y LLM.
featured image - Cómo evaluar eficazmente sus solicitudes RAG + LLM
Duy Huynh HackerNoon profile picture
0-item
1-item

¡Hola! ¿Alguna vez te has preguntado cómo algunas de las aplicaciones actuales parecen casi mágicamente inteligentes? Una gran parte de esa magia proviene de algo llamado RAG y LLM. Piense en RAG (Generación de recuperación aumentada) como el ratón de biblioteca inteligente del mundo de la IA. Explora toneladas de información para encontrar exactamente lo que se necesita para su pregunta. Luego, está el LLM (modelo de lenguaje grande), como la famosa serie GPT que generará una respuesta fluida basada en sus impresionantes capacidades de generación de texto. Con estos dos juntos, tienes una IA que no sólo es inteligente sino también súper relevante y consciente del contexto. Es como combinar un asistente de investigación súper rápido con un conversador ingenioso. Esta combinación es fantástica para cualquier cosa, desde ayudarle a encontrar información específica rápidamente hasta tener una conversación que parezca sorprendentemente real.


Pero aquí está el truco: ¿Cómo sabemos si nuestra IA realmente está siendo útil y no solo está diciendo una jerga sofisticada? Ahí es donde entra en juego la evaluación. Es crucial, no sólo algo agradable de tener. Necesitamos asegurarnos de que nuestra IA no solo sea precisa sino también relevante, útil y que no se vaya por tangentes extrañas. Después de todo, ¿de qué sirve un asistente inteligente si no puede entender lo que necesitas o te da respuestas que están muy equivocadas?


Evaluar nuestra solicitud RAG + LLM es como una verificación de la realidad. Nos dice si realmente vamos por buen camino en la creación de una IA que sea realmente útil y no sólo técnicamente impresionante. Entonces, en esta publicación, profundizaremos en cómo hacer precisamente eso: ¡garantizar que nuestra IA sea tan asombrosa en la práctica como lo es en teoría!

Fase de desarrollo

En la fase de desarrollo, es esencial pensar en la línea de un proceso típico de evaluación de un modelo de aprendizaje automático. En una configuración estándar de IA/ML, normalmente trabajamos con varios conjuntos de datos, como conjuntos de desarrollo, capacitación y pruebas, y empleamos métricas cuantitativas para medir la efectividad del modelo. Sin embargo, la evaluación de modelos de lenguaje grande (LLM) presenta desafíos únicos. Las métricas cuantitativas tradicionales luchan por capturar la calidad del resultado de los LLM porque estos modelos sobresalen en generar un lenguaje que es a la vez variado y creativo. En consecuencia, es difícil contar con un conjunto completo de etiquetas para una evaluación eficaz.


En los círculos académicos, los investigadores pueden emplear puntos de referencia y puntuaciones como MMLU para clasificar los LLM, y se pueden contratar expertos humanos para evaluar la calidad de los resultados de los LLM. Sin embargo, estos métodos no pasan sin problemas al entorno de producción, donde el ritmo de desarrollo es rápido y las aplicaciones prácticas requieren resultados inmediatos. No se trata únicamente del desempeño del LLM; Las demandas del mundo real tienen en cuenta todo el proceso, que incluye la recuperación de datos, la composición rápida y la contribución del LLM. No es práctico elaborar un punto de referencia seleccionado por humanos para cada nueva iteración del sistema o cuando hay cambios en documentos o dominios. Además, el rápido ritmo de desarrollo en la industria no permite el lujo de largas esperas para que los evaluadores humanos evalúen cada actualización antes de su implementación. Por lo tanto, ajustar las estrategias de evaluación que funcionan en el mundo académico para alinearlas con el entorno de producción rápido y centrado en resultados presenta un desafío considerable.


Entonces, si cae en este caso, puede pensar en algo así como una pseudo puntuación proporcionada por un maestro LLM. Esta puntuación podría reflejar una combinación de métricas de evaluación automatizadas y una esencia destilada del juicio humano. Este enfoque híbrido tiene como objetivo cerrar la brecha entre la comprensión matizada de los evaluadores humanos y el análisis sistemático y escalable de la evaluación mecánica.

Cadena RAG + LLM


Por ejemplo, si su equipo está desarrollando un LLM interno que está capacitado en su dominio y datos específicos, el proceso generalmente implicará un esfuerzo colaborativo de desarrolladores, ingenieros rápidos y científicos de datos. Cada miembro desempeña un papel fundamental:

  • Los desarrolladores son los arquitectos. Construyen el marco de la aplicación, asegurando que la cadena RAG + LLM esté perfectamente integrada y pueda navegar a través de diferentes escenarios sin esfuerzo.

  • Los ingenieros rápidos son los creativos. Idean escenarios e indicaciones que emulan las interacciones de los usuarios del mundo real. Reflexionan sobre los "qué pasaría si" y presionan al sistema para que aborde un amplio espectro de temas y preguntas.

  • Los científicos de datos son los estrategas. Analizan las respuestas, profundizan en los datos y utilizan su experiencia estadística para evaluar si el rendimiento de la IA cumple con los requisitos.


El circuito de retroalimentación aquí es esencial. A medida que nuestra IA responde a las indicaciones, el equipo examina cada resultado. ¿La IA entendió la pregunta? ¿La respuesta fue precisa y relevante? ¿Podría el lenguaje ser más fluido? Esta retroalimentación luego se reincorpora al sistema para realizar mejoras.


Para llevar esto a un nivel superior, imagine utilizar un LLM maestro como GPT-4 de OpenAI como punto de referencia para evaluar su LLM de desarrollo propio. Su objetivo es igualar o incluso superar el rendimiento de la serie GPT, conocida por su robustez y versatilidad. Así es como puede proceder:

  • Generar un conjunto de datos relevante: comience creando un conjunto de datos que refleje los matices de su dominio. Este conjunto de datos podría ser seleccionado por expertos o sintetizado con la ayuda de GPT-4 para ahorrar tiempo y garantizar que coincida con su estándar de oro.

  • Definición de métricas para el éxito: aproveche las fortalezas del maestro LLM para ayudarlo a definir sus métricas. Tiene la libertad de elegir las métricas que mejor se ajusten a sus objetivos, dado que el maestro LLM puede manejar las tareas más complejas. En el estándar de la comunidad, es posible que desee ver algún trabajo de Langchain y algunas otras bibliotecas como ragas . Tienen algunas métricas como fidelidad, recuerdo de contexto, precisión de contexto, similitud de respuestas, etc.

  • Automatización de su proceso de evaluación: para seguir el ritmo de los rápidos ciclos de desarrollo, establezca un proceso automatizado. Esto evaluará constantemente el rendimiento de la aplicación en comparación con sus métricas predefinidas después de cada actualización o cambio. Al automatizar el proceso, se asegura de que su evaluación no solo sea exhaustiva sino también iterativa de manera eficiente, lo que permitirá una rápida optimización y refinamiento.


Por ejemplo, en la siguiente demostración, le mostraré cómo evaluar automáticamente varios LLM de código abierto en una tarea de conversación de recuperación de documentos simple utilizando GPT-4 de OpenAI.


Primero, utilizamos OpenAI GPT-4 para crear un conjunto de datos sintetizados derivado de un documento como se muestra a continuación:

 import os import json import pandas as pd from dataclasses import dataclass from langchain.chat_models import ChatOpenAI from langchain.chains import LLMChain from langchain.prompts import PromptTemplate from langchain.document_loaders import PyPDFLoader from langchain.text_splitter import CharacterTextSplitter from langchain.output_parsers import JsonOutputToolsParser, PydanticOutputParser from langchain.prompts import ChatPromptTemplate, HumanMessagePromptTemplate QA_DATASET_GENERATION_PROMPT = PromptTemplate.from_template( "You are an expert on generate question-and-answer dataset based on a given context. You are given a context. " "Your task is to generate a question and answer based on the context. The generated question should be able to" " to answer by leverage the given context. And the generated question-and-answer pair must be grammatically " "and semantically correct. Your response must be in a json format with 2 keys: question, answer. For example," "\n\n" "Context: France, in Western Europe, encompasses medieval cities, alpine villages and Mediterranean beaches. Paris, its capital, is famed for its fashion houses, classical art museums including the Louvre and monuments like the Eiffel Tower." "\n\n" "Response: {{" "\n" " \"question\": \"Where is France and what is it's capital?\"," "\n" " \"answer\": \"France is in Western Europe and it's capital is Paris.\"" "\n" "}}" "\n\n" "Context: The University of California, Berkeley is a public land-grant research university in Berkeley, California. Established in 1868 as the state's first land-grant university, it was the first campus of the University of California system and a founding member of the Association of American Universities." "\n\n" "Response: {{" "\n" " \"question\": \"When was the University of California, Berkeley established?\"," "\n" " \"answer\": \"The University of California, Berkeley was established in 1868.\"" "\n" "}}" "\n\n" "Now your task is to generate a question-and-answer dataset based on the following context:" "\n\n" "Context: {context}" "\n\n" "Response: ", ) OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") if OPENAI_API_KEY is None: raise ValueError("OPENAI_API_KEY is not set") llm = ChatOpenAI( model="gpt-4-1106-preview", api_key=OPENAI_API_KEY, temperature=0.7, response_format={ "type": "json_object" }, ) chain = LLMChain( prompt=QA_DATASET_GENERATION_PROMPT, llm=llm ) file_loader = PyPDFLoader("./data/cidr_lakehouse.pdf") text_splitter = CharacterTextSplitter(chunk_size=1000) chunks = text_splitter.split_documents(file_loader.load()) questions, answers = [], [] for chunk in chunks: for _ in range(2): response = chain.invoke({ "context": chunk }) obj = json.loads(response["text"]) questions.append(obj["question"]) answers.append(obj["answer"]) df = pd.DataFrame({ "question": questions, "answer": answers }) df.to_csv("./data/cidr_lakehouse_qa.csv", index=False)


Después de ejecutar el código mencionado anteriormente, obtenemos un archivo CSV como resultado. Este archivo contiene pares de preguntas y respuestas relacionadas con el documento que ingresamos, de la siguiente manera:

Corpus de control de calidad sintetizado para el artículo "Lakehouse: una nueva generación de plataformas abiertas que unifican el almacenamiento de datos y el análisis avanzado".


Luego, construimos cadenas simples de DocumentRetrievalQA usando Langchain y las sustituimos por varios LLM de código abierto que operan localmente a través de Ollama. Puedes encontrar mi tutorial anterior sobre eso aquí.

 from tqdm import tqdm from langchain.chains import RetrievalQA from langchain.chat_models import ChatOllama from langchain.vectorstores import FAISS from langchain.embeddings import HuggingFaceEmbeddings vector_store = FAISS.from_documents(chunks, HuggingFaceEmbeddings()) retriever = vector_store.as_retriever() def test_local_retrieval_qa(model: str): chain = RetrievalQA.from_llm( llm=ChatOllama(model=model), retriever=retriever, ) predictions = [] for it, row in tqdm(df.iterrows(), total=len(df)): resp = chain.invoke({ "query": row["question"] }) predictions.append(resp["result"]) df[f"{model}_result"] = predictions test_local_retrieval_qa("mistral") test_local_retrieval_qa("llama2") test_local_retrieval_qa("zephyr") test_local_retrieval_qa("orca-mini") test_local_retrieval_qa("phi") df.to_csv("./data/cidr_lakehouse_qa_retrieval_prediction.csv", index=False)


En resumen, el código anterior establece una cadena de recuperación de documentos simple. Ejecutamos esta cadena utilizando varios modelos, como Mistral, Llama2, Zephyr, Orca-mini y Phi. Como resultado, agregamos cinco columnas adicionales a nuestro DataFrame existente para almacenar los resultados de predicción de cada modelo LLM.

Resultados de la predicción de control de calidad.


Ahora, definamos una cadena maestra usando GPT-4 de OpenAI para evaluar los resultados de la predicción. En esta configuración, calcularemos una puntuación de corrección similar a una puntuación F1 aproximada, como es común en los problemas tradicionales de IA/ML. Para lograr esto, aplicaremos conceptos paralelos como Verdaderos Positivos (TP), Falsos Positivos (FP) y Falsos Negativos (FN), definidos de la siguiente manera:


  • TP: Declaraciones que están presentes tanto en la respuesta como en la verdad fundamental.
  • FP: Declaraciones presentes en la respuesta pero no encontradas en la verdad fundamental.
  • FN: Declaraciones relevantes encontradas en la verdad sobre el terreno pero omitidas en la respuesta.


Con estas definiciones, podemos calcular la precisión, la recuperación y la puntuación F1 utilizando las siguientes fórmulas:

Puntuación F1 usando fórmulas


 import os import numpy as np import pandas as pd from tqdm import tqdm from langchain.chains import LLMChain from langchain.chat_models import ChatOpenAI from langchain.prompts import PromptTemplate OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") if OPENAI_API_KEY is None: raise ValueError("OPENAI_API_KEY is not set") CORRECTNESS_PROMPT = PromptTemplate.from_template( """ Extract following from given question and ground truth. Your response must be in a json format with 3 keys and does not need to be in any specific order: - statements that are present in both the answer and the ground truth - statements present in the answer but not found in the ground truth - relevant statements found in the ground truth but omitted in the answer Please be concise and do not include any unnecessary information. You should classify the statements as claims, facts, or opinions with semantic matching, no need exact word-by-word matching. Question:What powers the sun and what is its primary function? Answer: The sun is powered by nuclear fission, similar to nuclear reactors on Earth, and its primary function is to provide light to the solar system. Ground truth: The sun is actually powered by nuclear fusion, not fission. In its core, hydrogen atoms fuse to form helium, releasing a tremendous amount of energy. This energy is what lights up the sun and provides heat and light, essential for life on Earth. The sun's light also plays a critical role in Earth's climate system and helps to drive the weather and ocean currents. Extracted statements: [ {{ "statements that are present in both the answer and the ground truth": ["The sun's primary function is to provide light"], "statements present in the answer but not found in the ground truth": ["The sun is powered by nuclear fission", "similar to nuclear reactors on Earth"], "relevant statements found in the ground truth but omitted in the answer": ["The sun is powered by nuclear fusion, not fission", "In its core, hydrogen atoms fuse to form helium, releasing a tremendous amount of energy", "This energy provides heat and light, essential for life on Earth", "The sun's light plays a critical role in Earth's climate system", "The sun helps to drive the weather and ocean currents"] }} ] Question: What is the boiling point of water? Answer: The boiling point of water is 100 degrees Celsius at sea level. Ground truth: The boiling point of water is 100 degrees Celsius (212 degrees Fahrenheit) at sea level, but it can change with altitude. Extracted statements: [ {{ "statements that are present in both the answer and the ground truth": ["The boiling point of water is 100 degrees Celsius at sea level"], "statements present in the answer but not found in the ground truth": [], "relevant statements found in the ground truth but omitted in the answer": ["The boiling point can change with altitude", "The boiling point of water is 212 degrees Fahrenheit at sea level"] }} ] Question: {question} Answer: {answer} Ground truth: {ground_truth} Extracted statements:""", ) judy_llm = ChatOpenAI( model="gpt-4-1106-preview", api_key=OPENAI_API_KEY, temperature=0.0, response_format={ "type": "json_object" }, ) judy_chain = LLMChain( prompt=CORRECTNESS_PROMPT, llm=judy_llm ) def evaluate_correctness(column_name: str): chain = LLMChain( prompt=CORRECTNESS_PROMPT, llm=ChatOpenAI( model="gpt-4-1106-preview", api_key=OPENAI_API_KEY, temperature=0.0, response_format={ "type": "json_object" }, ) ) key_map = { "TP": "statements that are present in both the answer and the ground truth", "FP": "statements present in the answer but not found in the ground truth", "FN": "relevant statements found in the ground truth but omitted in the answer", # noqa: E501 } TP, FP, FN = [], [], [] for it, row in tqdm(df.iterrows(), total=len(df)): resp = chain.invoke({ "question": row["question"], "answer": row[column_name], "ground_truth": row["answer"] }) obj = json.loads(resp["text"]) TP.append(len(obj[key_map["TP"]])) FP.append(len(obj[key_map["FP"]])) FN.append(len(obj[key_map["FN"]])) # convert to numpy array TP = np.array(TP) FP = np.array(FP) FN = np.array(FN) df[f"{column_name}_recall"] = TP / (TP + FN) df[f"{column_name}_precision"] = TP / (TP + FP) df[f"{column_name}_correctness"] = 2 * df[f"{column_name}_recall"] * df[f"{column_name}_precision"] / (df[f"{column_name}_recall"] + df[f"{column_name}_precision"]) evaluate_correctness("mistral_result") evaluate_correctness("llama2_result") evaluate_correctness("zephyr_result") evaluate_correctness("orca-mini_result") evaluate_correctness("phi_result") print("|====Model====|=== Recall ===|== Precision ==|== Correctness ==|") print(f"|mistral | {df['mistral_result_recall'].mean():.4f} | {df['mistral_result_precision'].mean():.4f} | {df['mistral_result_correctness'].mean():.4f} |") print(f"|llama2 | {df['llama2_result_recall'].mean():.4f} | {df['llama2_result_precision'].mean():.4f} | {df['llama2_result_correctness'].mean():.4f} |") print(f"|zephyr | {df['zephyr_result_recall'].mean():.4f} | {df['zephyr_result_precision'].mean():.4f} | {df['zephyr_result_correctness'].mean():.4f} |") print(f"|orca-mini | {df['orca-mini_result_recall'].mean():.4f} | {df['orca-mini_result_precision'].mean():.4f} | {df['orca-mini_result_correctness'].mean():.4f} |") print(f"|phi | {df['phi_result_recall'].mean():.4f} | {df['phi_result_precision'].mean():.4f} | {df['phi_result_correctness'].mean():.4f} |") print("|==============================================================|") df.to_csv("./data/cidr_lakehouse_qa_retrieval_prediction_correctness.csv", index=False) 


Resultado


Bien, ahora tenemos un punto de referencia simple para varios modelos. Esto puede considerarse como un indicador preliminar de cómo cada modelo maneja la tarea de recuperación de documentos. Si bien estas cifras ofrecen una instantánea, son sólo el comienzo de la historia. Sirven como base para comprender qué modelos son mejores para recuperar información precisa y relevante de un corpus determinado. Puedes encontrar el código fuente aquí .

Retroalimentación humana en bucle

Cuando se trata de ajustar nuestra IA a través de Human-In-Loop Feedback, la sinergia entre los evaluadores humanos y el Master LLM es fundamental. Esta relación no se trata simplemente de recopilar comentarios, sino de crear un sistema de inteligencia artificial receptivo que se adapte y aprenda de los aportes humanos.

El proceso interactivo

  • La aportación del evaluador: los evaluadores interactúan con la cadena RAG + LLM y evalúan sus resultados desde una perspectiva humana. Proporcionan retroalimentación sobre aspectos como la relevancia, precisión y naturalidad de las respuestas de la IA.
  • Comentarios al Master LLM: Aquí es donde ocurre la magia. Los comentarios de los evaluadores humanos se comunican directamente al Master LLM. A diferencia de los modelos estándar, el Master LLM está diseñado para comprender e interpretar esta retroalimentación para perfeccionar sus resultados posteriores.
  • Ajuste de indicaciones por parte de Master LLM: armado con esta retroalimentación, Master LLM ajusta la indicación para nuestro LLM de desarrollo. Este proceso es análogo a un mentor que instruye a un estudiante. El Master LLM modifica cuidadosamente la forma en que el LLM de desarrollo interpreta y reacciona a las indicaciones, asegurando un mecanismo de respuesta más efectivo y contextualmente consciente.

El doble papel del Master LLM

El Master LLM funciona como punto de referencia para el LLM desarrollado internamente y como participante activo en el circuito de retroalimentación. Evalúa la retroalimentación, ajusta las indicaciones o los parámetros del modelo y esencialmente "aprende" de las interacciones humanas.

El beneficio de la adaptación en tiempo real

Este proceso es transformador. Permite que la IA se adapte en tiempo real, haciéndola más ágil y alineada con las complejidades del lenguaje y los procesos de pensamiento humanos. Esta adaptación en tiempo real garantiza que la curva de aprendizaje de la IA sea pronunciada y continua.

El ciclo de mejora

A través de este ciclo de interacción, retroalimentación y adaptación, nuestra IA se convierte en algo más que una simple herramienta; se convierte en una entidad de aprendizaje, capaz de mejorar a través de cada interacción con un evaluador humano. Este modelo humano-in-the-loop garantiza que nuestra IA no se estanque, sino que evolucione para convertirse en un asistente más eficiente e intuitivo.


En resumen, Human-In-Loop Feedback no se trata solo de recopilar conocimientos humanos, sino de crear una IA dinámica y adaptable que pueda ajustar su comportamiento para servir mejor a los usuarios. Este proceso iterativo garantiza que nuestras aplicaciones RAG + LLM permanezcan a la vanguardia, brindando no solo respuestas, sino respuestas matizadas y contextualmente conscientes que reflejan una comprensión genuina de las necesidades del usuario.


Para una demostración sencilla, puede ver cómo ClearML utiliza este concepto para mejorar Promptimizer en este vídeo .

Fase de Operación

La transición a la fase de operación es como pasar de los ensayos generales a la noche del estreno. Aquí, nuestras aplicaciones RAG + LLM ya no son entidades hipotéticas; se convierten en participantes activos en los flujos de trabajo diarios de usuarios reales. Esta fase es la prueba de fuego de toda la preparación y ajuste realizado en la fase de desarrollo.


En esta fase, nuestros equipos (operaciones, productos y analistas) se alinean para implementar y administrar las aplicaciones, garantizando que todo lo que hemos creado no solo funcione sino que también prospere en un entorno real. Es aquí donde podemos plantearnos implementar estrategias de testing A/B para medir la eficacia de nuestras aplicaciones de forma controlada.


  • Marco de pruebas A/B: dividimos nuestra base de usuarios en dos segmentos: el segmento de control, que continúa usando la versión establecida de la aplicación (Versión 1), y el segmento de prueba, que prueba las nuevas funciones de la Versión 2 (en realidad También puedes ejecutar varias pruebas A/B al mismo tiempo). Esto nos permite recopilar datos comparativos sobre la experiencia del usuario, la receptividad de las funciones y el rendimiento general.

  • Implementación operativa: el equipo de operaciones tiene la tarea de implementar sin problemas ambas versiones, garantizando que la infraestructura sea sólida y que cualquier transición de versión sea fluida para el usuario.

  • Evolución del producto: el equipo de producto, al tanto de los comentarios de los usuarios, trabaja para iterar el producto. Este equipo garantiza que las nuevas funciones se alineen con las necesidades del usuario y la visión general del producto.

  • Información analítica: el equipo de analistas examina rigurosamente los datos recopilados de la prueba A/B. Sus conocimientos son fundamentales para determinar si la nueva versión supera a la anterior y si está lista para un lanzamiento más amplio.

  • Métricas de rendimiento: los indicadores clave de rendimiento (KPI) se monitorean para medir el éxito de cada versión. Estos incluyen métricas de participación del usuario, puntuaciones de satisfacción y la precisión de los resultados de la aplicación.


La fase de operación es dinámica y está informada por ciclos de retroalimentación continua que no solo mejoran las aplicaciones sino que también mejoran la participación y la satisfacción del usuario. Es una fase caracterizada por el seguimiento, el análisis, la iteración y, sobre todo, el aprendizaje de los datos en vivo.


Mientras navegamos por esta fase, nuestro objetivo no solo es mantener los altos estándares establecidos por la fase de desarrollo, sino también superarlos, asegurando que nuestra aplicación RAG + LLM permanezca a la vanguardia de la innovación y la usabilidad.

Conclusión

En resumen, la integración de la generación aumentada de recuperación (RAG) y los modelos de lenguaje grande (LLM) marca un avance significativo en la IA, combinando la recuperación profunda de datos con la generación de texto sofisticada. Sin embargo, necesitamos un método de evaluación adecuado y eficaz y una estrategia de desarrollo iterativa. La fase de desarrollo enfatiza la personalización de la evaluación de la IA y su mejora con retroalimentación humana, asegurando que estos sistemas sean empáticos y adaptables a escenarios del mundo real. Este enfoque destaca la evolución de la IA de una mera herramienta a un socio colaborativo. La fase operativa prueba estas aplicaciones en escenarios del mundo real, utilizando estrategias como pruebas A/B y ciclos de retroalimentación continua para garantizar la efectividad y la evolución continua basada en la interacción del usuario.