curso
Tutorial de encadenamiento de instrucciones: ¿Qué es el encadenamiento de instrucciones y cómo utilizarlo?
¿Has intentado alguna vez montar un mueble sin leer las instrucciones? Si tienes suerte, puede que consigas juntar algunas piezas, pero el resultado puede ser bastante desordenado sin una guía paso a paso. Esto es similar al reto al que se enfrentan los grandes modelos lingüísticos (LLM) cuando abordan problemas complejos. Estos modelos tienen un potencial increíble, pero a menudo no dan en el blanco cuando una tarea requiere un razonamiento detallado y de varios pasos.
Cuando se les da una sola pregunta, los LLM pueden dar respuestas demasiado generales, poco profundas o que omiten detalles críticos. Esta limitación se debe a la dificultad de captar todo el contexto necesario y proporcionar una orientación adecuada en una sola indicación.
La solución es encadenamiento rápido.
El encadenamiento de instrucciones consiste en dividir una tarea compleja en una serie de instrucciones más pequeñas y manejables. Cada pregunta aborda una parte específica de la tarea, y la salida de una pregunta sirve como entrada para la siguiente. Este método permite un enfoque más estructurado, guiando al LLM a través de una cadena de pasos de razonamiento que conducen a una respuesta más precisa y completa. Mediante una secuencia lógica de indicaciones, podemos utilizar plenamente los LLM para resolver eficazmente problemas complejos.
Este tutorial forma parte de mi "Ingeniería Prompt: Serie de entradas de blog "De cero a héroe":
- Ingeniería rápida para todos
- Aviso de disparo cero
- Pocos disparos
- Encadenamiento de avisos
¿Qué es el encadenamiento de peticiones?
El encadenamiento de instrucciones es un método en el que la salida de una instrucción LLM se utiliza como entrada para la siguiente instrucción de una secuencia. Esta técnica consiste en crear una serie de indicaciones conectadas, cada una de ellas centrada en una parte específica del problema general. Seguir esta secuencia permite guiar al LLM a través de un proceso de razonamiento estructurado, ayudándole a producir respuestas más precisas y detalladas.
El objetivo principal del encadenamiento rápido es mejorar el rendimiento, la fiabilidad y la claridad de las aplicaciones LLM. Para las tareas complejas, una sola indicación a menudo no proporciona suficiente profundidad y contexto para una buena respuesta. El encadenamiento de avisos resuelve esto dividiendo la tarea en pasos más pequeños, asegurando que cada paso se maneja con cuidado. Este método mejora la calidad del resultado del LLM y facilita la comprensión de cómo se ha llegado al resultado final.
Veamos algunas de las ventajas del encadenamiento rápido:
Benefíciate |
Descripción |
Ejemplo |
Rompe la complejidad |
Descompone las tareas complejas en subtareas más pequeñas y manejables, permitiendo al LLM centrarse en un aspecto cada vez. |
Generar un trabajo de investigación paso a paso (esquema, apartados, conclusión) en lugar de todo a la vez. |
Mejora la precisión |
Guía el razonamiento del LLM a través de pasos intermedios, proporcionando más contexto para respuestas precisas y relevantes. |
Diagnosticar un problema técnico identificando los síntomas, reduciendo las causas y sugiriendo soluciones. |
Mejora la explicabilidad |
Aumenta la transparencia en el proceso de toma de decisiones del LLM, facilitando la comprensión de cómo se llega a las conclusiones. |
Explicar una decisión jurídica exponiendo las leyes pertinentes, aplicándolas a un caso y llegando a una conclusión con cada paso claramente documentado. |
Cómo implementar el encadenamiento de instrucciones
Implementar el encadenamiento de avisos implica un enfoque sistemático para descomponer una tarea compleja y guiar a un LLM a través de una serie de pasos bien definidos.
Veamos cómo puedes crear y ejecutar eficazmente una cadena de avisos.
Identificar subtareas
El primer paso en el encadenamiento de tareas es descomponer la tarea compleja en subtareas más pequeñas y manejables. Cada subtarea debe representar un aspecto distinto del problema general. De este modo, el LLM puede centrarse en una parte cada vez.
Por ejemplo, supongamos que quieres que el LLM redacte un informe exhaustivo sobre el cambio climático. Las subtareas podrían incluir
- Investigar datos climáticos históricos
- Resumir las principales conclusiones de la literatura científica
- Analizar el impacto del cambio climático en diferentes ecosistemas
- Proponer posibles soluciones y estrategias de mitigación
Sugerencias de diseño
A continuación, diseña indicaciones claras y concisas para cada subtarea. Cada indicación debe ser específica y directa, para garantizar que el LLM comprende la tarea y puede generar resultados relevantes. Y lo que es más importante, el resultado de un estímulo debe ser adecuado como entrada para el siguiente, creando un flujo de información.
Para nuestras subtareas anteriores, podríamos crear los siguientes avisos:
- Subtarea 1 Prompt: "Resume las tendencias clave de los cambios de temperatura global durante el siglo pasado".
- Subtarea 2 Prompt: "Basándote en las tendencias identificadas, enumera los principales estudios científicos que discuten las causas de estos cambios".
- Subtarea 3 Prompt: "Resume las conclusiones de los estudios enumerados, centrándote en el impacto del cambio climático en los ecosistemas marinos".
- Subtarea 4 Prompt: "Proponer tres estrategias para mitigar el impacto del cambio climático en los ecosistemas marinos basadas en las conclusiones resumidas".
Ejecución en cadena
Ahora tenemos que ejecutar los avisos secuencialmente, pasando la salida de un aviso como entrada del siguiente. Esta ejecución paso a paso garantiza que el LLM se base en sus resultados anteriores, creando un resultado cohesionado y completo.
Para nuestro ejemplo, los resultados de nuestras subtareas serían algo así:
- Resultado de la subtarea 1: "La temperatura global ha aumentado aproximadamente 1,2 grados Celsius en el último siglo, observándose aumentos significativos en los últimos 20 años".
- Aportaciones para la subtarea 2: "Dado que las temperaturas globales han aumentado 1,2 grados centígrados en el último siglo, enumera los principales estudios científicos que discuten las causas de estos cambios".
- Resultado de la subtarea 2: "Los estudios clave incluyen: El papel de los gases de efecto invernadero en el calentamiento global", por el Dr. Smith, "Deforestación y cambio climático" del Dr. Jones, y "Cambios oceánicos y patrones climáticos" del Dr. Lee".
- Aportaciones para la subtarea 3: "Resume las conclusiones de 'El papel de los gases de efecto invernadero en el calentamiento global', del Dr. Smith, "Deforestación y cambio climático" del Dr. Jones, y "Cambios oceánicos y patrones climáticos" del Dr. Lee, centrándose en el impacto del cambio climático en los ecosistemas marinos".
Tratamiento de errores
Implementar mecanismos de gestión de errores es clave para abordar posibles problemas durante la ejecución rápida. Esto puede incluir el establecimiento de comprobaciones para verificar la calidad y relevancia del resultado antes de pasar a la siguiente pregunta, y la creación de preguntas de emergencia para guiar al LLM por el buen camino si se desvía de la ruta esperada. Por ejemplo:
- Comprobación de errores 1: Después de cada salida, comprueba que la información es pertinente y completa. Si el resumen de las tendencias de los cambios de temperatura global es incompleto, pide al LLM que proporcione detalles adicionales.
- Pregunta de emergencia: Si el LLM no enumera estudios científicos relevantes, utiliza una indicación más específica como "Enumera cinco estudios revisados por expertos de la última década que traten sobre las causas del aumento de la temperatura global".
Aplicación
¡Veamos cómo implementar esto en Python!
Paso 1: Configurar el entorno
En primer lugar, tenemos que importar las bibliotecas necesarias. Utilizaremos la clase OpenAI
del paquete openai
y os
para gestionar las variables de entorno.
import openai
import os
Almacenar de forma segura la información sensible, como las claves API, es crucial. Una forma de conseguirlo es establecer la clave API como variable de entorno. Puedes hacerlo utilizando una API de OpenAI de OpenAI.
os.environ['OPENAI_API_KEY'] = 'your-api-key-here'
Asegúrate de sustituir 'your-api-key-here'
por tu clave de API de OpenAI real.
Con la clave API establecida, ahora puedes inicializar el cliente OpenAI. Este cliente se utilizará para hacer llamadas a la API de los servicios de OpenAI.
Client = OpenAI ()
Paso 2: Definir una función para interactuar con la API de finalización de chat de OpenAI.
Ahora, crearemos una función Python para interactuar con la API de finalización de chat de OpenAI. Esta función preguntará a la API y devolverá la respuesta generada.
def get_completion(prompt, model="gpt-3.5-turbo"):
try:
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": prompt}
],
temperature=0,
)
return response.choices[0].message.content
except Exception as e:
print(f"An error occurred: {e}")
return None
Desglosemos esta función-it:
- Toma un indicador y un parámetro opcional del modelo.
- Realiza una llamada a la API de OpenAI utilizando el punto final de finalización del chat.
- Establece la conversación con un mensaje del sistema y un mensaje del usuario (el aviso).
- Ajusta la temperatura a 0 para obtener salidas más deterministas (aumenta la temperatura para obtener salidas más creativas).
- Devuelve el contenido de la respuesta o
None
si se produce un error.
Paso 3: Encadenar varios avisos
Ahora, crearemos una función Python que encadene múltiples avisos, alimentando la salida de un aviso como entrada del siguiente.
def prompt_chain(initial_prompt, follow_up_prompts):
result = get_completion(initial_prompt)
if result is None:
return "Initial prompt failed."
print(f"Initial output: {result}\n")
for i, prompt in enumerate(follow_up_prompts, 1):
full_prompt = f"{prompt}\n\nPrevious output: {result}"
result = get_completion(full_prompt)
if result is None:
return f"Prompt {i} failed."
print(f"Step {i} output: {result}\n")
return result
La función prompt_chain
implementa el encadenamiento de avisos. Ello:
- Comienza con un aviso inicial y consigue su finalización.
- Recorre una lista de indicaciones de seguimiento.
- Para cada consulta de seguimiento, combina la consulta con la salida anterior, obtiene una finalización para esta consulta combinada y actualiza el resultado.
- Si falla algún paso, devuelve un mensaje de error.
- La salida de cada paso se imprime para que sea visible.
Paso 4: Ejemplo de uso
Ahora demostraremos cómo utilizar la función prompt_chain
para crear una secuencia de avisos que se construyan unos sobre otros. Este ejemplo se centrará en resumir las tendencias clave de los cambios de temperatura global y explorar los estudios científicos y las estrategias de mitigación relacionadas, ¡pero puedes aplicarlo a tu propio caso de uso!
initial_prompt = "Summarize the key trends in global temperature changes over the past century."
follow_up_prompts = [
"Based on the trends identified, list the major scientific studies that discuss the causes of these changes.",
"Summarize the findings of the listed studies, focusing on the impact of climate change on marine ecosystems.",
"Propose three strategies to mitigate the impact of climate change on marine ecosystems based on the summarized findings."
]
final_result = prompt_chain(initial_prompt, follow_up_prompts)
print("Final result:", final_result)
Aquí, definimos una pregunta inicial sobre los cambios de temperatura global y, a continuación, establecemos una lista de preguntas de seguimiento que se basan unas en otras. A continuación, llamamos a la función prompt_chain
con estas indicaciones y, por último, imprimimos el resultado final.
Cómo funciona en conjunto
Resumamos el proceso:
- La indicación inicial obtiene un resumen de las tendencias de temperatura.
- El primer seguimiento utiliza este resumen para encontrar estudios relevantes.
- El segundo seguimiento resume las conclusiones de estos estudios sobre los ecosistemas marinos.
- El aviso final utiliza toda esta información para proponer estrategias de mitigación.
Este encadenamiento permite un enfoque paso a paso de las consultas complejas, en el que cada paso se basa en la información de los pasos anteriores.
Técnicas de encadenamiento de instrucciones
El encadenamiento de instrucciones puede aplicarse de varias formas para adaptarse a distintos tipos de tareas y requisitos. Aquí exploramos tres técnicas principales: Encadenamiento Secuencial, Encadenamiento Condicional y Encadenamiento en Bucle.
Encadenamiento secuencial
El encadenamiento secuencial consiste en enlazar las indicaciones en una secuencia directa y lineal. Cada indicación depende de la salida de la anterior, creando un flujo de información y tareas paso a paso. Esta técnica es ideal para tareas que requieren una progresión lógica de una etapa a otra, como por ejemplo:
- Resumen de textos: Descomponer un documento largo en secciones resumidas, y luego combinar esos resúmenes en un resumen general cohesionado.
- Generación de código: Generar fragmentos de código paso a paso, como crear primero definiciones de funciones, luego implementar esas funciones y, por último, escribir casos de prueba.
El fragmento de código de la sección anterior es un ejemplo de encadenamiento secuencial.
Encadenamiento condicional
El encadenamiento condicional introduce bifurcaciones en la cadena de avisos en función de la salida del LLM. Esta técnica permite flujos de trabajo más flexibles y adaptables, permitiendo que el LLM tome diferentes caminos en función de las respuestas que genere.
Veamos cómo podemos aplicar el encadenamiento condicional para realizar el análisis de sentimientos.
def analyze_sentiment(text):
prompt = f"Analyze the sentiment of the following text and respond with only one word - 'positive', 'negative', or 'neutral': {text}"
sentiment = get_completion(prompt)
return sentiment.strip().lower()
def conditional_prompt_chain(initial_prompt):
result = get_completion(initial_prompt)
if result is None:
return "Initial prompt failed."
print(f"Initial output: {result}\n")
sentiment = analyze_sentiment(result)
print(f"Sentiment: {sentiment}\n")
if sentiment == 'positive':
follow_up = "Given this positive outlook, what are three potential opportunities we can explore?"
elif sentiment == 'negative':
follow_up = "Considering these challenges, what are three possible solutions we can implement?"
else: # neutral
follow_up = "Based on this balanced view, what are three key areas we should focus on for a comprehensive approach?"
final_result = get_completion(f"{follow_up}\n\nContext: {result}")
return final_result
# Example usage
initial_prompt = "Analyze the current state of renewable energy adoption globally."
final_result = conditional_prompt_chain(initial_prompt)
print("Final result:", final_result)
En primer lugar, definimos una nueva función, analyze_sentiment()
, que utiliza el modelo lingüístico para determinar el sentimiento de un texto dado. A continuación, en la función conditional_prompt_chain()
, empezamos con la pregunta inicial sobre la adopción de energías renovables. Tras obtener la respuesta inicial, analizamos su sentimiento. En función del sentimiento, elegimos una indicación de seguimiento diferente:
- Para un sentimiento positivo, preguntamos por las oportunidades.
- Para un sentimiento negativo, preguntamos por las soluciones.
- Para un sentimiento neutro, preguntamos por las áreas de interés clave.
La indicación de seguimiento elegida se envía entonces al modelo lingüístico junto con el contexto de la respuesta inicial. El resultado final es la respuesta a esta pregunta de seguimiento condicional.
Observa que la elección de la segunda pregunta no está predeterminada, sino que depende del contenido de la primera respuesta. Además, el flujo de la conversación se adapta en función del análisis de sentimientos, mostrando cómo la cadena puede bifurcarse en distintos caminos. Esto permite interacciones más dinámicas y conscientes del contexto con el modelo lingüístico.
Cuando ejecutes este código, la pregunta de seguimiento específica dependerá de si el análisis inicial de la adopción de energías renovables se percibe como positivo, negativo o neutro. Esto crea una cadena de avisos más adaptable y receptiva.
Encadenamiento en bucle
El encadenamiento de bucles consiste en crear bucles dentro de una cadena de instrucciones para iterar sobre los datos o realizar tareas repetitivas. Esta técnica es útil cuando se trata de listas o colecciones de elementos que requieren pasos de procesamiento similares. Algunos de los beneficios y retos de este enfoque son:
- Eficacia: Automatiza las tareas repetitivas, ahorrando tiempo y esfuerzo.
- Procesamiento de datos: Adecuado para tareas como el procesamiento de múltiples registros, la integración por lotes o las mejoras iterativas.
- Desafíos: Requiere un manejo cuidadoso para evitar bucles infinitos y garantizar que cada iteración produzca un progreso significativo.
Veamos cómo se implementaría el encadenamiento en bucle para una tarea de completitud de texto:
def check_completeness(text):
prompt = f"Analyze the following text and respond with only 'complete' if it covers all necessary aspects, or 'incomplete' if more information is needed:\n\n{text}"
response = get_completion(prompt)
return response.strip().lower() == 'complete'
def looping_prompt_chain(initial_prompt, max_iterations=5):
current_response = get_completion(initial_prompt)
if current_response is None:
return "Initial prompt failed."
print(f"Initial output: {current_response}\n")
iteration = 0
while iteration < max_iterations:
if check_completeness(current_response):
print(f"Complete response achieved after {iteration + 1} iterations.")
return current_response
print(f"Iteration {iteration + 1}: Response incomplete. Expanding...")
expand_prompt = f"The following response is incomplete. Please expand on it to make it more comprehensive:\n\n{current_response}"
new_response = get_completion(expand_prompt)
if new_response is None:
return f"Expansion failed at iteration {iteration + 1}."
current_response = new_response
print(f"Expanded response: {current_response}\n")
iteration += 1
print(f"Maximum iterations ({max_iterations}) reached without achieving completeness.")
return current_response
# Example usage
initial_prompt = "Explain the process of photosynthesis."
final_result = looping_prompt_chain(initial_prompt)
print("Final result:", final_result)
En primer lugar, definimos una nueva función, check_completeness()
, que utiliza el modelo lingüístico para determinar si una respuesta dada está completa o necesita más información.
A continuación, en la función looping_prompt_chain()
, empezamos con la pregunta inicial sobre la fotosíntesis. Tras obtener la respuesta inicial, entramos en un bucle:
- Comprobamos si la respuesta actual está completa utilizando
comprobar_completitud().
- Si se completa, salimos del bucle y devolvemos el resultado.
- Si está incompleta, generamos una nueva pregunta para que amplíes la respuesta anterior.
- A continuación, obtenemos una nueva respuesta basada en esta solicitud de ampliación.
Este proceso continúa hasta que obtengamos una respuesta considerada completa o alcancemos el número máximo de iteraciones (por defecto es 5).
El bucle garantiza que sigamos refinando y ampliando la respuesta hasta que se considere completa o lleguemos al límite de iteración.
Cuando ejecutes este código, intentará proporcionar una explicación exhaustiva de la fotosíntesis, pudiendo pasar por múltiples iteraciones de expansión si las respuestas iniciales se consideran incompletas. Esto crea una cadena de indicaciones más completa y adaptable, con el objetivo de obtener un resultado final completo.
Aplicaciones prácticas del encadenamiento de instrucciones
El encadenamiento de avisos puede mejorar significativamente las capacidades de los LLM en diversas aplicaciones. En esta sección, exploramos algunos usos prácticos del encadenamiento de avisos, demostrando cómo puede aplicarse a tareas del mundo real.
Respuesta a preguntas sobre documentos
El encadenamiento de preguntas puede utilizarse para resumir documentos largos y luego generar respuestas a preguntas concretas. Esto implica, en primer lugar, dividir el documento en secciones manejables, resumir cada sección y, a continuación, utilizar estos resúmenes para responder a preguntas detalladas.
Veamos cómo ponerlo en práctica:
def split_document(document, max_length=1000):
"""Split the document into sections of approximately max_length characters."""
words = document.split()
sections = []
current_section = []
current_length = 0
for word in words:
if current_length + len(word) + 1 > max_length and current_section:
sections.append(' '.join(current_section))
current_section = []
current_length = 0
current_section.append(word)
current_length += len(word) + 1
if current_section:
sections.append(' '.join(current_section))
return sections
def summarize_section(section):
prompt = f"Summarize the following text in a concise manner:\n\n{section}"
return get_completion(prompt)
def answer_question(summaries, question):
context = "\n\n".join(summaries)
prompt = f"Given the following context, answer the question:\n\nContext:\n{context}\n\nQuestion: {question}"
return get_completion(prompt)
def document_qa(document, questions):
# Step 1: Split the document
sections = split_document(document)
print(f"Document split into {len(sections)} sections.")
# Step 2: Summarize each section
summaries = []
for i, section in enumerate(sections):
summary = summarize_section(section)
summaries.append(summary)
print(f"Section {i+1} summarized.")
# Step 3: Answer questions
answers = []
for question in questions:
answer = answer_question(summaries, question)
answers.append((question, answer))
return answers
# Example usage
long_document = """
[Insert a long document here. For brevity, we are using a placeholder.
In a real scenario, this would be a much longer text, maybe several
paragraphs or pages about a specific topic.]
This is a long document about climate change. It discusses various aspects
including causes, effects, and potential solutions. The document covers
topics such as greenhouse gas emissions, rising global temperatures,
melting ice caps, sea level rise, extreme weather events, impact on
biodiversity, and strategies for mitigation and adaptation.
The document also explores the economic implications of climate change,
international agreements like the Paris Agreement, renewable energy
technologies, and the role of individual actions in combating climate change.
[Continue with more detailed information about climate change...]
"""
questions = [
"What are the main causes of climate change mentioned in the document?",
"What are some of the effects of climate change discussed?",
"What solutions or strategies are proposed to address climate change?"
]
results = document_qa(long_document, questions)
for question, answer in results:
print(f"\nQ: {question}")
print(f"A: {answer}")
Este fragmento de código demuestra cómo se puede utilizar el encadenamiento de instrucciones para tareas complejas como el análisis de documentos y la respuesta a preguntas. Descompone una tarea grande (comprender un documento largo) en pasos más pequeños y manejables (resumir secciones). Utiliza el resultado de un paso (resúmenes) como entrada para el siguiente (responder preguntas). Permite gestionar documentos que podrían ser demasiado largos para procesarlos en una sola solicitud.
Cuando ejecutes este código con un documento largo real, dividirá el documento en secciones manejables, resumirá cada sección y utilizará estos resúmenes para responder a las preguntas proporcionadas sobre las causas, efectos y soluciones del cambio climático.
Generación de textos con verificación de hechos
La generación de texto con verificación de hechos implica generar texto e incorporar pasos de verificación de hechos dentro de la cadena de indicaciones. Esto garantiza que el resultado no sólo sea coherente, sino también preciso.
def generate_text(topic):
prompt = f"Write a short paragraph about {topic}."
return get_completion(prompt)
def extract_facts(text):
prompt = f"Extract the key factual claims from the following text, listing each claim on a new line:\n\n{text}"
return get_completion(prompt)
def verify_facts(facts):
verified_facts = []
for fact in facts.split('\n'):
if fact.strip():
prompt = f"Verify the following statement and respond with 'True' if it's factually correct, 'False' if it's incorrect, or 'Uncertain' if it can't be verified without additional research: '{fact}'"
verification = get_completion(prompt)
verified_facts.append((fact, verification.strip()))
return verified_facts
def revise_text(original_text, verified_facts):
context = "Original text:\n" + original_text + "\n\nVerified facts:\n"
for fact, verification in verified_facts:
context += f"- {fact}: {verification}\n"
prompt = f"{context}\n\nRewrite the original text, keeping the verified facts, removing or correcting any false information, and indicating any uncertain claims as 'It is claimed that...' or similar phrasing."
return get_completion(prompt)
def text_generation_with_verification(topic):
print(f"Generating text about: {topic}")
# Step 1: Generate initial text
initial_text = generate_text(topic)
print("\nInitial Text:")
print(initial_text)
# Step 2: Extract facts
extracted_facts = extract_facts(initial_text)
print("\nExtracted Facts:")
print(extracted_facts)
# Step 3: Verify facts
verified_facts = verify_facts(extracted_facts)
print("\nVerified Facts:")
for fact, verification in verified_facts:
print(f"- {fact}: {verification}")
# Step 4: Revise text
revised_text = revise_text(initial_text, verified_facts)
print("\nRevised Text:")
print(revised_text)
return revised_text
# Example usage
topic = "the effects of climate change on polar bears"
final_text = text_generation_with_verification(topic)
La función text_generation_with_verification()
gestiona todo el proceso. Comienza utilizando generate_text()
para crear un párrafo inicial sobre el tema. A continuación, extract_facts()
extrae afirmaciones clave de este texto. verify_facts()
comprueba estas afirmaciones, etiquetándolas como Verdadero, Falso o Incierto. Por último, revise_text()
reescribe el texto original, corrigiendo los errores y anotando la información incierta. Este proceso ayuda a garantizar que el texto final sea informativo y preciso.
El encadenamiento de indicaciones se produce en varios pasos: la generación inicial del texto, la extracción de hechos del texto generado, la verificación de cada hecho extraído y la revisión del texto basada en los hechos verificados.
Cuando ejecutes este código con un tema como "los efectos del cambio climático en los osos polares", generará un texto inicial sobre el tema, extraerá afirmaciones fácticas de este texto, verificará cada una de estas afirmaciones y revisará el texto basándose en los hechos verificados, garantizando un resultado final más preciso. ¡Recuerda que puedes utilizar el tema que prefieras!
Generación de código con depuración
Utilizar el encadenamiento de instrucciones para escribir código y luego probarlo puede acelerar el desarrollo. Este método ayuda a asegurarse de que el código funciona correctamente y hace lo que se supone que debe hacer. Va más allá de asegurarse de que el código se ejecuta sin errores.
def generate_code(task):
prompt = f"Write a Python function to {task}. Include comments explaining the code."
return get_completion(prompt)
def generate_test_cases(code):
prompt = f"Given the following Python code, generate 3 test cases to verify its functionality. Include both input and expected output for each test case:\n\n{code}"
return get_completion(prompt)
def run_tests(code, test_cases):
prompt = f"""
Given the following Python code and test cases, run the tests and report the results.
If any tests fail, explain why and suggest fixes.
Code:
{code}
Test Cases:
{test_cases}
For each test case, respond with:
1. "PASS" if the test passes
2. "FAIL" if the test fails, along with an explanation of why it failed and a suggested fix
"""
return get_completion(prompt)
def debug_code(code, test_results):
prompt = f"""
Given the following Python code and test results, debug the code to fix any issues.
Provide the corrected code along with explanations of the changes made.
Original Code:
{code}
Test Results:
{test_results}
"""
return get_completion(prompt)
def code_generation_with_debugging(task):
print(f"Generating code for task: {task}")
# Step 1: Generate initial code
initial_code = generate_code(task)
print("\nInitial Code:")
print(initial_code)
# Step 2: Generate test cases
test_cases = generate_test_cases(initial_code)
print("\nGenerated Test Cases:")
print(test_cases)
# Step 3: Run tests
test_results = run_tests(initial_code, test_cases)
print("\nTest Results:")
print(test_results)
# Step 4: Debug code if necessary
if "FAIL" in test_results:
print("\nDebugging code...")
debugged_code = debug_code(initial_code, test_results)
print("\nDebugged Code:")
print(debugged_code)
# Optionally, you can run tests again on the debugged code
print("\nRe-running tests on debugged code...")
final_test_results = run_tests(debugged_code, test_cases)
print("\nFinal Test Results:")
print(final_test_results)
return debugged_code
else:
print("\nAll tests passed. No debugging necessary.")
return initial_code
# Example usage
task = "calculate the factorial of a number"
final_code = code_generation_with_debugging(task)
La función code_generation_with_debugging()
gestiona todo el proceso. Funciona así: En primer lugar, generate_code()
escribe algo de código Python para la tarea. A continuación, generate_test_cases()
crea pruebas para este código. run_tests()
comprueba si el código supera estas pruebas. Si alguna prueba falla, debug_code()
intenta solucionar los problemas.
Ten en cuenta que cada paso se basa en el anterior. Empieza escribiendo código, luego haz pruebas, ejecútalas y corrige cualquier problema. Esto descompone la codificación en pasos más pequeños y sencillos. Este método muestra cómo el encadenamiento de instrucciones puede manejar tareas complejas como la codificación. Copia cómo trabajan los programadores de verdad: escribe código, pruébalo y soluciona cualquier problema. Cada paso utiliza lo anterior, lo que permite una mejora constante del código.
Cuando ejecutes este código con una tarea como "calcular el factorial de un número", generará código Python inicial para calcular el factorial, creará casos de prueba para esta función, simulará la ejecución de estas pruebas e informará de los resultados. Si falla alguna prueba, intentará depurar y corregir el código, y luego volverá a ejecutar las pruebas.
Tareas de razonamiento en varios pasos
El encadenamiento de instrucciones puede resolver problemas complejos que requieran múltiples pasos de razonamiento, como problemas matemáticos de palabras o rompecabezas lógicos. Cada paso se basa en el anterior, garantizando un enfoque estructurado y exhaustivo.
def solve_step_by_step(problem):
steps = []
current_problem = problem
while True:
prompt = f"Solve the following problem step by step. Provide the next step only and explain it clearly:\n\n{current_problem}"
step = get_completion(prompt)
if step is None or "solution" in step.lower():
break
steps.append(step)
current_problem = f"{current_problem}\n\n{step}"
print(f"Step {len(steps)}: {step}\n")
return steps
def combine_steps(steps):
combined_steps = "\n".join(steps)
prompt = f"Combine the following steps into a coherent solution for the problem:\n\n{combined_steps}"
return get_completion(prompt)
def multi_step_reasoning(problem):
print(f"Solving problem: {problem}")
# Step 1: Solve step by step
steps = solve_step_by_step(problem)
# Step 2: Combine steps into a final solution
final_solution = combine_steps(steps)
print("\nFinal Solution:")
print(final_solution)
return final_solution
# Example usage
problem = "A car travels 60 miles per hour for 2 hours, then 40 miles per hour for 3 hours. What is the total distance traveled by the car?"
final_solution = multi_step_reasoning(problem)
En primer lugar, solve_step_by_step()
descompone el problema en partes más pequeñas. Pregunta al modelo de IA por cada paso, uno a uno, hasta completar la solución. Cada paso se guarda. A continuación, combine_steps()
toma todos estos pasos y pide a la IA que los fusione en una explicación clara. La función get_completion()
se encarga de hablar con la API de OpenAI durante todo este proceso.
Para este ejemplo, resolverá este problema: "Un coche circula a 100 km/h durante 2 horas, luego a 65 km/h durante 3 horas. ¿Hasta dónde llega en total?"
Cuando ejecutes este código, descompondrá el problema en pasos de razonamiento más pequeños, recogerá e imprimirá cada paso, y combinará los pasos en una solución final y la imprimirá.
Buenas prácticas para el encadenamiento de instrucciones
Es esencial seguir ciertas prácticas recomendadas para maximizar la eficacia del encadenamiento de avisos. Estas prácticas garantizan que tus cadenas sean sólidas, precisas y eficientes, lo que conduce a mejores resultados y a aplicaciones LLM más fiables.
Diseño rápido
Utilizar indicaciones claras y concisas es esencial para obtener los mejores resultados de un LLM. Cuando tus indicaciones son directas, el modelo puede entender fácilmente lo que necesitas, lo que reduce la confusión y mejora la calidad de las respuestas.
Aquí tienes algunos consejos:
- Utiliza un lenguaje sencillo: Evita las palabras complejas y la jerga técnica.
- Sé directo: Expresa claramente lo que quieres sin añadir detalles innecesarios.
- Céntrate en una tarea: Cada pregunta debe abordar una única tarea o cuestión.
Por ejemplo:
- En lugar de: "¿Podrías resumir los puntos clave de las tendencias históricas de las temperaturas globales durante el siglo pasado, centrándote en cualquier cambio significativo y sus posibles causas, así como en los acontecimientos notables que pudieran haber influido en estas tendencias?"
- Utiliza: "Resume los puntos clave de las tendencias históricas de la temperatura global durante el siglo pasado".
Utilizar indicaciones bien estructuradas también es clave para ayudar al LLM a seguir el flujo lógico de una tarea. Cuando tus indicaciones están organizadas y son coherentes, el modelo puede comprenderlas mejor y responder adecuadamente.
Aquí tienes algunos consejos:
- Desglosa las tareas complejas: Divide la tarea en pasos más pequeños y manejables.
- Garantiza un flujo lógico: Asegúrate de que cada pregunta se basa en la anterior y conduce lógicamente a la siguiente.
Estructurar las preguntas de este modo guía al LLM paso a paso a través de la tarea, lo que conduce a respuestas mejores y más precisas. Por ejemplo:
- Paso 1: "Enumera los principales cambios en las temperaturas globales durante el siglo pasado".
- Paso 2: "Identifica las causas potenciales de cada cambio importante en las temperaturas globales".
Experimentación
Diferentes tareas necesitan diferentes formas de encadenar las indicaciones. Elegir el método adecuado para tu tarea puede suponer una gran diferencia. Es una buena idea probar distintos enfoques y ver qué funciona mejor para lo que intentas hacer. Probar y comparar puede ayudarte a encontrar la mejor manera de obtener buenos resultados.
Es importante que compruebes a menudo el funcionamiento de tus cadenas de impulsos. Fíjate en lo precisos, completos y relevantes que son los resultados. Esto te ayuda a ver lo que funciona y lo que hay que mejorar. Si lo haces con regularidad, podrás introducir cambios y mejoras según sea necesario y asegurarte de que obtienes los mejores resultados.
Refinamiento iterativo
El perfeccionamiento iterativo basado en las reacciones y los resultados conduce a indicaciones más precisas y eficaces. Puedes mejorar continuamente el rendimiento de tu LLM recogiendo opiniones de los resultados, identificando las deficiencias y ajustando las indicaciones en consecuencia. Este proceso continuo garantiza que tus indicaciones sean cada vez más precisas y pertinentes con el paso del tiempo. Por ejemplo:
- Indicación inicial: "Describe el impacto del cambio climático".
- Aviso refinado: "Describe el impacto del cambio climático en los ecosistemas costeros durante la última década".
Afinar la estructura de la cadena
La forma en que dispongas tu cadena de impulsos puede afectar realmente al resultado final. Cambiar el orden y la lógica de tus indicaciones es útil en función de lo que veas que funciona. Así te aseguras de que cada paso tenga sentido después del anterior. Cuando hagas esto, podrás obtener respuestas mejores y más lógicas de la IA.
Tratamiento de errores
El sólido tratamiento de errores garantiza que la cadena de avisos pueda seguir funcionando aunque fallen avisos individuales. Estableciendo comprobaciones de la validez de la salida y utilizando avisos de retroceso, puedes guiar al LLM para que vuelva al buen camino cuando se produzcan errores. Este enfoque mantiene el flujo y la fiabilidad de la cadena rápida, garantizando un rendimiento constante.
Monitorización y registro
Es importante que vigiles el funcionamiento de tus cadenas rápidas. Esto te ayuda a entender qué es eficaz y a detectar cualquier problema. Utiliza herramientas para registrar información importante, como lo que entra en las indicaciones, lo que sale y cuánto tiempo lleva. Por ejemplo, anota cada paso de la cadena, lo que se produce y los errores que se producen. Si lo haces, podrás estudiar el proceso y mejorarlo, con lo que obtendrás mejores resultados.
Llevar un registro detallado te ayuda a solucionar problemas y a mejorar tus cadenas rápidas. Guarda estos registros de forma ordenada para que sea más fácil estudiarlos y aprender de ellos. Esto te ayuda a detectar problemas y a afinar tus cadenas rápidas. Como resultado, puedes hacer que funcionen mejor y den respuestas más precisas
Seguir estas prácticas recomendadas te permitirá crear cadenas de avisos eficaces y fiables que mejoren las capacidades de los LLM, asegurándote de que obtienes un mejor rendimiento y resultados más significativos en diversas aplicaciones.
Conclusión
En este artículo exploramos el encadenamiento de instrucciones, una técnica para mejorar el rendimiento de los LLM en tareas complejas dividiéndolas en instrucciones más pequeñas y manejables. Cubrimos diferentes métodos de encadenamiento, sus aplicaciones y las mejores prácticas para ayudarte a aprovechar eficazmente los LLM para una amplia gama de casos de uso.
Si quieres saber más sobre la ingeniería rápida, te recomiendo estos artículos:
Preguntas frecuentes
¿Existen marcos o herramientas que faciliten el encadenamiento rápido para los LLM?
Aunque no existe un marco específico para el encadenamiento de impulsos, pueden utilizarse herramientas como LangChain, PyTorch y TensorFlow para implementar y gestionar flujos de trabajo de encadenamiento de impulsos, utilizando sus capacidades para manejar datos secuenciales y salidas de modelos.
¿Cuáles son algunos enfoques alternativos para mejorar el rendimiento del LLM además del encadenamiento de avisos?
El ajuste fino sobre conjuntos de datos específicos del dominio, la destilación de conocimientos, la integración de funciones, el refinamiento iterativo y el ajuste de parámetros son algunos enfoques alternativos.
Ofrecen ventajas únicas y pueden utilizarse individualmente o en combinación para mejorar el rendimiento del LLM en tareas o casos de uso específicos.
¿Puede integrarse el encadenamiento de avisos con sistemas automatizados para aplicaciones en tiempo real?
Sí, el encadenamiento de avisos puede integrarse en sistemas automatizados como chatbots, asistentes virtuales y plataformas de análisis de datos en tiempo real para mejorar la precisión y coherencia de sus respuestas y resultados.
¿Cuáles son los retos potenciales de implantar el encadenamiento de avisos en entornos de producción?
Los retos incluyen gestionar las dependencias puntuales, garantizar una baja latencia para las aplicaciones en tiempo real, gestionar eficazmente los errores y las salidas incompletas, y mantener la escalabilidad y el rendimiento del sistema a medida que aumenta la complejidad de las tareas.
Más información sobre la IA
curso
ChatGPT Prompt Ingeniería para Desarrolladores
programa
Desarrollo de aplicaciones de IA
blog
¿Qué es un algoritmo?
DataCamp Team
11 min
blog
Clasificación en machine learning: Introducción
blog
¿Qué es la Inteligencia artificial limitada (Artificial Narrow Intelligence, ANI)?
blog
¿Qué es la IA simbólica?
DataCamp Team
4 min
tutorial
Tutorial sobre cómo crear aplicaciones LLM con LangChain
tutorial
Agrupación jerárquica en R
DataCamp Team
15 min