L'idea fondamentale di LangChain Agent è utilizzare LLM come cervello per pensare automaticamente, prendere decisioni ed eseguire diverse azioni per ultimare i compiti stabiliti.

Suggerimento: Da un punto di vista dello sviluppo, ciò significa sviluppare vari API in anticipo e quindi assegnare al Agente un compito, permettendo a LLM di analizzare quale API chiamare per completare il compito.

Per comprendere meglio il problema che LangChain Agent mira a risolvere, consideriamo un esempio.

Ad esempio:

Se vogliamo verificare se "Docker può essere utilizzato come soluzione di distribuzione in produzione", dovremmo prima cercare "introduzione a Docker" su Baidu, esaminare i risultati della ricerca, e quindi cercare ulteriormente "vantaggi e svantaggi della distribuzione di Docker" e esaminare i risultati, e così via, fino a giungere a una conclusione.

LangChain Agent mira a simulare questo processo. Posso preparare una serie di strumenti (ad esempio, ricerca su Baidu, strumenti di estrazione del contenuto URL), e poi assegnare al Agente un compito "Posso utilizzare Docker come soluzione di distribuzione in produzione?" L'Agente costruirà prompt per chiamare LLM. Per raggiungere questo compito, il prossimo passo è eseguire quale azione (cioè, chiamare quale strumento). L'IA restituirà lo strumento da chiamare, il codice eseguirà questo strumento, quindi passerà i risultati dell'esecuzione dello strumento all'IA e chiederà il prossimo passo nell'eseguire quale strumento. Ripetendo questo processo si completerà il compito menzionato in precedenza.

Suggerimento: Dall'uscita del modello GPT, questa è una capacità esplosiva, che consente a LLM di agire come il cervello, pensare attivamente e quindi chiamare vari API che abbiamo sviluppato. Questo potenzia notevolmente le capacità di LLM. Attualmente, questa funzionalità è ancora in fase sperimentale e chiamerà ripetutamente LLM, quindi consuma parecchi token. Completare un compito può costare decine di migliaia di token in pochi minuti. Se si desidera risparmiare denaro, si consiglia di lasciare prima che LLM esegua semplici compiti di giudizio logico.

Concetti principali

Introduciamo ora i componenti e i concetti correlati.

Agente

Un Agente può essere compreso come il nostro assistente, agire per nostro conto per prendere decisioni. Nell'implementazione sottostante di LangChain Agent, è attraverso LLM che viene determinata la prossima azione (o chiamata API). ReAct mode descrive il processo decisionale dell'IA. Coloro interessati possono esplorare questo ulteriormente.

LangChain fornisce diversi tipi di Agent per scenari diversi.

Strumenti

Penso che gli Strumenti siano meglio compresi come API, preconfezionate con varie API funzionali progettate per espandere le capacità di LLM. LLM determina quale specifica API chiamare per completare un compito.

Toolkit

I Toolkit di solito forniscono a LLM non solo uno o due strumenti, ma un insieme di strumenti per dare a LLM più opzioni nel completare i compiti.

AgentExecutor

Il proxy executor è responsabile dell'esecuzione dello strumento (API) selezionato da LLM. Il codice pseudo per questa runtime è il seguente:

next_action = agent.get_action(...)
while next_action != AgentFinish:
    observation = run(next_action)
    next_action = agent.get_action(..., next_action, observation)
return next_action

Anche se il processo di esecuzione non è complicato, l'esecutore gestisce molti dettagli, principalmente inclusi:

  1. Gestione della situazione in cui l'agente seleziona uno strumento inesistente
  2. Gestione delle situazioni di errore dello strumento
  3. Gestione delle situazioni in cui l'agente produce un output che non può essere risolto come chiamata di uno strumento
  4. Questioni di debug.

Avvio rapido

Questa sezione introduce l'uso di base di LangChain's Agent.

1. Caricare LLM

Prima, carichiamo il modello di linguaggio (LLM) che utilizzeremo per controllare l'agente.

from langchain_openai import ChatOpenAI

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

2. Definire Strumenti

Successivamente, definiamo alcuni strumenti da chiamare per l'Agente. Scriviamo una funzione Python molto semplice per calcolare la lunghezza della parola in input.

from langchain.agents import tool

@tool
def get_word_length(word: str) -> int:
    """Restituisce la lunghezza della parola."""
    return len(word)

get_word_length.invoke("abc")

Nota: I commenti della funzione sono molto importanti. Dicono a LLM quale problema può risolvere chiamandoli. La funzione get_word_length dice a LLM che può calcolare la lunghezza di una parola.

3

Definire un insieme di strumenti

tools = [get_word_length]

3. Creare un prompt

Ora creiamo un prompt. Poiché la chiamata della funzione OpenAI è stata ottimizzata per l'uso degli strumenti, non abbiamo bisogno di istruzioni riguardanti il ragionamento o il formato di output. Abbiamo solo due variabili di input: input e agent_scratchpad. input rappresenta la domanda inserita dall'utente, e agent_scratchpad è un segnaposto per le istruzioni di chiamata dell'agente, che verranno inserite nel modello del prompt durante l'esecuzione del comando di chiamata dello strumento.

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages(
    [
        (
            "sistema",
            "Sei un assistente molto potente ma non capisci la situazione attuale.",
        ),
        ("utente", "{input}"),
        MessagesPlaceholder(variable_name="agent_scratchpad"),
    ]
)

4. Collegare gli Strumenti a LLM

Come fa l'agente a sapere quali strumenti può utilizzare?

Ciò dipende dalla funzionalità di chiamata degli strumenti OpenAI (molti modelli supportano funzionalità simili). Dobbiamo solo dire al modello il formato di chiamata degli strumenti definito.

llm_with_tools = llm.bind_tools(tools)

5. Creare un agente

Ora che abbiamo integrato il contenuto precedente, possiamo procedere a creare il programma proxy. Importeremo le ultime due funzioni utility pratiche: una per formattare i passaggi intermedi (azioni proxy, output degli strumenti) in messaggi di input che possono essere inviati al modello, e un'altra per convertire i messaggi di output in azioni proxy/termini 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()
)

Definizione dell'esecutore dell'agente

from langchain.agents import AgentExecutor

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

Dimostriamo il funzionamento del programma proxy attraverso un esempio:

list(agent_executor.stream({"input": "Quante lettere ci sono nella parola 'eudca'?"}))

Esempio di log di output dell'agente

> Entrando in una nuova catena di esecuzione dell'agente...

Invocazione: Esecuzione di `get_word_length` con il parametro `{'word': 'educa'}`

Ci sono 5 lettere nella parola "educa".

> Catena di esecuzione completata.

Attraverso questo esempio, abbiamo dimostrato il processo completo del programma proxy.

Aggiunta della funzionalità di memoria all'agente

Se vogliamo che l'agente ricordi le conversazioni precedenti, è semplice: dobbiamo solo inserire il contenuto restituito dall'IA nel prompt e inviarlo insieme all'IA.

Modifica del modello del prompt

Di seguito modifico il modello del prompt per includere una variabile di modello per la cronologia della conversazione.

from langchain.prompts import MessagesPlaceholder

MEMORY_KEY = "chat_history"
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "sistema",
            "Sei un grande assistente, ma non bravo a calcolare la lunghezza delle parole.",
        ),
        MessagesPlaceholder(variable_name=MEMORY_KEY),
        ("utente", "{input}"),
        MessagesPlaceholder(variable_name="agent_scratchpad"),
    ]
)

Modifica della definizione del processo dell'agente

Modifico la definizione del processo dell'agente per fornire i dati della cronologia della conversazione al modello del prompt, come mostrato nel seguente codice, aggiungendo la gestione del parametro 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)

Fornire dati sulla cronologia delle conversazioni durante l'invocazione dell'agente

chat_history = []

input1 = "Quante lettere ci sono nella parola '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": "Questa parola esiste davvero?", "chat_history": chat_history})

In scenari di business reali, è possibile salvare la cronologia delle conversazioni in un database e inserire i dati nel prompt secondo le esigenze aziendali.

Suggerimento: attualmente, la funzione di memoria dei modelli di grandi dimensioni (LLM) è per lo più ottenuta inserendo il contenuto della conversazione storica nel prompt e inviandolo al LLM. LangChain fornisce semplicemente un'incapsulamento. È possibile scegliere di non utilizzarlo e concatenare manualmente la cronologia delle conversazioni nel modello del prompt.