Em seu núcleo, LangChain é uma estrutura inovadora adaptada para a criação de aplicativos que aproveitam os recursos dos modelos de linguagem. É um kit de ferramentas projetado para desenvolvedores criarem aplicativos que reconhecem o contexto e são capazes de raciocínio sofisticado.
Isso significa que os aplicativos LangChain podem compreender o contexto, como instruções imediatas ou respostas de base de conteúdo, e usar modelos de linguagem para tarefas de raciocínio complexas, como decidir como responder ou quais ações tomar. LangChain representa uma abordagem unificada para o desenvolvimento de aplicações inteligentes, simplificando a jornada do conceito à execução com seus diversos componentes.
Compreendendo LangChain
LangChain é muito mais do que apenas um framework; é um ecossistema completo que compreende várias partes integrantes.
- Em primeiro lugar, existem as Bibliotecas LangChain, disponíveis em Python e JavaScript. Essas bibliotecas são a espinha dorsal do LangChain, oferecendo interfaces e integrações para diversos componentes. Eles fornecem um tempo de execução básico para combinar esses componentes em cadeias e agentes coesos, juntamente com implementações prontas para uso imediato.
- A seguir, temos os modelos LangChain. Trata-se de uma coleção de arquiteturas de referência implantáveis, adaptadas para uma ampla gama de tarefas. Esteja você construindo um chatbot ou uma ferramenta analítica complexa, esses modelos oferecem um ponto de partida sólido.
- LangServe surge como uma biblioteca versátil para implantar cadeias LangChain como APIs REST. Esta ferramenta é essencial para transformar seus projetos LangChain em serviços web acessíveis e escaláveis.
- Por último, LangSmith serve como plataforma de desenvolvedor. Ele foi projetado para depurar, testar, avaliar e monitorar cadeias construídas em qualquer estrutura LLM. A integração perfeita com LangChain torna-o uma ferramenta indispensável para desenvolvedores que desejam refinar e aperfeiçoar suas aplicações.
Juntos, esses componentes permitem desenvolver, produzir e implantar aplicativos com facilidade. Com LangChain, você começa escrevendo seus aplicativos usando as bibliotecas, referenciando modelos para orientação. LangSmith então ajuda você a inspecionar, testar e monitorar suas cadeias, garantindo que seus aplicativos estejam constantemente melhorando e prontos para implantação. Finalmente, com LangServe, você pode transformar facilmente qualquer cadeia em uma API, facilitando a implantação.
Nas próximas seções, nos aprofundaremos em como configurar o LangChain e iniciaremos sua jornada na criação de aplicativos inteligentes baseados em modelos de linguagem.
Automatize tarefas e fluxos de trabalho manuais com nosso construtor de fluxo de trabalho baseado em IA, projetado pela Nanonets para você e suas equipes.
Instalação e configuração
Você está pronto para mergulhar no mundo do LangChain? A configuração é simples e este guia irá guiá-lo passo a passo pelo processo.
O primeiro passo em sua jornada no LangChain é instalá-lo. Você pode fazer isso facilmente usando pip ou conda. Execute o seguinte comando em seu terminal:
pip install langchain
Para aqueles que preferem os recursos mais recentes e se sentem confortáveis com um pouco mais de aventura, você pode instalar o LangChain diretamente da fonte. Clone o repositório e navegue até o langchain/libs/langchain
diretório. Então corra:
pip install -e .
Para recursos experimentais, considere instalar langchain-experimental
. É um pacote que contém código de ponta e se destina a pesquisas e fins experimentais. Instale-o usando:
pip install langchain-experimental
LangChain CLI é uma ferramenta útil para trabalhar com modelos LangChain e projetos LangServe. Para instalar a CLI LangChain, use:
pip install langchain-cli
LangServe é essencial para implantar suas cadeias LangChain como uma API REST. Ele é instalado junto com o LangChain CLI.
LangChain geralmente requer integrações com provedores de modelo, armazenamentos de dados, APIs, etc. Para este exemplo, usaremos APIs de modelo da OpenAI. Instale o pacote OpenAI Python usando:
pip install openai
Para acessar a API, defina sua chave de API OpenAI como uma variável de ambiente:
export OPENAI_API_KEY="your_api_key"
Alternativamente, passe a chave diretamente em seu ambiente python:
import os
os.environ['OPENAI_API_KEY'] = 'your_api_key'
LangChain permite a criação de aplicações de modelos de linguagem através de módulos. Esses módulos podem ser independentes ou compostos para casos de uso complexos. Esses módulos são -
- I / O de modelo: Facilita a interação com diversos modelos de linguagem, manipulando suas entradas e saídas de forma eficiente.
- Recuperação: permite acesso e interação com dados específicos de aplicativos, cruciais para a utilização dinâmica de dados.
- Agentes: Capacitar os aplicativos para selecionar ferramentas apropriadas com base em diretivas de alto nível, aprimorando as capacidades de tomada de decisão.
- Correntes: oferece composições reutilizáveis e predefinidas que servem como blocos de construção para o desenvolvimento de aplicativos.
- Memória: mantém o estado do aplicativo em várias execuções de cadeia, essencial para interações sensíveis ao contexto.
Cada módulo atende a necessidades específicas de desenvolvimento, tornando o LangChain um kit de ferramentas abrangente para a criação de aplicativos de modelos de linguagem avançados.
Junto com os componentes acima, também temos Linguagem de Expressão LangChain (LCEL), que é uma forma declarativa de compor módulos facilmente e permite o encadeamento de componentes usando uma interface Runnable universal.
LCEL se parece com isto –
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import BaseOutputParser # Example chain
chain = ChatPromptTemplate() | ChatOpenAI() | CustomOutputParser()
Agora que cobrimos o básico, continuaremos para:
- Aprofunde-se em detalhes de cada módulo Langchain.
- Aprenda como usar a linguagem de expressão LangChain.
- Explore casos de uso comuns e implemente-os.
- Implante um aplicativo ponta a ponta com LangServe.
- Confira LangSmith para depuração, teste e monitoramento.
Vamos começar!
Módulo I: Modelo de E/S
No LangChain, o elemento central de qualquer aplicação gira em torno do modelo de linguagem. Este módulo fornece os blocos de construção essenciais para uma interface eficaz com qualquer modelo de linguagem, garantindo integração e comunicação perfeitas.
Principais componentes do modelo I/O
- LLMs e modelos de bate-papo (usados de forma intercambiável):
- LLMs:
- Definição: Modelos de preenchimento de texto puro.
- Input / Output: pegue uma string de texto como entrada e retorne uma string de texto como saída.
- Modelos de bate-papo
- LLMs:
- Definição: Modelos que usam um modelo de linguagem como base, mas diferem nos formatos de entrada e saída.
- Input / Output: aceite uma lista de mensagens de bate-papo como entrada e retorne uma mensagem de bate-papo.
- Solicita: crie modelos, selecione dinamicamente e gerencie entradas de modelo. Permite a criação de prompts flexíveis e específicos ao contexto que orientam as respostas do modelo de linguagem.
- Analisadores de saída: extraia e formate informações das saídas do modelo. Útil para converter a saída bruta de modelos de linguagem em dados estruturados ou formatos específicos necessários ao aplicativo.
LLMs
A integração do LangChain com Large Language Models (LLMs) como OpenAI, Cohere e Hugging Face é um aspecto fundamental de sua funcionalidade. O próprio LangChain não hospeda LLMs, mas oferece uma interface uniforme para interagir com vários LLMs.
Esta seção fornece uma visão geral do uso do wrapper OpenAI LLM em LangChain, aplicável também a outros tipos de LLM. Já instalamos isso na seção “Introdução”. Vamos inicializar o LLM.
from langchain.llms import OpenAI
llm = OpenAI()
- LLMs implementam o Interface executável, o alicerce básico do Linguagem de Expressão LangChain (LCEL). Isso significa que eles apoiam
invoke
,ainvoke
,stream
,astream
,batch
,abatch
,astream_log
chamadas. - LLMs aceitam cordas como entradas ou objetos que podem ser coagidos a prompts de string, incluindo
List[BaseMessage]
ePromptValue
. (mais sobre isso mais tarde)
Vejamos alguns exemplos.
response = llm.invoke("List the seven wonders of the world.")
print(response)
Como alternativa, você pode chamar o método stream para transmitir a resposta de texto.
for chunk in llm.stream("Where were the 2012 Olympics held?"): print(chunk, end="", flush=True)
Modelos de bate-papo
A integração do LangChain com modelos de chat, uma variação especializada de modelos de linguagem, é essencial para a criação de aplicativos de chat interativos. Embora utilizem modelos de linguagem internamente, os modelos de chat apresentam uma interface distinta centrada em mensagens de chat como entradas e saídas. Esta seção fornece uma visão geral detalhada do uso do modelo de chat da OpenAI no LangChain.
from langchain.chat_models import ChatOpenAI
chat = ChatOpenAI()
Os modelos de bate-papo no LangChain funcionam com diferentes tipos de mensagens, como AIMessage
, HumanMessage
, SystemMessage
, FunctionMessage
e ChatMessage
(com um parâmetro de função arbitrário). Geralmente, HumanMessage
, AIMessage
e SystemMessage
são os mais usados.
Os modelos de chat aceitam principalmente List[BaseMessage]
como entradas. As strings podem ser convertidas em HumanMessage
e PromptValue
também é suportado.
from langchain.schema.messages import HumanMessage, SystemMessage
messages = [ SystemMessage(content="You are Micheal Jordan."), HumanMessage(content="Which shoe manufacturer are you associated with?"),
]
response = chat.invoke(messages)
print(response.content)
Solicita
As instruções são essenciais para orientar os modelos linguísticos para gerar resultados relevantes e coerentes. Eles podem variar de instruções simples a exemplos complexos de poucas cenas. No LangChain, o tratamento de prompts pode ser um processo muito simplificado, graças a várias classes e funções dedicadas.
LangChain's PromptTemplate
class é uma ferramenta versátil para criar prompts de string. Ele usa Python str.format
sintaxe, permitindo a geração dinâmica de prompts. Você pode definir um modelo com espaços reservados e preenchê-los com valores específicos conforme necessário.
from langchain.prompts import PromptTemplate # Simple prompt with placeholders
prompt_template = PromptTemplate.from_template( "Tell me a {adjective} joke about {content}."
) # Filling placeholders to create a prompt
filled_prompt = prompt_template.format(adjective="funny", content="robots")
print(filled_prompt)
Para modelos de chat, os prompts são mais estruturados, envolvendo mensagens com funções específicas. Ofertas LangChain ChatPromptTemplate
para esta finalidade.
from langchain.prompts import ChatPromptTemplate # Defining a chat prompt with various roles
chat_template = ChatPromptTemplate.from_messages( [ ("system", "You are a helpful AI bot. Your name is {name}."), ("human", "Hello, how are you doing?"), ("ai", "I'm doing well, thanks!"), ("human", "{user_input}"), ]
) # Formatting the chat prompt
formatted_messages = chat_template.format_messages(name="Bob", user_input="What is your name?")
for message in formatted_messages: print(message)
Esta abordagem permite a criação de chatbots interativos e envolventes com respostas dinâmicas.
Ambos PromptTemplate
e ChatPromptTemplate
integre-se perfeitamente com a LangChain Expression Language (LCEL), permitindo que façam parte de fluxos de trabalho maiores e complexos. Discutiremos mais sobre isso mais tarde.
Os modelos de prompt personalizados às vezes são essenciais para tarefas que exigem formatação exclusiva ou instruções específicas. A criação de um modelo de prompt personalizado envolve a definição de variáveis de entrada e um método de formatação personalizado. Essa flexibilidade permite que LangChain atenda a uma ampla gama de requisitos específicos de aplicações. Leia mais aqui.
LangChain também oferece suporte a solicitações de poucos disparos, permitindo que o modelo aprenda com exemplos. Esse recurso é vital para tarefas que exigem compreensão contextual ou padrões específicos. Modelos de prompt de poucos disparos podem ser criados a partir de um conjunto de exemplos ou utilizando um objeto Seletor de exemplo. Leia mais aqui.
Analisadores de saída
Os analisadores de saída desempenham um papel crucial no Langchain, permitindo aos usuários estruturar as respostas geradas pelos modelos de linguagem. Nesta seção, exploraremos o conceito de analisadores de saída e forneceremos exemplos de código usando PydanticOutputParser, SimpleJsonOutputParser, CommaSeparatedListOutputParser, DatetimeOutputParser e XMLOutputParser da Langchain.
PydanticOutputParser
Langchain fornece o PydanticOutputParser para analisar respostas em estruturas de dados Pydantic. Abaixo está um exemplo passo a passo de como usá-lo:
from typing import List
from langchain.llms import OpenAI
from langchain.output_parsers import PydanticOutputParser
from langchain.prompts import PromptTemplate
from langchain.pydantic_v1 import BaseModel, Field, validator # Initialize the language model
model = OpenAI(model_name="text-davinci-003", temperature=0.0) # Define your desired data structure using Pydantic
class Joke(BaseModel): setup: str = Field(description="question to set up a joke") punchline: str = Field(description="answer to resolve the joke") @validator("setup") def question_ends_with_question_mark(cls, field): if field[-1] != "?": raise ValueError("Badly formed question!") return field # Set up a PydanticOutputParser
parser = PydanticOutputParser(pydantic_object=Joke) # Create a prompt with format instructions
prompt = PromptTemplate( template="Answer the user query.n{format_instructions}n{query}n", input_variables=["query"], partial_variables={"format_instructions": parser.get_format_instructions()},
) # Define a query to prompt the language model
query = "Tell me a joke." # Combine prompt, model, and parser to get structured output
prompt_and_model = prompt | model
output = prompt_and_model.invoke({"query": query}) # Parse the output using the parser
parsed_result = parser.invoke(output) # The result is a structured object
print(parsed_result)
A saída será:
SimpleJsonOutputParser
SimpleJsonOutputParser de Langchain é usado quando você deseja analisar saídas semelhantes a JSON. Aqui está um exemplo:
from langchain.output_parsers.json import SimpleJsonOutputParser # Create a JSON prompt
json_prompt = PromptTemplate.from_template( "Return a JSON object with `birthdate` and `birthplace` key that answers the following question: {question}"
) # Initialize the JSON parser
json_parser = SimpleJsonOutputParser() # Create a chain with the prompt, model, and parser
json_chain = json_prompt | model | json_parser # Stream through the results
result_list = list(json_chain.stream({"question": "When and where was Elon Musk born?"})) # The result is a list of JSON-like dictionaries
print(result_list)
CommaSeparatedListOutputParser
O CommaSeparatedListOutputParser é útil quando você deseja extrair listas separadas por vírgulas das respostas do modelo. Aqui está um exemplo:
from langchain.output_parsers import CommaSeparatedListOutputParser
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI # Initialize the parser
output_parser = CommaSeparatedListOutputParser() # Create format instructions
format_instructions = output_parser.get_format_instructions() # Create a prompt to request a list
prompt = PromptTemplate( template="List five {subject}.n{format_instructions}", input_variables=["subject"], partial_variables={"format_instructions": format_instructions}
) # Define a query to prompt the model
query = "English Premier League Teams" # Generate the output
output = model(prompt.format(subject=query)) # Parse the output using the parser
parsed_result = output_parser.parse(output) # The result is a list of items
print(parsed_result)
DatetimeOutputParser
O DatetimeOutputParser do Langchain foi projetado para analisar informações de data e hora. Veja como usá-lo:
from langchain.prompts import PromptTemplate
from langchain.output_parsers import DatetimeOutputParser
from langchain.chains import LLMChain
from langchain.llms import OpenAI # Initialize the DatetimeOutputParser
output_parser = DatetimeOutputParser() # Create a prompt with format instructions
template = """
Answer the user's question:
{question}
{format_instructions} """ prompt = PromptTemplate.from_template( template, partial_variables={"format_instructions": output_parser.get_format_instructions()},
) # Create a chain with the prompt and language model
chain = LLMChain(prompt=prompt, llm=OpenAI()) # Define a query to prompt the model
query = "when did Neil Armstrong land on the moon in terms of GMT?" # Run the chain
output = chain.run(query) # Parse the output using the datetime parser
parsed_result = output_parser.parse(output) # The result is a datetime object
print(parsed_result)
Esses exemplos mostram como os analisadores de saída do Langchain podem ser usados para estruturar vários tipos de respostas de modelo, tornando-os adequados para diferentes aplicações e formatos. Os analisadores de saída são uma ferramenta valiosa para melhorar a usabilidade e interpretabilidade dos resultados do modelo de linguagem em Langchain.
Automatize tarefas e fluxos de trabalho manuais com nosso construtor de fluxo de trabalho baseado em IA, projetado pela Nanonets para você e suas equipes.
Módulo II: Recuperação
A recuperação em LangChain desempenha um papel crucial em aplicações que requerem dados específicos do usuário, não incluídos no conjunto de treinamento do modelo. Esse processo, conhecido como Retrieval Augmented Generation (RAG), envolve a busca de dados externos e sua integração ao processo de geração do modelo de linguagem. LangChain fornece um conjunto abrangente de ferramentas e funcionalidades para facilitar esse processo, atendendo aplicações simples e complexas.
LangChain consegue a recuperação por meio de uma série de componentes que discutiremos um por um.
carregadores de documentos
Os carregadores de documentos no LangChain permitem a extração de dados de várias fontes. Com mais de 100 carregadores disponíveis, eles suportam uma variedade de tipos de documentos, aplicativos e fontes (buckets S3 privados, sites públicos, bancos de dados).
Você pode escolher um carregador de documentos com base em suas necessidades SUA PARTICIPAÇÃO FAZ A DIFERENÇA.
Todos esses carregadores ingerem dados em ISO Aulas. Aprenderemos como usar os dados ingeridos nas classes Document mais tarde.
Carregador de arquivo de texto: Carregue um simples .txt
arquivar em um documento.
from langchain.document_loaders import TextLoader loader = TextLoader("./sample.txt")
document = loader.load()
Carregador CSV: Carregue um arquivo CSV em um documento.
from langchain.document_loaders.csv_loader import CSVLoader loader = CSVLoader(file_path='./example_data/sample.csv')
documents = loader.load()
Podemos optar por personalizar a análise especificando nomes de campos –
loader = CSVLoader(file_path='./example_data/mlb_teams_2012.csv', csv_args={ 'delimiter': ',', 'quotechar': '"', 'fieldnames': ['MLB Team', 'Payroll in millions', 'Wins']
})
documents = loader.load()
Carregadores de PDF: Os carregadores de PDF no LangChain oferecem vários métodos para analisar e extrair conteúdo de arquivos PDF. Cada carregador atende a diferentes requisitos e usa diferentes bibliotecas subjacentes. Abaixo estão exemplos detalhados para cada carregador.
PyPDFLoader é usado para análise básica de PDF.
from langchain.document_loaders import PyPDFLoader loader = PyPDFLoader("example_data/layout-parser-paper.pdf")
pages = loader.load_and_split()
MathPixLoader é ideal para extrair conteúdo matemático e diagramas.
from langchain.document_loaders import MathpixPDFLoader loader = MathpixPDFLoader("example_data/math-content.pdf")
data = loader.load()
PyMuPDFLoader é rápido e inclui extração detalhada de metadados.
from langchain.document_loaders import PyMuPDFLoader loader = PyMuPDFLoader("example_data/layout-parser-paper.pdf")
data = loader.load() # Optionally pass additional arguments for PyMuPDF's get_text() call
data = loader.load(option="text")
PDFMiner Loader é usado para um controle mais granular sobre a extração de texto.
from langchain.document_loaders import PDFMinerLoader loader = PDFMinerLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
AmazonTexttractPDFParser utiliza AWS Textract para OCR e outros recursos avançados de análise de PDF.
from langchain.document_loaders import AmazonTextractPDFLoader # Requires AWS account and configuration
loader = AmazonTextractPDFLoader("example_data/complex-layout.pdf")
documents = loader.load()
PDFMinerPDFasHTMLLoader gera HTML a partir de PDF para análise semântica.
from langchain.document_loaders import PDFMinerPDFasHTMLLoader loader = PDFMinerPDFasHTMLLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
PDFPlumberLoader fornece metadados detalhados e suporta um documento por página.
from langchain.document_loaders import PDFPlumberLoader loader = PDFPlumberLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
Carregadores Integrados: LangChain oferece uma ampla variedade de carregadores personalizados para carregar dados diretamente de seus aplicativos (como Slack, Sigma, Notion, Confluence, Google Drive e muitos mais) e bancos de dados e usá-los em aplicativos LLM.
A lista completa é SUA PARTICIPAÇÃO FAZ A DIFERENÇA.
Abaixo estão alguns exemplos para ilustrar isso -
Exemplo I – Folga
Slack, uma plataforma de mensagens instantâneas amplamente utilizada, pode ser integrada a fluxos de trabalho e aplicativos LLM.
- Vá para a página de gerenciamento do Slack Workspace.
- Navegar para
{your_slack_domain}.slack.com/services/export
. - Selecione o intervalo de datas desejado e inicie a exportação.
- O Slack notifica por e-mail e DM quando a exportação estiver pronta.
- A exportação resulta em
.zip
arquivo localizado na pasta Downloads ou no caminho de download designado. - Atribua o caminho do download
.zip
arquivo paraLOCAL_ZIPFILE
. - Use o
SlackDirectoryLoader
dolangchain.document_loaders
pacote.
from langchain.document_loaders import SlackDirectoryLoader SLACK_WORKSPACE_URL = "https://xxx.slack.com" # Replace with your Slack URL
LOCAL_ZIPFILE = "" # Path to the Slack zip file loader = SlackDirectoryLoader(LOCAL_ZIPFILE, SLACK_WORKSPACE_URL)
docs = loader.load()
print(docs)
Exemplo II – Figma
Figma, uma ferramenta popular para design de interface, oferece uma API REST para integração de dados.
- Obtenha a chave do arquivo Figma no formato URL:
https://www.figma.com/file/{filekey}/sampleFilename
. - Os IDs dos nós são encontrados no parâmetro URL
?node-id={node_id}
. - Gere um token de acesso seguindo as instruções no Central de Ajuda Figma.
- A
FigmaFileLoader
classe delangchain.document_loaders.figma
é usado para carregar dados Figma. - Vários módulos LangChain como
CharacterTextSplitter
,ChatOpenAI
, etc., são empregados para processamento.
import os
from langchain.document_loaders.figma import FigmaFileLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.chat_models import ChatOpenAI
from langchain.indexes import VectorstoreIndexCreator
from langchain.chains import ConversationChain, LLMChain
from langchain.memory import ConversationBufferWindowMemory
from langchain.prompts.chat import ChatPromptTemplate, SystemMessagePromptTemplate, AIMessagePromptTemplate, HumanMessagePromptTemplate figma_loader = FigmaFileLoader( os.environ.get("ACCESS_TOKEN"), os.environ.get("NODE_IDS"), os.environ.get("FILE_KEY"),
) index = VectorstoreIndexCreator().from_loaders([figma_loader])
figma_doc_retriever = index.vectorstore.as_retriever()
- A
generate_code
função usa os dados Figma para criar código HTML/CSS. - Ele emprega uma conversa modelo com um modelo baseado em GPT.
def generate_code(human_input): # Template for system and human prompts system_prompt_template = "Your coding instructions..." human_prompt_template = "Code the {text}. Ensure it's mobile responsive" # Creating prompt templates system_message_prompt = SystemMessagePromptTemplate.from_template(system_prompt_template) human_message_prompt = HumanMessagePromptTemplate.from_template(human_prompt_template) # Setting up the AI model gpt_4 = ChatOpenAI(temperature=0.02, model_name="gpt-4") # Retrieving relevant documents relevant_nodes = figma_doc_retriever.get_relevant_documents(human_input) # Generating and formatting the prompt conversation = [system_message_prompt, human_message_prompt] chat_prompt = ChatPromptTemplate.from_messages(conversation) response = gpt_4(chat_prompt.format_prompt(context=relevant_nodes, text=human_input).to_messages()) return response # Example usage
response = generate_code("page top header")
print(response.content)
- A
generate_code
A função, quando executada, retorna o código HTML/CSS com base na entrada do design Figma.
Vamos agora usar nosso conhecimento para criar alguns conjuntos de documentos.
Primeiro carregamos um PDF, o relatório anual de sustentabilidade do BCG.
Usamos o PyPDFLoader para isso.
from langchain.document_loaders import PyPDFLoader loader = PyPDFLoader("bcg-2022-annual-sustainability-report-apr-2023.pdf")
pdfpages = loader.load_and_split()
Iremos ingerir dados do Airtable agora. Temos um Airtable contendo informações sobre vários modelos de OCR e extração de dados –
Vamos usar o AirtableLoader para isso, encontrado na lista de carregadores integrados.
from langchain.document_loaders import AirtableLoader api_key = "XXXXX"
base_id = "XXXXX"
table_id = "XXXXX" loader = AirtableLoader(api_key, table_id, base_id)
airtabledocs = loader.load()
Vamos agora prosseguir e aprender como usar essas classes de documentos.
Transformadores de documentos
Os transformadores de documentos no LangChain são ferramentas essenciais projetadas para manipular documentos, que criamos em nossa subseção anterior.
Eles são usados para tarefas como dividir documentos longos em partes menores, combinar e filtrar, que são cruciais para adaptar documentos à janela de contexto de um modelo ou atender às necessidades específicas do aplicativo.
Uma dessas ferramentas é o RecursiveCharacterTextSplitter, um divisor de texto versátil que usa uma lista de caracteres para divisão. Ele permite parâmetros como tamanho do bloco, sobreposição e índice inicial. Aqui está um exemplo de como ele é usado em Python:
from langchain.text_splitter import RecursiveCharacterTextSplitter state_of_the_union = "Your long text here..." text_splitter = RecursiveCharacterTextSplitter( chunk_size=100, chunk_overlap=20, length_function=len, add_start_index=True,
) texts = text_splitter.create_documents([state_of_the_union])
print(texts[0])
print(texts[1])
Outra ferramenta é o CharacterTextSplitter, que divide o texto com base em um caractere especificado e inclui controles para tamanho e sobreposição de blocos:
from langchain.text_splitter import CharacterTextSplitter text_splitter = CharacterTextSplitter( separator="nn", chunk_size=1000, chunk_overlap=200, length_function=len, is_separator_regex=False,
) texts = text_splitter.create_documents([state_of_the_union])
print(texts[0])
O HTMLHeaderTextSplitter foi projetado para dividir o conteúdo HTML com base em tags de cabeçalho, mantendo a estrutura semântica:
from langchain.text_splitter import HTMLHeaderTextSplitter html_string = "Your HTML content here..."
headers_to_split_on = [("h1", "Header 1"), ("h2", "Header 2")] html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
html_header_splits = html_splitter.split_text(html_string)
print(html_header_splits[0])
Uma manipulação mais complexa pode ser obtida combinando HTMLHeaderTextSplitter com outro divisor, como o Pipelined Splitter:
from langchain.text_splitter import HTMLHeaderTextSplitter, RecursiveCharacterTextSplitter url = "https://example.com"
headers_to_split_on = [("h1", "Header 1"), ("h2", "Header 2")]
html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
html_header_splits = html_splitter.split_text_from_url(url) chunk_size = 500
text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size)
splits = text_splitter.split_documents(html_header_splits)
print(splits[0])
LangChain também oferece divisores específicos para diferentes linguagens de programação, como Python Code Splitter e JavaScript Code Splitter:
from langchain.text_splitter import RecursiveCharacterTextSplitter, Language python_code = """
def hello_world(): print("Hello, World!")
hello_world() """ python_splitter = RecursiveCharacterTextSplitter.from_language( language=Language.PYTHON, chunk_size=50
)
python_docs = python_splitter.create_documents([python_code])
print(python_docs[0]) js_code = """
function helloWorld() { console.log("Hello, World!");
}
helloWorld(); """ js_splitter = RecursiveCharacterTextSplitter.from_language( language=Language.JS, chunk_size=60
)
js_docs = js_splitter.create_documents([js_code])
print(js_docs[0])
Para dividir texto com base na contagem de tokens, o que é útil para modelos de linguagem com limites de tokens, o TokenTextSplitter é usado:
from langchain.text_splitter import TokenTextSplitter text_splitter = TokenTextSplitter(chunk_size=10)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
Finalmente, o LongContextReorder reordena documentos para evitar degradação de desempenho em modelos devido a contextos longos:
from langchain.document_transformers import LongContextReorder reordering = LongContextReorder()
reordered_docs = reordering.transform_documents(docs)
print(reordered_docs[0])
Essas ferramentas demonstram várias maneiras de transformar documentos em LangChain, desde simples divisão de texto até reordenação complexa e divisão específica de idioma. Para casos de uso mais aprofundados e específicos, a seção de documentação e integrações do LangChain deve ser consultada.
Em nossos exemplos, os carregadores já criaram documentos fragmentados para nós e esta parte já foi tratada.
Modelos de incorporação de texto
Os modelos de incorporação de texto no LangChain fornecem uma interface padronizada para vários provedores de modelos de incorporação, como OpenAI, Cohere e Hugging Face. Esses modelos transformam texto em representações vetoriais, possibilitando operações como busca semântica por meio de similaridade de texto no espaço vetorial.
Para começar a usar modelos de incorporação de texto, normalmente você precisa instalar pacotes específicos e configurar chaves de API. Já fizemos isso para OpenAI
Na LangChain, o embed_documents
O método é usado para incorporar vários textos, fornecendo uma lista de representações vetoriais. Por exemplo:
from langchain.embeddings import OpenAIEmbeddings # Initialize the model
embeddings_model = OpenAIEmbeddings() # Embed a list of texts
embeddings = embeddings_model.embed_documents( ["Hi there!", "Oh, hello!", "What's your name?", "My friends call me World", "Hello World!"]
)
print("Number of documents embedded:", len(embeddings))
print("Dimension of each embedding:", len(embeddings[0]))
Para incorporar um único texto, como uma consulta de pesquisa, o embed_query
método é usado. Isto é útil para comparar uma consulta a um conjunto de incorporações de documentos. Por exemplo:
from langchain.embeddings import OpenAIEmbeddings # Initialize the model
embeddings_model = OpenAIEmbeddings() # Embed a single query
embedded_query = embeddings_model.embed_query("What was the name mentioned in the conversation?")
print("First five dimensions of the embedded query:", embedded_query[:5])
Compreender essas incorporações é crucial. Cada trecho de texto é convertido em um vetor, cuja dimensão depende do modelo utilizado. Por exemplo, os modelos OpenAI normalmente produzem vetores de 1536 dimensões. Essas incorporações são então usadas para recuperar informações relevantes.
A funcionalidade de incorporação do LangChain não se limita ao OpenAI, mas foi projetada para funcionar com vários provedores. A configuração e o uso podem diferir ligeiramente dependendo do provedor, mas o conceito central de incorporar textos no espaço vetorial permanece o mesmo. Para uso detalhado, incluindo configurações avançadas e integrações com diferentes provedores de modelos de incorporação, a documentação do LangChain na seção Integrações é um recurso valioso.
Lojas de vetores
As lojas de vetores no LangChain oferecem suporte ao armazenamento e pesquisa eficientes de incorporações de texto. LangChain se integra a mais de 50 lojas de vetores, fornecendo uma interface padronizada para facilidade de uso.
Exemplo: Armazenando e Pesquisando Embeddings
Depois de incorporar os textos, podemos armazená-los em um armazenamento de vetores como Chroma
e realizar pesquisas de similaridade:
from langchain.vectorstores import Chroma db = Chroma.from_texts(embedded_texts)
similar_texts = db.similarity_search("search query")
Alternativamente, usaremos o armazenamento de vetores FAISS para criar índices para nossos documentos.
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS pdfstore = FAISS.from_documents(pdfpages, embedding=OpenAIEmbeddings()) airtablestore = FAISS.from_documents(airtabledocs, embedding=OpenAIEmbeddings())
Recuperadores
Recuperadores em LangChain são interfaces que retornam documentos em resposta a uma consulta não estruturada. Eles são mais gerais que os armazenamentos de vetores, concentrando-se na recuperação e não no armazenamento. Embora os armazenamentos de vetores possam ser usados como espinha dorsal de um recuperador, também existem outros tipos de recuperadores.
Para configurar um Chroma retriever, primeiro instale-o usando pip install chromadb
. Em seguida, você carrega, divide, incorpora e recupera documentos usando uma série de comandos Python. Aqui está um exemplo de código para configurar um Chroma retriever:
from langchain.embeddings import OpenAIEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import Chroma full_text = open("state_of_the_union.txt", "r").read()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
texts = text_splitter.split_text(full_text) embeddings = OpenAIEmbeddings()
db = Chroma.from_texts(texts, embeddings)
retriever = db.as_retriever() retrieved_docs = retriever.invoke("What did the president say about Ketanji Brown Jackson?")
print(retrieved_docs[0].page_content)
O MultiQueryRetriever automatiza o ajuste de prompt gerando diversas consultas para uma consulta de entrada do usuário e combinando os resultados. Aqui está um exemplo de seu uso simples:
from langchain.chat_models import ChatOpenAI
from langchain.retrievers.multi_query import MultiQueryRetriever question = "What are the approaches to Task Decomposition?"
llm = ChatOpenAI(temperature=0)
retriever_from_llm = MultiQueryRetriever.from_llm( retriever=db.as_retriever(), llm=llm
) unique_docs = retriever_from_llm.get_relevant_documents(query=question)
print("Number of unique documents:", len(unique_docs))
A compactação contextual no LangChain compacta os documentos recuperados usando o contexto da consulta, garantindo que apenas as informações relevantes sejam retornadas. Isto envolve redução de conteúdo e filtragem de documentos menos relevantes. O exemplo de código a seguir mostra como usar o Contextual Compression Retriever:
from langchain.llms import OpenAI
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor llm = OpenAI(temperature=0)
compressor = LLMChainExtractor.from_llm(llm)
compression_retriever = ContextualCompressionRetriever(base_compressor=compressor, base_retriever=retriever) compressed_docs = compression_retriever.get_relevant_documents("What did the president say about Ketanji Jackson Brown")
print(compressed_docs[0].page_content)
O EnsembleRetriever combina diferentes algoritmos de recuperação para obter melhor desempenho. Um exemplo de combinação de BM25 e FAISS Retrievers é mostrado no código a seguir:
from langchain.retrievers import BM25Retriever, EnsembleRetriever
from langchain.vectorstores import FAISS bm25_retriever = BM25Retriever.from_texts(doc_list).set_k(2)
faiss_vectorstore = FAISS.from_texts(doc_list, OpenAIEmbeddings())
faiss_retriever = faiss_vectorstore.as_retriever(search_kwargs={"k": 2}) ensemble_retriever = EnsembleRetriever( retrievers=[bm25_retriever, faiss_retriever], weights=[0.5, 0.5]
) docs = ensemble_retriever.get_relevant_documents("apples")
print(docs[0].page_content)
MultiVector Retriever em LangChain permite consultar documentos com vários vetores por documento, o que é útil para capturar diferentes aspectos semânticos dentro de um documento. Os métodos para criar vários vetores incluem dividir em pedaços menores, resumir ou gerar questões hipotéticas. Para dividir documentos em partes menores, o seguinte código Python pode ser usado:
python
from langchain.retrievers.multi_vector import MultiVectorRetriever
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.storage import InMemoryStore
from langchain.document_loaders from TextLoader
import uuid loaders = [TextLoader("file1.txt"), TextLoader("file2.txt")]
docs = [doc for loader in loaders for doc in loader.load()]
text_splitter = RecursiveCharacterTextSplitter(chunk_size=10000)
docs = text_splitter.split_documents(docs) vectorstore = Chroma(collection_name="full_documents", embedding_function=OpenAIEmbeddings())
store = InMemoryStore()
id_key = "doc_id"
retriever = MultiVectorRetriever(vectorstore=vectorstore, docstore=store, id_key=id_key) doc_ids = [str(uuid.uuid4()) for _ in docs]
child_text_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
sub_docs = [sub_doc for doc in docs for sub_doc in child_text_splitter.split_documents([doc])]
for sub_doc in sub_docs: sub_doc.metadata[id_key] = doc_ids[sub_docs.index(sub_doc)] retriever.vectorstore.add_documents(sub_docs)
retriever.docstore.mset(list(zip(doc_ids, docs)))
Gerar resumos para melhor recuperação devido a uma representação de conteúdo mais focada é outro método. Aqui está um exemplo de geração de resumos:
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.document import Document chain = (lambda x: x.page_content) | ChatPromptTemplate.from_template("Summarize the following document:nn{doc}") | ChatOpenAI(max_retries=0) | StrOutputParser()
summaries = chain.batch(docs, {"max_concurrency": 5}) summary_docs = [Document(page_content=s, metadata={id_key: doc_ids[i]}) for i, s in enumerate(summaries)]
retriever.vectorstore.add_documents(summary_docs)
retriever.docstore.mset(list(zip(doc_ids, docs)))
Gerar questões hipotéticas relevantes para cada documento usando LLM é outra abordagem. Isso pode ser feito com o seguinte código:
functions = [{"name": "hypothetical_questions", "parameters": {"questions": {"type": "array", "items": {"type": "string"}}}}]
from langchain.output_parsers.openai_functions import JsonKeyOutputFunctionsParser chain = (lambda x: x.page_content) | ChatPromptTemplate.from_template("Generate 3 hypothetical questions:nn{doc}") | ChatOpenAI(max_retries=0).bind(functions=functions, function_call={"name": "hypothetical_questions"}) | JsonKeyOutputFunctionsParser(key_name="questions")
hypothetical_questions = chain.batch(docs, {"max_concurrency": 5}) question_docs = [Document(page_content=q, metadata={id_key: doc_ids[i]}) for i, questions in enumerate(hypothetical_questions) for q in questions]
retriever.vectorstore.add_documents(question_docs)
retriever.docstore.mset(list(zip(doc_ids, docs)))
O Parent Document Retriever é outro recuperador que atinge um equilíbrio entre a precisão da incorporação e a retenção de contexto, armazenando pequenos pedaços e recuperando seus documentos pais maiores. Sua implementação é a seguinte:
from langchain.retrievers import ParentDocumentRetriever loaders = [TextLoader("file1.txt"), TextLoader("file2.txt")]
docs = [doc for loader in loaders for doc in loader.load()] child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
vectorstore = Chroma(collection_name="full_documents", embedding_function=OpenAIEmbeddings())
store = InMemoryStore()
retriever = ParentDocumentRetriever(vectorstore=vectorstore, docstore=store, child_splitter=child_splitter) retriever.add_documents(docs, ids=None) retrieved_docs = retriever.get_relevant_documents("query")
Um recuperador de autoconsulta constrói consultas estruturadas a partir de entradas de linguagem natural e as aplica ao seu VectorStore subjacente. Sua implementação é mostrada no código a seguir:
from langchain.chat_models from ChatOpenAI
from langchain.chains.query_constructor.base from AttributeInfo
from langchain.retrievers.self_query.base from SelfQueryRetriever metadata_field_info = [AttributeInfo(name="genre", description="...", type="string"), ...]
document_content_description = "Brief summary of a movie"
llm = ChatOpenAI(temperature=0) retriever = SelfQueryRetriever.from_llm(llm, vectorstore, document_content_description, metadata_field_info) retrieved_docs = retriever.invoke("query")
O WebResearchRetriever realiza pesquisas na web com base em uma determinada consulta –
from langchain.retrievers.web_research import WebResearchRetriever # Initialize components
llm = ChatOpenAI(temperature=0)
search = GoogleSearchAPIWrapper()
vectorstore = Chroma(embedding_function=OpenAIEmbeddings()) # Instantiate WebResearchRetriever
web_research_retriever = WebResearchRetriever.from_llm(vectorstore=vectorstore, llm=llm, search=search) # Retrieve documents
docs = web_research_retriever.get_relevant_documents("query")
Para nossos exemplos, também podemos usar o recuperador padrão já implementado como parte de nosso objeto de armazenamento de vetores da seguinte forma –
Agora podemos consultar os recuperadores. A saída da nossa consulta serão objetos de documento relevantes para a consulta. Em última análise, eles serão utilizados para criar respostas relevantes em seções posteriores.
Automatize tarefas e fluxos de trabalho manuais com nosso construtor de fluxo de trabalho baseado em IA, projetado pela Nanonets para você e suas equipes.
Módulo III: Agentes
LangChain apresenta um conceito poderoso chamado “Agentes” que leva a ideia de cadeias a um nível totalmente novo. Os agentes aproveitam modelos de linguagem para determinar dinamicamente sequências de ações a serem executadas, tornando-os incrivelmente versáteis e adaptáveis. Ao contrário das cadeias tradicionais, onde as ações são codificadas, os agentes empregam modelos de linguagem como motores de raciocínio para decidir quais ações tomar e em que ordem.
O agente é o principal componente responsável pela tomada de decisões. Ele aproveita o poder de um modelo de linguagem e um prompt para determinar as próximas etapas para atingir um objetivo específico. As entradas para um agente normalmente incluem:
- Ferramentas: Descrições das ferramentas disponíveis (mais sobre isso posteriormente).
- Entrada do usuário: O objetivo ou consulta de alto nível do usuário.
- Etapas intermediárias: Um histórico de pares (ação, saída da ferramenta) executados para alcançar a entrada atual do usuário.
A saída de um agente pode ser a próxima açao tomar medidas (Ações do Agente) ou o final resposta para enviar ao usuário (AgenteFinish). A açao especifica um ferramenta e os votos de entrada para essa ferramenta.
Ferramentas
Ferramentas são interfaces que um agente pode usar para interagir com o mundo. Eles permitem que os agentes executem diversas tarefas, como pesquisar na web, executar comandos shell ou acessar APIs externas. No LangChain, as ferramentas são essenciais para ampliar as capacidades dos agentes e permitir-lhes realizar diversas tarefas.
Para usar ferramentas no LangChain, você pode carregá-las usando o seguinte trecho:
from langchain.agents import load_tools tool_names = [...]
tools = load_tools(tool_names)
Algumas ferramentas podem exigir um modelo de linguagem base (LLM) para inicializar. Nesses casos, você também pode passar em um LLM:
from langchain.agents import load_tools tool_names = [...]
llm = ...
tools = load_tools(tool_names, llm=llm)
Essa configuração permite acessar uma variedade de ferramentas e integrá-las aos fluxos de trabalho do seu agente. A lista completa de ferramentas com documentação de uso é SUA PARTICIPAÇÃO FAZ A DIFERENÇA.
Vejamos alguns exemplos de ferramentas.
DuckDuckGo
A ferramenta DuckDuckGo permite realizar pesquisas na web usando seu mecanismo de busca. Veja como usá-lo:
from langchain.tools import DuckDuckGoSearchRun
search = DuckDuckGoSearchRun()
search.run("manchester united vs luton town match summary")
DataForSeo
O kit de ferramentas DataForSeo permite obter resultados de mecanismos de pesquisa usando a API DataForSeo. Para usar este kit de ferramentas, você precisará configurar suas credenciais de API. Veja como configurar as credenciais:
import os os.environ["DATAFORSEO_LOGIN"] = "<your_api_access_username>"
os.environ["DATAFORSEO_PASSWORD"] = "<your_api_access_password>"
Depois que suas credenciais estiverem definidas, você poderá criar um DataForSeoAPIWrapper
ferramenta para acessar a API:
from langchain.utilities.dataforseo_api_search import DataForSeoAPIWrapper wrapper = DataForSeoAPIWrapper() result = wrapper.run("Weather in Los Angeles")
A DataForSeoAPIWrapper
ferramenta recupera resultados de mecanismos de pesquisa de várias fontes.
Você pode personalizar o tipo de resultados e campos retornados na resposta JSON. Por exemplo, você pode especificar os tipos de resultados e campos e definir uma contagem máxima para o número de resultados principais a serem retornados:
json_wrapper = DataForSeoAPIWrapper( json_result_types=["organic", "knowledge_graph", "answer_box"], json_result_fields=["type", "title", "description", "text"], top_count=3,
) json_result = json_wrapper.results("Bill Gates")
Este exemplo personaliza a resposta JSON especificando tipos de resultados, campos e limitando o número de resultados.
Você também pode especificar o local e o idioma dos resultados da pesquisa, passando parâmetros adicionais ao wrapper da API:
customized_wrapper = DataForSeoAPIWrapper( top_count=10, json_result_types=["organic", "local_pack"], json_result_fields=["title", "description", "type"], params={"location_name": "Germany", "language_code": "en"},
) customized_result = customized_wrapper.results("coffee near me")
Ao fornecer parâmetros de localização e idioma, você pode personalizar os resultados da pesquisa para regiões e idiomas específicos.
Você tem flexibilidade para escolher o mecanismo de pesquisa que deseja usar. Basta especificar o mecanismo de pesquisa desejado:
customized_wrapper = DataForSeoAPIWrapper( top_count=10, json_result_types=["organic", "local_pack"], json_result_fields=["title", "description", "type"], params={"location_name": "Germany", "language_code": "en", "se_name": "bing"},
) customized_result = customized_wrapper.results("coffee near me")
Neste exemplo, a pesquisa é personalizada para usar o Bing como mecanismo de pesquisa.
O wrapper da API também permite especificar o tipo de pesquisa que deseja realizar. Por exemplo, você pode realizar uma pesquisa em mapas:
maps_search = DataForSeoAPIWrapper( top_count=10, json_result_fields=["title", "value", "address", "rating", "type"], params={ "location_coordinate": "52.512,13.36,12z", "language_code": "en", "se_type": "maps", },
) maps_search_result = maps_search.results("coffee near me")
Isso personaliza a pesquisa para recuperar informações relacionadas a mapas.
Concha (bash)
O kit de ferramentas Shell fornece aos agentes acesso ao ambiente shell, permitindo-lhes executar comandos shell. Esse recurso é poderoso, mas deve ser usado com cautela, especialmente em ambientes de área restrita. Veja como você pode usar a ferramenta Shell:
from langchain.tools import ShellTool shell_tool = ShellTool() result = shell_tool.run({"commands": ["echo 'Hello World!'", "time"]})
Neste exemplo, a ferramenta Shell executa dois comandos shell: ecoando “Hello World!” e exibindo a hora atual.
Você pode fornecer a ferramenta Shell a um agente para executar tarefas mais complexas. Aqui está um exemplo de um agente buscando links de uma página da web usando a ferramenta Shell:
from langchain.agents import AgentType, initialize_agent
from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(temperature=0.1) shell_tool.description = shell_tool.description + f"args {shell_tool.args}".replace( "{", "{{"
).replace("}", "}}")
self_ask_with_search = initialize_agent( [shell_tool], llm, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)
self_ask_with_search.run( "Download the langchain.com webpage and grep for all urls. Return only a sorted list of them. Be sure to use double quotes."
)
Nesse cenário, o agente usa a ferramenta Shell para executar uma sequência de comandos para buscar, filtrar e classificar URLs de uma página da web.
Os exemplos fornecidos demonstram algumas das ferramentas disponíveis no LangChain. Em última análise, essas ferramentas ampliam as capacidades dos agentes (exploradas na próxima subseção) e os capacitam a executar diversas tarefas com eficiência. Dependendo dos seus requisitos, você pode escolher as ferramentas e kits de ferramentas que melhor atendem às necessidades do seu projeto e integrá-los aos fluxos de trabalho do seu agente.
Voltar para Agentes
Vamos passar para os agentes agora.
O AgentExecutor é o ambiente de tempo de execução de um agente. É responsável por chamar o agente, executar as ações selecionadas, repassar as saídas da ação ao agente e repetir o processo até que o agente termine. Em pseudocódigo, o AgentExecutor pode ser parecido com isto:
next_action = agent.get_action(...)
while next_action != AgentFinish: observation = run(next_action) next_action = agent.get_action(..., next_action, observation)
return next_action
O AgentExecutor lida com diversas complexidades, como lidar com casos em que o agente seleciona uma ferramenta inexistente, lidar com erros da ferramenta, gerenciar saídas produzidas pelo agente e fornecer registro e observabilidade em todos os níveis.
Embora a classe AgentExecutor seja o principal tempo de execução do agente no LangChain, há outros tempos de execução mais experimentais suportados, incluindo:
- Agente de planejar e executar
- bebê AGI
- GPT automático
Para entender melhor a estrutura do agente, vamos construir um agente básico do zero e depois explorar os agentes pré-construídos.
Antes de mergulharmos na construção do agente, é essencial revisitar algumas terminologias e esquemas importantes:
- Ação do Agente: Esta é uma classe de dados que representa a ação que um agente deve realizar. Consiste em um
tool
propriedade (o nome da ferramenta a ser invocada) e umtool_input
propriedade (a entrada para essa ferramenta). - AgenteFinish: Esta classe de dados indica que o agente concluiu sua tarefa e deve retornar uma resposta ao usuário. Normalmente inclui um dicionário de valores de retorno, geralmente com uma “saída” chave contendo o texto da resposta.
- Etapas intermediárias: Estes são os registros de ações anteriores do agente e resultados correspondentes. Eles são cruciais para passar o contexto para futuras iterações do agente.
Em nosso exemplo, usaremos OpenAI Function Calling para criar nosso agente. Esta abordagem é confiável para a criação de agentes. Começaremos criando uma ferramenta simples que calcula o comprimento de uma palavra. Esta ferramenta é útil porque os modelos de linguagem às vezes podem cometer erros devido à tokenização ao contar o comprimento das palavras.
Primeiro, vamos carregar o modelo de linguagem que usaremos para controlar o agente:
from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
Vamos testar o modelo com um cálculo de comprimento de palavra:
llm.invoke("how many letters in the word educa?")
A resposta deverá indicar o número de letras da palavra “educa”.
A seguir, definiremos uma função Python simples para calcular o comprimento de uma palavra:
from langchain.agents import tool @tool
def get_word_length(word: str) -> int: """Returns the length of a word.""" return len(word)
Criamos uma ferramenta chamada get_word_length
que recebe uma palavra como entrada e retorna seu comprimento.
Agora, vamos criar o prompt para o agente. O prompt instrui o agente sobre como raciocinar e formatar a saída. No nosso caso, estamos usando OpenAI Function Calling, que requer instruções mínimas. Definiremos o prompt com espaços reservados para entrada do usuário e bloco de notas do agente:
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder prompt = ChatPromptTemplate.from_messages( [ ( "system", "You are a very powerful assistant but not great at calculating word lengths.", ), ("user", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad"), ]
)
Agora, como o agente sabe quais ferramentas pode usar? Contamos com modelos de linguagem de chamada de função OpenAI, que exigem que as funções sejam passadas separadamente. Para fornecer nossas ferramentas ao agente, iremos formatá-las como chamadas de função OpenAI:
from langchain.tools.render import format_tool_to_openai_function llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools])
Agora podemos criar o agente definindo mapeamentos de entrada e conectando os componentes:
Esta é a linguagem LCEL. Discutiremos isso mais tarde em detalhes.
from langchain.agents.format_scratchpad import format_to_openai_function_messages
from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai _function_messages( x["intermediate_steps"] ), } | prompt | llm_with_tools | OpenAIFunctionsAgentOutputParser()
)
Criamos nosso agente, que entende a entrada do usuário, usa as ferramentas disponíveis e formata a saída. Agora, vamos interagir com ele:
agent.invoke({"input": "how many letters in the word educa?", "intermediate_steps": []})
O agente deverá responder com uma AgentAction, indicando a próxima ação a ser tomada.
Criamos o agente, mas agora precisamos escrever um tempo de execução para ele. O tempo de execução mais simples é aquele que chama continuamente o agente, executa ações e repete até que o agente termine. Aqui está um exemplo:
from langchain.schema.agent import AgentFinish user_input = "how many letters in the word educa?"
intermediate_steps = [] while True: output = agent.invoke( { "input": user_input, "intermediate_steps": intermediate_steps, } ) if isinstance(output, AgentFinish): final_result = output.return_values["output"] break else: print(f"TOOL NAME: {output.tool}") print(f"TOOL INPUT: {output.tool_input}") tool = {"get_word_length": get_word_length}[output.tool] observation = tool.run(output.tool_input) intermediate_steps.append((output, observation)) print(final_result)
Neste loop, chamamos repetidamente o agente, executamos ações e atualizamos as etapas intermediárias até que o agente termine. Também lidamos com interações de ferramentas dentro do loop.
Para simplificar esse processo, LangChain fornece a classe AgentExecutor, que encapsula a execução do agente e oferece tratamento de erros, parada antecipada, rastreamento e outras melhorias. Vamos usar AgentExecutor para interagir com o agente:
from langchain.agents import AgentExecutor agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) agent_executor.invoke({"input": "how many letters in the word educa?"})
AgentExecutor simplifica o processo de execução e fornece uma maneira conveniente de interagir com o agente.
A memória também será discutida em detalhes posteriormente.
O agente que criamos até agora não tem estado, o que significa que não se lembra de interações anteriores. Para permitir perguntas e conversas de acompanhamento, precisamos adicionar memória ao agente. Isso envolve duas etapas:
- Adicione uma variável de memória no prompt para armazenar o histórico de bate-papo.
- Acompanhe o histórico de bate-papo durante as interações.
Vamos começar adicionando um espaço reservado de memória no prompt:
from langchain.prompts import MessagesPlaceholder MEMORY_KEY = "chat_history"
prompt = ChatPromptTemplate.from_messages( [ ( "system", "You are a very powerful assistant but not great at calculating word lengths.", ), MessagesPlaceholder(variable_name=MEMORY_KEY), ("user", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad"), ]
)
Agora, crie uma lista para rastrear o histórico de bate-papo:
from langchain.schema.messages import HumanMessage, AIMessage chat_history = []
Na etapa de criação do agente, incluiremos também a memória:
agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai_function_messages( x["intermediate_steps"] ), "chat_history": lambda x: x["chat_history"], } | prompt | llm_with_tools | OpenAIFunctionsAgentOutputParser()
)
Agora, ao executar o agente, certifique-se de atualizar o histórico de chat:
input1 = "how many letters in the word 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": "is that a real word?", "chat_history": chat_history})
Isso permite que o agente mantenha um histórico de conversas e responda perguntas de acompanhamento com base em interações anteriores.
Parabéns! Você criou e executou com sucesso seu primeiro agente ponta a ponta no LangChain. Para se aprofundar nos recursos do LangChain, você pode explorar:
- Diferentes tipos de agentes suportados.
- Agentes pré-construídos
- Como trabalhar com ferramentas e integrações de ferramentas.
Tipos de Agente
LangChain oferece vários tipos de agentes, cada um adequado para casos de uso específicos. Aqui estão alguns dos agentes disponíveis:
- Reação de tiro zero: Este agente usa a estrutura ReAct para escolher ferramentas com base apenas em suas descrições. Requer descrições para cada ferramenta e é altamente versátil.
- ReAct de entrada estruturada: Este agente lida com ferramentas de múltiplas entradas e é adequado para tarefas complexas, como navegar em um navegador da web. Ele usa um esquema de argumentos de ferramentas para entrada estruturada.
- Funções OpenAI: Projetado especificamente para modelos ajustados para chamadas de funções, este agente é compatível com modelos como gpt-3.5-turbo-0613 e gpt-4-0613. Usamos isso para criar nosso primeiro agente acima.
- Conversacional: Projetado para ambientes de conversação, este agente usa ReAct para seleção de ferramentas e utiliza memória para lembrar interações anteriores.
- Pergunte a si mesmo com pesquisa: Esse agente conta com uma única ferramenta, “Resposta Intermediária”, que busca respostas factuais às perguntas. É equivalente à autopergunta original do documento de pesquisa.
- Armazenamento de documentos ReAct: Este agente interage com um armazenamento de documentos usando a estrutura ReAct. Requer ferramentas de “Pesquisa” e “Pesquisa” e é semelhante ao exemplo da Wikipedia do artigo original do ReAct.
Explore esses tipos de agentes para encontrar aquele que melhor atende às suas necessidades em LangChain. Esses agentes permitem vincular um conjunto de ferramentas dentro deles para lidar com ações e gerar respostas. Saiba mais em como construir seu próprio agente com ferramentas aqui.
Agentes pré-construídos
Vamos continuar nossa exploração de agentes, com foco nos agentes pré-construídos disponíveis no LangChain.
Gmail
LangChain oferece um kit de ferramentas do Gmail que permite conectar seu e-mail LangChain à API do Gmail. Para começar, você precisará configurar suas credenciais, explicadas na documentação da API do Gmail. Depois de baixar o credentials.json
arquivo, você pode continuar usando a API do Gmail. Além disso, você precisará instalar algumas bibliotecas necessárias usando os seguintes comandos:
pip install --upgrade google-api-python-client > /dev/null
pip install --upgrade google-auth-oauthlib > /dev/null
pip install --upgrade google-auth-httplib2 > /dev/null
pip install beautifulsoup4 > /dev/null # Optional for parsing HTML messages
Você pode criar o kit de ferramentas do Gmail da seguinte maneira:
from langchain.agents.agent_toolkits import GmailToolkit toolkit = GmailToolkit()
Você também pode personalizar a autenticação de acordo com suas necessidades. Nos bastidores, um recurso googleapi é criado usando os seguintes métodos:
from langchain.tools.gmail.utils import build_resource_service, get_gmail_credentials credentials = get_gmail_credentials( token_file="token.json", scopes=["https://mail.google.com/"], client_secrets_file="credentials.json",
)
api_resource = build_resource_service(credentials=credentials)
toolkit = GmailToolkit(api_resource=api_resource)
O kit de ferramentas oferece diversas ferramentas que podem ser usadas em um agente, incluindo:
GmailCreateDraft
: crie um rascunho de e-mail com campos de mensagem especificados.GmailSendMessage
: envie mensagens de e-mail.GmailSearch
: pesquise mensagens de e-mail ou tópicos.GmailGetMessage
: busque um e-mail por ID de mensagem.GmailGetThread
: pesquise mensagens de e-mail.
Para usar essas ferramentas em um agente, você pode inicializar o agente da seguinte maneira:
from langchain.llms import OpenAI
from langchain.agents import initialize_agent, AgentType llm = OpenAI(temperature=0)
agent = initialize_agent( tools=toolkit.get_tools(), llm=llm, agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
)
Aqui estão alguns exemplos de como essas ferramentas podem ser usadas:
- Crie um rascunho do Gmail para edição:
agent.run( "Create a gmail draft for me to edit of a letter from the perspective of a sentient parrot " "who is looking to collaborate on some research with her estranged friend, a cat. " "Under no circumstances may you send the message, however."
)
- Pesquise o e-mail mais recente em seus rascunhos:
agent.run("Could you search in my drafts for the latest email?")
Esses exemplos demonstram os recursos do kit de ferramentas do Gmail da LangChain em um agente, permitindo que você interaja com o Gmail de maneira programática.
Agente de banco de dados SQL
Esta seção fornece uma visão geral de um agente projetado para interagir com bancos de dados SQL, particularmente o banco de dados Chinook. Este agente pode responder perguntas gerais sobre um banco de dados e se recuperar de erros. Observe que ele ainda está em desenvolvimento ativo e nem todas as respostas podem estar corretas. Tenha cuidado ao executá-lo em dados confidenciais, pois ele pode executar instruções DML no seu banco de dados.
Para usar este agente, você pode inicializá-lo da seguinte maneira:
from langchain.agents import create_sql_agent
from langchain.agents.agent_toolkits import SQLDatabaseToolkit
from langchain.sql_database import SQLDatabase
from langchain.llms.openai import OpenAI
from langchain.agents import AgentExecutor
from langchain.agents.agent_types import AgentType
from langchain.chat_models import ChatOpenAI db = SQLDatabase.from_uri("sqlite:///../../../../../notebooks/Chinook.db")
toolkit = SQLDatabaseToolkit(db=db, llm=OpenAI(temperature=0)) agent_executor = create_sql_agent( llm=OpenAI(temperature=0), toolkit=toolkit, verbose=True, agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
)
Este agente pode ser inicializado usando o ZERO_SHOT_REACT_DESCRIPTION
tipo de agente. Ele foi projetado para responder perguntas e fornecer descrições. Alternativamente, você pode inicializar o agente usando o OPENAI_FUNCTIONS
tipo de agente com o modelo GPT-3.5-turbo da OpenAI, que usamos em nosso cliente anterior.
Aviso Legal
- A cadeia de consulta pode gerar consultas de inserção/atualização/exclusão. Seja cauteloso e use um prompt personalizado ou crie um usuário SQL sem permissões de gravação, se necessário.
- Esteja ciente de que a execução de determinadas consultas, como “executar a maior consulta possível”, pode sobrecarregar seu banco de dados SQL, especialmente se ele contiver milhões de linhas.
- Os bancos de dados orientados para data warehouse geralmente oferecem suporte a cotas no nível do usuário para limitar o uso de recursos.
Você pode pedir ao agente para descrever uma tabela, como a tabela “playlisttrack”. Aqui está um exemplo de como fazer isso:
agent_executor.run("Describe the playlisttrack table")
O agente fornecerá informações sobre o esquema da tabela e linhas de amostra.
Se você perguntar por engano sobre uma tabela que não existe, o agente poderá recuperar e fornecer informações sobre a tabela correspondente mais próxima. Por exemplo:
agent_executor.run("Describe the playlistsong table")
O agente encontrará a tabela correspondente mais próxima e fornecerá informações sobre ela.
Você também pode solicitar ao agente que execute consultas no banco de dados. Por exemplo:
agent_executor.run("List the total sales per country. Which country's customers spent the most?")
O agente executará a consulta e fornecerá o resultado, como o país com maior total de vendas.
Para obter o número total de faixas em cada playlist, você pode usar a seguinte consulta:
agent_executor.run("Show the total number of tracks in each playlist. The Playlist name should be included in the result.")
O agente retornará os nomes das playlists junto com a contagem total de faixas correspondente.
Nos casos em que o agente encontra erros, ele pode se recuperar e fornecer respostas precisas. Por exemplo:
agent_executor.run("Who are the top 3 best selling artists?")
Mesmo após encontrar um erro inicial, o agente irá se ajustar e dar a resposta correta, que, neste caso, são os 3 artistas mais vendidos.
Agente Pandas DataFrame
Esta seção apresenta um agente projetado para interagir com Pandas DataFrames para fins de resposta a perguntas. Observe que este agente utiliza o agente Python nos bastidores para executar o código Python gerado por um modelo de linguagem (LLM). Tenha cuidado ao usar este agente para evitar possíveis danos causados por código Python malicioso gerado pelo LLM.
Você pode inicializar o agente Pandas DataFrame da seguinte maneira:
from langchain_experimental.agents.agent_toolkits import create_pandas_dataframe_agent
from langchain.chat_models import ChatOpenAI
from langchain.agents.agent_types import AgentType from langchain.llms import OpenAI
import pandas as pd df = pd.read_csv("titanic.csv") # Using ZERO_SHOT_REACT_DESCRIPTION agent type
agent = create_pandas_dataframe_agent(OpenAI(temperature=0), df, verbose=True) # Alternatively, using OPENAI_FUNCTIONS agent type
# agent = create_pandas_dataframe_agent(
# ChatOpenAI(temperature=0, model="gpt-3.5-turbo-0613"),
# df,
# verbose=True,
# agent_type=AgentType.OPENAI_FUNCTIONS,
# )
Você pode pedir ao agente para contar o número de linhas no DataFrame:
agent.run("how many rows are there?")
O agente executará o código df.shape[0]
e forneça a resposta, como “Existem 891 linhas no dataframe”.
Você também pode pedir ao agente para filtrar as linhas com base em critérios específicos, como encontrar o número de pessoas com mais de três irmãos:
agent.run("how many people have more than 3 siblings")
O agente executará o código df[df['SibSp'] > 3].shape[0]
e forneça a resposta, como “30 pessoas têm mais de 3 irmãos”.
Se quiser calcular a raiz quadrada da idade média, você pode perguntar ao agente:
agent.run("whats the square root of the average age?")
O agente calculará a idade média usando df['Age'].mean()
e então calcule a raiz quadrada usando math.sqrt()
. Ele fornecerá a resposta, como “A raiz quadrada da idade média é 5.449689683556195”.
Vamos criar uma cópia do DataFrame e os valores de idade ausentes serão preenchidos com a idade média:
df1 = df.copy()
df1["Age"] = df1["Age"].fillna(df1["Age"].mean())
Então, você pode inicializar o agente com ambos os DataFrames e fazer uma pergunta:
agent = create_pandas_dataframe_agent(OpenAI(temperature=0), [df, df1], verbose=True)
agent.run("how many rows in the age column are different?")
O agente comparará as colunas de idade em ambos os DataFrames e fornecerá a resposta, como “177 linhas na coluna de idade são diferentes”.
Kit de ferramentas Jira
Esta seção explica como usar o kit de ferramentas do JIRA, que permite que os agentes interajam com uma instância do JIRA. Você pode executar diversas ações, como procurar e criar problemas usando este kit de ferramentas. Ele utiliza a biblioteca atlassian-python-api. Para usar este kit de ferramentas, você precisa definir variáveis de ambiente para sua instância do JIRA, incluindo JIRA_API_TOKEN, JIRA_USERNAME e JIRA_INSTANCE_URL. Além disso, pode ser necessário definir sua chave de API OpenAI como uma variável de ambiente.
Para começar, instale a biblioteca atlassian-python-api e defina as variáveis de ambiente necessárias:
%pip install atlassian-python-api import os
from langchain.agents import AgentType
from langchain.agents import initialize_agent
from langchain.agents.agent_toolkits.jira.toolkit import JiraToolkit
from langchain.llms import OpenAI
from langchain.utilities.jira import JiraAPIWrapper os.environ["JIRA_API_TOKEN"] = "abc"
os.environ["JIRA_USERNAME"] = "123"
os.environ["JIRA_INSTANCE_URL"] = "https://jira.atlassian.com"
os.environ["OPENAI_API_KEY"] = "xyz" llm = OpenAI(temperature=0)
jira = JiraAPIWrapper()
toolkit = JiraToolkit.from_jira_api_wrapper(jira)
agent = initialize_agent( toolkit.get_tools(), llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)
Você pode instruir o agente a criar um novo problema em um projeto específico com um resumo e uma descrição:
agent.run("make a new issue in project PW to remind me to make more fried rice")
O agente executará as ações necessárias para criar o problema e fornecerá uma resposta, como “Um novo problema foi criado no projeto PW com o resumo 'Faça mais arroz frito' e a descrição 'Lembrete para fazer mais arroz frito'”.
Isso permite que você interaja com sua instância do JIRA usando instruções em linguagem natural e o kit de ferramentas do JIRA.
Automatize tarefas e fluxos de trabalho manuais com nosso construtor de fluxo de trabalho baseado em IA, projetado pela Nanonets para você e suas equipes.
Módulo IV: Correntes
LangChain é uma ferramenta projetada para utilizar Large Language Models (LLMs) em aplicações complexas. Ele fornece estruturas para a criação de cadeias de componentes, incluindo LLMs e outros tipos de componentes. Duas estruturas principais
- A linguagem de expressão LangChain (LCEL)
- Interface da Cadeia Legada
A LangChain Expression Language (LCEL) é uma sintaxe que permite a composição intuitiva de cadeias. Ele oferece suporte a recursos avançados como streaming, chamadas assíncronas, lote, paralelização, novas tentativas, fallbacks e rastreamento. Por exemplo, você pode compor um prompt, um modelo e um analisador de saída em LCEL conforme mostrado no código a seguir:
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
prompt = ChatPromptTemplate.from_messages([ ("system", "You're a very knowledgeable historian who provides accurate and eloquent answers to historical questions."), ("human", "{question}")
])
runnable = prompt | model | StrOutputParser() for chunk in runnable.stream({"question": "What are the seven wonders of the world"}): print(chunk, end="", flush=True)
Alternativamente, o LLMChain é uma opção semelhante ao LCEL para composição de componentes. O exemplo LLMChain é o seguinte:
from langchain.chains import LLMChain chain = LLMChain(llm=model, prompt=prompt, output_parser=StrOutputParser())
chain.run(question="What are the seven wonders of the world")
As cadeias em LangChain também podem ter estado incorporando um objeto Memory. Isso permite a persistência de dados entre chamadas, conforme mostrado neste exemplo:
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory conversation = ConversationChain(llm=chat, memory=ConversationBufferMemory())
conversation.run("Answer briefly. What are the first 3 colors of a rainbow?")
conversation.run("And the next 4?")
LangChain também oferece suporte à integração com APIs de chamada de função da OpenAI, o que é útil para obter resultados estruturados e executar funções dentro de uma cadeia. Para obter resultados estruturados, você pode especificá-los usando classes Pydantic ou JsonSchema, conforme ilustrado abaixo:
from langchain.pydantic_v1 import BaseModel, Field
from langchain.chains.openai_functions import create_structured_output_runnable
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate class Person(BaseModel): name: str = Field(..., description="The person's name") age: int = Field(..., description="The person's age") fav_food: Optional[str] = Field(None, description="The person's favorite food") llm = ChatOpenAI(model="gpt-4", temperature=0)
prompt = ChatPromptTemplate.from_messages([ # Prompt messages here
]) runnable = create_structured_output_runnable(Person, llm, prompt)
runnable.invoke({"input": "Sally is 13"})
Para resultados estruturados, também está disponível uma abordagem legada usando LLMChain:
from langchain.chains.openai_functions import create_structured_output_chain class Person(BaseModel): name: str = Field(..., description="The person's name") age: int = Field(..., description="The person's age") chain = create_structured_output_chain(Person, llm, prompt, verbose=True)
chain.run("Sally is 13")
LangChain aproveita as funções OpenAI para criar várias cadeias específicas para diferentes propósitos. Isso inclui cadeias para extração, marcação, OpenAPI e controle de qualidade com citações.
No contexto da extração, o processo é semelhante à cadeia de produção estruturada, mas concentra-se na extração de informações ou entidades. Para marcação, a ideia é rotular um documento com classes como sentimento, idioma, estilo, tópicos abordados ou tendência política.
Um exemplo de como funciona a marcação em LangChain pode ser demonstrado com um código Python. O processo começa com a instalação dos pacotes necessários e a configuração do ambiente:
pip install langchain openai
# Set env var OPENAI_API_KEY or load from a .env file:
# import dotenv
# dotenv.load_dotenv() from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import create_tagging_chain, create_tagging_chain_pydantic
O esquema para marcação é definido, especificando as propriedades e seus tipos esperados:
schema = { "properties": { "sentiment": {"type": "string"}, "aggressiveness": {"type": "integer"}, "language": {"type": "string"}, }
} llm = ChatOpenAI(temperature=0, model="gpt-3.5-turbo-0613")
chain = create_tagging_chain(schema, llm)
Exemplos de execução da cadeia de marcação com diferentes entradas mostram a capacidade do modelo de interpretar sentimentos, linguagens e agressividade:
inp = "Estoy increiblemente contento de haberte conocido! Creo que seremos muy buenos amigos!"
chain.run(inp)
# {'sentiment': 'positive', 'language': 'Spanish'} inp = "Estoy muy enojado con vos! Te voy a dar tu merecido!"
chain.run(inp)
# {'sentiment': 'enojado', 'aggressiveness': 1, 'language': 'es'}
Para um controle mais preciso, o esquema pode ser definido mais especificamente, incluindo valores possíveis, descrições e propriedades necessárias. Um exemplo desse controle aprimorado é mostrado abaixo:
schema = { "properties": { # Schema definitions here }, "required": ["language", "sentiment", "aggressiveness"],
} chain = create_tagging_chain(schema, llm)
Esquemas Pydantic também podem ser usados para definir critérios de marcação, fornecendo uma maneira Pythonic de especificar propriedades e tipos necessários:
from enum import Enum
from pydantic import BaseModel, Field class Tags(BaseModel): # Class fields here chain = create_tagging_chain_pydantic(Tags, llm)
Além disso, o transformador de documento tagger de metadados do LangChain pode ser usado para extrair metadados de documentos LangChain, oferecendo funcionalidade semelhante à cadeia de marcação, mas aplicada a um documento LangChain.
A citação de fontes de recuperação é outro recurso do LangChain, que usa funções OpenAI para extrair citações do texto. Isso é demonstrado no código a seguir:
from langchain.chains import create_citation_fuzzy_match_chain
from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(temperature=0, model="gpt-3.5-turbo-0613")
chain = create_citation_fuzzy_match_chain(llm)
# Further code for running the chain and displaying results
No LangChain, o encadeamento em aplicativos Large Language Model (LLM) normalmente envolve a combinação de um modelo de prompt com um LLM e, opcionalmente, um analisador de saída. A maneira recomendada de fazer isso é por meio da LangChain Expression Language (LCEL), embora a abordagem legada LLMChain também seja suportada.
Usando LCEL, BasePromptTemplate, BaseLanguageModel e BaseOutputParser implementam a interface Runnable e podem ser facilmente canalizados um para o outro. Aqui está um exemplo que demonstra isso:
from langchain.prompts import PromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain.schema import StrOutputParser prompt = PromptTemplate.from_template( "What is a good name for a company that makes {product}?"
)
runnable = prompt | ChatOpenAI() | StrOutputParser()
runnable.invoke({"product": "colorful socks"})
# Output: 'VibrantSocks'
O roteamento em LangChain permite a criação de cadeias não determinísticas onde a saída de uma etapa anterior determina a próxima etapa. Isso ajuda a estruturar e manter a consistência nas interações com os LLMs. Por exemplo, se você tiver dois modelos otimizados para diferentes tipos de perguntas, poderá escolher o modelo com base nas informações do usuário.
Veja como você pode conseguir isso usando LCEL com um RunnableBranch, que é inicializado com uma lista de pares (condição, executável) e um executável padrão:
from langchain.chat_models import ChatOpenAI
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnableBranch
# Code for defining physics_prompt and math_prompt general_prompt = PromptTemplate.from_template( "You are a helpful assistant. Answer the question as accurately as you can.nn{input}"
)
prompt_branch = RunnableBranch( (lambda x: x["topic"] == "math", math_prompt), (lambda x: x["topic"] == "physics", physics_prompt), general_prompt,
) # More code for setting up the classifier and final chain
A cadeia final é então construída usando vários componentes, como um classificador de tópico, ramificação de prompt e um analisador de saída, para determinar o fluxo com base no tópico da entrada:
from operator import itemgetter
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough final_chain = ( RunnablePassthrough.assign(topic=itemgetter("input") | classifier_chain) | prompt_branch | ChatOpenAI() | StrOutputParser()
) final_chain.invoke( { "input": "What is the first prime number greater than 40 such that one plus the prime number is divisible by 3?" }
)
# Output: Detailed answer to the math question
Essa abordagem exemplifica a flexibilidade e o poder do LangChain no tratamento de consultas complexas e no roteamento adequado delas com base na entrada.
No domínio dos modelos de linguagem, uma prática comum é acompanhar uma chamada inicial com uma série de chamadas subsequentes, usando a saída de uma chamada como entrada para a próxima. Essa abordagem sequencial é especialmente benéfica quando você deseja aproveitar as informações geradas em interações anteriores. Embora a LangChain Expression Language (LCEL) seja o método recomendado para criar essas sequências, o método SequentialChain ainda está documentado por sua compatibilidade com versões anteriores.
Para ilustrar isso, vamos considerar um cenário em que primeiro geramos uma sinopse da peça e depois uma revisão baseada nessa sinopse. Usando Python langchain.prompts
, criamos dois PromptTemplate
instâncias: uma para a sinopse e outra para a resenha. Aqui está o código para configurar esses modelos:
from langchain.prompts import PromptTemplate synopsis_prompt = PromptTemplate.from_template( "You are a playwright. Given the title of play, it is your job to write a synopsis for that title.nnTitle: {title}nPlaywright: This is a synopsis for the above play:"
) review_prompt = PromptTemplate.from_template( "You are a play critic from the New York Times. Given the synopsis of play, it is your job to write a review for that play.nnPlay Synopsis:n{synopsis}nReview from a New York Times play critic of the above play:"
)
Na abordagem LCEL, encadeamos esses prompts com ChatOpenAI
e StrOutputParser
para criar uma sequência que primeiro gere uma sinopse e depois uma revisão. O trecho de código é o seguinte:
from langchain.chat_models import ChatOpenAI
from langchain.schema import StrOutputParser llm = ChatOpenAI()
chain = ( {"synopsis": synopsis_prompt | llm | StrOutputParser()} | review_prompt | llm | StrOutputParser()
)
chain.invoke({"title": "Tragedy at sunset on the beach"})
Se precisarmos da sinopse e da revisão, podemos usar RunnablePassthrough
para criar uma cadeia separada para cada um e depois combiná-los:
from langchain.schema.runnable import RunnablePassthrough synopsis_chain = synopsis_prompt | llm | StrOutputParser()
review_chain = review_prompt | llm | StrOutputParser()
chain = {"synopsis": synopsis_chain} | RunnablePassthrough.assign(review=review_chain)
chain.invoke({"title": "Tragedy at sunset on the beach"})
Para cenários envolvendo sequências mais complexas, o SequentialChain
método entra em jogo. Isso permite múltiplas entradas e saídas. Considere um caso em que precisamos de uma sinopse baseada no título e na época de uma peça. Veja como podemos configurá-lo:
from langchain.llms import OpenAI
from langchain.chains import LLMChain, SequentialChain
from langchain.prompts import PromptTemplate llm = OpenAI(temperature=0.7) synopsis_template = "You are a playwright. Given the title of play and the era it is set in, it is your job to write a synopsis for that title.nnTitle: {title}nEra: {era}nPlaywright: This is a synopsis for the above play:"
synopsis_prompt_template = PromptTemplate(input_variables=["title", "era"], template=synopsis_template)
synopsis_chain = LLMChain(llm=llm, prompt=synopsis_prompt_template, output_key="synopsis") review_template = "You are a play critic from the New York Times. Given the synopsis of play, it is your job to write a review for that play.nnPlay Synopsis:n{synopsis}nReview from a New York Times play critic of the above play:"
prompt_template = PromptTemplate(input_variables=["synopsis"], template=review_template)
review_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="review") overall_chain = SequentialChain( chains=[synopsis_chain, review_chain], input_variables=["era", "title"], output_variables=["synopsis", "review"], verbose=True,
) overall_chain({"title": "Tragedy at sunset on the beach", "era": "Victorian England"})
Em cenários onde você deseja manter o contexto ao longo de uma cadeia ou para uma parte posterior da cadeia, SimpleMemory
pode ser usado. Isto é particularmente útil para gerenciar relacionamentos complexos de entrada/saída. Por exemplo, em um cenário em que queremos gerar postagens nas redes sociais com base no título, época, sinopse e crítica de uma peça, SimpleMemory
pode ajudar a gerenciar essas variáveis:
from langchain.memory import SimpleMemory
from langchain.chains import SequentialChain template = "You are a social media manager for a theater company. Given the title of play, the era it is set in, the date, time and location, the synopsis of the play, and the review of the play, it is your job to write a social media post for that play.nnHere is some context about the time and location of the play:nDate and Time: {time}nLocation: {location}nnPlay Synopsis:n{synopsis}nReview from a New York Times play critic of the above play:n{review}nnSocial Media Post:"
prompt_template = PromptTemplate(input_variables=["synopsis", "review", "time", "location"], template=template)
social_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="social_post_text") overall_chain = SequentialChain( memory=SimpleMemory(memories={"time": "December 25th, 8pm PST", "location": "Theater in the Park"}), chains=[synopsis_chain, review_chain, social_chain], input_variables=["era", "title"], output_variables=["social_post_text"], verbose=True,
) overall_chain({"title": "Tragedy at sunset on the beach", "era": "Victorian England"})
Além das cadeias sequenciais, existem cadeias especializadas para trabalhar com documentos. Cada uma dessas cadeias serve a um propósito diferente, desde combinar documentos até refinar respostas com base na análise iterativa de documentos, até mapear e reduzir o conteúdo do documento para resumo ou reclassificação com base em respostas pontuadas. Essas cadeias podem ser recriadas com LCEL para flexibilidade e personalização adicionais.
-
StuffDocumentsChain
combina uma lista de documentos em um único prompt passado para um LLM. -
RefineDocumentsChain
atualiza sua resposta iterativamente para cada documento, adequado para tarefas onde os documentos excedem a capacidade de contexto do modelo. -
MapReduceDocumentsChain
aplica uma cadeia a cada documento individualmente e depois combina os resultados. -
MapRerankDocumentsChain
pontua cada resposta baseada em documento e seleciona a de maior pontuação.
Aqui está um exemplo de como você pode configurar um MapReduceDocumentsChain
usando LCEL:
from functools import partial
from langchain.chains.combine_documents import collapse_docs, split_list_of_docs
from langchain.schema import Document, StrOutputParser
from langchain.schema.prompt_template import format_document
from langchain.schema.runnable import RunnableParallel, RunnablePassthrough llm = ChatAnthropic()
document_prompt = PromptTemplate.from_template("{page_content}")
partial_format_document = partial(format_document, prompt=document_prompt) map_chain = ( {"context": partial_format_document} | PromptTemplate.from_template("Summarize this content:nn{context}") | llm | StrOutputParser()
) map_as_doc_chain = ( RunnableParallel({"doc": RunnablePassthrough(), "content": map_chain}) | (lambda x: Document(page_content=x["content"], metadata=x["doc"].metadata))
).with_config(run_name="Summarize (return doc)") def format_docs(docs): return "nn".join(partial_format_document(doc) for doc in docs) collapse_chain = ( {"context": format_docs} | PromptTemplate.from_template("Collapse this content:nn{context}") | llm | StrOutputParser()
) reduce_chain = ( {"context": format_docs} | PromptTemplate.from_template("Combine these summaries:nn{context}") | llm | StrOutputParser()
).with_config(run_name="Reduce") map_reduce = (map_as_doc_chain.map() | collapse | reduce_chain).with_config(run_name="Map reduce")
Esta configuração permite uma análise detalhada e abrangente do conteúdo do documento, aproveitando os pontos fortes do LCEL e do modelo de linguagem subjacente.
Automatize tarefas e fluxos de trabalho manuais com nosso construtor de fluxo de trabalho baseado em IA, projetado pela Nanonets para você e suas equipes.
Módulo V: Memória
No LangChain, a memória é um aspecto fundamental das interfaces conversacionais, permitindo que os sistemas façam referência a interações passadas. Isto é conseguido através do armazenamento e consulta de informações, com duas ações principais: leitura e escrita. O sistema de memória interage com uma cadeia duas vezes durante uma execução, aumentando as entradas do usuário e armazenando as entradas e saídas para referência futura.
Construindo memória em um sistema
- Armazenando mensagens de bate-papo: O módulo de memória LangChain integra vários métodos para armazenar mensagens de bate-papo, desde listas na memória até bancos de dados. Isso garante que todas as interações do chat sejam registradas para referência futura.
- Consultando mensagens de bate-papo: Além de armazenar mensagens de chat, LangChain emprega estruturas de dados e algoritmos para criar uma visão útil dessas mensagens. Sistemas de memória simples podem retornar mensagens recentes, enquanto sistemas mais avançados podem resumir interações passadas ou focar em entidades mencionadas na interação atual.
Para demonstrar o uso de memória no LangChain, considere o ConversationBufferMemory
class, um formulário de memória simples que armazena mensagens de bate-papo em um buffer. Aqui está um exemplo:
from langchain.memory import ConversationBufferMemory memory = ConversationBufferMemory()
memory.chat_memory.add_user_message("Hello!")
memory.chat_memory.add_ai_message("How can I assist you?")
Ao integrar a memória em uma cadeia, é crucial compreender as variáveis retornadas da memória e como elas são usadas na cadeia. Por exemplo, o load_memory_variables
O método ajuda a alinhar as variáveis lidas da memória com as expectativas da cadeia.
Exemplo ponta a ponta com LangChain
Considere usar ConversationBufferMemory
num LLMChain
. A cadeia, combinada com um modelo de prompt apropriado e a memória, proporciona uma experiência de conversação perfeita. Aqui está um exemplo simplificado:
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.memory import ConversationBufferMemory llm = OpenAI(temperature=0)
template = "Your conversation template here..."
prompt = PromptTemplate.from_template(template)
memory = ConversationBufferMemory(memory_key="chat_history")
conversation = LLMChain(llm=llm, prompt=prompt, memory=memory) response = conversation({"question": "What's the weather like?"})
Este exemplo ilustra como o sistema de memória do LangChain se integra às suas cadeias para fornecer uma experiência de conversação coerente e contextualmente consciente.
Tipos de memória em Langchain
Langchain oferece vários tipos de memória que podem ser utilizados para aprimorar as interações com os modelos de IA. Cada tipo de memória possui seus próprios parâmetros e tipos de retorno, tornando-os adequados para diferentes cenários. Vamos explorar alguns dos tipos de memória disponíveis no Langchain junto com exemplos de código.
1. Memória tampão de conversa
Este tipo de memória permite armazenar e extrair mensagens de conversas. Você pode extrair o histórico como uma string ou como uma lista de mensagens.
from langchain.memory import ConversationBufferMemory memory = ConversationBufferMemory()
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.load_memory_variables({}) # Extract history as a string
{'history': 'Human: hinAI: whats up'} # Extract history as a list of messages
{'history': [HumanMessage(content='hi', additional_kwargs={}), AIMessage(content='whats up', additional_kwargs={})]}
Você também pode usar o Conversation Buffer Memory em uma cadeia para interações semelhantes a bate-papo.
2. Memória da janela do buffer de conversa
Este tipo de memória mantém uma lista de interações recentes e usa as últimas K interações, evitando que o buffer fique muito grande.
from langchain.memory import ConversationBufferWindowMemory memory = ConversationBufferWindowMemory(k=1)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.save_context({"input": "not much you"}, {"output": "not much"})
memory.load_memory_variables({}) {'history': 'Human: not much younAI: not much'}
Assim como o Conversation Buffer Memory, você também pode usar esse tipo de memória em uma cadeia para interações semelhantes a bate-papo.
3. Memória de entidade de conversação
Este tipo de memória lembra fatos sobre entidades específicas em uma conversa e extrai informações usando um LLM.
from langchain.memory import ConversationEntityMemory
from langchain.llms import OpenAI llm = OpenAI(temperature=0)
memory = ConversationEntityMemory(llm=llm)
_input = {"input": "Deven & Sam are working on a hackathon project"}
memory.load_memory_variables(_input)
memory.save_context( _input, {"output": " That sounds like a great project! What kind of project are they working on?"}
)
memory.load_memory_variables({"input": 'who is Sam'}) {'history': 'Human: Deven & Sam are working on a hackathon projectnAI: That sounds like a great project! What kind of project are they working on?', 'entities': {'Sam': 'Sam is working on a hackathon project with Deven.'}}
4. Memória do Gráfico de Conhecimento de Conversação
Este tipo de memória usa um gráfico de conhecimento para recriar a memória. Você pode extrair entidades atuais e trigêmeos de conhecimento das mensagens.
from langchain.memory import ConversationKGMemory
from langchain.llms import OpenAI llm = OpenAI(temperature=0)
memory = ConversationKGMemory(llm=llm)
memory.save_context({"input": "say hi to sam"}, {"output": "who is sam"})
memory.save_context({"input": "sam is a friend"}, {"output": "okay"})
memory.load_memory_variables({"input": "who is sam"}) {'history': 'On Sam: Sam is friend.'}
Você também pode usar esse tipo de memória em uma cadeia para recuperação de conhecimento baseada em conversação.
5. Memória de resumo de conversa
Este tipo de memória cria um resumo da conversa ao longo do tempo, útil para condensar informações de conversas mais longas.
from langchain.memory import ConversationSummaryMemory
from langchain.llms import OpenAI llm = OpenAI(temperature=0)
memory = ConversationSummaryMemory(llm=llm)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.load_memory_variables({}) {'history': 'nThe human greets the AI, to which the AI responds.'}
6. Memória tampão de resumo de conversa
Este tipo de memória combina o resumo da conversa e o buffer, mantendo um equilíbrio entre as interações recentes e um resumo. Ele usa o comprimento do token para determinar quando liberar as interações.
from langchain.memory import ConversationSummaryBufferMemory
from langchain.llms import OpenAI llm = OpenAI()
memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=10)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.save_context({"input": "not much you"}, {"output": "not much"})
memory.load_memory_variables({}) {'history': 'System: nThe human says "hi", and the AI responds with "whats up".nHuman: not much younAI: not much'}
Você pode usar esses tipos de memória para aprimorar suas interações com modelos de IA em Langchain. Cada tipo de memória atende a uma finalidade específica e pode ser selecionado com base em seus requisitos.
7. Memória buffer de token de conversa
ConversationTokenBufferMemory é outro tipo de memória que mantém um buffer de interações recentes na memória. Ao contrário dos tipos de memória anteriores que se concentram no número de interações, este usa o comprimento do token para determinar quando liberar as interações.
Usando memória com LLM:
from langchain.memory import ConversationTokenBufferMemory
from langchain.llms import OpenAI llm = OpenAI() memory = ConversationTokenBufferMemory(llm=llm, max_token_limit=10)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.save_context({"input": "not much you"}, {"output": "not much"}) memory.load_memory_variables({}) {'history': 'Human: not much younAI: not much'}
Neste exemplo, a memória está configurada para limitar as interações com base no comprimento do token e não no número de interações.
Você também pode obter o histórico como uma lista de mensagens ao usar este tipo de memória.
memory = ConversationTokenBufferMemory( llm=llm, max_token_limit=10, return_messages=True
)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.save_context({"input": "not much you"}, {"output": "not much"})
Usando em uma cadeia:
Você pode usar ConversationTokenBufferMemory em uma cadeia para aprimorar as interações com o modelo de IA.
from langchain.chains import ConversationChain conversation_with_summary = ConversationChain( llm=llm, # We set a very low max_token_limit for the purposes of testing. memory=ConversationTokenBufferMemory(llm=OpenAI(), max_token_limit=60), verbose=True,
)
conversation_with_summary.predict(input="Hi, what's up?")
Neste exemplo, ConversationTokenBufferMemory é usado em um ConversationChain para gerenciar a conversa e limitar as interações com base no comprimento do token.
8. VectorStoreRetrieverMemória
VectorStoreRetrieverMemory armazena memórias em um armazenamento de vetores e consulta os K documentos mais “salientes” sempre que é chamado. Este tipo de memória não rastreia explicitamente a ordem das interações, mas usa recuperação vetorial para buscar memórias relevantes.
from datetime import datetime
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.llms import OpenAI
from langchain.memory import VectorStoreRetrieverMemory
from langchain.chains import ConversationChain
from langchain.prompts import PromptTemplate # Initialize your vector store (specifics depend on the chosen vector store)
import faiss
from langchain.docstore import InMemoryDocstore
from langchain.vectorstores import FAISS embedding_size = 1536 # Dimensions of the OpenAIEmbeddings
index = faiss.IndexFlatL2(embedding_size)
embedding_fn = OpenAIEmbeddings().embed_query
vectorstore = FAISS(embedding_fn, index, InMemoryDocstore({}), {}) # Create your VectorStoreRetrieverMemory
retriever = vectorstore.as_retriever(search_kwargs=dict(k=1))
memory = VectorStoreRetrieverMemory(retriever=retriever) # Save context and relevant information to the memory
memory.save_context({"input": "My favorite food is pizza"}, {"output": "that's good to know"})
memory.save_context({"input": "My favorite sport is soccer"}, {"output": "..."})
memory.save_context({"input": "I don't like the Celtics"}, {"output": "ok"}) # Retrieve relevant information from memory based on a query
print(memory.load_memory_variables({"prompt": "what sport should i watch?"})["history"])
Neste exemplo, VectorStoreRetrieverMemory é usado para armazenar e recuperar informações relevantes de uma conversa baseada na recuperação de vetores.
Você também pode usar VectorStoreRetrieverMemory em uma cadeia para recuperação de conhecimento baseada em conversação, conforme mostrado nos exemplos anteriores.
Esses diferentes tipos de memória no Langchain fornecem várias maneiras de gerenciar e recuperar informações de conversas, aprimorando as capacidades dos modelos de IA na compreensão e resposta às consultas e ao contexto do usuário. Cada tipo de memória pode ser selecionado com base nos requisitos específicos da sua aplicação.
Agora aprenderemos como usar memória com um LLMChain. A memória em um LLMChain permite que o modelo se lembre de interações e contextos anteriores para fornecer respostas mais coerentes e conscientes do contexto.
Para configurar a memória em um LLMChain, você precisa criar uma classe de memória, como ConversationBufferMemory. Veja como você pode configurá-lo:
from langchain.chains import LLMChain
from langchain.llms import OpenAI
from langchain.memory import ConversationBufferMemory
from langchain.prompts import PromptTemplate template = """You are a chatbot having a conversation with a human. {chat_history}
Human: {human_input}
Chatbot:""" prompt = PromptTemplate( input_variables=["chat_history", "human_input"], template=template
)
memory = ConversationBufferMemory(memory_key="chat_history") llm = OpenAI()
llm_chain = LLMChain( llm=llm, prompt=prompt, verbose=True, memory=memory,
) llm_chain.predict(human_input="Hi there my friend")
Neste exemplo, o ConversationBufferMemory é usado para armazenar o histórico da conversa. O memory_key
parâmetro especifica a chave usada para armazenar o histórico da conversa.
Se você estiver usando um modelo de bate-papo em vez de um modelo de estilo de conclusão, poderá estruturar seus prompts de maneira diferente para utilizar melhor a memória. Aqui está um exemplo de como configurar um LLMChain baseado em modelo de chat com memória:
from langchain.chat_models import ChatOpenAI
from langchain.schema import SystemMessage
from langchain.prompts import ( ChatPromptTemplate, HumanMessagePromptTemplate, MessagesPlaceholder,
) # Create a ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages( [ SystemMessage( content="You are a chatbot having a conversation with a human." ), # The persistent system prompt MessagesPlaceholder( variable_name="chat_history" ), # Where the memory will be stored. HumanMessagePromptTemplate.from_template( "{human_input}" ), # Where the human input will be injected ]
) memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) llm = ChatOpenAI() chat_llm_chain = LLMChain( llm=llm, prompt=prompt, verbose=True, memory=memory,
) chat_llm_chain.predict(human_input="Hi there my friend")
Neste exemplo, o ChatPromptTemplate é usado para estruturar o prompt e o ConversationBufferMemory é usado para armazenar e recuperar o histórico da conversa. Essa abordagem é particularmente útil para conversas no estilo chat, onde o contexto e a história desempenham um papel crucial.
A memória também pode ser adicionada a uma cadeia com múltiplas entradas, como uma cadeia de perguntas/respostas. Aqui está um exemplo de como configurar a memória em uma cadeia de perguntas/respostas:
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.embeddings.cohere import CohereEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores.elastic_vector_search import ElasticVectorSearch
from langchain.vectorstores import Chroma
from langchain.docstore.document import Document
from langchain.chains.question_answering import load_qa_chain
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.memory import ConversationBufferMemory # Split a long document into smaller chunks
with open("../../state_of_the_union.txt") as f: state_of_the_union = f.read()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_text(state_of_the_union) # Create an ElasticVectorSearch instance to index and search the document chunks
embeddings = OpenAIEmbeddings()
docsearch = Chroma.from_texts( texts, embeddings, metadatas=[{"source": i} for i in range(len(texts))]
) # Perform a question about the document
query = "What did the president say about Justice Breyer"
docs = docsearch.similarity_search(query) # Set up a prompt for the question-answering chain with memory
template = """You are a chatbot having a conversation with a human. Given the following extracted parts of a long document and a question, create a final answer. {context} {chat_history}
Human: {human_input}
Chatbot:""" prompt = PromptTemplate( input_variables=["chat_history", "human_input", "context"], template=template
)
memory = ConversationBufferMemory(memory_key="chat_history", input_key="human_input")
chain = load_qa_chain( OpenAI(temperature=0), chain_type="stuff", memory=memory, prompt=prompt
) # Ask the question and retrieve the answer
query = "What did the president say about Justice Breyer"
result = chain({"input_documents": docs, "human_input": query}, return_only_outputs=True) print(result)
print(chain.memory.buffer)
Neste exemplo, uma pergunta é respondida usando um documento dividido em partes menores. O ConversationBufferMemory é usado para armazenar e recuperar o histórico da conversa, permitindo que o modelo forneça respostas baseadas no contexto.
Adicionar memória a um agente permite que ele lembre e use interações anteriores para responder perguntas e fornecer respostas sensíveis ao contexto. Veja como você pode configurar a memória em um agente:
from langchain.agents import ZeroShotAgent, Tool, AgentExecutor
from langchain.memory import ConversationBufferMemory
from langchain.llms import OpenAI
from langchain.chains import LLMChain
from langchain.utilities import GoogleSearchAPIWrapper # Create a tool for searching
search = GoogleSearchAPIWrapper()
tools = [ Tool( name="Search", func=search.run, description="useful for when you need to answer questions about current events", )
] # Create a prompt with memory
prefix = """Have a conversation with a human, answering the following questions as best you can. You have access to the following tools:"""
suffix = """Begin!" {chat_history}
Question: {input}
{agent_scratchpad}""" prompt = ZeroShotAgent.create_prompt( tools, prefix=prefix, suffix=suffix, input_variables=["input", "chat_history", "agent_scratchpad"],
)
memory = ConversationBufferMemory(memory_key="chat_history") # Create an LLMChain with memory
llm_chain = LLMChain(llm=OpenAI(temperature=0), prompt=prompt)
agent = ZeroShotAgent(llm_chain=llm_chain, tools=tools, verbose=True)
agent_chain = AgentExecutor.from_agent_and_tools( agent=agent, tools=tools, verbose=True, memory=memory
) # Ask a question and retrieve the answer
response = agent_chain.run(input="How many people live in Canada?")
print(response) # Ask a follow-up question
response = agent_chain.run(input="What is their national anthem called?")
print(response)
Neste exemplo, a memória é adicionada a um agente, permitindo que ele se lembre do histórico de conversas anteriores e forneça respostas baseadas no contexto. Isso permite que o agente responda perguntas de acompanhamento com precisão com base nas informações armazenadas na memória.
Linguagem de expressão LangChain
No mundo do processamento de linguagem natural e do aprendizado de máquina, compor cadeias complexas de operações pode ser uma tarefa difícil. Felizmente, a LangChain Expression Language (LCEL) vem em socorro, fornecendo uma maneira declarativa e eficiente de construir e implantar pipelines sofisticados de processamento de linguagem. O LCEL foi projetado para simplificar o processo de composição de cadeias, possibilitando passar da prototipagem à produção com facilidade. Neste blog, exploraremos o que é LCEL e por que você pode querer usá-lo, juntamente com exemplos práticos de código para ilustrar seus recursos.
LCEL, ou LangChain Expression Language, é uma ferramenta poderosa para compor cadeias de processamento de linguagem. Ele foi desenvolvido especificamente para oferecer suporte à transição da prototipagem para a produção de maneira transparente, sem exigir grandes alterações no código. Esteja você construindo uma cadeia simples de “prompt + LLM” ou um pipeline complexo com centenas de etapas, a LCEL tem o que você precisa.
Aqui estão alguns motivos para usar LCEL em seus projetos de processamento de linguagem:
- Fast Token Streaming: LCEL entrega tokens de um modelo de linguagem para um analisador de saída em tempo real, melhorando a capacidade de resposta e a eficiência.
- APIs versáteis: LCEL oferece suporte a APIs síncronas e assíncronas para prototipagem e uso em produção, lidando com múltiplas solicitações com eficiência.
- Paralelização automática: o LCEL otimiza a execução paralela quando possível, reduzindo a latência nas interfaces sincronizadas e assíncronas.
- Configurações confiáveis: configure novas tentativas e substitutos para maior confiabilidade da cadeia em escala, com suporte de streaming no desenvolvimento.
- Transmitir resultados intermediários: acesse resultados intermediários durante o processamento para atualizações do usuário ou para fins de depuração.
- Geração de esquema: LCEL gera esquemas Pydantic e JSONSchema para validação de entrada e saída.
- Rastreamento abrangente: LangSmith rastreia automaticamente todas as etapas em cadeias complexas para observabilidade e depuração.
- Fácil implantação: implante cadeias criadas por LCEL sem esforço usando LangServe.
Agora, vamos mergulhar em exemplos práticos de código que demonstram o poder do LCEL. Exploraremos tarefas e cenários comuns onde o LCEL se destaca.
Alerta + LLM
A composição mais fundamental envolve combinar um prompt e um modelo de linguagem para criar uma cadeia que recebe a entrada do usuário, adiciona-a a um prompt, passa-a para um modelo e retorna a saída bruta do modelo. Aqui está um exemplo:
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI prompt = ChatPromptTemplate.from_template("tell me a joke about {foo}")
model = ChatOpenAI()
chain = prompt | model result = chain.invoke({"foo": "bears"})
print(result)
Neste exemplo, a corrente gera uma piada sobre ursos.
Você pode anexar sequências de parada à sua cadeia para controlar como ela processa o texto. Por exemplo:
chain = prompt | model.bind(stop=["n"])
result = chain.invoke({"foo": "bears"})
print(result)
Esta configuração interrompe a geração de texto quando um caractere de nova linha é encontrado.
LCEL suporta anexar informações de chamada de função à sua cadeia. Aqui está um exemplo:
functions = [ { "name": "joke", "description": "A joke", "parameters": { "type": "object", "properties": { "setup": {"type": "string", "description": "The setup for the joke"}, "punchline": { "type": "string", "description": "The punchline for the joke", }, }, "required": ["setup", "punchline"], }, }
]
chain = prompt | model.bind(function_call={"name": "joke"}, functions=functions)
result = chain.invoke({"foo": "bears"}, config={})
print(result)
Este exemplo anexa informações de chamada de função para gerar uma piada.
Prompt + LLM + OutputParser
Você pode adicionar um analisador de saída para transformar a saída do modelo bruto em um formato mais funcional. Veja como você pode fazer isso:
from langchain.schema.output_parser import StrOutputParser chain = prompt | model | StrOutputParser()
result = chain.invoke({"foo": "bears"})
print(result)
A saída agora está em formato de string, o que é mais conveniente para tarefas posteriores.
Ao especificar uma função a ser retornada, você pode analisá-la diretamente usando LCEL. Por exemplo:
from langchain.output_parsers.openai_functions import JsonOutputFunctionsParser chain = ( prompt | model.bind(function_call={"name": "joke"}, functions=functions) | JsonOutputFunctionsParser()
)
result = chain.invoke({"foo": "bears"})
print(result)
Este exemplo analisa a saída da função “joke” diretamente.
Estes são apenas alguns exemplos de como o LCEL simplifica tarefas complexas de processamento de linguagem. Esteja você criando chatbots, gerando conteúdo ou realizando transformações complexas de texto, o LCEL pode agilizar seu fluxo de trabalho e tornar seu código mais fácil de manter.
RAG (geração aumentada de recuperação)
LCEL pode ser usado para criar cadeias de geração aumentadas por recuperação, que combinam etapas de recuperação e geração de linguagem. Aqui está um exemplo:
from operator import itemgetter from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain.embeddings import OpenAIEmbeddings
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough, RunnableLambda
from langchain.vectorstores import FAISS # Create a vector store and retriever
vectorstore = FAISS.from_texts( ["harrison worked at kensho"], embedding=OpenAIEmbeddings()
)
retriever = vectorstore.as_retriever() # Define templates for prompts
template = """Answer the question based only on the following context:
{context} Question: {question} """
prompt = ChatPromptTemplate.from_template(template) model = ChatOpenAI() # Create a retrieval-augmented generation chain
chain = ( {"context": retriever, "question": RunnablePassthrough()} | prompt | model | StrOutputParser()
) result = chain.invoke("where did harrison work?")
print(result)
Neste exemplo, a cadeia recupera informações relevantes do contexto e gera uma resposta à pergunta.
Cadeia de recuperação conversacional
Você pode adicionar facilmente o histórico de conversas às suas cadeias. Aqui está um exemplo de cadeia de recuperação conversacional:
from langchain.schema.runnable import RunnableMap
from langchain.schema import format_document from langchain.prompts.prompt import PromptTemplate # Define templates for prompts
_template = """Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question, in its original language. Chat History:
{chat_history}
Follow Up Input: {question}
Standalone question:"""
CONDENSE_QUESTION_PROMPT = PromptTemplate.from_template(_template) template = """Answer the question based only on the following context:
{context} Question: {question} """
ANSWER_PROMPT = ChatPromptTemplate.from_template(template) # Define input map and context
_inputs = RunnableMap( standalone_question=RunnablePassthrough.assign( chat_history=lambda x: _format_chat_history(x["chat_history"]) ) | CONDENSE_QUESTION_PROMPT | ChatOpenAI(temperature=0) | StrOutputParser(),
)
_context = { "context": itemgetter("standalone_question") | retriever | _combine_documents, "question": lambda x: x["standalone_question"],
}
conversational_qa_chain = _inputs | _context | ANSWER_PROMPT | ChatOpenAI() result = conversational_qa_chain.invoke( { "question": "where did harrison work?", "chat_history": [], }
)
print(result)
Neste exemplo, a cadeia trata de uma pergunta de acompanhamento dentro de um contexto de conversação.
Com memória e devolução de documentos originais
LCEL também suporta memória e retorno de documentos de origem. Veja como você pode usar a memória em uma cadeia:
from operator import itemgetter
from langchain.memory import ConversationBufferMemory # Create a memory instance
memory = ConversationBufferMemory( return_messages=True, output_key="answer", input_key="question"
) # Define steps for the chain
loaded_memory = RunnablePassthrough.assign( chat_history=RunnableLambda(memory.load_memory_variables) | itemgetter("history"),
) standalone_question = { "standalone_question": { "question": lambda x: x["question"], "chat_history": lambda x: _format_chat_history(x["chat_history"]), } | CONDENSE_QUESTION_PROMPT | ChatOpenAI(temperature=0) | StrOutputParser(),
} retrieved_documents = { "docs": itemgetter("standalone_question") | retriever, "question": lambda x: x["standalone_question"],
} final_inputs = { "context": lambda x: _combine_documents(x["docs"]), "question": itemgetter("question"),
} answer = { "answer": final_inputs | ANSWER_PROMPT | ChatOpenAI(), "docs": itemgetter("docs"),
} # Create the final chain by combining the steps
final_chain = loaded_memory | standalone_question | retrieved_documents | answer inputs = {"question": "where did harrison work?"}
result = final_chain.invoke(inputs)
print(result)
Neste exemplo, a memória é usada para armazenar e recuperar o histórico de conversas e documentos de origem.
Múltiplas Cadeias
Você pode encadear várias cadeias usando Runnables. Aqui está um exemplo:
from operator import itemgetter from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser prompt1 = ChatPromptTemplate.from_template("what is the city {person} is from?")
prompt2 = ChatPromptTemplate.from_template( "what country is the city {city} in? respond in {language}"
) model = ChatOpenAI() chain1 = prompt1 | model | StrOutputParser() chain2 = ( {"city": chain1, "language": itemgetter("language")} | prompt2 | model | StrOutputParser()
) result = chain2.invoke({"person": "obama", "language": "spanish"})
print(result)
Neste exemplo, duas cadeias são combinadas para gerar informações sobre uma cidade e seu país em um idioma específico.
Ramificação e fusão
LCEL permite dividir e mesclar cadeias usando RunnableMaps. Aqui está um exemplo de ramificação e fusão:
from operator import itemgetter from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser planner = ( ChatPromptTemplate.from_template("Generate an argument about: {input}") | ChatOpenAI() | StrOutputParser() | {"base_response": RunnablePassthrough()}
) arguments_for = ( ChatPromptTemplate.from_template( "List the pros or positive aspects of {base_response}" ) | ChatOpenAI() | StrOutputParser()
)
arguments_against = ( ChatPromptTemplate.from_template( "List the cons or negative aspects of {base_response}" ) | ChatOpenAI() | StrOutputParser()
) final_responder = ( ChatPromptTemplate.from_messages( [ ("ai", "{original_response}"), ("human", "Pros:n{results_1}nnCons:n{results_2}"), ("system", "Generate a final response given the critique"), ] ) | ChatOpenAI() | StrOutputParser()
) chain = ( planner | { "results_1": arguments_for, "results_2": arguments_against, "original_response": itemgetter("base_response"), } | final_responder
) result = chain.invoke({"input": "scrum"})
print(result)
Neste exemplo, uma cadeia de ramificação e fusão é usada para gerar um argumento e avaliar seus prós e contras antes de gerar uma resposta final.
Escrevendo código Python com LCEL
Uma das aplicações poderosas da LangChain Expression Language (LCEL) é escrever código Python para resolver problemas do usuário. Abaixo está um exemplo de como usar LCEL para escrever código Python:
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain_experimental.utilities import PythonREPL template = """Write some python code to solve the user's problem. Return only python code in Markdown format, e.g.: ```python
....
```"""
prompt = ChatPromptTemplate.from_messages([("system", template), ("human", "{input}")]) model = ChatOpenAI() def _sanitize_output(text: str): _, after = text.split("```python") return after.split("```")[0] chain = prompt | model | StrOutputParser() | _sanitize_output | PythonREPL().run result = chain.invoke({"input": "what's 2 plus 2"})
print(result)
Neste exemplo, um usuário fornece entrada e LCEL gera código Python para resolver o problema. O código é então executado usando um REPL Python, e o código Python resultante é retornado no formato Markdown.
Observe que usar um REPL Python pode executar código arbitrário, portanto, use-o com cuidado.
Adicionando memória a uma cadeia
A memória é essencial em muitas aplicações de IA conversacional. Veja como adicionar memória a uma cadeia arbitrária:
from operator import itemgetter
from langchain.chat_models import ChatOpenAI
from langchain.memory import ConversationBufferMemory
from langchain.schema.runnable import RunnablePassthrough, RunnableLambda
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder model = ChatOpenAI()
prompt = ChatPromptTemplate.from_messages( [ ("system", "You are a helpful chatbot"), MessagesPlaceholder(variable_name="history"), ("human", "{input}"), ]
) memory = ConversationBufferMemory(return_messages=True) # Initialize memory
memory.load_memory_variables({}) chain = ( RunnablePassthrough.assign( history=RunnableLambda(memory.load_memory_variables) | itemgetter("history") ) | prompt | model
) inputs = {"input": "hi, I'm Bob"}
response = chain.invoke(inputs)
response # Save the conversation in memory
memory.save_context(inputs, {"output": response.content}) # Load memory to see the conversation history
memory.load_memory_variables({})
Neste exemplo, a memória é usada para armazenar e recuperar o histórico de conversas, permitindo que o chatbot mantenha o contexto e responda adequadamente.
Usando ferramentas externas com executáveis
LCEL permite integrar perfeitamente ferramentas externas com Runnables. Aqui está um exemplo usando a ferramenta DuckDuckGo Search:
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain.tools import DuckDuckGoSearchRun search = DuckDuckGoSearchRun() template = """Turn the following user input into a search query for a search engine: {input}"""
prompt = ChatPromptTemplate.from_template(template) model = ChatOpenAI() chain = prompt | model | StrOutputParser() | search search_result = chain.invoke({"input": "I'd like to figure out what games are tonight"})
print(search_result)
Neste exemplo, LCEL integra a ferramenta DuckDuckGo Search na cadeia, permitindo gerar uma consulta de pesquisa a partir da entrada do usuário e recuperar os resultados da pesquisa.
A flexibilidade do LCEL facilita a incorporação de diversas ferramentas e serviços externos em seus pipelines de processamento de linguagem, aprimorando seus recursos e funcionalidades.
Adicionando moderação a um aplicativo LLM
Para garantir que seu aplicativo LLM cumpra as políticas de conteúdo e inclua proteções de moderação, você pode integrar verificações de moderação em sua cadeia. Veja como adicionar moderação usando LangChain:
from langchain.chains import OpenAIModerationChain
from langchain.llms import OpenAI
from langchain.prompts import ChatPromptTemplate moderate = OpenAIModerationChain() model = OpenAI()
prompt = ChatPromptTemplate.from_messages([("system", "repeat after me: {input}")]) chain = prompt | model # Original response without moderation
response_without_moderation = chain.invoke({"input": "you are stupid"})
print(response_without_moderation) moderated_chain = chain | moderate # Response after moderation
response_after_moderation = moderated_chain.invoke({"input": "you are stupid"})
print(response_after_moderation)
Neste exemplo, o OpenAIModerationChain
é usado para adicionar moderação à resposta gerada pelo LLM. A cadeia de moderação verifica a resposta em busca de conteúdo que viole a política de conteúdo da OpenAI. Se alguma violação for encontrada, a resposta será sinalizada de acordo.
Roteamento por similaridade semântica
LCEL permite implementar lógica de roteamento personalizada com base na semelhança semântica da entrada do usuário. Aqui está um exemplo de como determinar dinamicamente a lógica da cadeia com base na entrada do usuário:
from langchain.chat_models import ChatOpenAI
from langchain.embeddings import OpenAIEmbeddings
from langchain.prompts import PromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnableLambda, RunnablePassthrough
from langchain.utils.math import cosine_similarity physics_template = """You are a very smart physics professor. You are great at answering questions about physics in a concise and easy to understand manner. When you don't know the answer to a question you admit that you don't know. Here is a question:
{query}""" math_template = """You are a very good mathematician. You are great at answering math questions. You are so good because you are able to break down hard problems into their component parts, answer the component parts, and then put them together to answer the broader question. Here is a question:
{query}""" embeddings = OpenAIEmbeddings()
prompt_templates = [physics_template, math_template]
prompt_embeddings = embeddings.embed_documents(prompt_templates) def prompt_router(input): query_embedding = embeddings.embed_query(input["query"]) similarity = cosine_similarity([query_embedding], prompt_embeddings)[0] most_similar = prompt_templates[similarity.argmax()] print("Using MATH" if most_similar == math_template else "Using PHYSICS") return PromptTemplate.from_template(most_similar) chain = ( {"query": RunnablePassthrough()} | RunnableLambda(prompt_router) | ChatOpenAI() | StrOutputParser()
) print(chain.invoke({"query": "What's a black hole"}))
print(chain.invoke({"query": "What's a path integral"}))
Neste exemplo, o prompt_router
A função calcula a semelhança de cosseno entre a entrada do usuário e modelos de prompt predefinidos para questões de física e matemática. Com base na pontuação de similaridade, a cadeia seleciona dinamicamente o modelo de prompt mais relevante, garantindo que o chatbot responda adequadamente à pergunta do usuário.
Usando agentes e executáveis
LangChain permite criar agentes combinando Runnables, prompts, modelos e ferramentas. Aqui está um exemplo de como construir um agente e usá-lo:
from langchain.agents import XMLAgent, tool, AgentExecutor
from langchain.chat_models import ChatAnthropic model = ChatAnthropic(model="claude-2") @tool
def search(query: str) -> str: """Search things about current events.""" return "32 degrees" tool_list = [search] # Get prompt to use
prompt = XMLAgent.get_default_prompt() # Logic for going from intermediate steps to a string to pass into the model
def convert_intermediate_steps(intermediate_steps): log = "" for action, observation in intermediate_steps: log += ( f"<tool>{action.tool}</tool><tool_input>{action.tool_input}" f"</tool_input><observation>{observation}</observation>" ) return log # Logic for converting tools to a string to go in the prompt
def convert_tools(tools): return "n".join([f"{tool.name}: {tool.description}" for tool in tools]) agent = ( { "question": lambda x: x["question"], "intermediate_steps": lambda x: convert_intermediate_steps( x["intermediate_steps"] ), } | prompt.partial(tools=convert_tools(tool_list)) | model.bind(stop=["</tool_input>", "</final_answer>"]) | XMLAgent.get_default_output_parser()
) agent_executor = AgentExecutor(agent=agent, tools=tool_list, verbose=True) result = agent_executor.invoke({"question": "What's the weather in New York?"})
print(result)
Neste exemplo, um agente é criado combinando um modelo, ferramentas, um prompt e uma lógica customizada para etapas intermediárias e conversão de ferramentas. O agente é então executado, fornecendo uma resposta à consulta do usuário.
Consultando um banco de dados SQL
Você pode usar LangChain para consultar um banco de dados SQL e gerar consultas SQL com base nas perguntas do usuário. Aqui está um exemplo:
from langchain.prompts import ChatPromptTemplate template = """Based on the table schema below, write a SQL query that would answer the user's question:
{schema} Question: {question}
SQL Query:"""
prompt = ChatPromptTemplate.from_template(template) from langchain.utilities import SQLDatabase # Initialize the database (you'll need the Chinook sample DB for this example)
db = SQLDatabase.from_uri("sqlite:///./Chinook.db") def get_schema(_): return db.get_table_info() def run_query(query): return db.run(query) from langchain.chat_models import ChatOpenAI
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough model = ChatOpenAI() sql_response = ( RunnablePassthrough.assign(schema=get_schema) | prompt | model.bind(stop=["nSQLResult:"]) | StrOutputParser()
) result = sql_response.invoke({"question": "How many employees are there?"})
print(result) template = """Based on the table schema below, question, SQL query, and SQL response, write a natural language response:
{schema} Question: {question}
SQL Query: {query}
SQL Response: {response}"""
prompt_response = ChatPromptTemplate.from_template(template) full_chain = ( RunnablePassthrough.assign(query=sql_response) | RunnablePassthrough.assign( schema=get_schema, response=lambda x: db.run(x["query"]), ) | prompt_response | model
) response = full_chain.invoke({"question": "How many employees are there?"})
print(response)
Neste exemplo, LangChain é usado para gerar consultas SQL com base nas perguntas do usuário e recuperar respostas de um banco de dados SQL. Os prompts e respostas são formatados para fornecer interações em linguagem natural com o banco de dados.
Automatize tarefas e fluxos de trabalho manuais com nosso construtor de fluxo de trabalho baseado em IA, projetado pela Nanonets para você e suas equipes.
LangServe e LangSmith
LangServe ajuda os desenvolvedores a implantar executáveis e cadeias LangChain como uma API REST. Esta biblioteca está integrada com FastAPI e usa pydantic para validação de dados. Além disso, ele fornece um cliente que pode ser usado para chamar executáveis implantados em um servidor, e um cliente JavaScript está disponível em LangChainJS.
Funcionalidades
- Os esquemas de entrada e saída são inferidos automaticamente do seu objeto LangChain e aplicados em cada chamada de API, com mensagens de erro ricas.
- Uma página de documentos da API com JSONSchema e Swagger está disponível.
- Endpoints /invoke, /batch e /stream eficientes com suporte para muitas solicitações simultâneas em um único servidor.
- /stream_log endpoint para transmitir todas (ou algumas) etapas intermediárias de sua cadeia/agente.
- Página do Playground em /playground com saída de streaming e etapas intermediárias.
- Rastreamento integrado (opcional) para LangSmith; basta adicionar sua chave API (consulte as instruções).
- Tudo construído com bibliotecas Python de código aberto testadas em batalha, como FastAPI, Pydantic, uvloop e asyncio.
Limitações
- Os retornos de chamada do cliente ainda não são suportados para eventos originados no servidor.
- Os documentos OpenAPI não serão gerados ao usar o Pydantic V2. FastAPI não oferece suporte à mistura de namespaces pydantic v1 e v2. Consulte a seção abaixo para obter mais detalhes.
Use a CLI LangChain para inicializar um projeto LangServe rapidamente. Para usar o langchain CLI, certifique-se de ter uma versão recente do langchain-cli instalada. Você pode instalá-lo com pip install -U langchain-cli.
langchain app new ../path/to/directory
Comece sua instância LangServe rapidamente com os modelos LangChain. Para mais exemplos, consulte o índice de modelos ou o diretório de exemplos.
Aqui está um servidor que implanta um modelo de chat OpenAI, um modelo de chat Antrópico e uma cadeia que usa o modelo Antrópico para contar uma piada sobre um tópico.
#!/usr/bin/env python
from fastapi import FastAPI
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatAnthropic, ChatOpenAI
from langserve import add_routes app = FastAPI( title="LangChain Server", version="1.0", description="A simple api server using Langchain's Runnable interfaces",
) add_routes( app, ChatOpenAI(), path="/openai",
) add_routes( app, ChatAnthropic(), path="/anthropic",
) model = ChatAnthropic()
prompt = ChatPromptTemplate.from_template("tell me a joke about {topic}")
add_routes( app, prompt | model, path="/chain",
) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="localhost", port=8000)
Depois de implantar o servidor acima, você poderá visualizar os documentos OpenAPI gerados usando:
curl localhost:8000/docs
Certifique-se de adicionar o sufixo /docs.
from langchain.schema import SystemMessage, HumanMessage
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnableMap
from langserve import RemoteRunnable openai = RemoteRunnable("http://localhost:8000/openai/")
anthropic = RemoteRunnable("http://localhost:8000/anthropic/")
joke_chain = RemoteRunnable("http://localhost:8000/chain/") joke_chain.invoke({"topic": "parrots"}) # or async
await joke_chain.ainvoke({"topic": "parrots"}) prompt = [ SystemMessage(content='Act like either a cat or a parrot.'), HumanMessage(content='Hello!')
] # Supports astream
async for msg in anthropic.astream(prompt): print(msg, end="", flush=True) prompt = ChatPromptTemplate.from_messages( [("system", "Tell me a long story about {topic}")]
) # Can define custom chains
chain = prompt | RunnableMap({ "openai": openai, "anthropic": anthropic,
}) chain.batch([{ "topic": "parrots" }, { "topic": "cats" }])
Em TypeScript (requer LangChain.js versão 0.0.166 ou posterior):
import { RemoteRunnable } from "langchain/runnables/remote"; const chain = new RemoteRunnable({ url: `http://localhost:8000/chain/invoke/`,
});
const result = await chain.invoke({ topic: "cats",
});
Python usando solicitações:
import requests
response = requests.post( "http://localhost:8000/chain/invoke/", json={'input': {'topic': 'cats'}}
)
response.json()
Você também pode usar curl:
curl --location --request POST 'http://localhost:8000/chain/invoke/' --header 'Content-Type: application/json' --data-raw '{ "input": { "topic": "cats" } }'
O seguinte código:
...
add_routes( app, runnable, path="/my_runnable",
)
adiciona esses endpoints ao servidor:
- POST /my_runnable/invoke – invoca o executável em uma única entrada
- POST /my_runnable/batch – invoca o executável em um lote de entradas
- POST /my_runnable/stream – invoca em uma única entrada e transmite a saída
- POST /my_runnable/stream_log – invoca em uma única entrada e transmite a saída, incluindo a saída de etapas intermediárias conforme ela é gerada
- GET /my_runnable/input_schema – esquema json para entrada no executável
- GET /my_runnable/output_schema – esquema json para saída do executável
- GET /my_runnable/config_schema – esquema json para configuração do executável
Você pode encontrar uma página de playground para seu executável em /my_runnable/playground. Isso expõe uma UI simples para configurar e invocar seu executável com saída de streaming e etapas intermediárias.
Para cliente e servidor:
pip install "langserve[all]"
ou pip install “langserve[client]” para código do cliente e pip install “langserve[server]” para código do servidor.
Se você precisar adicionar autenticação ao seu servidor, consulte a documentação de segurança e a documentação de middleware do FastAPI.
Você pode implantar no GCP Cloud Run usando o seguinte comando:
gcloud run deploy [your-service-name] --source . --port 8001 --allow-unauthenticated --region us-central1 --set-env-vars=OPENAI_API_KEY=your_key
LangServe fornece suporte para Pydantic 2 com algumas limitações. Os documentos OpenAPI não serão gerados para invocar/batch/stream/stream_log ao usar o Pydantic V2. A API rápida não oferece suporte à mistura de namespaces pydantic v1 e v2. LangChain usa o namespace v1 no Pydantic v2. Leia as diretrizes a seguir para garantir a compatibilidade com LangChain. Exceto por essas limitações, esperamos que os endpoints da API, o playground e quaisquer outros recursos funcionem conforme o esperado.
Os aplicativos LLM geralmente lidam com arquivos. Existem diferentes arquiteturas que podem ser feitas para implementar o processamento de arquivos; em alto nível:
- O arquivo pode ser carregado no servidor por meio de um terminal dedicado e processado usando um terminal separado.
- O arquivo pode ser carregado por valor (bytes de arquivo) ou referência (por exemplo, url s3 para o conteúdo do arquivo).
- O endpoint de processamento pode ser bloqueador ou não bloqueador.
- Se for necessário um processamento significativo, o processamento poderá ser transferido para um pool de processos dedicado.
Você deve determinar qual é a arquitetura apropriada para seu aplicativo. Atualmente, para fazer upload de arquivos por valor para um executável, use a codificação base64 para o arquivo (multipart/form-data ainda não é compatível).
Aqui está um exemplo que mostra como usar a codificação base64 para enviar um arquivo para um executável remoto. Lembre-se, você sempre pode fazer upload de arquivos por referência (por exemplo, URL s3) ou carregá-los como multipart/form-data para um endpoint dedicado.
Os tipos de entrada e saída são definidos em todos os executáveis. Você pode acessá-los por meio das propriedades input_schema e output_schema. LangServe usa esses tipos para validação e documentação. Se quiser substituir os tipos inferidos padrão, você pode usar o método with_types.
Aqui está um exemplo de brinquedo para ilustrar a ideia:
from typing import Any
from fastapi import FastAPI
from langchain.schema.runnable import RunnableLambda app = FastAPI() def func(x: Any) -> int: """Mistyped function that should accept an int but accepts anything.""" return x + 1 runnable = RunnableLambda(func).with_types( input_schema=int,
) add_routes(app, runnable)
Herde de CustomUserType se desejar que os dados sejam desserializados em um modelo pydantic em vez da representação de dict equivalente. No momento, esse tipo funciona apenas no lado do servidor e é usado para especificar o comportamento de decodificação desejado. Se herdar deste tipo, o servidor manterá o tipo decodificado como um modelo pydantic em vez de convertê-lo em um ditado.
from fastapi import FastAPI
from langchain.schema.runnable import RunnableLambda
from langserve import add_routes
from langserve.schema import CustomUserType app = FastAPI() class Foo(CustomUserType): bar: int def func(foo: Foo) -> int: """Sample function that expects a Foo type which is a pydantic model""" assert isinstance(foo, Foo) return foo.bar add_routes(app, RunnableLambda(func), path="/foo")
O playground permite que você defina widgets personalizados para seu executável no backend. Um widget é especificado no nível do campo e enviado como parte do esquema JSON do tipo de entrada. Um widget deve conter uma chave chamada type com o valor sendo um de uma lista bem conhecida de widgets. Outras chaves de widget serão associadas a valores que descrevem caminhos em um objeto JSON.
Esquema geral:
type JsonPath = number | string | (number | string)[];
type NameSpacedPath = { title: string; path: JsonPath }; // Using title to mimic json schema, but can use namespace
type OneOfPath = { oneOf: JsonPath[] }; type Widget = { type: string // Some well-known type (e.g., base64file, chat, etc.) [key: string]: JsonPath | NameSpacedPath | OneOfPath;
};
Permite a criação de uma entrada de upload de arquivo no playground da UI para arquivos que são carregados como strings codificadas em base64. Aqui está o exemplo completo.
try: from pydantic.v1 import Field
except ImportError: from pydantic import Field from langserve import CustomUserType # ATTENTION: Inherit from CustomUserType instead of BaseModel otherwise
# the server will decode it into a dict instead of a pydantic model.
class FileProcessingRequest(CustomUserType): """Request including a base64 encoded file.""" # The extra field is used to specify a widget for the playground UI. file: str = Field(..., extra={"widget": {"type": "base64file"}}) num_chars: int = 100
Automatize tarefas e fluxos de trabalho manuais com nosso construtor de fluxo de trabalho baseado em IA, projetado pela Nanonets para você e suas equipes.
Introdução ao LangSmith
LangChain facilita a prototipagem de aplicativos e agentes LLM. No entanto, entregar aplicativos LLM para produção pode ser extremamente difícil. Você provavelmente terá que personalizar e iterar fortemente seus prompts, cadeias e outros componentes para criar um produto de alta qualidade.
Para auxiliar nesse processo, foi introduzido o LangSmith, uma plataforma unificada para depuração, teste e monitoramento de seus aplicativos LLM.
Quando isso pode ser útil? Você pode achar útil quando quiser depurar rapidamente uma nova cadeia, agente ou conjunto de ferramentas, visualizar como os componentes (cadeias, llms, recuperadores, etc.) se relacionam e são usados, avaliar diferentes prompts e LLMs para um único componente, execute uma determinada cadeia várias vezes em um conjunto de dados para garantir que ela atenda consistentemente a um padrão de qualidade ou capture rastreamentos de uso e use LLMs ou pipelines analíticos para gerar insights.
Pré-requisitos:
- Crie uma conta LangSmith e crie uma chave API (veja o canto inferior esquerdo).
- Familiarize-se com a plataforma consultando a documentação.
Agora, vamos começar!
Primeiro, configure suas variáveis de ambiente para informar ao LangChain para registrar rastreamentos. Isso é feito definindo a variável de ambiente LANGCHAIN_TRACING_V2 como verdadeira. Você pode informar ao LangChain em qual projeto registrar-se definindo a variável de ambiente LANGCHAIN_PROJECT (se não estiver definida, as execuções serão registradas no projeto padrão). Isso criará automaticamente o projeto para você, caso ele não exista. Você também deve definir as variáveis de ambiente LANGCHAIN_ENDPOINT e LANGCHAIN_API_KEY.
NOTA: Você também pode usar um gerenciador de contexto em python para registrar rastreamentos usando:
from langchain.callbacks.manager import tracing_v2_enabled with tracing_v2_enabled(project_name="My Project"): agent.run("How many people live in canada as of 2023?")
Porém, neste exemplo, usaremos variáveis de ambiente.
%pip install openai tiktoken pandas duckduckgo-search --quiet import os
from uuid import uuid4 unique_id = uuid4().hex[0:8]
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = f"Tracing Walkthrough - {unique_id}"
os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
os.environ["LANGCHAIN_API_KEY"] = "<YOUR-API-KEY>" # Update to your API key # Used by the agent in this tutorial
os.environ["OPENAI_API_KEY"] = "<YOUR-OPENAI-API-KEY>"
Crie o cliente LangSmith para interagir com a API:
from langsmith import Client client = Client()
Crie um componente LangChain e registre as execuções na plataforma. Neste exemplo, criaremos um agente estilo ReAct com acesso a uma ferramenta de pesquisa geral (DuckDuckGo). O prompt do agente pode ser visualizado no Hub aqui:
from langchain import hub
from langchain.agents import AgentExecutor
from langchain.agents.format_scratchpad import format_to_openai_function_messages
from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser
from langchain.chat_models import ChatOpenAI
from langchain.tools import DuckDuckGoSearchResults
from langchain.tools.render import format_tool_to_openai_function # Fetches the latest version of this prompt
prompt = hub.pull("wfh/langsmith-agent-prompt:latest") llm = ChatOpenAI( model="gpt-3.5-turbo-16k", temperature=0,
) tools = [ DuckDuckGoSearchResults( name="duck_duck_go" ), # General internet search using DuckDuckGo
] llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools]) runnable_agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai_function_messages( x["intermediate_steps"] ), } | prompt | llm_with_tools | OpenAIFunctionsAgentOutputParser()
) agent_executor = AgentExecutor( agent=runnable_agent, tools=tools, handle_parsing_errors=True
)
Estamos executando o agente simultaneamente em várias entradas para reduzir a latência. As execuções são registradas no LangSmith em segundo plano, portanto a latência de execução não é afetada:
inputs = [ "What is LangChain?", "What's LangSmith?", "When was Llama-v2 released?", "What is the langsmith cookbook?", "When did langchain first announce the hub?",
] results = agent_executor.batch([{"input": x} for x in inputs], return_exceptions=True) results[:2]
Supondo que você configurou seu ambiente com êxito, os rastreamentos do agente deverão aparecer na seção Projetos do aplicativo. Parabéns!
Parece que o agente não está usando as ferramentas de maneira eficaz. Vamos avaliar isso para termos uma linha de base.
Além de registrar execuções, o LangSmith também permite testar e avaliar suas aplicações LLM.
Nesta seção, você aproveitará o LangSmith para criar um conjunto de dados de benchmark e executar avaliadores assistidos por IA em um agente. Você fará isso em algumas etapas:
- Crie um conjunto de dados LangSmith:
Abaixo, usamos o cliente LangSmith para criar um conjunto de dados a partir das perguntas de entrada acima e uma lista de rótulos. Você os usará posteriormente para medir o desempenho de um novo agente. Um conjunto de dados é uma coleção de exemplos, que nada mais são do que pares de entrada-saída que você pode usar como casos de teste para seu aplicativo:
outputs = [ "LangChain is an open-source framework for building applications using large language models. It is also the name of the company building LangSmith.", "LangSmith is a unified platform for debugging, testing, and monitoring language model applications and agents powered by LangChain", "July 18, 2023", "The langsmith cookbook is a github repository containing detailed examples of how to use LangSmith to debug, evaluate, and monitor large language model-powered applications.", "September 5, 2023",
] dataset_name = f"agent-qa-{unique_id}" dataset = client.create_dataset( dataset_name, description="An example dataset of questions over the LangSmith documentation.",
) for query, answer in zip(inputs, outputs): client.create_example( inputs={"input": query}, outputs={"output": answer}, dataset_id=dataset.id )
- Inicialize um novo agente para benchmark:
LangSmith permite avaliar qualquer LLM, cadeia, agente ou até mesmo uma função personalizada. Os agentes conversacionais têm estado (têm memória); para garantir que esse estado não seja compartilhado entre as execuções do conjunto de dados, passaremos um chain_factory (
também conhecida como construtor) para inicializar para cada chamada:
# Since chains can be stateful (e.g. they can have memory), we provide
# a way to initialize a new chain for each row in the dataset. This is done
# by passing in a factory function that returns a new chain for each row.
def agent_factory(prompt): llm_with_tools = llm.bind( functions=[format_tool_to_openai_function(t) for t in tools] ) runnable_agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai_function_messages( x["intermediate_steps"] ), } | prompt | llm_with_tools | OpenAIFunctionsAgentOutputParser() ) return AgentExecutor(agent=runnable_agent, tools=tools, handle_parsing_errors=True)
- Configurar avaliação:
Comparar manualmente os resultados das cadeias na IU é eficaz, mas pode ser demorado. Pode ser útil usar métricas automatizadas e feedback assistido por IA para avaliar o desempenho do seu componente:
from langchain.evaluation import EvaluatorType
from langchain.smith import RunEvalConfig evaluation_config = RunEvalConfig( evaluators=[ EvaluatorType.QA, EvaluatorType.EMBEDDING_DISTANCE, RunEvalConfig.LabeledCriteria("helpfulness"), RunEvalConfig.LabeledScoreString( { "accuracy": """
Score 1: The answer is completely unrelated to the reference.
Score 3: The answer has minor relevance but does not align with the reference.
Score 5: The answer has moderate relevance but contains inaccuracies.
Score 7: The answer aligns with the reference but has minor errors or omissions.
Score 10: The answer is completely accurate and aligns perfectly with the reference.""" }, normalize_by=10, ), ], custom_evaluators=[],
)
- Execute o agente e os avaliadores:
Use a função run_on_dataset (ou arun_on_dataset assíncrona) para avaliar seu modelo. Isso vai:
- Busque linhas de exemplo do conjunto de dados especificado.
- Execute seu agente (ou qualquer função personalizada) em cada exemplo.
- Aplique avaliadores aos rastreamentos de execução resultantes e aos exemplos de referência correspondentes para gerar feedback automatizado.
Os resultados serão visíveis no aplicativo LangSmith:
chain_results = run_on_dataset( dataset_name=dataset_name, llm_or_chain_factory=functools.partial(agent_factory, prompt=prompt), evaluation=evaluation_config, verbose=True, client=client, project_name=f"runnable-agent-test-5d466cbc-{unique_id}", tags=[ "testing-notebook", "prompt:5d466cbc", ],
)
Agora que temos os resultados do teste, podemos fazer alterações em nosso agente e compará-los. Vamos tentar novamente com um prompt diferente e ver os resultados:
candidate_prompt = hub.pull("wfh/langsmith-agent-prompt:39f3bbd0") chain_results = run_on_dataset( dataset_name=dataset_name, llm_or_chain_factory=functools.partial(agent_factory, prompt=candidate_prompt), evaluation=evaluation_config, verbose=True, client=client, project_name=f"runnable-agent-test-39f3bbd0-{unique_id}", tags=[ "testing-notebook", "prompt:39f3bbd0", ],
)
LangSmith permite exportar dados para formatos comuns, como CSV ou JSONL diretamente no aplicativo web. Você também pode usar o cliente para buscar execuções para análise posterior, para armazenar em seu próprio banco de dados ou para compartilhar com outras pessoas. Vamos buscar os rastreamentos da execução de avaliação:
runs = client.list_runs(project_name=chain_results["project_name"], execution_order=1) # After some time, these will be populated.
client.read_project(project_name=chain_results["project_name"]).feedback_stats
Este foi um guia rápido para começar, mas há muitas outras maneiras de usar o LangSmith para acelerar o fluxo do desenvolvedor e produzir melhores resultados.
Para obter mais informações sobre como você pode aproveitar ao máximo o LangSmith, consulte a documentação do LangSmith.
Suba de nível com Nanonets
Embora LangChain seja uma ferramenta valiosa para integração de modelos de linguagem (LLMs) com seus aplicativos, ele pode enfrentar limitações quando se trata de casos de uso corporativo. Vamos explorar como Nanonets vai além do LangChain para enfrentar esses desafios:
1. Conectividade de dados abrangente:
LangChain oferece conectores, mas pode não cobrir todos os aplicativos de espaço de trabalho e formatos de dados dos quais as empresas dependem. Nanonets fornece conectores de dados para mais de 100 aplicativos de espaço de trabalho amplamente utilizados, incluindo Slack, Notion, Google Suite, Salesforce, Zendesk e muitos mais. Ele também oferece suporte a todos os tipos de dados não estruturados, como PDFs, TXTs, imagens, arquivos de áudio e arquivos de vídeo, bem como tipos de dados estruturados, como CSVs, planilhas, MongoDB e bancos de dados SQL.
2. Automação de tarefas para aplicativos de espaço de trabalho:
Embora a geração de texto/resposta funcione muito bem, os recursos do LangChain são limitados quando se trata de usar linguagem natural para executar tarefas em vários aplicativos. Nanonets oferece agentes de gatilho/ação para os aplicativos de espaço de trabalho mais populares, permitindo configurar fluxos de trabalho que detectam eventos e executam ações. Por exemplo, você pode automatizar respostas de email, entradas de CRM, consultas SQL e muito mais, tudo por meio de comandos de linguagem natural.
3. Sincronização de dados em tempo real:
LangChain busca dados estáticos com conectores de dados, que podem não acompanhar as alterações de dados no banco de dados de origem. Por outro lado, Nanonets garante sincronização em tempo real com fontes de dados, garantindo que você esteja sempre trabalhando com as informações mais recentes.
3. Configuração simplificada:
Configurar os elementos do pipeline LangChain, como recuperadores e sintetizadores, pode ser um processo complexo e demorado. Nanonets simplifica isso, fornecendo ingestão e indexação de dados otimizadas para cada tipo de dados, tudo tratado em segundo plano pelo AI Assistant. Isso reduz a carga de ajuste fino e facilita a configuração e o uso.
4. Solução Unificada:
Ao contrário do LangChain, que pode exigir implementações exclusivas para cada tarefa, Nanonets serve como uma solução completa para conectar seus dados com LLMs. Quer você precise criar aplicativos LLM ou fluxos de trabalho de IA, Nanonets oferece uma plataforma unificada para suas diversas necessidades.
Fluxos de trabalho de IA da Nanonets
Nanonets Workflows é um assistente de IA seguro e multifuncional que simplifica a integração de seu conhecimento e dados com LLMs e facilita a criação de aplicativos e fluxos de trabalho sem código. Ele oferece uma interface de usuário fácil de usar, tornando-o acessível tanto para indivíduos quanto para organizações.
Para começar, você pode agendar uma ligação com um de nossos especialistas em IA, que pode fornecer uma demonstração personalizada e uma avaliação dos fluxos de trabalho Nanonets adaptados ao seu caso de uso específico.
Depois de configurado, você pode usar linguagem natural para projetar e executar aplicativos e fluxos de trabalho complexos com tecnologia LLMs, integrando-se perfeitamente com seus aplicativos e dados.
Turbine suas equipes com Nanonets AI para criar aplicativos e integrar seus dados com aplicativos e fluxos de trabalho orientados por IA, permitindo que suas equipes se concentrem no que realmente importa.
Automatize tarefas e fluxos de trabalho manuais com nosso construtor de fluxo de trabalho baseado em IA, projetado pela Nanonets para você e suas equipes.
- Conteúdo com tecnologia de SEO e distribuição de relações públicas. Seja amplificado hoje.
- PlatoData.Network Gerativa Vertical Ai. Capacite-se. Acesse aqui.
- PlatoAiStream. Inteligência Web3. Conhecimento Amplificado. Acesse aqui.
- PlatãoESG. Carbono Tecnologia Limpa, Energia, Ambiente, Solar, Gestão de resíduos. Acesse aqui.
- PlatoHealth. Inteligência em Biotecnologia e Ensaios Clínicos. Acesse aqui.
- Fonte: https://nanonets.com/blog/langchain/
- :tem
- :é
- :não
- :onde
- $UP
- 1
- 10
- 100
- 114
- 13
- 15%
- 2000
- 2012
- 2023
- 25
- 30
- 32
- 36
- 40
- 400
- 408
- 50
- 500
- 7
- 8
- a
- abc
- habilidade
- Capaz
- Sobre
- sobre isso
- acima
- ACEITAR
- Aceita
- Acesso
- acessível
- acessando
- realizar
- conformemente
- Conta
- precisão
- preciso
- exatamente
- Alcançar
- alcançado
- Alcança
- em
- Aja
- Açao Social
- ações
- ativo
- adaptação
- adaptativo
- adicionar
- adicionado
- acrescentando
- Adição
- Adicional
- Adicionalmente
- endereço
- Adiciona
- Admitem
- avançado
- Aventura
- Depois de
- novamente
- idade
- Agente
- agentes
- AI
- Assistente de IA
- Modelos de IA
- Ajuda
- Visando
- algoritmos
- alinhar
- Alinha
- Todos os Produtos
- permitir
- Permitindo
- permite
- sozinho
- juntamente
- ao lado de
- já
- tb
- Apesar
- sempre
- an
- análise
- Análises
- analítica
- e
- Angeles
- Anunciar
- anual
- Outro
- responder
- respostas
- hino
- Antrópico
- qualquer
- nada
- api
- CHAVES DE API
- APIs
- app
- relevante
- Aplicação
- Desenvolvimento de Aplicações
- aplicações
- aplicado
- aplica
- abordagem
- se aproxima
- apropriado
- adequadamente
- Aplicativos
- arquitetura
- SOMOS
- argumento
- argumentos
- Armstrong
- por aí
- Ordem
- Artistas
- AS
- perguntar
- aspecto
- aspectos
- auxiliar
- Assistente
- associado
- At
- anexar
- por WhatsApp.
- auditivo
- aumentado
- Autenticação
- automatizar
- Automatizado
- automatiza
- automaticamente
- Automação
- disponível
- média
- aguardam
- consciente
- AWS
- em caminho duplo
- Espinha dorsal
- Backend
- fundo
- seriamente
- Equilíbrio
- Barra
- base
- baseado
- Linha de Base
- bater
- basic
- fundamentos básicos
- BCG
- BE
- Beach
- Bears
- Porque
- sido
- antes
- começar
- comportamento
- atrás
- Por trás das cenas
- ser
- abaixo
- referência
- benéfico
- MELHOR
- Melhor
- entre
- Pós
- O maior
- Projeto de lei
- Bill Gates
- vincular
- Bing
- Pouco
- Preto
- Buraco negro
- Bloquear
- bloqueio
- Blocos
- Blog
- grão
- Bootstrap
- nascido
- Bot
- ambos
- Inferior
- Ramo
- Break
- brisa
- brevemente
- mais amplo
- marrom
- navegador
- amortecer
- construir
- construtor
- Prédio
- construído
- carga
- negócios
- mas a
- by
- calcular
- calcula
- cálculo
- Cálculo
- chamada
- retornos de chamada
- chamado
- chamada
- chamadas
- CAN
- Pode obter
- Localização: Canadá
- capacidades
- capaz
- Capacidade
- capturar
- Capturar
- casas
- casos
- CAT
- fornecer
- restauração
- atende
- Gatos
- cautela
- cauteloso
- centralizado
- certo
- cadeia
- correntes
- desafios
- Alterações
- personagem
- chatbot
- chatbots
- verificar
- Cheques
- Escolha
- escolhido
- circunstâncias
- Cidades
- classe
- aulas
- cliente
- Na nuvem
- código
- Codificação
- Café
- COERENTE
- coeso
- colaborar
- menos -
- coleção
- colorido
- Coluna
- colunas
- COM
- combinar
- combinado
- combina
- combinando
- como
- vem
- confortável
- comum
- Comunicação
- Empresa
- comparar
- comparando
- compatibilidade
- compatível
- completar
- completamente
- realização
- integrações
- complexidades
- componente
- componentes
- composta
- composição
- compreensivo
- composta
- conceito
- conciso
- concorrente
- condição
- Configuração
- confluência
- Contato
- Conexão de
- Conectividade
- Desvantagens
- Considerar
- consistentemente
- consiste
- cônsul
- constantemente
- construções
- não contenho
- contém
- conteúdo
- contexto
- Contextos
- contextual
- continuar
- continuamente
- contraste
- ao controle
- controles
- Conveniente
- Conversa
- conversação
- IA conversacional
- conversas
- Conversão
- convertido
- conversão
- núcleo
- Canto
- correta
- Correspondente
- poderia
- contando
- país
- Casal
- cobrir
- coberto
- crio
- criado
- cria
- Criar
- criação
- Credenciais
- critérios
- Crítico
- CRM
- crucial
- Atual
- Atualmente
- personalizadas
- Clientes
- personalização
- personalizar
- personalizado
- ponta
- dados,
- Estrutura de dados
- banco de dados
- bases de dados
- Data
- datetime
- acordo
- lidar
- Dezembro
- decidir
- Decidindo
- Tomada de Decisão
- decodificação
- dedicado
- mais profunda
- Padrão
- definir
- definido
- definição
- definições
- entregando
- entrega
- mergulhar
- demonstração
- demonstrar
- demonstraram
- demonstrando
- depender
- Dependendo
- depende
- implantar
- implantado
- Implantação
- desenvolvimento
- implanta
- descreve
- descrição
- Design
- designado
- projetado
- desejado
- detalhe
- detalhado
- detalhes
- Determinar
- determina
- desenvolver
- Developer
- desenvolvedores
- em desenvolvimento
- Desenvolvimento
- diagramas
- DICT
- DID
- diferir
- diferente
- diferentemente
- difícil
- Dimensão
- dimensões
- directivas
- diretamente
- discutir
- discutido
- exibindo
- distinto
- mergulho
- diferente
- DM
- do
- documento
- documentação
- INSTITUCIONAIS
- parece
- não
- fazer
- don
- feito
- duplo
- down
- download
- de downloads
- rascunho
- distância
- dois
- durante
- dinâmico
- dinamicamente
- e
- cada
- Mais cedo
- Cedo
- facilidade
- facilidade de utilização
- mais fácil
- facilmente
- fácil
- fácil de usar
- eco
- ecossistema
- Eficaz
- efetivamente
- eficiência
- eficiente
- eficientemente
- sem esforço
- ou
- elemento
- elementos
- Elon
- Elon Musk
- outro
- embutir
- incorporado
- embutindo
- empregada
- colaboradores
- emprega
- autorizar
- permitir
- permite
- permitindo
- encapsula
- encontrando
- end-to-end
- Ponto final
- noivando
- Motor
- Motores
- Inglaterra
- Inglês
- Campeonato Inglês
- aumentar
- aprimorada
- aprimorando
- garantir
- garante
- assegurando
- Empreendimento
- entidades
- entidade
- Meio Ambiente
- ambientes
- Equivalente
- Era
- erro
- erros
- especialmente
- essencial
- afastado
- etc.
- avaliar
- avaliação
- Mesmo
- eventos
- Cada
- exemplo
- exemplos
- excedem
- Exceto
- executar
- executado
- Executa
- executando
- execução
- exemplifica
- Exercício
- existir
- esperar
- expectativas
- esperado
- espera
- vasta experiência
- experimental
- especialistas
- explicado
- Explica
- explicitamente
- exploração
- explorar
- Explorado
- exportar
- expressão
- estender
- estendendo
- extenso
- externo
- extra
- extrato
- Extração
- Extractos
- Rosto
- facilitar
- facilita
- fábrica
- fatos
- longe
- RÁPIDO
- Favorito
- Característica
- Funcionalidades
- retornos
- poucos
- campo
- Campos
- figma
- Figura
- Envie o
- Arquivos
- preencher
- preenchida
- o preenchimento
- filtro
- filtragem
- final
- Finalmente
- Encontre
- descoberta
- Primeiro nome
- cinco
- Flexibilidade
- flexível
- fluxo
- Foco
- focado
- concentra-se
- focando
- seguir
- seguinte
- segue
- comida
- Escolha
- formulário
- formato
- formado
- Felizmente
- encontrado
- Quadro
- enquadramentos
- freqüentemente
- amigos
- amigos
- da
- cheio
- De pleno Direito
- função
- funcionalidades
- funcionalidade
- funções
- fundamental
- engraçado
- mais distante
- futuro
- Ganho
- Games
- Portões
- Geral
- geralmente
- gerar
- gerado
- gera
- gerando
- geração
- genre
- Alemanha
- ter
- obtendo
- gif
- GitHub
- dado
- GMT
- Go
- vai
- vai
- Bom estado, com sinais de uso
- granular
- gráfico
- ótimo
- maior
- orientações
- guia
- orientações
- hackathon
- manipular
- Alças
- Manipulação
- acessível
- Queijos duros
- prejudicar
- arreios
- Ter
- ter
- fortemente
- Herói
- ajudar
- útil
- ajuda
- sua experiência
- SUA PARTICIPAÇÃO FAZ A DIFERENÇA
- hi
- Alta
- de alto nível
- alta qualidade
- mais
- altamente
- histórico
- história
- Buraco
- capuz
- hospedeiro
- Como funciona o dobrador de carta de canal
- Como Negociar
- Contudo
- HTML
- http
- HTTPS
- Hub
- humano
- Centenas
- i
- ID
- idéia
- ideal
- ids
- if
- ii
- iii
- ilustrar
- ilustra
- imagens
- Imediato
- executar
- implementação
- implementações
- implementado
- importar
- melhorias
- melhorar
- in
- em profundidade
- incluir
- incluído
- inclui
- Incluindo
- incorporar
- incorporando
- incrivelmente
- índice
- índices
- indicam
- indicam
- Individualmente
- indivíduos
- INFORMAÇÕES
- do estado inicial,
- iniciar
- inovadores
- entrada
- inputs
- insights
- instalar
- instalado
- instalando
- instância
- instantâneos
- em vez disso
- instruções
- integral
- integrar
- integrado
- Integra-se
- Integração
- integração
- integrações
- Inteligente
- Pretendido
- interagir
- interação
- interações
- interativo
- interage
- Interface
- interfaces de
- internamente
- Internet
- para dentro
- introduzido
- Introduz
- intuitivo
- envolvendo
- isn
- emitem
- questões
- IT
- Unid
- iterações
- ESTÁ
- se
- Jackson
- JavaScript
- Trabalho
- Jordânia
- viagem
- json
- Julho
- apenas por
- Justiça
- Guarda
- mantém
- Chave
- chaves
- Tipo
- Saber
- Conhecimento
- Gráfico conhecimento
- conhecido
- O rótulo
- Rótulos
- Terreno
- língua
- Idiomas
- grande
- Maior
- Sobrenome
- Latência
- mais tarde
- mais recente
- Liga
- APRENDER
- aprendizagem
- esquerda
- Legado
- Comprimento
- menos
- deixar
- Permite
- carta
- Nível
- níveis
- Alavancagem
- aproveita as
- aproveitando
- bibliotecas
- Biblioteca
- como
- Provável
- LIMITE
- limitações
- Limitado
- limitando
- limites
- Links
- Lista
- ouço
- listas
- viver
- ll
- LLM
- carregar
- carregador
- localizado
- localização
- log
- registrado
- logging
- lógica
- longo
- mais
- olhar
- procurando
- OLHARES
- pesquisa
- os
- Los Angeles
- Baixo
- máquina
- aprendizado de máquina
- moldadas
- a manter
- Sustentável
- Manter
- mantém
- fazer
- FAZ
- Fazendo
- gerencia
- de grupos
- Gerente
- gestão
- Manchester
- Manchester United
- Manipulação
- maneira
- manual
- Fabricante
- muitos
- muitas pessoas
- mapa,
- mapeamento
- mapas
- Match
- correspondente
- matemática
- matemático
- Matéria
- máximo
- Posso..
- me
- significar
- significado
- significa
- a medida
- Mídia
- reunião
- atende
- Memórias
- Memória
- mencionado
- ir
- fusão
- mensagem
- mensagens
- mensagens
- metadados
- método
- métodos
- Métrica
- poder
- milhões
- mínimo
- menor
- desaparecido
- erros
- Misturando
- MLB
- Móvel Esteira
- modelo
- modelos
- moderação
- Módulo
- Módulos
- momento
- MongoDB
- Monitore
- monitoração
- Moon
- mais
- a maioria
- Mais populares
- mover
- filme
- muito
- múltiplo
- múltiplas cadeias
- Almíscar
- devo
- my
- nome
- Nomeado
- nomes
- Nacional
- natural
- Processamento de linguagem natural
- Navegar
- navegação
- Perto
- necessário
- você merece...
- necessário
- Cria
- negativo
- Novo
- New York
- New York Times
- Próximo
- não
- nenhum
- nada
- Noção
- agora
- número
- Obama
- objeto
- objetivo
- objetos
- observação
- obter
- obtendo
- OCR
- of
- oferecer
- oferecendo treinamento para distância
- Oferece
- frequentemente
- oh
- OK
- Jogos Olímpicos
- on
- uma vez
- ONE
- só
- open source
- OpenAI
- Operações
- operador
- otimizado
- Otimiza
- Opção
- or
- ordem
- orgânico
- organizações
- original
- OS
- Outros
- Outros
- de outra forma
- A Nossa
- Fora
- saída
- outputs
- Acima de
- override
- Visão geral
- próprio
- pacote
- pacotes
- página
- páginas
- pares
- pandas
- Papel
- Paralelo
- parâmetro
- parâmetros
- Park
- parte
- particularmente
- peças
- passar
- passou
- passes
- Passagem
- passado
- caminho
- caminhos
- padrões
- Folha de pagamento
- Pessoas
- para
- perfeita
- perfeitamente
- Realizar
- atuação
- realização
- executa
- permissões
- persistência
- pessoa
- Personalizado
- perspectiva
- Física
- peça
- oleoduto
- Pizza
- espaço reservado
- plataforma
- platão
- Inteligência de Dados Platão
- PlatãoData
- Jogar
- recreio
- desempenha
- por favor
- mais
- ponto
- políticas
- Privacidade
- político
- piscina
- Popular
- populosa
- positivo
- possível
- Publique
- POSTAGENS
- potencial
- poder
- alimentado
- poderoso
- Prática
- prática
- preferir
- premier
- presente
- presidente
- evitar
- impedindo
- anterior
- principalmente
- primário
- Prime
- privado
- Problema
- problemas
- prosseguir
- processo
- Processado
- processos
- em processamento
- produzir
- Produto
- Produção
- Professor
- Programação
- linguagens de programação
- projeto
- projetos
- Propriedades
- propriedade
- PROS
- protótipo
- prototipagem
- fornecer
- fornecido
- provedor
- fornecedores
- fornece
- fornecendo
- público
- propósito
- fins
- colocar
- Python
- Dúvidas
- qualidade
- consultas
- questão
- Frequentes
- Links
- rapidamente
- citações
- R
- aumentar
- alcance
- variando
- em vez
- classificação
- Cru
- RE
- alcançar
- Reagir
- Leia
- Leitura
- pronto
- reais
- em tempo real
- dados em tempo real
- reino
- razão
- razões
- recentemente
- Recomenda
- gravado
- registros
- Recuperar
- reduzir
- reduz
- redução
- redução
- referência
- referência
- refinar
- refinação
- regiões
- Relacionamentos
- liberado
- relevância
- relevante
- confiabilidade
- confiável
- depender
- contando
- permanece
- lembrar
- lembrete
- remoto
- tornar
- repetir
- REPETIDAMENTE
- reformular
- substituir
- Denunciar
- repositório
- representação
- representando
- representa
- solicitar
- pedidos
- requerer
- requeridos
- Requisitos
- exige
- resgatar
- pesquisa
- resolver
- recurso
- Responder
- responder
- resposta
- respostas
- responsável
- responsivo
- DESCANSO
- resultar
- resultando
- Resultados
- retenção
- retenção
- retorno
- voltar
- Retorna
- reutilizável
- rever
- gira
- arroz
- Rico
- robôs
- Tipo
- papéis
- raiz
- roteamento
- LINHA
- Execute
- corrida
- é executado
- tempo de execução
- s
- proteções
- vendas
- Salesforce
- Sam
- mesmo
- Salvar
- dizer
- diz
- escalável
- Escala
- cenário
- cenários
- Cenas
- cronograma
- Ponto
- arranhar
- desatado
- sem problemas
- Pesquisar
- motor de busca
- pesquisas
- pesquisar
- Seção
- seções
- seguro
- segurança
- Vejo
- selecionado
- doadores,
- Vender
- enviar
- sensível
- sentimento
- sentimentos
- separado
- Setembro
- Seqüência
- Série
- servir
- servidor
- serve
- Serviços
- conjunto
- Conjuntos
- contexto
- Configurações
- instalação
- Sete
- vários
- Partilhar
- compartilhado
- concha
- brilha
- enviado
- rede de apoio social
- mostrar
- mostrar
- mostrando
- Shows
- Sigma
- periodo
- semelhante
- simples
- simplificada
- simplificar
- simplificando
- simplesmente
- desde
- solteiro
- Tamanho
- folga
- pequeno
- menor
- smart
- fragmento
- So
- até aqui
- futebol
- Redes Sociais
- meios de comunicação social
- Publicações nas redes sociais
- unicamente
- sólido
- solução
- RESOLVER
- alguns
- algo
- às vezes
- sofisticado
- sons
- fonte
- Fontes
- Espaço
- Espanhol
- especializado
- específico
- especificamente
- especificidades
- especificada
- velocidade
- gasto
- divisão
- splits
- Desporto
- quadrado
- suporte
- autônoma
- padrão
- começo
- começado
- Comece
- Estado
- declarações
- estático
- Passo
- Passos
- Ainda
- Dê um basta
- paragem
- Pára
- armazenamento
- loja
- armazenadas
- lojas
- armazenar
- História
- franco
- transmitir canais
- de streaming
- simplificar
- simplificada
- pontos fortes
- Greves
- Tanga
- estrutura
- estruturada
- estruturas
- estruturação
- estilo
- sujeito
- subseqüente
- entraram com sucesso
- tal
- terno
- adequado
- suíte
- resumir
- RESUMO
- pôr do sol
- ajuda
- Suportado
- suportes
- certo
- Sustentabilidade
- Sincronização
- sinopse
- sintaxe
- .
- sistemas
- mesa
- Alfaiate
- adaptados
- Tire
- toma
- tem como alvo
- Tarefa
- tarefas
- Profissionais
- equipes
- dizer
- modelo
- modelos
- terminal
- terminologia
- condições
- teste
- ensaio
- texto
- do que
- obrigado
- que
- A
- O Básico
- o hub
- as informações
- The New York Times
- Os projetos
- A fonte
- o mundo
- deles
- Eles
- então
- Lá.
- Este
- deles
- coisas
- isto
- aqueles
- Apesar?
- Através da
- todo
- tempo
- demorado
- vezes
- Título
- para
- juntos
- token
- tokenization
- Tokens
- também
- ferramenta
- kit de ferramentas
- ferramentas
- topo
- tópico
- Temas
- Total
- cidade
- Traçado
- pista
- tradicional
- Training
- Transformar
- transformações
- transformador
- transformadores
- transição
- julgamento
- verdadeiro
- verdadeiramente
- tentar
- sintonização
- VIRAR
- Passando
- tutorial
- Twice
- dois
- tipo
- tipos
- Datilografado
- tipicamente
- ui
- Em última análise
- não afetado
- para
- subjacente
- compreender
- compreensão
- entende
- unificado
- único
- Unido
- Universal
- ao contrário
- até
- Atualizar
- Atualizações
- carregado
- URL
- us
- usabilidade
- Uso
- usar
- caso de uso
- usava
- Utilizador
- Interface de Usuário
- usuários
- usos
- utilização
- utilitários
- utilizar
- utilizado
- utiliza
- Utilizando
- v1
- validação
- Validador
- Valioso
- valor
- Valores
- variável
- variedade
- vário
- Ve
- versátil
- versão
- muito
- via
- Vídeo
- Ver
- Violações
- visível
- visualizar
- vital
- vs
- andar
- Passo a passo
- queremos
- foi
- Assistir
- Caminho..
- maneiras
- we
- Clima
- web
- navegador web
- serviços web
- sites
- BEM
- bem conhecido
- foram
- O Quê
- O que é a
- O que é
- quando
- se
- qual
- enquanto
- QUEM
- inteiro
- porque
- Largo
- largamente
- Widget
- Wikipedia
- precisarão
- janela
- Vitórias
- de
- dentro
- sem
- Word
- Atividades:
- trabalhou
- de gestão de documentos
- fluxos de trabalho
- trabalhar
- trabalho
- mundo
- seria
- escrever
- escrita
- X
- ainda
- Iorque
- Vocês
- investimentos
- você mesmo
- Youtube
- Zendesk
- zefirnet
- Zip