A ideia principal do Agente LangChain é usar LLM como um cérebro para pensar automaticamente, tomar decisões e executar diferentes ações para alcançar nossas tarefas alvo.

Dica: Do ponto de vista do desenvolvimento, isso significa que desenvolvemos várias APIs antecipadamente e então damos uma tarefa ao Agente, permitindo que o LLM analise qual API chamar para completar a tarefa.

Para entender melhor o problema que o Agente LangChain visa resolver, vamos considerar um exemplo.

Por exemplo:

Se quisermos pesquisar se "Docker pode ser usado como solução de implantação em produção", primeiro pesquisaríamos "introdução ao Docker" no Baidu, navegaríamos pelos resultados da pesquisa e depois pesquisaríamos "vantagens e desvantagens da implantação do Docker" e navegaríamos pelos resultados, e assim por diante, até chegarmos a uma conclusão.

O Agente LangChain visa simular esse processo. Eu posso pré-empacotar uma série de ferramentas (por exemplo, busca no Baidu, ferramentas de extração de conteúdo de URL) e então dar ao Agente a tarefa alvo "Docker pode ser usado como solução de implantação em produção?" O Agente então construirá prompts para chamar o LLM. Para alcançar esta tarefa, o próximo passo é executar qual ação (ou seja, chamar qual ferramenta). A IA retornará a ferramenta a ser chamada, o código executará esta ferramenta e depois passará os resultados da execução da ferramenta de volta para a IA e pedirá pelo próximo passo em executar qual ferramenta. Repetindo este processo completará a tarefa mencionada anteriormente.

Dica: Desde o lançamento do modelo GPT, esta é uma capacidade explosiva, permitindo que o LLM atue como o cérebro, pense ativamente e então chame várias APIs que desenvolvemos. Isso aprimora muito as capacidades do LLM. Atualmente, este recurso ainda está na fase experimental e chamará repetidamente o LLM, então ele consome bastante tokens. Completar uma tarefa pode custar dezenas de milhares de tokens em minutos. Se você quer economizar dinheiro, é recomendado primeiro permitir que o LLM realize tarefas de julgamento lógico simples.

Conceitos Principais

Agora vamos introduzir os componentes e conceitos relacionados.

Agente

Um Agente pode ser compreendido como nosso assistente, agindo em nosso nome para tomar decisões. Na implementação subjacente do Agente LangChain, é através do LLM que a próxima ação (ou chamada de API) é determinada. O modo ReAct descreve o processo de tomada de decisão da IA. Aqueles interessados podem explorar isso mais a fundo.

LangChain fornece vários tipos de Agentes para diferentes cenários.

Ferramentas

Eu acho que Ferramentas são melhor compreendidas como APIs, pré-empacotadas com várias APIs funcionais projetadas para expandir as capacidades do LLM. O LLM determina qual API específica chamar para completar uma tarefa.

Conjuntos de Ferramentas

Os Conjuntos de Ferramentas geralmente fornecem ao LLM não apenas uma ou duas ferramentas, mas um conjunto de ferramentas para dar ao LLM mais opções ao completar tarefas.

Executor do Agente

O executor proxy é responsável por executar a ferramenta (API) selecionada pelo LLM. O pseudocódigo para esta execução é o seguinte:

próxima_ação = agente.obter_ação(...)
enquanto próxima_ação != AgenteTerminar:
    observação = executar(próxima_ação)
    próxima_ação = agente.obter_ação(..., próxima_ação, observação)
retorne próxima_ação

Embora o processo de execução não seja complicado, o executor lida com muitas questões detalhadas, incluindo principalmente:

  1. Lidar com a situação em que o agente seleciona uma ferramenta inexistente
  2. Lidar com situações de erro da ferramenta
  3. Lidar com situações em que o agente produz saídas que não podem ser resolvidas como uma chamada de ferramenta
  4. Questões de depuração.

Início Rápido

Esta seção introduz o uso básico do Agente da LangChain.

1. Carregar LLM

Primeiro, vamos carregar o modelo de linguagem (LLM) que iremos usar para controlar o agente.

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)

2. Definir Ferramentas

Em seguida, definimos algumas ferramentas para o Agente chamar. Escreveremos uma função Python muito simples para calcular o comprimento da palavra de entrada.

from langchain.agents import tool

@tool
def get_word_length(word: str) -> int:
    """Retorna o comprimento da palavra."""
    return len(word)

get_word_length.invoke("abc")

Nota: Comentários de função são muito importantes. Eles dizem ao LLM que problema ele pode resolver chamando-os. A função get_word_length diz ao LLM que pode calcular o comprimento de uma palavra.

3

Definir um conjunto de ferramentas

ferramentas = [get_word_length]

3. Criar um Prompt

Agora vamos criar um prompt. Como a Chamada de Função OpenAI foi otimizada para uso de ferramentas, praticamente não precisamos de instruções sobre raciocínio ou formato de saída. Nós só temos duas variáveis de entrada: input e agent_scratchpad. input representa a pergunta de entrada do usuário, e agent_scratchpad é um espaço reservado para as instruções de chamada do agente, que serão inseridas no modelo do prompt ao executar o comando da chamada da ferramenta.

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "Você é um assistente muito poderoso, mas não compreende a situação atual.",
        ),
        ("user", "{input}"),
        MessagesPlaceholder(variable_name="agent_scratchpad"),
    ]
)

4. Vincular Ferramentas ao LLM

Como o agente sabe quais ferramentas pode usar?

Isso depende do recurso de chamada de ferramenta da OpenAI (muitos modelos suportam recursos semelhantes). Só precisamos informar ao modelo o formato de chamada de ferramenta definido.

llm_with_tools = llm.bind_tools(tools)

5. Criando um agente

Agora que integramos o conteúdo anterior, podemos prosseguir para criar o programa proxy. Vamos importar as últimas duas funções de utilidade prática: uma para formatar etapas intermediárias (ações do proxy, saídas de ferramentas) em mensagens de entrada que podem ser enviadas ao modelo, e outra para converter mensagens de saída em ações do proxy/finais do proxy.

from langchain.agents.format_scratchpad.openai_tools import format_to_openai_tool_messages
from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser

agent = (
    {
        "input": lambda x: x["input"],
        "agent_scratchpad": lambda x: format_to_openai_tool_messages(x["intermediate_steps"]),
    }
    | prompt
    | llm_with_tools
    | OpenAIToolsAgentOutputParser()
)

Definindo o executor do agente

from langchain.agents import AgentExecutor

agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

Vamos demonstrar a operação do programa proxy por meio de um exemplo:

list(agent_executor.stream({"input": "Quantas letras há na palavra 'eudca'?"}))

Exemplo de log de saída do agente

> Entrando em uma nova cadeia de execução do agente...

Invocação: Executando `get_word_length` com o parâmetro `{'word': 'educa'}`

Existem 5 letras na palavra "educa".

> Cadeia de execução concluída.

Por meio desse exemplo, demonstramos o processo completo do programa proxy.

Adicionando funcionalidade de memória ao Agente

Se desejarmos que o agente se lembre de conversas anteriores, é bastante simples: precisamos apenas inserir o conteúdo retornado pela IA no prompt e enviá-lo junto à IA.

Modificando o modelo do prompt

Abaixo, modificamos o modelo do prompt para incluir uma variável de modelo de histórico de conversa.

from langchain.prompts import MessagesPlaceholder

MEMORY_KEY = "chat_history"
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "Você é um ótimo assistente, mas não é bom em calcular o comprimento das palavras.",
        ),
        MessagesPlaceholder(variable_name=MEMORY_KEY),
        ("user", "{input}"),
        MessagesPlaceholder(variable_name="agent_scratchpad"),
    ]
)

Modificando a definição do processo do agente

Modifique a definição do processo do agente para fornecer dados de histórico de conversa para o modelo do prompt, como mostrado no código a seguir, adicionando o tratamento do parâmetro chat_history.

agent = (
    {
        "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()
)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
chat_history = []

input1 = "Quantas letras há na palavra 'educa'?"
result = executor_do_agente.invocar({"input": input1, "chat_history": chat_history})
chat_history.extend(
    [
        MensagemHumana(conteudo=input1),
        MensagemDoAgente(conteudo=result["output"]),
    ]
)
executor_do_agente.invocar({"input": "Essa palavra realmente existe?", "chat_history": chat_history})