La idea principal de LangChain Agent es utilizar LLM como un cerebro para pensar automáticamente, tomar decisiones y ejecutar diferentes acciones para finalmente lograr nuestras tareas objetivo.
Consejo: Desde una perspectiva de desarrollo, esto significa que desarrollamos varios APIs de antemano y luego le damos al Agente una tarea, permitiendo que LLM analice qué API llamar para completar la tarea.
Para comprender mejor el problema que LangChain Agent pretende resolver, consideremos un ejemplo.
Por ejemplo:
Si queremos investigar si "Docker se puede utilizar como una solución de implementación en producción", primero buscaríamos "introducción a Docker" en Baidu, navegaríamos por los resultados de la búsqueda, y luego buscaríamos "ventajas y desventajas de la implementación de Docker" y revisaríamos los resultados, y así sucesivamente, hasta llegar a una conclusión.
LangChain Agent tiene como objetivo simular este proceso. Puedo preempaquetar una serie de herramientas (por ejemplo, búsqueda en Baidu, herramientas de extracción de contenido de URL), y luego darle al Agente una tarea objetivo "¿Se puede utilizar Docker como una solución de implementación en producción?" El Agente construirá indicaciones para llamar a LLM. Para lograr esta tarea, el siguiente paso es ejecutar qué acción (es decir, llamar a qué herramienta). La IA devolverá la herramienta a llamar, el código ejecutará esta herramienta, luego pasará los resultados de la ejecución de la herramienta de vuelta a la IA, y preguntará cuál es el próximo paso para ejecutar qué herramienta. Repitiendo este proceso se completará la tarea mencionada anteriormente.
Consejo: Desde el lanzamiento del modelo GPT, esta es una capacidad explosiva, permitiendo que LLM actúe como el cerebro, piense activamente y luego llame a varios APIs que hemos desarrollado. Esto mejora enormemente las capacidades de LLM. Actualmente, esta función todavía está en la etapa experimental y llamará repetidamente a LLL, por lo que consume bastantes tokens. Completar una tarea puede costar decenas de miles de tokens en minutos. Si desea ahorrar dinero, se recomienda primero dejar que LLM realice tareas de juicio lógico simples.
Conceptos Principales
Ahora introduciremos componentes y conceptos relacionados.
Agente
Un Agente puede entenderse como nuestro asistente, actuando en nuestro nombre para tomar decisiones. En la implementación subyacente del Agente de LangChain, es a través de LLM que se determina la próxima acción (o llamada a API). El modo ReAct describe el proceso de toma de decisiones de la IA. Los interesados pueden explorar esto más a fondo.
LangChain proporciona varios tipos de Agente para diferentes escenarios.
Herramientas
Creo que es mejor entender las Herramientas como APIs, preempaquetadas con varias APIs funcionales diseñadas para expandir las capacidades de LLM. LLM determina qué API específica llamar para completar una tarea.
Conjuntos de herramientas
Los conjuntos de herramientas generalmente proporcionan a LLM no solo una o dos herramientas, sino un conjunto de herramientas para dar a LLM más opciones al completar tareas.
AgentExecutor
El ejecutor proxy es responsable de ejecutar la herramienta (API) seleccionada por LLM. El seudocódigo para esta ejecución es el siguiente:
next_action = agent.get_action(...)
while next_action != AgentFinish:
observation = run(next_action)
next_action = agent.get_action(..., next_action, observation)
return next_action
Aunque el proceso de ejecución no es complicado, el ejecutor maneja muchos problemas detallados, principalmente incluyendo:
- Manejar la situación en la que el agente selecciona una herramienta inexistente.
- Manejar situaciones de error de herramientas.
- Manejar situaciones en las que el agente produce una salida que no se puede resolver como una llamada a herramienta.
- Problemas de depuración.
Inicio rápido
Esta sección presenta el uso básico del Agente de LangChain.
1. Cargar LLM
Primero, carguemos el modelo de lenguaje (LLM) que utilizaremos para controlar el agente.
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
2. Definir Herramientas
A continuación, definimos algunas herramientas para que el Agente las llame. Escribiremos una función simple en Python para calcular la longitud de la palabra de entrada.
from langchain.agents import tool
@tool
def get_word_length(word: str) -> int:
"""Devuelve la longitud de la palabra."""
return len(word)
get_word_length.invoke("abc")
Nota: Los comentarios de las funciones son muy importantes. Le dicen a LLM qué problema puede resolver llamándolos. La función
get_word_length
le dice a LLM que puede calcular la longitud de una palabra.
3
Definir un conjunto de herramientas
tools = [get_word_length]
3. Crear un Prompt
Ahora crearemos un prompt. Debido a que la llamada de función de OpenAI ha sido optimizada para el uso de herramientas, apenas necesitamos instrucciones sobre el razonamiento o el formato de salida. Solo tenemos dos variables de entrada: input
y agent_scratchpad
. input
representa la pregunta de entrada del usuario, y agent_scratchpad
es un marcador de posición para las instrucciones de llamada del agente, que se insertarán en la plantilla del prompt al ejecutar el comando de llamada de la herramienta.
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"Eres un asistente muy poderoso pero no comprendes la situación actual.",
),
("user", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
]
)
4. Vincular Herramientas a LLM
¿Cómo sabe el agente qué herramientas puede utilizar?
Esto depende de la característica de llamada de herramientas de OpenAI (muchos modelos admiten características similares). Solo tenemos que indicar al modelo el formato de llamada de herramientas definido.
llm_with_tools = llm.bind_tools(tools)
5. Creación de un agente
Ahora que hemos integrado el contenido anterior, podemos proceder a crear el programa proxy. Importaremos las dos últimas funciones de utilidad práctica: una para formatear pasos intermedios (acciones proxy, salidas de herramientas) en mensajes de entrada que se pueden enviar al modelo, y otra para convertir mensajes de salida en acciones proxy/finales del proxy.
from langchain.agents.format_scratchpad.openai_tools import format_to_openai_tool_messages
from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser
agente = (
{
"input": lambda x: x["input"],
"agent_scratchpad": lambda x: format_to_openai_tool_messages(x["intermediate_steps"]),
}
| prompt
| llm_with_tools
| OpenAIToolsAgentOutputParser()
)
Definición del ejecutor del agente
from langchain.agents import AgentExecutor
ejecutor_agente = AgentExecutor(agent=agente, tools=herramientas, verbose=True)
Demostraremos el funcionamiento del programa proxy a través de un ejemplo:
list(ejecutor_agente.stream({"input": "¿Cuántas letras hay en la palabra 'educa'?"}))
Ejemplo de registro de salida del agente
> Entrando en una nueva cadena de ejecución del agente...
Invocación: Ejecutando `get_word_length` con el parámetro `{'word': 'educa'}`
Hay 5 letras en la palabra "educa".
> Cadena de ejecución completada.
A través de este ejemplo, hemos demostrado el proceso completo del programa proxy.
Agregar funcionalidad de memoria al Agente
Si queremos que el agente recuerde conversaciones anteriores, en realidad es bastante simple: solo necesitamos insertar el contenido devuelto por la IA en el prompt y enviarlo junto a la IA.
Modificando la plantilla del prompt
A continuación modificamos la plantilla del prompt para incluir una variable de plantilla de historial de conversación.
from langchain.prompts import MessagesPlaceholder
MEMORY_KEY = "historial_chat"
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"Eres un gran asistente, pero no eres bueno calculando la longitud de las palabras.",
),
MessagesPlaceholder(variable_name=MEMORY_KEY),
("user", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
]
)
Modificando la definición del proceso del agente
Modifica la definición del proceso del agente para proporcionar datos de historial de conversación para la plantilla del prompt, como se muestra en el siguiente código, agregando el manejo del parámetro chat_history
.
agente = (
{
"input": lambda x: x["input"],
"agent_scratchpad": lambda x: format_to_openai_tool_messages(
x["intermediate_steps"]
),
"chat_history": lambda x: x["chat_history"],
}
| prompt
| llm_with_tools
| OpenAIToolsAgentOutputParser()
)
ejecutor_agente = AgentExecutor(agent=agente, herramientas=herramientas, verbose=True)
chat_history = []
input1 = "¿Cuántas letras hay en la palabra 'educa'?"
result = agent_executor.invoke({"input": input1, "chat_history": chat_history})
chat_history.extend(
[
HumanMessage(content=input1),
AIMessage(content=result["output"]),
]
)
agent_executor.invoke({"input": "¿Esta palabra realmente existe?", "chat_history": chat_history})