En son coeur, LangChaîne est un framework innovant conçu pour créer des applications qui exploitent les capacités des modèles de langage. Il s'agit d'une boîte à outils conçue pour permettre aux développeurs de créer des applications sensibles au contexte et capables d'un raisonnement sophistiqué.
Cela signifie que les applications LangChain peuvent comprendre le contexte, comme les instructions rapides ou les réponses de base du contenu, et utiliser des modèles de langage pour des tâches de raisonnement complexes, comme décider comment répondre ou quelles actions entreprendre. LangChain représente une approche unifiée pour développer des applications intelligentes, simplifiant le parcours du concept à l'exécution grâce à ses divers composants.
Comprendre LangChain
LangChain est bien plus qu’un simple framework ; c'est un écosystème à part entière comprenant plusieurs parties intégrantes.
- Tout d’abord, il existe les bibliothèques LangChain, disponibles en Python et JavaScript. Ces bibliothèques constituent l'épine dorsale de LangChain, offrant des interfaces et des intégrations pour divers composants. Ils fournissent un environnement d'exécution de base pour combiner ces composants en chaînes et agents cohérents, ainsi que des implémentations prêtes à l'emploi pour une utilisation immédiate.
- Ensuite, nous avons les modèles LangChain. Il s'agit d'un ensemble d'architectures de référence déployables adaptées à un large éventail de tâches. Que vous construisiez un chatbot ou un outil analytique complexe, ces modèles offrent un point de départ solide.
- LangServe intervient en tant que bibliothèque polyvalente pour déployer des chaînes LangChain en tant qu'API REST. Cet outil est essentiel pour transformer vos projets LangChain en services web accessibles et évolutifs.
- Enfin, LangSmith sert de plateforme de développement. Il est conçu pour déboguer, tester, évaluer et surveiller les chaînes construites sur n'importe quel framework LLM. L'intégration transparente avec LangChain en fait un outil indispensable pour les développeurs souhaitant affiner et perfectionner leurs applications.
Ensemble, ces composants vous permettent de développer, de produire et de déployer des applications en toute simplicité. Avec LangChain, vous commencez par écrire vos applications à l'aide des bibliothèques, en référençant des modèles pour vous guider. LangSmith vous aide ensuite à inspecter, tester et surveiller vos chaînes, garantissant ainsi que vos applications s'améliorent constamment et sont prêtes à être déployées. Enfin, avec LangServe, vous pouvez facilement transformer n'importe quelle chaîne en API, ce qui rend le déploiement un jeu d'enfant.
Dans les sections suivantes, nous approfondirons la façon de configurer LangChain et commencerons votre parcours dans la création d'applications intelligentes basées sur des modèles de langage.
Automatisez les tâches et les flux de travail manuels avec notre générateur de flux de travail basé sur l'IA, conçu par Nanonets pour vous et vos équipes.
Installation et configuration
Êtes-vous prêt à plonger dans le monde de LangChain ? Sa configuration est simple et ce guide vous guidera tout au long du processus, étape par étape.
La première étape de votre parcours LangChain consiste à l’installer. Vous pouvez le faire facilement en utilisant pip ou conda. Exécutez la commande suivante dans votre terminal :
pip install langchain
Pour ceux qui préfèrent les dernières fonctionnalités et sont à l’aise avec un peu plus d’aventure, vous pouvez installer LangChain directement à partir de la source. Clonez le référentiel et accédez au langchain/libs/langchain
annuaire. Ensuite, exécutez :
pip install -e .
Pour les fonctionnalités expérimentales, envisagez d'installer langchain-experimental
. Il s'agit d'un package qui contient du code de pointe et est destiné à des fins de recherche et d'expérimentation. Installez-le en utilisant :
pip install langchain-experimental
LangChain CLI est un outil pratique pour travailler avec les modèles LangChain et les projets LangServe. Pour installer la CLI LangChain, utilisez :
pip install langchain-cli
LangServe est essentiel pour déployer vos chaînes LangChain en tant qu'API REST. Il est installé avec la CLI LangChain.
LangChain nécessite souvent des intégrations avec des fournisseurs de modèles, des magasins de données, des API, etc. Pour cet exemple, nous utiliserons les API de modèle d'OpenAI. Installez le package OpenAI Python en utilisant :
pip install openai
Pour accéder à l'API, définissez votre clé API OpenAI comme variable d'environnement :
export OPENAI_API_KEY="your_api_key"
Vous pouvez également transmettre la clé directement dans votre environnement python :
import os
os.environ['OPENAI_API_KEY'] = 'your_api_key'
LangChain permet la création d'applications de modèles de langage via des modules. Ces modules peuvent être autonomes ou être composés pour des cas d'utilisation complexes. Ces modules sont –
- Modèle E/S: Facilite l’interaction avec divers modèles de langage, en gérant efficacement leurs entrées et sorties.
- Récupération: permet l’accès et l’interaction avec les données spécifiques à l’application, cruciales pour l’utilisation dynamique des données.
- Agents: Donnez aux applications les moyens de sélectionner les outils appropriés sur la base de directives de haut niveau, améliorant ainsi les capacités de prise de décision.
- Chaînes: propose des compositions prédéfinies et réutilisables qui servent de blocs de construction pour le développement d'applications.
- Mémoire: Maintient l’état de l’application sur plusieurs exécutions en chaîne, essentiel pour les interactions contextuelles.
Chaque module cible des besoins de développement spécifiques, faisant de LangChain une boîte à outils complète pour créer des applications de modèle de langage avancées.
Outre les composants ci-dessus, nous avons également Langage d'expression LangChain (LCEL), qui est un moyen déclaratif de composer facilement des modules ensemble, ce qui permet le chaînage de composants à l'aide d'une interface Runnable universelle.
LCEL ressemble à ceci :
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import BaseOutputParser # Example chain
chain = ChatPromptTemplate() | ChatOpenAI() | CustomOutputParser()
Maintenant que nous avons couvert les bases, nous allons passer à :
- Approfondissez chaque module Langchain en détail.
- Apprenez à utiliser le langage d'expression LangChain.
- Explorez les cas d'utilisation courants et mettez-les en œuvre.
- Déployez une application de bout en bout avec LangServe.
- Consultez LangSmith pour le débogage, les tests et la surveillance.
Commençons!
Module I : Modèle E/S
Dans LangChain, l'élément central de toute application tourne autour du modèle de langage. Ce module fournit les éléments de base essentiels pour s'interfacer efficacement avec n'importe quel modèle de langage, garantissant une intégration et une communication transparentes.
Composants clés du modèle d'E/S
- LLM et modèles de chat (utilisés de manière interchangeable) :
- LLM :
- Définition: Modèles de complétion de texte pur.
- Entrée / Sortie: prend une chaîne de texte en entrée et renvoie une chaîne de texte en sortie.
- Modèles de discussion
- LLM :
- Définition: modèles qui utilisent un modèle de langage comme base mais diffèrent par les formats d'entrée et de sortie.
- Entrée / Sortie: Acceptez une liste de messages de discussion en entrée et renvoyez un message de discussion.
- Instructions : modélisez, sélectionnez dynamiquement et gérez les entrées du modèle. Permet la création d'invites flexibles et spécifiques au contexte qui guident les réponses du modèle de langage.
- Analyseurs de sortie: extraire et formater les informations des sorties du modèle. Utile pour convertir la sortie brute des modèles de langage en données structurées ou en formats spécifiques requis par l'application.
LLM
L'intégration de LangChain avec des modèles de langage étendus (LLM) comme OpenAI, Cohere et Hugging Face est un aspect fondamental de sa fonctionnalité. LangChain lui-même n'héberge pas de LLM mais offre une interface uniforme pour interagir avec différents LLM.
Cette section fournit un aperçu de l'utilisation du wrapper OpenAI LLM dans LangChain, applicable également à d'autres types de LLM. Nous l'avons déjà installé dans la section « Mise en route ». Initialisons le LLM.
from langchain.llms import OpenAI
llm = OpenAI()
- Les LLM mettent en œuvre le Interface exécutable, l'élément de base du Langage d'expression LangChain (LCEL). Cela signifie qu'ils soutiennent
invoke
,ainvoke
,stream
,astream
,batch
,abatch
,astream_log
appels. - Les LLM acceptent instruments à cordes comme entrées ou objets qui peuvent être contraints à des invites de chaîne, y compris
List[BaseMessage]
ainsi quePromptValue
. (nous en reparlerons plus tard)
Regardons quelques exemples.
response = llm.invoke("List the seven wonders of the world.")
print(response)
Vous pouvez également appeler la méthode stream pour diffuser la réponse textuelle.
for chunk in llm.stream("Where were the 2012 Olympics held?"): print(chunk, end="", flush=True)
Modèles de discussion
L'intégration de LangChain avec les modèles de chat, une variante spécialisée des modèles de langage, est essentielle pour créer des applications de chat interactives. Bien qu'ils utilisent des modèles de langage en interne, les modèles de chat présentent une interface distincte centrée sur les messages de chat comme entrées et sorties. Cette section fournit un aperçu détaillé de l'utilisation du modèle de discussion d'OpenAI dans LangChain.
from langchain.chat_models import ChatOpenAI
chat = ChatOpenAI()
Les modèles de discussion dans LangChain fonctionnent avec différents types de messages tels que AIMessage
, HumanMessage
, SystemMessage
, FunctionMessage
et une ChatMessage
(avec un paramètre de rôle arbitraire). En général, HumanMessage
, AIMessage
et une SystemMessage
sont les plus fréquemment utilisés.
Les modèles de chat acceptent principalement List[BaseMessage]
comme entrées. Les chaînes peuvent être converties en HumanMessage
et une PromptValue
est également supporté.
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)
Instructions
Les invites sont essentielles pour guider les modèles de langage afin de générer des résultats pertinents et cohérents. Ils peuvent aller d’instructions simples à des exemples complexes de quelques plans. Dans LangChain, la gestion des invites peut être un processus très simplifié, grâce à plusieurs classes et fonctions dédiées.
LangChain's PromptTemplate
class est un outil polyvalent pour créer des invites de chaîne. Il utilise Python str.format
syntaxe, permettant la génération d’invites dynamiques. Vous pouvez définir un modèle avec des espaces réservés et les remplir avec des valeurs spécifiques selon vos besoins.
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)
Pour les modèles de chat, les invites sont plus structurées et impliquent des messages avec des rôles spécifiques. Offres LangChain ChatPromptTemplate
dans ce but.
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)
Cette approche permet la création de chatbots interactifs et engageants avec des réponses dynamiques.
Les deux PromptTemplate
ainsi que ChatPromptTemplate
s'intègrent de manière transparente au LangChain Expression Language (LCEL), leur permettant de faire partie de flux de travail plus vastes et complexes. Nous en discuterons davantage plus tard.
Les modèles d'invites personnalisés sont parfois essentiels pour les tâches nécessitant un formatage unique ou des instructions spécifiques. La création d'un modèle d'invite personnalisé implique la définition de variables d'entrée et d'une méthode de formatage personnalisée. Cette flexibilité permet à LangChain de répondre à un large éventail d'exigences spécifiques aux applications. Lire la suite ici.
LangChain prend également en charge les invites en quelques tirs, permettant au modèle d'apprendre à partir d'exemples. Cette fonctionnalité est vitale pour les tâches nécessitant une compréhension contextuelle ou des modèles spécifiques. Des modèles d'invites à quelques prises de vue peuvent être créés à partir d'un ensemble d'exemples ou en utilisant un objet Sélecteur d'exemple. Lire la suite ici.
Analyseurs de sortie
Les analyseurs de sortie jouent un rôle crucial dans Langchain, permettant aux utilisateurs de structurer les réponses générées par les modèles de langage. Dans cette section, nous explorerons le concept des analyseurs de sortie et fournirons des exemples de code utilisant PydanticOutputParser, SimpleJsonOutputParser, CommaSeparatedListOutputParser, DatetimeOutputParser et XMLOutputParser de Langchain.
PydanticOutputParser
Langchain fournit le PydanticOutputParser pour analyser les réponses dans les structures de données Pydantic. Vous trouverez ci-dessous un exemple étape par étape de la façon de l'utiliser :
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)
La sortie sera:
SimpleJsonOutputParser
SimpleJsonOutputParser de Langchain est utilisé lorsque vous souhaitez analyser des sorties de type JSON. Voici un exemple :
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
Le CommaSeparatedListOutputParser est pratique lorsque vous souhaitez extraire des listes séparées par des virgules à partir des réponses du modèle. Voici un exemple :
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
DatetimeOutputParser de Langchain est conçu pour analyser les informations datetime. Voici comment l'utiliser :
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)
Ces exemples montrent comment les analyseurs de sortie de Langchain peuvent être utilisés pour structurer différents types de réponses de modèle, les rendant ainsi adaptés à différentes applications et formats. Les analyseurs de sortie sont un outil précieux pour améliorer la convivialité et l’interprétabilité des sorties du modèle de langage dans Langchain.
Automatisez les tâches et les flux de travail manuels avec notre générateur de flux de travail basé sur l'IA, conçu par Nanonets pour vous et vos équipes.
Module II : Récupération
La récupération dans LangChain joue un rôle crucial dans les applications qui nécessitent des données spécifiques à l'utilisateur, non incluses dans l'ensemble de formation du modèle. Ce processus, connu sous le nom de Retrieval Augmented Generation (RAG), consiste à récupérer des données externes et à les intégrer dans le processus de génération du modèle de langage. LangChain fournit une suite complète d'outils et de fonctionnalités pour faciliter ce processus, s'adressant à la fois aux applications simples et complexes.
LangChain réalise la récupération grâce à une série de composants dont nous discuterons un par un.
Chargeurs de documents
Les chargeurs de documents dans LangChain permettent l'extraction de données à partir de diverses sources. Avec plus de 100 chargeurs disponibles, ils prennent en charge une gamme de types de documents, d'applications et de sources (compartiments s3 privés, sites Web publics, bases de données).
Vous pouvez choisir un chargeur de documents en fonction de vos besoins ici.
Tous ces chargeurs ingèrent des données dans Documents Des classes. Nous apprendrons plus tard comment utiliser les données ingérées dans les classes Document.
Chargeur de fichiers texte : Charger un simple .txt
déposer dans un document.
from langchain.document_loaders import TextLoader loader = TextLoader("./sample.txt")
document = loader.load()
Chargeur CSV : Chargez un fichier CSV dans un document.
from langchain.document_loaders.csv_loader import CSVLoader loader = CSVLoader(file_path='./example_data/sample.csv')
documents = loader.load()
Nous pouvons choisir de personnaliser l’analyse en spécifiant les noms de champs –
loader = CSVLoader(file_path='./example_data/mlb_teams_2012.csv', csv_args={ 'delimiter': ',', 'quotechar': '"', 'fieldnames': ['MLB Team', 'Payroll in millions', 'Wins']
})
documents = loader.load()
Chargeurs PDF : Les chargeurs PDF de LangChain offrent diverses méthodes pour analyser et extraire le contenu des fichiers PDF. Chaque chargeur répond à des exigences différentes et utilise différentes bibliothèques sous-jacentes. Vous trouverez ci-dessous des exemples détaillés pour chaque chargeur.
PyPDFLoader est utilisé pour l'analyse PDF de base.
from langchain.document_loaders import PyPDFLoader loader = PyPDFLoader("example_data/layout-parser-paper.pdf")
pages = loader.load_and_split()
MathPixLoader est idéal pour extraire du contenu mathématique et des diagrammes.
from langchain.document_loaders import MathpixPDFLoader loader = MathpixPDFLoader("example_data/math-content.pdf")
data = loader.load()
PyMuPDFLoader est rapide et inclut une extraction détaillée des métadonnées.
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 est utilisé pour un contrôle plus granulaire sur l'extraction de texte.
from langchain.document_loaders import PDFMinerLoader loader = PDFMinerLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
AmazonTextractPDFParser utilise AWS Texttract pour l'OCR et d'autres fonctionnalités avancées d'analyse PDF.
from langchain.document_loaders import AmazonTextractPDFLoader # Requires AWS account and configuration
loader = AmazonTextractPDFLoader("example_data/complex-layout.pdf")
documents = loader.load()
PDFMinerPDFasHTMLLoader génère du HTML à partir de PDF pour l'analyse sémantique.
from langchain.document_loaders import PDFMinerPDFasHTMLLoader loader = PDFMinerPDFasHTMLLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
PDFPlumberLoader fournit des métadonnées détaillées et prend en charge un document par page.
from langchain.document_loaders import PDFPlumberLoader loader = PDFPlumberLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
Chargeurs intégrés : LangChain propose une grande variété de chargeurs personnalisés pour charger directement les données de vos applications (telles que Slack, Sigma, Notion, Confluence, Google Drive et bien d'autres) et de bases de données et les utiliser dans des applications LLM.
La liste complète est ici.
Voici quelques exemples pour illustrer cela –
Exemple I – Slack
Slack, une plateforme de messagerie instantanée largement utilisée, peut être intégrée aux flux de travail et aux applications LLM.
- Accédez à votre page de gestion de l’espace de travail Slack.
- Accédez à
{your_slack_domain}.slack.com/services/export
. - Sélectionnez la plage de dates souhaitée et lancez l’exportation.
- Slack informe par e-mail et DM une fois que l'exportation est prête.
- L'exportation donne lieu à un
.zip
fichier situé dans votre dossier Téléchargements ou dans votre chemin de téléchargement désigné. - Attribuer le chemin du fichier téléchargé
.zip
déposer àLOCAL_ZIPFILE
. - Utilisez l'option
SlackDirectoryLoader
dulangchain.document_loaders
paquet.
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)
Exemple II – Figma
Figma, un outil populaire pour la conception d'interfaces, propose une API REST pour l'intégration des données.
- Obtenez la clé du fichier Figma à partir du format URL :
https://www.figma.com/file/{filekey}/sampleFilename
. - Les ID de nœud se trouvent dans le paramètre URL
?node-id={node_id}
. - Générez un jeton d'accès en suivant les instructions du Centre d'aide Figma.
- La
FigmaFileLoader
classe delangchain.document_loaders.figma
est utilisé pour charger les données Figma. - Divers modules LangChain comme
CharacterTextSplitter
,ChatOpenAI
, etc., sont utilisés pour le traitement.
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()
- La
generate_code
La fonction utilise les données Figma pour créer du code HTML/CSS. - Il utilise une conversation basée sur un modèle avec un modèle basé sur 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)
- La
generate_code
La fonction, une fois exécutée, renvoie le code HTML/CSS basé sur l'entrée de conception Figma.
Utilisons maintenant nos connaissances pour créer quelques ensembles de documents.
Nous chargeons d’abord un PDF, le rapport annuel de développement durable du BCG.
Nous utilisons le PyPDFLoader pour cela.
from langchain.document_loaders import PyPDFLoader loader = PyPDFLoader("bcg-2022-annual-sustainability-report-apr-2023.pdf")
pdfpages = loader.load_and_split()
Nous allons maintenant ingérer les données d'Airtable. Nous avons une Airtable contenant des informations sur divers modèles d'OCR et d'extraction de données -
Utilisons pour cela le AirtableLoader, trouvé dans la liste des chargeurs intégrés.
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()
Continuons maintenant et apprenons à utiliser ces classes de documents.
Transformateurs de documents
Les transformateurs de documents dans LangChain sont des outils essentiels conçus pour manipuler des documents, que nous avons créés dans notre sous-section précédente.
Ils sont utilisés pour des tâches telles que la division de longs documents en morceaux plus petits, la combinaison et le filtrage, qui sont cruciales pour adapter les documents à la fenêtre contextuelle d'un modèle ou répondre aux besoins spécifiques d'une application.
L'un de ces outils est RecursiveCharacterTextSplitter, un séparateur de texte polyvalent qui utilise une liste de caractères pour le fractionnement. Il autorise des paramètres tels que la taille du bloc, le chevauchement et l'index de départ. Voici un exemple de la façon dont il est utilisé en 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])
Un autre outil est CharacterTextSplitter, qui divise le texte en fonction d'un caractère spécifié et inclut des contrôles pour la taille des morceaux et le chevauchement :
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])
HTMLHeaderTextSplitter est conçu pour diviser le contenu HTML en fonction des balises d'en-tête, en conservant la structure sémantique :
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])
Une manipulation plus complexe peut être réalisée en combinant HTMLHeaderTextSplitter avec un autre séparateur, comme le 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 propose également des séparateurs spécifiques pour différents langages de programmation, comme le Python Code Splitter et le 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])
Pour diviser le texte en fonction du nombre de jetons, ce qui est utile pour les modèles de langage avec des limites de jetons, le TokenTextSplitter est utilisé :
from langchain.text_splitter import TokenTextSplitter text_splitter = TokenTextSplitter(chunk_size=10)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
Enfin, LongContextReorder réorganise les documents pour éviter la dégradation des performances dans les modèles en raison de contextes longs :
from langchain.document_transformers import LongContextReorder reordering = LongContextReorder()
reordered_docs = reordering.transform_documents(docs)
print(reordered_docs[0])
Ces outils démontrent différentes manières de transformer des documents dans LangChain, du simple fractionnement de texte à la réorganisation complexe et au fractionnement spécifique à la langue. Pour des cas d'utilisation plus approfondis et spécifiques, la section Documentation et intégrations de LangChain doit être consultée.
Dans nos exemples, les chargeurs ont déjà créé pour nous des documents fragmentés, et cette partie est déjà gérée.
Modèles d'intégration de texte
Les modèles d'intégration de texte dans LangChain fournissent une interface standardisée pour divers fournisseurs de modèles d'intégration tels que OpenAI, Cohere et Hugging Face. Ces modèles transforment le texte en représentations vectorielles, permettant des opérations telles que la recherche sémantique grâce à la similarité de texte dans l'espace vectoriel.
Pour démarrer avec les modèles d'intégration de texte, vous devez généralement installer des packages spécifiques et configurer des clés API. Nous l'avons déjà fait pour OpenAI
Dans LangChain, le embed_documents
La méthode est utilisée pour intégrer plusieurs textes, fournissant une liste de représentations vectorielles. Par exemple:
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]))
Pour intégrer un seul texte, tel qu'une requête de recherche, le embed_query
méthode est utilisée. Ceci est utile pour comparer une requête à un ensemble d’incorporations de documents. Par exemple:
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])
Comprendre ces intégrations est crucial. Chaque morceau de texte est converti en un vecteur dont la dimension dépend du modèle utilisé. Par exemple, les modèles OpenAI produisent généralement des vecteurs à 1536 XNUMX dimensions. Ces intégrations sont ensuite utilisées pour récupérer des informations pertinentes.
La fonctionnalité d'intégration de LangChain ne se limite pas à OpenAI mais est conçue pour fonctionner avec divers fournisseurs. La configuration et l'utilisation peuvent légèrement différer selon le fournisseur, mais le concept de base de l'intégration de textes dans l'espace vectoriel reste le même. Pour une utilisation détaillée, y compris des configurations avancées et des intégrations avec différents fournisseurs de modèles d'intégration, la documentation LangChain dans la section Intégrations est une ressource précieuse.
Magasins de vecteurs
Les magasins de vecteurs dans LangChain prennent en charge le stockage et la recherche efficaces des intégrations de texte. LangChain s'intègre à plus de 50 magasins de vecteurs, fournissant une interface standardisée pour une utilisation facile.
Exemple : stockage et recherche d'intégrations
Après avoir intégré les textes, nous pouvons les stocker dans un magasin de vecteurs comme Chroma
et effectuez des recherches de similarité :
from langchain.vectorstores import Chroma db = Chroma.from_texts(embedded_texts)
similar_texts = db.similarity_search("search query")
Utilisons alternativement le magasin de vecteurs FAISS pour créer des index pour nos documents.
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS pdfstore = FAISS.from_documents(pdfpages, embedding=OpenAIEmbeddings()) airtablestore = FAISS.from_documents(airtabledocs, embedding=OpenAIEmbeddings())
Récupérateurs
Les récupérateurs de LangChain sont des interfaces qui renvoient des documents en réponse à une requête non structurée. Ils sont plus généraux que les magasins de vecteurs et se concentrent sur la récupération plutôt que sur le stockage. Bien que les magasins de vecteurs puissent être utilisés comme colonne vertébrale d'un récupérateur, il existe également d'autres types de récupérateurs.
Pour configurer un récupérateur de Chroma, vous l'installez d'abord en utilisant pip install chromadb
. Ensuite, vous chargez, divisez, intégrez et récupérez des documents à l'aide d'une série de commandes Python. Voici un exemple de code pour configurer un récupérateur de Chroma :
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)
Le MultiQueryRetriever automatise le réglage des invites en générant plusieurs requêtes pour une requête d'entrée utilisateur et combine les résultats. Voici un exemple de son utilisation simple :
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))
La compression contextuelle dans LangChain compresse les documents récupérés en utilisant le contexte de la requête, garantissant que seules les informations pertinentes sont renvoyées. Cela implique une réduction du contenu et le filtrage des documents les moins pertinents. L'exemple de code suivant montre comment utiliser 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)
L'EnsembleRetriever combine différents algorithmes de récupération pour obtenir de meilleures performances. Un exemple de combinaison de BM25 et de FAISS Retrievers est présenté dans le code suivant :
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 dans LangChain permet d'interroger des documents avec plusieurs vecteurs par document, ce qui est utile pour capturer différents aspects sémantiques au sein d'un document. Les méthodes permettant de créer plusieurs vecteurs incluent la division en morceaux plus petits, la synthèse ou la génération de questions hypothétiques. Pour diviser des documents en morceaux plus petits, le code Python suivant peut être utilisé :
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)))
Générer des résumés pour une meilleure récupération grâce à une représentation du contenu plus ciblée est une autre méthode. Voici un exemple de génération de résumés :
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)))
Générer des questions hypothétiques pertinentes pour chaque document à l'aide de LLM est une autre approche. Cela peut être fait avec le code suivant :
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)))
Le Parent Document Retriever est un autre outil de récupération qui établit un équilibre entre la précision de l'intégration et la rétention du contexte en stockant de petits morceaux et en récupérant leurs documents parents plus volumineux. Sa mise en œuvre est la suivante :
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")
Un récupérateur d'auto-interrogation construit des requêtes structurées à partir d'entrées en langage naturel et les applique à son VectorStore sous-jacent. Son implémentation est illustrée dans le code suivant :
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")
Le WebResearchRetriever effectue une recherche Web basée sur une requête donnée –
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")
Pour nos exemples, nous pouvons également utiliser le récupérateur standard déjà implémenté dans le cadre de notre objet de magasin vectoriel comme suit :
Nous pouvons maintenant interroger les récupérateurs. Le résultat de notre requête sera des objets de document pertinents pour la requête. Ceux-ci seront finalement utilisés pour créer des réponses pertinentes dans les sections suivantes.
Automatisez les tâches et les flux de travail manuels avec notre générateur de flux de travail basé sur l'IA, conçu par Nanonets pour vous et vos équipes.
Module III : Agents
LangChain introduit un concept puissant appelé « Agents » qui élève l'idée des chaînes à un tout autre niveau. Les agents exploitent des modèles de langage pour déterminer dynamiquement des séquences d'actions à effectuer, ce qui les rend incroyablement polyvalents et adaptatifs. Contrairement aux chaînes traditionnelles, où les actions sont codées en dur dans le code, les agents utilisent des modèles de langage comme moteurs de raisonnement pour décider quelles actions entreprendre et dans quel ordre.
L'agent est l’élément central responsable de la prise de décision. Il exploite la puissance d'un modèle de langage et d'une invite pour déterminer les prochaines étapes pour atteindre un objectif spécifique. Les entrées d'un agent incluent généralement :
- Outils: Descriptions des outils disponibles (nous y reviendrons plus tard).
- Entrée utilisateur : L’objectif ou la requête de haut niveau de l’utilisateur.
- Étapes intermédiaires : Un historique des paires (action, sortie de l'outil) exécutées pour atteindre l'entrée utilisateur actuelle.
La sortie d'un agent peut être la suivante action prendre des mesures (Actions de l'agent) ou la finale réponse à envoyer à l'utilisateur (Fin de l'agent). Un action spécifie un outil et les terres parsemées de contribution pour cet outil.
Outils
Les outils sont des interfaces qu'un agent peut utiliser pour interagir avec le monde. Ils permettent aux agents d'effectuer diverses tâches, telles que rechercher sur le Web, exécuter des commandes shell ou accéder à des API externes. Dans LangChain, les outils sont essentiels pour étendre les capacités des agents et leur permettre d'accomplir diverses tâches.
Pour utiliser les outils dans LangChain, vous pouvez les charger à l'aide de l'extrait suivant :
from langchain.agents import load_tools tool_names = [...]
tools = load_tools(tool_names)
Certains outils peuvent nécessiter un modèle de langage de base (LLM) pour s'initialiser. Dans de tels cas, vous pouvez également réussir un LLM :
from langchain.agents import load_tools tool_names = [...]
llm = ...
tools = load_tools(tool_names, llm=llm)
Cette configuration vous permet d'accéder à une variété d'outils et de les intégrer dans les flux de travail de votre agent. La liste complète des outils avec documentation d'utilisation est ici.
Regardons quelques exemples d'outils.
DuckDuckGo
L'outil DuckDuckGo vous permet d'effectuer des recherches sur le Web à l'aide de son moteur de recherche. Voici comment l'utiliser :
from langchain.tools import DuckDuckGoSearchRun
search = DuckDuckGoSearchRun()
search.run("manchester united vs luton town match summary")
DonnéesPourSeo
La boîte à outils DataForSeo vous permet d'obtenir les résultats des moteurs de recherche à l'aide de l'API DataForSeo. Pour utiliser cette boîte à outils, vous devrez configurer vos informations d'identification API. Voici comment configurer les informations d'identification :
import os os.environ["DATAFORSEO_LOGIN"] = "<your_api_access_username>"
os.environ["DATAFORSEO_PASSWORD"] = "<your_api_access_password>"
Une fois vos informations d'identification définies, vous pouvez créer un DataForSeoAPIWrapper
outil pour accéder à l'API :
from langchain.utilities.dataforseo_api_search import DataForSeoAPIWrapper wrapper = DataForSeoAPIWrapper() result = wrapper.run("Weather in Los Angeles")
La DataForSeoAPIWrapper
L'outil récupère les résultats des moteurs de recherche à partir de diverses sources.
Vous pouvez personnaliser le type de résultats et les champs renvoyés dans la réponse JSON. Par exemple, vous pouvez spécifier les types de résultats, les champs et définir un nombre maximum pour le nombre de meilleurs résultats à renvoyer :
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")
Cet exemple personnalise la réponse JSON en spécifiant les types de résultats, les champs et en limitant le nombre de résultats.
Vous pouvez également spécifier l'emplacement et la langue de vos résultats de recherche en transmettant des paramètres supplémentaires au wrapper de l'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")
En fournissant des paramètres de localisation et de langue, vous pouvez adapter vos résultats de recherche à des régions et des langues spécifiques.
Vous avez la possibilité de choisir le moteur de recherche que vous souhaitez utiliser. Précisez simplement le moteur de recherche souhaité :
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")
Dans cet exemple, la recherche est personnalisée pour utiliser Bing comme moteur de recherche.
Le wrapper API vous permet également de spécifier le type de recherche que vous souhaitez effectuer. Par exemple, vous pouvez effectuer une recherche sur des cartes :
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")
Cela personnalise la recherche pour récupérer les informations relatives aux cartes.
Coquille (bash)
La boîte à outils Shell fournit aux agents un accès à l'environnement shell, leur permettant d'exécuter des commandes shell. Cette fonctionnalité est puissante mais doit être utilisée avec prudence, en particulier dans les environnements sandbox. Voici comment utiliser l'outil Shell :
from langchain.tools import ShellTool shell_tool = ShellTool() result = shell_tool.run({"commands": ["echo 'Hello World!'", "time"]})
Dans cet exemple, l'outil Shell exécute deux commandes shell : en faisant écho à « Hello World ! » et afficher l'heure actuelle.
Vous pouvez fournir l'outil Shell à un agent pour effectuer des tâches plus complexes. Voici un exemple d'agent récupérant des liens à partir d'une page Web à l'aide de l'outil 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."
)
Dans ce scénario, l'agent utilise l'outil Shell pour exécuter une séquence de commandes afin de récupérer, filtrer et trier les URL d'une page Web.
Les exemples fournis démontrent certains des outils disponibles dans LangChain. Ces outils étendent en fin de compte les capacités des agents (explorées dans la sous-section suivante) et leur permettent d'effectuer diverses tâches efficacement. En fonction de vos besoins, vous pouvez choisir les outils et boîtes à outils les mieux adaptés aux besoins de votre projet et les intégrer dans les flux de travail de votre agent.
Retour aux agents
Passons maintenant aux agents.
AgentExecutor est l'environnement d'exécution d'un agent. Il est chargé d'appeler l'agent, d'exécuter les actions qu'il sélectionne, de renvoyer les résultats de l'action à l'agent et de répéter le processus jusqu'à ce que l'agent termine. En pseudocode, AgentExecutor pourrait ressembler à ceci :
next_action = agent.get_action(...)
while next_action != AgentFinish: observation = run(next_action) next_action = agent.get_action(..., next_action, observation)
return next_action
AgentExecutor gère diverses complexités, telles que le traitement des cas où l'agent sélectionne un outil inexistant, la gestion des erreurs d'outil, la gestion des sorties produites par l'agent et la fourniture de journalisation et d'observabilité à tous les niveaux.
Bien que la classe AgentExecutor soit le principal environnement d'exécution de l'agent dans LangChain, d'autres environnements d'exécution plus expérimentaux sont pris en charge, notamment :
- Agent de planification et d'exécution
- Bébé AGI
- GPT automatique
Pour mieux comprendre le cadre des agents, créons un agent de base à partir de zéro, puis passons à l'exploration des agents prédéfinis.
Avant de nous lancer dans la création de l'agent, il est essentiel de revoir certains schémas et terminologies clés :
- Action de l'agent : Il s'agit d'une classe de données représentant l'action qu'un agent doit entreprendre. Il se compose d'un
tool
propriété (le nom de l'outil à invoquer) et untool_input
propriété (l’entrée de cet outil). - Fin de l'agent : Cette classe de données indique que l'agent a terminé sa tâche et doit renvoyer une réponse à l'utilisateur. Il comprend généralement un dictionnaire de valeurs de retour, souvent avec une « sortie » clé contenant le texte de la réponse.
- Étapes intermédiaires : Il s'agit des enregistrements des actions précédentes de l'agent et des résultats correspondants. Ils sont cruciaux pour transmettre le contexte aux futures itérations de l’agent.
Dans notre exemple, nous utiliserons OpenAI Function Calling pour créer notre agent. Cette approche est fiable pour la création d'agents. Nous allons commencer par créer un outil simple qui calcule la longueur d'un mot. Cet outil est utile car les modèles de langage peuvent parfois commettre des erreurs en raison de la tokenisation lors du comptage de la longueur des mots.
Tout d’abord, chargeons le modèle de langage que nous utiliserons pour contrôler l’agent :
from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
Testons le modèle avec un calcul de longueur de mot :
llm.invoke("how many letters in the word educa?")
La réponse doit indiquer le nombre de lettres du mot « educa ».
Ensuite, nous définirons une fonction Python simple pour calculer la longueur d'un mot :
from langchain.agents import tool @tool
def get_word_length(word: str) -> int: """Returns the length of a word.""" return len(word)
Nous avons créé un outil nommé get_word_length
qui prend un mot en entrée et renvoie sa longueur.
Créons maintenant l'invite pour l'agent. L'invite indique à l'agent comment raisonner et formater la sortie. Dans notre cas, nous utilisons OpenAI Function Calling, qui nécessite un minimum d'instructions. Nous allons définir l'invite avec des espaces réservés pour la saisie de l'utilisateur et le bloc-notes de l'agent :
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"), ]
)
Maintenant, comment l’agent sait-il quels outils il peut utiliser ? Nous nous appuyons sur des modèles de langage d'appel de fonctions OpenAI, qui nécessitent que les fonctions soient transmises séparément. Pour fournir nos outils à l'agent, nous les formaterons sous forme d'appels de fonction 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])
Maintenant, nous pouvons créer l'agent en définissant les mappages d'entrée et en connectant les composants :
C'est le langage LCEL. Nous en discuterons plus tard en détail.
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()
)
Nous avons créé notre agent, qui comprend les entrées des utilisateurs, utilise les outils disponibles et formate la sortie. Maintenant, interagissons avec lui :
agent.invoke({"input": "how many letters in the word educa?", "intermediate_steps": []})
L'agent doit répondre avec un AgentAction, indiquant la prochaine action à entreprendre.
Nous avons créé l'agent, mais nous devons maintenant écrire un environnement d'exécution pour celui-ci. Le runtime le plus simple est celui qui appelle continuellement l'agent, exécute des actions et se répète jusqu'à ce que l'agent ait terminé. Voici un exemple :
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)
Dans cette boucle, nous appelons l'agent à plusieurs reprises, exécutons des actions et mettons à jour les étapes intermédiaires jusqu'à ce que l'agent termine. Nous gérons également les interactions des outils au sein de la boucle.
Pour simplifier ce processus, LangChain fournit la classe AgentExecutor, qui encapsule l'exécution de l'agent et offre une gestion des erreurs, un arrêt anticipé, un traçage et d'autres améliorations. Utilisons AgentExecutor pour interagir avec l'agent :
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 simplifie le processus d'exécution et fournit un moyen pratique d'interagir avec l'agent.
La mémoire est également abordée en détail plus tard.
L'agent que nous avons créé jusqu'à présent est apatride, ce qui signifie qu'il ne se souvient pas des interactions précédentes. Pour permettre le suivi des questions et des conversations, nous devons ajouter de la mémoire à l'agent. Cela implique deux étapes :
- Ajoutez une variable de mémoire dans l'invite pour stocker l'historique des discussions.
- Gardez une trace de l'historique des discussions pendant les interactions.
Commençons par ajouter un espace réservé à la mémoire dans l'invite :
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"), ]
)
Maintenant, créez une liste pour suivre l’historique des discussions :
from langchain.schema.messages import HumanMessage, AIMessage chat_history = []
Lors de l'étape de création de l'agent, nous inclurons également la mémoire :
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()
)
Désormais, lors de l'exécution de l'agent, assurez-vous de mettre à jour l'historique des discussions :
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})
Cela permet à l'agent de conserver un historique des conversations et de répondre aux questions de suivi en fonction des interactions précédentes.
Toutes nos félicitations! Vous avez créé et exécuté avec succès votre premier agent de bout en bout dans LangChain. Pour approfondir les capacités de LangChain, vous pouvez explorer :
- Différents types d'agents pris en charge.
- Agents prédéfinis
- Comment travailler avec des outils et des intégrations d'outils.
Types d'agents
LangChain propose différents types d'agents, chacun adapté à des cas d'utilisation spécifiques. Voici quelques-uns des agents disponibles :
- Réaction zéro tir : Cet agent utilise le framework ReAct pour choisir des outils en fonction uniquement de leurs descriptions. Il nécessite des descriptions pour chaque outil et est très polyvalent.
- Entrée structurée ReAct : Cet agent gère des outils multi-entrées et convient aux tâches complexes comme la navigation dans un navigateur Web. Il utilise le schéma d'arguments d'un outil pour une entrée structurée.
- Fonctions OpenAI : Spécialement conçu pour les modèles optimisés pour l'appel de fonctions, cet agent est compatible avec des modèles tels que gpt-3.5-turbo-0613 et gpt-4-0613. Nous l'avons utilisé pour créer notre premier agent ci-dessus.
- De la conversation: Conçu pour les environnements conversationnels, cet agent utilise ReAct pour la sélection des outils et utilise la mémoire pour mémoriser les interactions précédentes.
- Auto-question avec recherche : Cet agent s'appuie sur un seul outil, « Intermediate Answer », qui recherche des réponses factuelles aux questions. C'est l'équivalent de l'auto-demande originale avec papier de recherche.
- Magasin de documents ReAct : Cet agent interagit avec un magasin de documents à l'aide du framework ReAct. Il nécessite des outils de « Recherche » et « Lookup » et est similaire à l'exemple Wikipédia du document ReAct original.
Explorez ces types d’agents pour trouver celui qui correspond le mieux à vos besoins dans LangChain. Ces agents vous permettent de lier un ensemble d’outils en leur sein pour gérer des actions et générer des réponses. En savoir plus sur comment créer votre propre agent avec des outils ici.
Agents prédéfinis
Poursuivons notre exploration des agents, en nous concentrant sur les agents prédéfinis disponibles dans LangChain.
Gmail
LangChain propose une boîte à outils Gmail qui vous permet de connecter votre messagerie LangChain à l'API Gmail. Pour commencer, vous devrez configurer vos informations d'identification, qui sont expliquées dans la documentation de l'API Gmail. Une fois que vous avez téléchargé le credentials.json
fichier, vous pouvez continuer à utiliser l'API Gmail. De plus, vous devrez installer certaines bibliothèques requises à l'aide des commandes suivantes :
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
Vous pouvez créer la boîte à outils Gmail comme suit :
from langchain.agents.agent_toolkits import GmailToolkit toolkit = GmailToolkit()
Vous pouvez également personnaliser l'authentification selon vos besoins. En coulisses, une ressource googleapi est créée à l'aide des méthodes suivantes :
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)
La boîte à outils propose divers outils pouvant être utilisés au sein d'un agent, notamment :
GmailCreateDraft
: Créez un brouillon d'e-mail avec les champs de message spécifiés.GmailSendMessage
: envoyer des messages électroniques.GmailSearch
: recherchez des messages électroniques ou des fils de discussion.GmailGetMessage
: Récupérer un e-mail par ID de message.GmailGetThread
: Rechercher des e-mails.
Pour utiliser ces outils au sein d'un agent, vous pouvez initialiser l'agent comme suit :
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,
)
Voici quelques exemples de la façon dont ces outils peuvent être utilisés :
- Créez un brouillon Gmail à modifier :
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."
)
- Recherchez le dernier e-mail dans vos brouillons :
agent.run("Could you search in my drafts for the latest email?")
Ces exemples démontrent les capacités de la boîte à outils Gmail de LangChain au sein d'un agent, vous permettant d'interagir avec Gmail par programmation.
Agent de base de données SQL
Cette section fournit une présentation d'un agent conçu pour interagir avec les bases de données SQL, en particulier la base de données Chinook. Cet agent peut répondre à des questions générales sur une base de données et récupérer des erreurs. Veuillez noter qu'il est toujours en développement actif et que toutes les réponses peuvent ne pas être correctes. Soyez prudent lorsque vous l'exécutez sur des données sensibles, car il peut exécuter des instructions DML sur votre base de données.
Pour utiliser cet agent, vous pouvez l'initialiser comme suit :
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,
)
Cet agent peut être initialisé à l'aide du ZERO_SHOT_REACT_DESCRIPTION
type d'agent. Il est conçu pour répondre aux questions et fournir des descriptions. Vous pouvez également initialiser l'agent à l'aide de la commande OPENAI_FUNCTIONS
type d'agent avec le modèle GPT-3.5-turbo d'OpenAI, que nous avons utilisé dans notre client précédent.
Clause de non-responsabilité
- La chaîne de requêtes peut générer des requêtes d'insertion/mise à jour/suppression. Soyez prudent et utilisez une invite personnalisée ou créez un utilisateur SQL sans autorisations d'écriture si nécessaire.
- Sachez que l'exécution de certaines requêtes, telles que « exécuter la plus grande requête possible », pourrait surcharger votre base de données SQL, surtout si elle contient des millions de lignes.
- Les bases de données orientées entrepôt de données prennent souvent en charge des quotas au niveau des utilisateurs pour limiter l'utilisation des ressources.
Vous pouvez demander à l'agent de décrire une table, comme la table « playlisttrack ». Voici un exemple de la façon de procéder :
agent_executor.run("Describe the playlisttrack table")
L'agent fournira des informations sur le schéma de la table et des exemples de lignes.
Si vous posez par erreur une question sur une table qui n'existe pas, l'agent peut récupérer et fournir des informations sur la table correspondante la plus proche. Par exemple:
agent_executor.run("Describe the playlistsong table")
L'agent trouvera la table correspondante la plus proche et fournira des informations à ce sujet.
Vous pouvez également demander à l'agent d'exécuter des requêtes sur la base de données. Par exemple:
agent_executor.run("List the total sales per country. Which country's customers spent the most?")
L'agent exécutera la requête et fournira le résultat, par exemple le pays avec les ventes totales les plus élevées.
Pour obtenir le nombre total de pistes dans chaque playlist, vous pouvez utiliser la requête suivante :
agent_executor.run("Show the total number of tracks in each playlist. The Playlist name should be included in the result.")
L'agent renverra les noms des listes de lecture ainsi que le nombre total de pistes correspondant.
Dans les cas où l'agent rencontre des erreurs, il peut récupérer et fournir des réponses précises. Par exemple:
agent_executor.run("Who are the top 3 best selling artists?")
Même après avoir rencontré une première erreur, l'agent s'ajustera et fournira la bonne réponse, qui, dans ce cas, correspond au top 3 des artistes les plus vendus.
Agent DataFrame Pandas
Cette section présente un agent conçu pour interagir avec Pandas DataFrames à des fins de réponse aux questions. Veuillez noter que cet agent utilise l'agent Python sous le capot pour exécuter le code Python généré par un modèle de langage (LLM). Faites preuve de prudence lorsque vous utilisez cet agent pour éviter tout dommage potentiel dû au code Python malveillant généré par le LLM.
Vous pouvez initialiser l'agent Pandas DataFrame comme suit :
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,
# )
Vous pouvez demander à l'agent de compter le nombre de lignes dans le DataFrame :
agent.run("how many rows are there?")
L'agent exécutera le code df.shape[0]
» et fournissez la réponse, telle que « Il y a 891 lignes dans la trame de données. »
Vous pouvez également demander à l'agent de filtrer les lignes en fonction de critères spécifiques, comme rechercher le nombre de personnes ayant plus de 3 frères et sœurs :
agent.run("how many people have more than 3 siblings")
L'agent exécutera le code df[df['SibSp'] > 3].shape[0]
» et fournissez la réponse, par exemple « 30 personnes ont plus de 3 frères et sœurs ».
Si vous souhaitez calculer la racine carrée de l’âge moyen, vous pouvez demander à l’agent :
agent.run("whats the square root of the average age?")
L'agent calculera l'âge moyen en utilisant df['Age'].mean()
puis calculez la racine carrée en utilisant math.sqrt()
. Il fournira la réponse, telle que « La racine carrée de l’âge moyen est 5.449689683556195 ».
Créons une copie du DataFrame, et les valeurs d'âge manquantes sont remplies avec l'âge moyen :
df1 = df.copy()
df1["Age"] = df1["Age"].fillna(df1["Age"].mean())
Ensuite, vous pouvez initialiser l'agent avec les deux DataFrames et lui poser une question :
agent = create_pandas_dataframe_agent(OpenAI(temperature=0), [df, df1], verbose=True)
agent.run("how many rows in the age column are different?")
L'agent comparera les colonnes d'âge dans les deux DataFrames et fournira la réponse, par exemple « 177 lignes de la colonne d'âge sont différentes ».
Boîte à outils Jira
Cette section explique comment utiliser la boîte à outils Jira, qui permet aux agents d'interagir avec une instance Jira. Vous pouvez effectuer diverses actions telles que rechercher des problèmes et créer des problèmes à l'aide de cette boîte à outils. Il utilise la bibliothèque atlassian-python-api. Pour utiliser cette boîte à outils, vous devez définir des variables d'environnement pour votre instance Jira, notamment JIRA_API_TOKEN, JIRA_USERNAME et JIRA_INSTANCE_URL. De plus, vous devrez peut-être définir votre clé API OpenAI comme variable d'environnement.
Pour commencer, installez la bibliothèque atlassian-python-api et définissez les variables d'environnement requises :
%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
)
Vous pouvez demander à l'agent de créer un nouveau problème dans un projet spécifique avec un résumé et une description :
agent.run("make a new issue in project PW to remind me to make more fried rice")
L'agent exécutera les actions nécessaires pour créer le problème et fournira une réponse, telle que « Un nouveau problème a été créé dans le projet PW avec le résumé « Faire plus de riz frit » et la description « Rappel pour faire plus de riz frit ».
Cela vous permet d'interagir avec votre instance Jira à l'aide d'instructions en langage naturel et de la boîte à outils Jira.
Automatisez les tâches et les flux de travail manuels avec notre générateur de flux de travail basé sur l'IA, conçu par Nanonets pour vous et vos équipes.
Module IV : Chaînes
LangChain est un outil conçu pour utiliser des modèles linguistiques étendus (LLM) dans des applications complexes. Il fournit des cadres pour créer des chaînes de composants, notamment des LLM et d'autres types de composants. Deux cadres principaux
- Le langage d'expression LangChain (LCEL)
- Interface de chaîne héritée
Le LangChain Expression Language (LCEL) est une syntaxe qui permet une composition intuitive de chaînes. Il prend en charge des fonctionnalités avancées telles que le streaming, les appels asynchrones, le traitement par lots, la parallélisation, les tentatives, les replis et le traçage. Par exemple, vous pouvez composer un analyseur d'invite, de modèle et de sortie dans LCEL, comme indiqué dans le code suivant :
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)
Alternativement, le LLMChain est une option similaire au LCEL pour composer des composants. L'exemple de LLMChain est le suivant :
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")
Les chaînes dans LangChain peuvent également être avec état en incorporant un objet Memory. Cela permet la persistance des données entre les appels, comme le montre cet exemple :
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 prend également en charge l'intégration avec les API d'appel de fonctions d'OpenAI, ce qui est utile pour obtenir des sorties structurées et exécuter des fonctions au sein d'une chaîne. Pour obtenir des sorties structurées, vous pouvez les spécifier à l'aide de classes Pydantic ou de JsonSchema, comme illustré ci-dessous :
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"})
Pour les sorties structurées, une approche existante utilisant LLMChain est également disponible :
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 exploite les fonctions OpenAI pour créer diverses chaînes spécifiques à des fins différentes. Il s'agit notamment de chaînes d'extraction, de marquage, d'OpenAPI et de contrôle qualité avec citations.
Dans le contexte de l'extraction, le processus est similaire à la chaîne de production structurée mais se concentre sur l'extraction d'informations ou d'entités. Pour le balisage, l'idée est d'étiqueter un document avec des classes telles que le sentiment, la langue, le style, les sujets abordés ou la tendance politique.
Un exemple du fonctionnement du balisage dans LangChain peut être démontré avec un code Python. Le processus commence par l'installation des packages nécessaires et la configuration de l'environnement :
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
Le schéma de balisage est défini, en précisant les propriétés et leurs types attendus :
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)
Des exemples d'exécution de la chaîne de marquage avec différentes entrées montrent la capacité du modèle à interpréter les sentiments, les langages et l'agressivité :
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'}
Pour un contrôle plus fin, le schéma peut être défini plus spécifiquement, y compris les valeurs possibles, les descriptions et les propriétés requises. Un exemple de ce contrôle amélioré est présenté ci-dessous :
schema = { "properties": { # Schema definitions here }, "required": ["language", "sentiment", "aggressiveness"],
} chain = create_tagging_chain(schema, llm)
Les schémas Pydantic peuvent également être utilisés pour définir des critères de balisage, fournissant un moyen pythonique de spécifier les propriétés et les types requis :
from enum import Enum
from pydantic import BaseModel, Field class Tags(BaseModel): # Class fields here chain = create_tagging_chain_pydantic(Tags, llm)
De plus, le transformateur de document de balisage de métadonnées de LangChain peut être utilisé pour extraire des métadonnées de documents LangChain, offrant des fonctionnalités similaires à la chaîne de balisage mais appliquée à un document LangChain.
La citation de sources de récupération est une autre fonctionnalité de LangChain, qui utilise les fonctions OpenAI pour extraire des citations du texte. Ceci est démontré dans le code suivant :
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
Dans LangChain, le chaînage dans les applications Large Language Model (LLM) implique généralement de combiner un modèle d'invite avec un LLM et éventuellement un analyseur de sortie. La méthode recommandée pour ce faire consiste à utiliser le langage d'expression LangChain (LCEL), bien que l'approche LLMChain héritée soit également prise en charge.
À l'aide de LCEL, BasePromptTemplate, BaseLanguageModel et BaseOutputParser implémentent tous l'interface Runnable et peuvent être facilement intégrés les uns aux autres. Voici un exemple démontrant cela :
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'
Le routage dans LangChain permet de créer des chaînes non déterministes où le résultat d'une étape précédente détermine l'étape suivante. Cela aide à structurer et à maintenir la cohérence dans les interactions avec les LLM. Par exemple, si vous disposez de deux modèles optimisés pour différents types de questions, vous pouvez choisir le modèle en fonction des entrées de l'utilisateur.
Voici comment y parvenir en utilisant LCEL avec un RunnableBranch, qui est initialisé avec une liste de paires (condition, exécutable) et un exécutable par défaut :
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
La chaîne finale est ensuite construite à l'aide de divers composants, tels qu'un classificateur de sujet, une branche d'invite et un analyseur de sortie, pour déterminer le flux en fonction du sujet de l'entrée :
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
Cette approche illustre la flexibilité et la puissance de LangChain pour gérer des requêtes complexes et les acheminer de manière appropriée en fonction de l'entrée.
Dans le domaine des modèles de langage, une pratique courante consiste à faire suivre un appel initial d'une série d'appels ultérieurs, en utilisant la sortie d'un appel comme entrée du suivant. Cette approche séquentielle est particulièrement bénéfique lorsque vous souhaitez vous appuyer sur les informations générées lors des interactions précédentes. Bien que le LangChain Expression Language (LCEL) soit la méthode recommandée pour créer ces séquences, la méthode SequentialChain est toujours documentée pour sa compatibilité ascendante.
Pour illustrer cela, considérons un scénario dans lequel nous générons d'abord un synopsis de jeu, puis une critique basée sur ce synopsis. Utiliser Python langchain.prompts
, on crée deux PromptTemplate
instances : une pour le synopsis et une autre pour la critique. Voici le code pour configurer ces modèles :
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:"
)
Dans l'approche LCEL, nous enchaînons ces invites avec ChatOpenAI
ainsi que StrOutputParser
pour créer une séquence qui génère d'abord un synopsis puis une critique. L'extrait de code est le suivant :
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"})
Si nous avons besoin à la fois du résumé et de la critique, nous pouvons utiliser RunnablePassthrough
pour créer une chaîne distincte pour chacun, puis les combiner :
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"})
Pour les scénarios impliquant des séquences plus complexes, le SequentialChain
la méthode entre en jeu. Cela permet plusieurs entrées et sorties. Prenons un cas où nous avons besoin d'un synopsis basé sur le titre et l'époque d'une pièce. Voici comment nous pourrions le configurer :
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"})
Dans les scénarios où vous souhaitez conserver le contexte tout au long d'une chaîne ou pour une partie ultérieure de la chaîne, SimpleMemory
peut être utilisé. Ceci est particulièrement utile pour gérer des relations entrées/sorties complexes. Par exemple, dans un scénario où nous souhaitons générer des publications sur les réseaux sociaux basées sur le titre, l'époque, le synopsis et la critique d'une pièce, SimpleMemory
peut aider à gérer ces variables :
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"})
En plus des chaînes séquentielles, il existe des chaînes spécialisées pour travailler avec des documents. Chacune de ces chaînes répond à un objectif différent, depuis la combinaison de documents jusqu'à l'affinement des réponses sur la base d'une analyse itérative des documents, jusqu'à la cartographie et la réduction du contenu des documents pour le résumer ou le reclassement en fonction des réponses notées. Ces chaînes peuvent être recréées avec LCEL pour plus de flexibilité et de personnalisation.
-
StuffDocumentsChain
combine une liste de documents en une seule invite transmise à un LLM. -
RefineDocumentsChain
met à jour sa réponse de manière itérative pour chaque document, adapté aux tâches où les documents dépassent la capacité contextuelle du modèle. -
MapReduceDocumentsChain
applique une chaîne à chaque document individuellement, puis combine les résultats. -
MapRerankDocumentsChain
note chaque réponse basée sur un document et sélectionne celle qui obtient le score le plus élevé.
Voici un exemple de la façon dont vous pourriez configurer un MapReduceDocumentsChain
en utilisant 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")
Cette configuration permet une analyse détaillée et complète du contenu du document, en tirant parti des atouts de LCEL et du modèle linguistique sous-jacent.
Automatisez les tâches et les flux de travail manuels avec notre générateur de flux de travail basé sur l'IA, conçu par Nanonets pour vous et vos équipes.
Module V : Mémoire
Dans LangChain, la mémoire est un aspect fondamental des interfaces conversationnelles, permettant aux systèmes de référencer les interactions passées. Ceci est réalisé grâce au stockage et à l’interrogation d’informations, avec deux actions principales : la lecture et l’écriture. Le système de mémoire interagit avec une chaîne deux fois au cours d'une exécution, augmentant les entrées de l'utilisateur et stockant les entrées et les sorties pour référence future.
Construire de la mémoire dans un système
- Stockage des messages de discussion : Le module de mémoire LangChain intègre diverses méthodes pour stocker les messages de discussion, allant des listes en mémoire aux bases de données. Cela garantit que toutes les interactions de chat sont enregistrées pour référence future.
- Interrogation des messages de discussion : Au-delà du stockage des messages de discussion, LangChain utilise des structures de données et des algorithmes pour créer une vue utile de ces messages. Des systèmes de mémoire simples peuvent renvoyer des messages récents, tandis que des systèmes plus avancés peuvent résumer les interactions passées ou se concentrer sur les entités mentionnées dans l'interaction en cours.
Pour démontrer l'utilisation de la mémoire dans LangChain, considérons le ConversationBufferMemory
classe, une forme de mémoire simple qui stocke les messages de discussion dans un tampon. Voici un exemple :
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?")
Lors de l'intégration de mémoire dans une chaîne, il est crucial de comprendre les variables renvoyées par la mémoire et comment elles sont utilisées dans la chaîne. Par exemple, le load_memory_variables
La méthode permet d'aligner les variables lues en mémoire avec les attentes de la chaîne.
Exemple de bout en bout avec LangChain
Pensez à utiliser ConversationBufferMemory
dans un LLMChain
. La chaîne, combinée à un modèle d'invite approprié et à la mémoire, offre une expérience conversationnelle transparente. Voici un exemple simplifié :
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?"})
Cet exemple illustre comment le système de mémoire de LangChain s'intègre à ses chaînes pour fournir une expérience conversationnelle cohérente et contextuelle.
Types de mémoire dans Langchain
Langchain propose différents types de mémoire qui peuvent être utilisés pour améliorer les interactions avec les modèles d'IA. Chaque type de mémoire possède ses propres paramètres et types de retour, ce qui les rend adaptés à différents scénarios. Explorons certains des types de mémoire disponibles dans Langchain ainsi que des exemples de code.
1. Mémoire tampon de conversation
Ce type de mémoire vous permet de stocker et d'extraire les messages des conversations. Vous pouvez extraire l'historique sous forme de chaîne ou sous forme de liste de messages.
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={})]}
Vous pouvez également utiliser la mémoire tampon de conversation dans une chaîne pour des interactions de type chat.
2. Mémoire de la fenêtre tampon de conversation
Ce type de mémoire conserve une liste des interactions récentes et utilise les K dernières interactions, empêchant ainsi le tampon de devenir trop volumineux.
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'}
Comme la mémoire tampon de conversation, vous pouvez également utiliser ce type de mémoire dans une chaîne pour des interactions de type chat.
3. Mémoire d'entité de conversation
Ce type de mémoire mémorise des faits sur des entités spécifiques dans une conversation et extrait des informations à l'aide d'un 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. Mémoire du graphique de connaissances de conversation
Ce type de mémoire utilise un graphe de connaissances pour recréer la mémoire. Vous pouvez extraire les entités actuelles et les triplets de connaissances des messages.
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.'}
Vous pouvez également utiliser ce type de mémoire dans une chaîne de récupération de connaissances basée sur des conversations.
5. Mémoire de résumé de conversation
Ce type de mémoire crée un résumé de la conversation au fil du temps, utile pour condenser les informations provenant de conversations plus longues.
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. Mémoire tampon du résumé de la conversation
Ce type de mémoire combine le résumé de la conversation et le tampon, maintenant un équilibre entre les interactions récentes et un résumé. Il utilise la longueur du jeton pour déterminer quand vider les interactions.
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'}
Vous pouvez utiliser ces types de mémoire pour améliorer vos interactions avec les modèles d'IA dans Langchain. Chaque type de mémoire répond à un objectif spécifique et peut être sélectionné en fonction de vos besoins.
7. Mémoire tampon du jeton de conversation
ConversationTokenBufferMemory est un autre type de mémoire qui conserve en mémoire un tampon des interactions récentes. Contrairement aux types de mémoire précédents qui se concentrent sur le nombre d’interactions, celui-ci utilise la longueur du jeton pour déterminer quand vider les interactions.
Utiliser la mémoire avec 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'}
Dans cet exemple, la mémoire est configurée pour limiter les interactions en fonction de la longueur du jeton plutôt que du nombre d'interactions.
Vous pouvez également obtenir l'historique sous forme de liste de messages lorsque vous utilisez ce type de mémoire.
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"})
Utilisation en chaîne :
Vous pouvez utiliser ConversationTokenBufferMemory dans une chaîne pour améliorer les interactions avec le modèle d'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?")
Dans cet exemple, ConversationTokenBufferMemory est utilisé dans une ConversationChain pour gérer la conversation et limiter les interactions en fonction de la longueur du jeton.
8. VectorStoreRetrieverMémoire
VectorStoreRetrieverMemory stocke les mémoires dans un magasin vectoriel et interroge les documents les plus « saillants » à chaque fois qu'il est appelé. Ce type de mémoire ne suit pas explicitement l'ordre des interactions mais utilise la récupération vectorielle pour récupérer les mémoires pertinentes.
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"])
Dans cet exemple, VectorStoreRetrieverMemory est utilisé pour stocker et récupérer des informations pertinentes à partir d'une conversation basée sur la récupération vectorielle.
Vous pouvez également utiliser VectorStoreRetrieverMemory dans une chaîne pour la récupération de connaissances basée sur des conversations, comme indiqué dans les exemples précédents.
Ces différents types de mémoire dans Langchain offrent différentes manières de gérer et de récupérer des informations à partir de conversations, améliorant ainsi les capacités des modèles d'IA à comprendre et à répondre aux requêtes et au contexte des utilisateurs. Chaque type de mémoire peut être sélectionné en fonction des exigences spécifiques de votre application.
Nous allons maintenant apprendre à utiliser la mémoire avec une LLMChain. La mémoire dans une LLMChain permet au modèle de se souvenir des interactions et du contexte précédents pour fournir des réponses plus cohérentes et contextuelles.
Pour configurer la mémoire dans un LLMChain, vous devez créer une classe de mémoire, telle que ConversationBufferMemory. Voici comment vous pouvez le configurer :
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")
Dans cet exemple, ConversationBufferMemory est utilisé pour stocker l’historique des conversations. Le memory_key
Le paramètre spécifie la clé utilisée pour stocker l’historique des conversations.
Si vous utilisez un modèle de discussion au lieu d'un modèle de style complétion, vous pouvez structurer vos invites différemment pour mieux utiliser la mémoire. Voici un exemple de configuration d'une LLMChain basée sur un modèle de chat avec de la mémoire :
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")
Dans cet exemple, ChatPromptTemplate est utilisé pour structurer l'invite et ConversationBufferMemory est utilisé pour stocker et récupérer l'historique des conversations. Cette approche est particulièrement utile pour les conversations de type chat dans lesquelles le contexte et l'historique jouent un rôle crucial.
La mémoire peut également être ajoutée à une chaîne avec plusieurs entrées, comme une chaîne de questions/réponses. Voici un exemple de configuration de la mémoire dans une chaîne de questions/réponses :
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)
Dans cet exemple, la réponse à une question est effectuée à l'aide d'un document divisé en morceaux plus petits. Le ConversationBufferMemory est utilisé pour stocker et récupérer l'historique des conversations, permettant au modèle de fournir des réponses contextuelles.
L'ajout de mémoire à un agent lui permet de se souvenir et d'utiliser les interactions précédentes pour répondre aux questions et fournir des réponses contextuelles. Voici comment configurer la mémoire dans un agent :
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)
Dans cet exemple, de la mémoire est ajoutée à un agent, lui permettant de se souvenir de l'historique des conversations précédentes et de fournir des réponses contextuelles. Cela permet à l'agent de répondre avec précision aux questions de suivi en fonction des informations stockées en mémoire.
Langage d'expression LangChain
Dans le monde du traitement du langage naturel et de l’apprentissage automatique, composer des chaînes d’opérations complexes peut s’avérer une tâche ardue. Heureusement, LangChain Expression Language (LCEL) vient à la rescousse, offrant un moyen déclaratif et efficace de créer et de déployer des pipelines de traitement de langage sophistiqués. LCEL est conçu pour simplifier le processus de composition des chaînes, permettant de passer facilement du prototypage à la production. Dans ce blog, nous explorerons ce qu'est LCEL et pourquoi vous pourriez vouloir l'utiliser, ainsi que des exemples de code pratiques pour illustrer ses capacités.
LCEL, ou LangChain Expression Language, est un outil puissant pour composer des chaînes de traitement de langage. Il a été spécialement conçu pour prendre en charge la transition du prototypage à la production de manière transparente, sans nécessiter de modifications importantes du code. Que vous construisiez une simple chaîne « invite + LLM » ou un pipeline complexe comportant des centaines d'étapes, LCEL a ce qu'il vous faut.
Voici quelques raisons d’utiliser LCEL dans vos projets de traitement du langage :
- Streaming rapide de jetons : LCEL fournit des jetons d'un modèle de langage à un analyseur de sortie en temps réel, améliorant ainsi la réactivité et l'efficacité.
- API polyvalentes : LCEL prend en charge les API synchrones et asynchrones pour le prototypage et l'utilisation en production, gérant efficacement plusieurs requêtes.
- Parallélisation automatique : LCEL optimise l'exécution parallèle lorsque cela est possible, réduisant ainsi la latence dans les interfaces synchronisées et asynchrones.
- Configurations fiables : configurez les tentatives et les replis pour une fiabilité de chaîne améliorée à grande échelle, avec prise en charge du streaming en cours de développement.
- Flux de résultats intermédiaires : accédez aux résultats intermédiaires pendant le traitement à des fins de mise à jour utilisateur ou de débogage.
- Génération de schéma : LCEL génère des schémas Pydantic et JSONSchema pour la validation des entrées et des sorties.
- Traçage complet : LangSmith trace automatiquement toutes les étapes des chaînes complexes à des fins d'observabilité et de débogage.
- Déploiement facile : déployez sans effort les chaînes créées par LCEL à l’aide de LangServe.
Passons maintenant à des exemples de code pratiques qui démontrent la puissance de LCEL. Nous explorerons les tâches et les scénarios courants dans lesquels LCEL brille.
Invite + LLM
La composition la plus fondamentale consiste à combiner une invite et un modèle de langage pour créer une chaîne qui prend en compte les entrées de l'utilisateur, les ajoute à une invite, les transmet à un modèle et renvoie la sortie brute du modèle. Voici un exemple :
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)
Dans cet exemple, la chaîne génère une blague sur les ours.
Vous pouvez attacher des séquences d'arrêt à votre chaîne pour contrôler la façon dont elle traite le texte. Par exemple:
chain = prompt | model.bind(stop=["n"])
result = chain.invoke({"foo": "bears"})
print(result)
Cette configuration arrête la génération de texte lorsqu'un caractère de nouvelle ligne est rencontré.
LCEL prend en charge l'attachement d'informations d'appel de fonction à votre chaîne. Voici un exemple :
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)
Cet exemple joint des informations sur l'appel de fonction pour générer une blague.
Invite + LLM + OutputParser
Vous pouvez ajouter un analyseur de sortie pour transformer la sortie brute du modèle dans un format plus exploitable. Voici comment procéder :
from langchain.schema.output_parser import StrOutputParser chain = prompt | model | StrOutputParser()
result = chain.invoke({"foo": "bears"})
print(result)
La sortie est désormais au format chaîne, ce qui est plus pratique pour les tâches en aval.
Lorsque vous spécifiez une fonction à renvoyer, vous pouvez l'analyser directement à l'aide de LCEL. Par exemple:
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)
Cet exemple analyse directement la sortie de la fonction « blague ».
Ce ne sont là que quelques exemples de la façon dont LCEL simplifie les tâches complexes de traitement du langage. Que vous créiez des chatbots, génériez du contenu ou effectuiez des transformations de texte complexes, LCEL peut rationaliser votre flux de travail et rendre votre code plus facile à gérer.
RAG (génération augmentée par récupération)
LCEL peut être utilisé pour créer des chaînes de génération augmentées par récupération, qui combinent les étapes de récupération et de génération de langage. Voici un exemple :
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)
Dans cet exemple, la chaîne récupère les informations pertinentes du contexte et génère une réponse à la question.
Chaîne de récupération conversationnelle
Vous pouvez facilement ajouter l'historique des conversations à vos chaînes. Voici un exemple de chaîne de récupération conversationnelle :
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)
Dans cet exemple, la chaîne gère une question de suivi dans un contexte conversationnel.
Avec mémoire et renvoi de documents sources
LCEL prend également en charge la mémoire et le renvoi des documents sources. Voici comment utiliser la mémoire dans une chaîne :
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)
Dans cet exemple, la mémoire est utilisée pour stocker et récupérer l'historique des conversations et les documents sources.
Plusieurs chaînes
Vous pouvez enchaîner plusieurs chaînes à l’aide de Runnables. Voici un exemple :
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)
Dans cet exemple, deux chaînes sont combinées pour générer des informations sur une ville et son pays dans une langue spécifiée.
Branchement et fusion
LCEL vous permet de diviser et de fusionner des chaînes à l'aide de RunnableMaps. Voici un exemple de branchement et de fusion :
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)
Dans cet exemple, une chaîne de branchement et de fusion est utilisée pour générer un argument et évaluer ses avantages et ses inconvénients avant de générer une réponse finale.
Écrire du code Python avec LCEL
L'une des applications puissantes du LangChain Expression Language (LCEL) consiste à écrire du code Python pour résoudre les problèmes des utilisateurs. Vous trouverez ci-dessous un exemple d'utilisation de LCEL pour écrire du code 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)
Dans cet exemple, un utilisateur fournit une entrée et LCEL génère du code Python pour résoudre le problème. Le code est ensuite exécuté à l'aide d'un Python REPL et le code Python résultant est renvoyé au format Markdown.
Veuillez noter que l'utilisation d'un Python REPL peut exécuter du code arbitraire, alors utilisez-le avec prudence.
Ajouter de la mémoire à une chaîne
La mémoire est essentielle dans de nombreuses applications d’IA conversationnelle. Voici comment ajouter de la mémoire à une chaîne arbitraire :
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({})
Dans cet exemple, la mémoire est utilisée pour stocker et récupérer l'historique des conversations, permettant au chatbot de conserver le contexte et de répondre de manière appropriée.
Utiliser des outils externes avec Runnables
LCEL vous permet d'intégrer de manière transparente des outils externes avec Runnables. Voici un exemple utilisant l'outil de recherche DuckDuckGo :
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)
Dans cet exemple, LCEL intègre l'outil DuckDuckGo Search dans la chaîne, lui permettant de générer une requête de recherche à partir des entrées de l'utilisateur et de récupérer les résultats de la recherche.
La flexibilité de LCEL facilite l'intégration de divers outils et services externes dans vos pipelines de traitement linguistique, améliorant ainsi leurs capacités et fonctionnalités.
Ajout de modération à une candidature LLM
Pour garantir que votre application LLM respecte les politiques de contenu et inclut des garanties de modération, vous pouvez intégrer des contrôles de modération dans votre chaîne. Voici comment ajouter une modération à l'aide de 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)
Dans cet exemple, le OpenAIModerationChain
est utilisé pour ajouter de la modération à la réponse générée par le LLM. La chaîne de modération vérifie la réponse pour le contenu qui viole la politique de contenu d'OpenAI. Si des violations sont constatées, il signalera la réponse en conséquence.
Routage par similarité sémantique
LCEL vous permet d'implémenter une logique de routage personnalisée basée sur la similarité sémantique des entrées utilisateur. Voici un exemple de la manière de déterminer dynamiquement la logique de la chaîne en fonction des entrées de l'utilisateur :
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"}))
Dans cet exemple, le prompt_router
La fonction calcule la similarité cosinus entre la saisie de l'utilisateur et les modèles d'invite prédéfinis pour les questions de physique et de mathématiques. Sur la base du score de similarité, la chaîne sélectionne dynamiquement le modèle d'invite le plus pertinent, garantissant que le chatbot répond de manière appropriée à la question de l'utilisateur.
Utilisation d'agents et d'exécutables
LangChain vous permet de créer des agents en combinant des Runnables, des invites, des modèles et des outils. Voici un exemple de création d'un agent et de son utilisation :
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)
Dans cet exemple, un agent est créé en combinant un modèle, des outils, une invite et une logique personnalisée pour les étapes intermédiaires et la conversion des outils. L'agent est ensuite exécuté, fournissant une réponse à la requête de l'utilisateur.
Interroger une base de données SQL
Vous pouvez utiliser LangChain pour interroger une base de données SQL et générer des requêtes SQL basées sur les questions des utilisateurs. Voici un exemple :
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)
Dans cet exemple, LangChain est utilisé pour générer des requêtes SQL basées sur les questions des utilisateurs et récupérer les réponses d'une base de données SQL. Les invites et les réponses sont formatées pour fournir des interactions en langage naturel avec la base de données.
Automatisez les tâches et les flux de travail manuels avec notre générateur de flux de travail basé sur l'IA, conçu par Nanonets pour vous et vos équipes.
LangServe et LangSmith
LangServe aide les développeurs à déployer les exécutables et les chaînes LangChain en tant qu'API REST. Cette bibliothèque est intégrée à FastAPI et utilise pydantic pour la validation des données. De plus, il fournit un client qui peut être utilisé pour appeler des exécutables déployés sur un serveur, et un client JavaScript est disponible dans LangChainJS.
Fonctionnalités:
- Les schémas d'entrée et de sortie sont automatiquement déduits de votre objet LangChain et appliqués à chaque appel d'API, avec des messages d'erreur riches.
- Une page de documentation API avec JSONSchema et Swagger est disponible.
- Points de terminaison /invoke, /batch et /stream efficaces avec prise en charge de nombreuses requêtes simultanées sur un seul serveur.
- Point de terminaison /stream_log pour diffuser toutes (ou certaines) les étapes intermédiaires de votre chaîne/agent.
- Page Playground sur /playground avec sortie en streaming et étapes intermédiaires.
- Traçage intégré (facultatif) vers LangSmith ; ajoutez simplement votre clé API (voir instructions).
- Tous construits avec des bibliothèques Python open source testées au combat telles que FastAPI, Pydantic, uvloop et asyncio.
Limites
- Les rappels client ne sont pas encore pris en charge pour les événements provenant du serveur.
- Les documents OpenAPI ne seront pas générés lors de l'utilisation de Pydantic V2. FastAPI ne prend pas en charge le mélange des espaces de noms pydantic v1 et v2. Voir la section ci-dessous pour plus de détails.
Utilisez la CLI LangChain pour démarrer rapidement un projet LangServe. Pour utiliser la CLI langchain, assurez-vous qu’une version récente de langchain-cli est installée. Vous pouvez l'installer avec pip install -U langchain-cli.
langchain app new ../path/to/directory
Démarrez rapidement votre instance LangServe avec les modèles LangChain. Pour plus d'exemples, consultez l'index des modèles ou le répertoire des exemples.
Voici un serveur qui déploie un modèle de chat OpenAI, un modèle de chat Anthropic et une chaîne qui utilise le modèle Anthropic pour raconter une blague sur un sujet.
#!/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)
Une fois que vous avez déployé le serveur ci-dessus, vous pouvez afficher les documents OpenAPI générés en utilisant :
curl localhost:8000/docs
Assurez-vous d'ajouter le suffixe /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" }])
En TypeScript (nécessite LangChain.js version 0.0.166 ou ultérieure) :
import { RemoteRunnable } from "langchain/runnables/remote"; const chain = new RemoteRunnable({ url: `http://localhost:8000/chain/invoke/`,
});
const result = await chain.invoke({ topic: "cats",
});
Python utilisant des requêtes :
import requests
response = requests.post( "http://localhost:8000/chain/invoke/", json={'input': {'topic': 'cats'}}
)
response.json()
Vous pouvez également utiliser curl :
curl --location --request POST 'http://localhost:8000/chain/invoke/' --header 'Content-Type: application/json' --data-raw '{ "input": { "topic": "cats" } }'
Le code suivant:
...
add_routes( app, runnable, path="/my_runnable",
)
ajoute ces points de terminaison au serveur :
- POST /my_runnable/invoke – invoque l'exécutable sur une seule entrée
- POST /my_runnable/batch – invoque l'exécutable sur un lot d'entrées
- POST /my_runnable/stream – invoque sur une seule entrée et diffuse la sortie
- POST /my_runnable/stream_log – invoque sur une seule entrée et diffuse la sortie, y compris la sortie des étapes intermédiaires au fur et à mesure de sa génération
- GET /my_runnable/input_schema – schéma json pour l'entrée dans l'exécutable
- GET /my_runnable/output_schema – schéma json pour la sortie du runnable
- GET /my_runnable/config_schema – schéma json pour la configuration du runnable
Vous pouvez trouver une page de terrain de jeu pour votre exécutable sur /my_runnable/playground. Cela expose une interface utilisateur simple pour configurer et appeler votre exécutable avec une sortie en streaming et des étapes intermédiaires.
Pour le client et le serveur :
pip install "langserve[all]"
ou pip install « langserve[client] » pour le code client et pip install « langserve[server] » pour le code serveur.
Si vous devez ajouter une authentification à votre serveur, veuillez consulter la documentation de sécurité et la documentation du middleware de FastAPI.
Vous pouvez déployer sur GCP Cloud Run à l'aide de la commande suivante :
gcloud run deploy [your-service-name] --source . --port 8001 --allow-unauthenticated --region us-central1 --set-env-vars=OPENAI_API_KEY=your_key
LangServe prend en charge Pydantic 2 avec certaines limitations. Les documents OpenAPI ne seront pas générés pour Invoke/batch/stream/stream_log lors de l'utilisation de Pydantic V2. L'API rapide ne prend pas en charge le mélange des espaces de noms pydantic v1 et v2. LangChain utilise l'espace de noms v1 dans Pydantic v2. Veuillez lire les directives suivantes pour garantir la compatibilité avec LangChain. À l'exception de ces limitations, nous nous attendons à ce que les points de terminaison de l'API, le terrain de jeu et toutes les autres fonctionnalités fonctionnent comme prévu.
Les applications LLM traitent souvent des fichiers. Il existe différentes architectures qui peuvent être réalisées pour implémenter le traitement des fichiers ; À un haut niveau:
- Le fichier peut être téléchargé sur le serveur via un point de terminaison dédié et traité à l'aide d'un point de terminaison distinct.
- Le fichier peut être téléchargé soit par valeur (octets du fichier), soit par référence (par exemple, URL s3 vers le contenu du fichier).
- Le point final de traitement peut être bloquant ou non bloquant.
- Si un traitement important est requis, le traitement peut être déchargé vers un pool de processus dédié.
Vous devez déterminer quelle est l'architecture appropriée pour votre application. Actuellement, pour télécharger des fichiers par valeur vers un exécutable, utilisez l'encodage base64 pour le fichier (multipart/form-data n'est pas encore pris en charge).
Voici un exemple qui montre comment utiliser le codage base64 pour envoyer un fichier à un exécutable distant. N'oubliez pas que vous pouvez toujours télécharger des fichiers par référence (par exemple, URL s3) ou les télécharger sous forme de données multipart/form sur un point de terminaison dédié.
Les types d’entrée et de sortie sont définis sur tous les exécutables. Vous pouvez y accéder via les propriétés input_schema et output_schema. LangServe utilise ces types pour la validation et la documentation. Si vous souhaitez remplacer les types inférés par défaut, vous pouvez utiliser la méthode with_types.
Voici un exemple de jouet pour illustrer l'idée :
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)
Héritez de CustomUserType si vous souhaitez que les données soient désérialisées dans un modèle pydantique plutôt que dans la représentation dict équivalente. Pour le moment, ce type ne fonctionne que côté serveur et est utilisé pour spécifier le comportement de décodage souhaité. S'il hérite de ce type, le serveur conservera le type décodé comme modèle pydantique au lieu de le convertir en dict.
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")
Le terrain de jeu vous permet de définir des widgets personnalisés pour votre exécutable depuis le backend. Un widget est spécifié au niveau du champ et livré dans le cadre du schéma JSON du type d'entrée. Un widget doit contenir une clé appelée type dont la valeur fait partie d'une liste bien connue de widgets. D'autres clés de widget seront associées à des valeurs qui décrivent les chemins dans un objet JSON.
Schéma général :
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;
};
Permet la création d'une entrée de téléchargement de fichier dans le terrain de jeu de l'interface utilisateur pour les fichiers téléchargés sous forme de chaînes codées en base64. Voici l'exemple complet.
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
Automatisez les tâches et les flux de travail manuels avec notre générateur de flux de travail basé sur l'IA, conçu par Nanonets pour vous et vos équipes.
Introduction à LangSmith
LangChain facilite le prototype d'applications et d'agents LLM. Cependant, la mise en production d’applications LLM peut s’avérer trompeusement difficile. Vous devrez probablement personnaliser et itérer fortement vos invites, chaînes et autres composants pour créer un produit de haute qualité.
Pour faciliter ce processus, LangSmith a été introduit, une plate-forme unifiée pour le débogage, les tests et la surveillance de vos applications LLM.
Quand cela pourrait-il être utile ? Cela peut s'avérer utile lorsque vous souhaitez déboguer rapidement une nouvelle chaîne, un agent ou un ensemble d'outils, visualiser la manière dont les composants (chaînes, LLM, récupérateurs, etc.) sont liés et utilisés, évaluer différentes invites et LLM pour un seul composant, exécutez une chaîne donnée plusieurs fois sur un ensemble de données pour vous assurer qu'elle répond systématiquement à une barre de qualité, ou capturez des traces d'utilisation et utilisez des LLM ou des pipelines d'analyse pour générer des informations.
Pré-requis :
- Créez un compte LangSmith et créez une clé API (voir coin inférieur gauche).
- Familiarisez-vous avec la plateforme en parcourant la documentation.
Maintenant, commençons!
Tout d’abord, configurez vos variables d’environnement pour indiquer à LangChain d’enregistrer les traces. Cela se fait en définissant la variable d'environnement LANGCHAIN_TRACING_V2 sur true. Vous pouvez indiquer à LangChain à quel projet se connecter en définissant la variable d'environnement LANGCHAIN_PROJECT (si elle n'est pas définie, les exécutions seront enregistrées dans le projet par défaut). Cela créera automatiquement le projet pour vous s'il n'existe pas. Vous devez également définir les variables d'environnement LANGCHAIN_ENDPOINT et LANGCHAIN_API_KEY.
REMARQUE : Vous pouvez également utiliser un gestionnaire de contexte en python pour enregistrer les traces en utilisant :
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?")
Cependant, dans cet exemple, nous utiliserons des variables d'environnement.
%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>"
Créez le client LangSmith pour interagir avec l'API :
from langsmith import Client client = Client()
Créez un composant LangChain et enregistrez les exécutions sur la plateforme. Dans cet exemple, nous allons créer un agent de style ReAct avec accès à un outil de recherche général (DuckDuckGo). L'invite de l'agent peut être consultée dans le Hub ici :
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
)
Nous exécutons l'agent simultanément sur plusieurs entrées pour réduire la latence. Les exécutions sont enregistrées dans LangSmith en arrière-plan, la latence d'exécution n'est donc pas affectée :
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]
En supposant que vous avez configuré avec succès votre environnement, les traces de vos agents devraient apparaître dans la section Projets de l'application. Bravo!
Il semble cependant que l’agent n’utilise pas efficacement les outils. Évaluons cela afin d'avoir une base de référence.
En plus des exécutions de journalisation, LangSmith vous permet également de tester et d'évaluer vos applications LLM.
Dans cette section, vous utiliserez LangSmith pour créer un ensemble de données de référence et exécuter des évaluateurs assistés par l'IA sur un agent. Vous le ferez en quelques étapes :
- Créez un ensemble de données LangSmith :
Ci-dessous, nous utilisons le client LangSmith pour créer un ensemble de données à partir des questions d'entrée ci-dessus et une liste d'étiquettes. Vous les utiliserez ultérieurement pour mesurer les performances d'un nouvel agent. Un ensemble de données est une collection d'exemples, qui ne sont rien de plus que des paires d'entrées-sorties que vous pouvez utiliser comme cas de test pour votre application :
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 )
- Initialisez un nouvel agent à évaluer :
LangSmith vous permet d'évaluer n'importe quel LLM, chaîne, agent ou même une fonction personnalisée. Les agents conversationnels sont avec état (ils ont de la mémoire) ; pour garantir que cet état n'est pas partagé entre les exécutions de l'ensemble de données, nous transmettrons un chain_factory (
alias un constructeur) fonction à initialiser pour chaque appel :
# 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)
- Configurer l'évaluation :
Comparer manuellement les résultats des chaînes dans l’interface utilisateur est efficace, mais cela peut prendre du temps. Il peut être utile d'utiliser des métriques automatisées et des commentaires assistés par l'IA pour évaluer les performances de votre composant :
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=[],
)
- Exécutez l'agent et les évaluateurs :
Utilisez la fonction run_on_dataset (ou asynchrone arun_on_dataset) pour évaluer votre modèle. Cette volonté:
- Récupère des exemples de lignes à partir de l'ensemble de données spécifié.
- Exécutez votre agent (ou toute fonction personnalisée) sur chaque exemple.
- Appliquez les évaluateurs aux traces d'exécution résultantes et aux exemples de référence correspondants pour générer des commentaires automatisés.
Les résultats seront visibles dans l'application 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", ],
)
Maintenant que nous avons les résultats de nos tests, nous pouvons apporter des modifications à notre agent et les comparer. Essayons à nouveau avec une invite différente et voyons les résultats :
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 vous permet d'exporter des données vers des formats courants tels que CSV ou JSONL directement dans l'application Web. Vous pouvez également utiliser le client pour récupérer des analyses en vue d'une analyse plus approfondie, pour les stocker dans votre propre base de données ou pour les partager avec d'autres. Récupérons les traces d'exécution de l'exécution d'évaluation :
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
Il s'agissait d'un guide rapide pour démarrer, mais il existe de nombreuses autres façons d'utiliser LangSmith pour accélérer votre flux de développement et produire de meilleurs résultats.
Pour plus d'informations sur la manière de tirer le meilleur parti de LangSmith, consultez la documentation de LangSmith.
Passez au niveau supérieur avec les Nanonets
Bien que LangChain soit un outil précieux pour intégrer des modèles de langage (LLM) à vos applications, il peut être confronté à des limites lorsqu'il s'agit de cas d'utilisation en entreprise. Explorons comment Nanonets va au-delà de LangChain pour relever ces défis :
1. Connectivité complète des données :
LangChain propose des connecteurs, mais il ne couvre peut-être pas toutes les applications d'espace de travail et tous les formats de données dont s'appuient les entreprises. Nanonets fournit des connecteurs de données pour plus de 100 applications d'espace de travail largement utilisées, notamment Slack, Notion, Google Suite, Salesforce, Zendesk et bien d'autres. Il prend également en charge tous les types de données non structurées telles que les PDF, les TXT, les images, les fichiers audio et les fichiers vidéo, ainsi que les types de données structurées telles que les CSV, les feuilles de calcul, MongoDB et les bases de données SQL.
2. Automatisation des tâches pour les applications Workspace :
Bien que la génération de texte/réponse fonctionne très bien, les capacités de LangChain sont limitées lorsqu'il s'agit d'utiliser le langage naturel pour effectuer des tâches dans diverses applications. Nanonets propose des agents de déclenchement/action pour les applications d'espace de travail les plus populaires, vous permettant de configurer des flux de travail qui écoutent les événements et effectuent des actions. Par exemple, vous pouvez automatiser les réponses aux e-mails, les entrées CRM, les requêtes SQL, etc., via des commandes en langage naturel.
3. Synchronisation des données en temps réel :
LangChain récupère les données statiques avec des connecteurs de données, qui peuvent ne pas suivre les modifications des données dans la base de données source. En revanche, Nanonets assure une synchronisation en temps réel avec les sources de données, garantissant ainsi que vous travaillez toujours avec les informations les plus récentes.
3. Configuration simplifiée :
La configuration des éléments du pipeline LangChain, tels que les récupérateurs et les synthétiseurs, peut être un processus complexe et long. Nanonets rationalise cela en fournissant une ingestion et une indexation optimisées des données pour chaque type de données, le tout géré en arrière-plan par l'assistant AI. Cela réduit la charge de réglage fin et facilite la configuration et l’utilisation.
4. Solution unifiée :
Contrairement à LangChain, qui peut nécessiter des implémentations uniques pour chaque tâche, Nanonets constitue une solution unique pour connecter vos données aux LLM. Que vous ayez besoin de créer des applications LLM ou des flux de travail d'IA, Nanonets offre une plate-forme unifiée pour vos divers besoins.
Flux de travail IA Nanonets
Nanonets Workflows est un assistant d'IA sécurisé et polyvalent qui simplifie l'intégration de vos connaissances et données avec les LLM et facilite la création d'applications et de flux de travail sans code. Il offre une interface utilisateur facile à utiliser, la rendant accessible aussi bien aux particuliers qu'aux organisations.
Pour commencer, vous pouvez planifier un appel avec l'un de nos experts en IA, qui pourra vous proposer une démonstration personnalisée et un essai des workflows Nanonets adaptés à votre cas d'utilisation spécifique.
Une fois configuré, vous pouvez utiliser le langage naturel pour concevoir et exécuter des applications et des flux de travail complexes optimisés par les LLM, en s'intégrant de manière transparente à vos applications et données.
Boostez vos équipes avec Nanonets AI pour créer des applications et intégrer vos données avec des applications et des flux de travail basés sur l'IA, permettant ainsi à vos équipes de se concentrer sur ce qui compte vraiment.
Automatisez les tâches et les flux de travail manuels avec notre générateur de flux de travail basé sur l'IA, conçu par Nanonets pour vous et vos équipes.
- Contenu propulsé par le référencement et distribution de relations publiques. Soyez amplifié aujourd'hui.
- PlatoData.Network Ai générative verticale. Autonomisez-vous. Accéder ici.
- PlatoAiStream. Intelligence Web3. Connaissance Amplifiée. Accéder ici.
- PlatonESG. Carbone, Technologie propre, Énergie, Environnement, Solaire, La gestion des déchets. Accéder ici.
- PlatoHealth. Veille biotechnologique et essais cliniques. Accéder ici.
- La source: https://nanonets.com/blog/langchain/
- :possède
- :est
- :ne pas
- :où
- $UP
- 1
- 10
- 100
- 114
- 13
- 15%
- 2000
- 2012
- 2023
- 25
- 30
- 32
- 36
- 40
- 400
- 408
- 50
- 500
- 7
- 8
- a
- abc
- capacité
- Capable
- A Propos
- à propos de ça
- au dessus de
- Accepter
- Accepte
- accès
- accessible
- accès
- accomplir
- en conséquence
- Compte
- précision
- Avec cette connaissance vient le pouvoir de prendre
- avec précision
- atteindre
- atteint
- Atteint
- à travers
- Agis
- Action
- actes
- infection
- s'adapter
- adaptatif
- ajouter
- ajoutée
- ajoutant
- ajout
- Supplémentaire
- En outre
- propos
- Ajoute
- admettre
- Avancée
- Aventure
- Après
- encore
- âge
- Agent
- agents
- AI
- Assistant IA
- Modèles AI
- Aide
- Visée
- algorithmes
- aligner
- Aligne
- Tous
- permettre
- Permettre
- permet
- seul
- le long de
- aux côtés de
- déjà
- aussi
- Bien que
- toujours
- an
- selon une analyse de l’Université de Princeton
- Analytique
- analytique
- ainsi que
- Angeles
- Annoncer
- annuel
- Une autre
- répondre
- réponses
- hymne
- Anthropique
- tous
- quoi que ce soit d'artificiel
- api
- CLÉS API
- Apis
- appli
- en vigueur
- Application
- Le développement d'applications
- applications
- appliqué
- s'applique
- une approche
- approches
- approprié
- de manière appropriée
- applications
- architecture
- SONT
- argument
- arguments
- Armstrong
- autour
- tableau
- Artistes
- AS
- demander
- d'aspect
- aspects
- aider
- Assistante gérante
- associé
- At
- joindre
- précaution
- acoustique
- augmentée
- Authentification
- automatiser
- Automatisation
- Automates
- automatiquement
- Automation
- disponibles
- moyen
- attendre
- conscients
- AWS
- RETOUR
- Colonne vertébrale
- backend
- fond
- mal
- Balance
- barre
- base
- basé
- Baseline
- bash
- Essentiel
- Basics
- BCG
- BE
- Plage
- Ours
- car
- était
- before
- commencer
- humain
- derrière
- Dans les coulisses
- va
- ci-dessous
- référence
- avantageux
- LES MEILLEURS
- Améliorée
- jusqu'à XNUMX fois
- Au-delà
- Le plus grand
- Projet de loi
- Bill Gates
- lier
- Bing
- Bit
- Noir
- Trou noir
- Block
- blocage
- Blocs
- Blog
- grain
- Bootstrap
- né
- Bot
- tous les deux
- Bas et Leggings
- Branche
- Pause
- brise
- brièvement
- plus large
- marron
- navigateur
- tampon
- construire
- constructeur
- Développement
- construit
- fardeau
- entreprises
- mais
- by
- calculer
- calcule
- le calcul
- calcul
- Appelez-nous
- rappels
- appelé
- appel
- Appels
- CAN
- Peut obtenir
- Canada
- capacités
- capable
- Compétences
- capturer
- Capturer
- maisons
- cas
- CHAT
- répondre
- VIP gastronomie à bord,
- répond
- Chats
- prudence
- prudent
- centré
- certaines
- chaîne
- Chaînes
- globaux
- Modifications
- caractère
- Chatbot
- Chatbots
- vérifier
- Contrôles
- Selectionnez
- choisi
- conditions
- Ville
- classe
- les classes
- client
- le cloud
- code
- Codage
- Café
- COHÉRENT
- cohésif
- collaborons
- Effondrement
- collection
- coloré
- Colonne
- Colonnes
- COM
- combiner
- combiné
- moissonneuses-batteuses
- combinant
- comment
- vient
- confortable
- Commun
- Communication
- Société
- comparer
- comparant
- compatibilité
- compatible
- complet
- complètement
- achèvement
- complexe
- complexités
- composant
- composants électriques
- composé
- composition
- complet
- comprenant
- concept
- concis
- concurrent
- condition
- configuration
- confluence
- NOUS CONTACTER
- Connecter les
- Connectivité
- Inconvénients
- Considérer
- régulièrement
- consiste
- Console
- constamment
- constructions
- contiennent
- contient
- contenu
- contexte
- contextes
- contextuel
- continuer
- continuellement
- contraste
- des bactéries
- contrôles
- Pratique
- Conversation
- de la conversation
- IA conversationnel
- conversations
- Conversion
- converti
- conversion
- Core
- Coin
- correct
- Correspondant
- pourriez
- compte
- Pays
- Couples
- couverture
- couvert
- engendrent
- créée
- crée des
- La création
- création
- Lettres de créance
- critères
- Critique
- CRM
- crucial
- Courant
- Lecture
- Customiser
- Clients
- personnalisation
- personnaliser
- sont adaptées
- En investissant dans une technologie de pointe, les restaurants peuvent non seulement rester compétitifs dans un marché en constante évolution, mais aussi améliorer significativement l'expérience de leurs clients.
- données
- Structure de données
- Base de données
- bases de données
- Date
- datetime
- affaire
- traitement
- Décembre
- décider
- Décider
- La prise de décision
- Le décryptage
- dévoué
- profond
- Réglage par défaut
- Vous permet de définir
- défini
- définir
- définitions
- livrer
- offre
- delve
- demo
- démontrer
- démontré
- démontrer
- dépendre
- Selon
- dépend
- déployer
- déployé
- déployer
- déploiement
- déploie
- décrire
- la description
- Conception
- désigné
- un
- voulu
- détail
- détaillé
- détails
- Déterminer
- détermine
- développer
- Développeur
- mobiles
- développement
- Développement
- diagrammes
- DICT
- DID
- différer
- différent
- différemment
- difficile
- Dimension
- dimensions
- directives
- directement
- discuter
- discuté
- afficher
- distinct
- plongeon
- plusieurs
- DM
- do
- document
- Documentation
- INSTITUTIONNELS
- doesn
- faire
- Don
- fait
- double
- down
- download
- téléchargements
- avant-projet
- motivation
- deux
- pendant
- Dynamic
- dynamiquement
- e
- chacun
- Plus tôt
- "Early Bird"
- facilité
- facilité d'utilisation
- plus facilement
- même
- Easy
- facile à utiliser
- echo
- risque numérique
- Efficace
- de manière efficace
- efficace
- efficace
- efficacement
- d'effort
- non plus
- élément
- éléments
- Elon
- Elon Musk
- d'autre
- enchâsser
- intégré
- enrobage
- employés
- employés
- emploie
- vous accompagner
- permettre
- permet
- permettant
- encapsule
- rencontrer
- end-to-end
- Endpoint
- engageant
- Moteur
- Moteurs
- de l'Angleterre
- Anglais
- Premier League anglaise
- de renforcer
- améliorée
- améliorer
- assurer
- Assure
- assurer
- Entreprise
- entités
- entité
- Environment
- environnements
- Équivalent
- Ère
- erreur
- Erreurs
- notamment
- essential
- éloigné
- etc
- évaluer
- évaluation
- Pourtant, la
- événements
- Chaque
- exemple
- exemples
- dépassent
- Sauf
- exécuter
- réalisé
- Exécute
- exécution
- exécution
- illustre
- Exercises
- exister
- attendre
- attentes
- attendu
- attend
- d'experience
- expérimental
- de santé
- expliqué
- Explique
- explicitement
- exploration
- explorez
- Exploré
- Exporter
- expression
- étendre
- extension
- les
- externe
- supplémentaire
- extrait
- extraction
- Extraits
- Visage
- faciliter
- facilite
- PERSONNEL
- réalités
- loin
- RAPIDE
- Favori
- Fonctionnalité
- Fonctionnalités:
- Réactions
- few
- champ
- Des champs
- figma
- Figure
- Déposez votre dernière attestation
- Fichiers
- remplir
- rempli
- remplissage
- une fonction filtre
- filtration
- finale
- finalement
- Trouvez
- trouver
- Prénom
- cinq
- Flexibilité
- flexible
- flux
- Focus
- concentré
- se concentre
- mettant l'accent
- suivre
- Abonnement
- suit
- nourriture
- Pour
- formulaire
- le format
- formé
- Heureusement
- trouvé
- Framework
- cadres
- fréquemment
- Ami
- amis
- De
- plein
- à part entière
- fonction
- fonctionnalités
- fonctions
- fondamental
- drôle
- plus
- avenir
- Gain
- Games
- Portes
- Général
- généralement
- générer
- généré
- génère
- générateur
- génération
- genre
- Allemagne
- obtenez
- obtention
- gif
- GitHub
- donné
- GMT
- Go
- Goes
- aller
- Bien
- granulaire
- graphique
- l'
- plus grand
- l'orientation
- guide
- lignes directrices
- hackathon
- manipuler
- Poignées
- Maniabilité
- pratique
- Dur
- nuire
- harnais
- Vous avez
- ayant
- fortement
- Tenue
- vous aider
- utile
- aide
- ici
- ici
- hi
- Haute
- de haut niveau
- de haute qualité
- le plus élevé
- très
- historique
- Histoire
- Trou
- capuche
- hôte
- Comment
- How To
- Cependant
- HTML
- http
- HTTPS
- Moyeu
- humain
- Des centaines
- i
- ID
- idée
- idéal
- ids
- if
- ii
- iii
- illustrer
- illustre
- satellite
- Immédiat
- Mettre en oeuvre
- la mise en oeuvre
- implémentations
- mis en œuvre
- importer
- améliorations
- l'amélioration de
- in
- en profondeur
- comprendre
- inclus
- inclut
- Y compris
- intégrer
- incorporation
- incroyablement
- indice
- index
- indiquer
- indique
- Individuellement
- individus
- d'information
- initiale
- initier
- technologie innovante
- contribution
- entrées
- idées.
- installer
- Installé
- installer
- instance
- instantané
- plutôt ;
- Des instructions
- intégrale
- intégrer
- des services
- Intègre
- Intégration
- l'intégration
- intégrations
- Intelligent
- prévu
- interagir
- l'interaction
- interactions
- Interactif
- interagit
- Interfaces
- interfaces
- intérieurement
- Internet
- développement
- introduit
- Introduit
- intuitif
- impliquant
- ISN
- aide
- vous aider à faire face aux problèmes qui vous perturbent
- IT
- articles
- itérations
- SES
- lui-même
- Jackson
- JavaScript
- Emploi
- Jordanie
- chemin
- json
- Juillet
- juste
- Justice
- XNUMX éléments à
- Conserve
- ACTIVITES
- clés
- Genre
- Savoir
- spécialisées
- Graphique connaissances
- connu
- Libellé
- Etiquettes
- Transport routier
- langue
- Langues
- gros
- plus importantes
- Nom
- Latence
- plus tard
- Nouveautés
- Ligue
- APPRENTISSAGE
- apprentissage
- à gauche
- Legacy
- Longueur
- moins
- laisser
- Allons-y
- lettre
- Niveau
- niveaux
- Levier
- les leviers
- en tirant parti
- bibliothèques
- Bibliothèque
- comme
- Probable
- LIMIT
- limites
- limité
- limiter
- limites
- Gauche
- Liste
- écouter
- Liste
- le travail
- ll
- LLM
- charge
- chargeur
- situé
- emplacement
- enregistrer
- Connecté
- enregistrement
- logique
- Location
- plus long
- Style
- recherchez-
- LOOKS
- rechercher
- les
- Los Angeles
- Faible
- click
- machine learning
- LES PLANTES
- maintenir
- Maintenable
- Maintenir
- maintient
- a prendre une
- FAIT DU
- Fabrication
- gérer
- gestion
- manager
- les gérer
- Manchester
- Manchester United
- Manipulation
- manière
- Manuel
- Fabricants
- de nombreuses
- Beaucoup de gens
- Localisation
- cartographie
- Map
- Match
- assorti
- math
- mathématique
- compte
- maximales
- Mai..
- me
- signifier
- sens
- veux dire
- mesurer
- Médias
- réunion
- Se rencontre
- Souvenirs
- Mémoire
- mentionné
- aller
- fusion
- message
- messages
- messagerie
- Métadonnées
- méthode
- méthodes
- Métrique
- pourrait
- des millions
- minimal
- mineur
- manquant
- erreurs
- Mixage audio
- MLB
- Breeze Mobile
- modèle
- numériques jumeaux (digital twin models)
- modération
- Module
- Modules
- moment
- MongoDB
- Surveiller
- Stack monitoring
- Lune
- PLUS
- (en fait, presque toutes)
- Le Plus Populaire
- Bougez
- film
- beaucoup
- plusieurs
- plusieurs chaînes
- Musc
- must
- my
- prénom
- Nommé
- noms
- Nationales
- Nature
- Traitement du langage naturel
- NAVIGUER
- navigation
- Près
- nécessaire
- Besoin
- nécessaire
- Besoins
- négatif
- Nouveauté
- New York
- next
- aucune
- Aucun
- rien
- Notion
- maintenant
- nombre
- Obama
- objet
- objectif
- objets
- observation
- obtenir
- obtention
- OCR
- of
- code
- offrant
- Offres Speciales
- souvent
- oh
- Bien
- Jeux olympiques
- on
- une fois
- ONE
- uniquement
- open source
- OpenAI
- Opérations
- opérateur
- optimisé
- Optimise
- Option
- or
- de commander
- biologique
- organisations
- original
- OS
- Autre
- Autres
- autrement
- nos
- ande
- sortie
- sorties
- plus de
- Commande
- vue d'ensemble
- propre
- paquet
- Forfaits
- page
- pages
- paires
- pandas
- Papier
- Parallèle
- paramètre
- paramètres
- Parc
- partie
- particulièrement
- les pièces
- pass
- passé
- passes
- En passant
- passé
- chemin
- chemins
- motifs
- Paie
- Personnes
- /
- parfaite
- à la perfection
- Effectuer
- performant
- effectuer
- effectue
- autorisations
- persistance
- personne
- Personnalisé
- objectifs
- Physique
- pièce
- pipeline
- Pizza
- espace réservé
- plateforme
- Platon
- Intelligence des données Platon
- PlatonDonnées
- Jouez
- cour de récréation
- joue
- veuillez cliquer
- plus
- Point
- politiques
- politique
- politique
- pool
- Populaire
- peuplé
- positif
- possible
- Post
- Poteaux
- défaillances
- power
- alimenté
- solide
- Méthode
- pratique
- préfère
- premier
- représentent
- président
- empêcher
- prévention
- précédent
- qui se déroulent
- primaire
- Prime
- Privé
- Problème
- d'ouvrabilité
- procéder
- processus
- Traité
- les process
- traitement
- produire
- Produit
- Vidéo
- Professeur
- Programmation
- langages de programmation
- Projet
- projets
- propriétés
- propriété
- AVANTAGES
- prototype
- prototypage
- fournir
- à condition de
- de voiture.
- fournisseurs
- fournit
- aportando
- public
- but
- des fins
- mettre
- Python
- Questions et réponses
- qualité
- requêtes
- question
- fréquemment posées
- Rapide
- vite.
- citations
- R
- augmenter
- gamme
- allant
- plutôt
- clients
- raw
- RE
- nous joindre
- Réagir
- Lire
- en cours
- solutions
- réal
- en temps réel
- données en temps réel à grande vitesse.
- royaume
- raison
- Les raisons
- récent
- recommandé
- enregistré
- Articles
- Récupérer
- réduire
- réduit
- réduire
- réduction
- référence
- référencement
- affiner
- raffinage
- régions
- Les relations
- libéré
- pertinence
- pertinent
- fiabilité
- fiable
- compter
- s'appuyer
- reste
- rappeler
- rappel
- éloigné
- rendement
- répéter
- À PLUSIEURS REPRISES
- reformuler
- remplacer
- rapport
- dépôt
- représentation
- représentation
- représente
- nécessaire
- demandes
- exigent
- conditions
- Exigences
- a besoin
- sauver
- un article
- résoudre
- ressource
- Réagir
- répondre
- réponse
- réponses
- responsables
- sensible
- REST
- résultat
- résultant
- Résultats
- retenue
- rétention
- retourner
- retour
- Retours
- réutilisable
- Avis
- tourne
- Riz
- Rich
- Collaboratif
- Rôle
- rôle
- racine
- routage
- RANGÉE
- Courir
- pour le running
- fonctionne
- d'exécution
- s
- garanties
- vente
- force de vente
- Sam
- même
- Épargnez
- dire
- dit
- évolutive
- Escaliers intérieurs
- scénario
- scénarios
- Scènes
- calendrier
- But
- gratter
- fluide
- de façon transparente
- Rechercher
- moteur de recherche
- recherches
- recherche
- Section
- les sections
- sécurisé
- sécurité
- sur le lien
- choisi
- sélection
- Disponible
- envoyer
- sensible
- sentiment
- des sentiments
- séparé
- Septembre
- Séquence
- Série
- besoin
- serveur
- sert
- Services
- set
- Sets
- mise
- Paramétres
- installation
- sept
- plusieurs
- Partager
- commun
- coquillage
- brille
- expédiés
- devrait
- montrer
- vitrine
- montré
- Spectacles
- Sigma
- significative
- similaires
- étapes
- simplifié
- simplifier
- simplifiant
- simplement
- depuis
- unique
- Taille
- mou
- petit
- faibles
- smart
- Fragment
- So
- jusqu'à présent
- Football
- Réseaux sociaux
- réseaux sociaux
- Publications sur les réseaux sociaux
- uniquement
- solide
- sur mesure
- RÉSOUDRE
- quelques
- quelque chose
- parfois
- sophistiqué
- sons
- Identifier
- Sources
- Space
- Espagnol
- spécialisé
- groupe de neurones
- spécifiquement
- détails
- spécifié
- vitesse
- dépensé
- scission
- splits
- Sportive
- carré
- Utilisation d'un
- autonome
- Standard
- Commencer
- j'ai commencé
- Commencez
- Région
- déclarations
- statique
- étapes
- Étapes
- Encore
- Arrêter
- arrêt
- Arrête
- storage
- Boutique
- stockée
- STORES
- stockage
- Histoire
- simple
- courant
- streaming
- rationaliser
- rationalisé
- forces
- Grèves
- Chaîne
- structure
- structuré
- structures
- structurant
- Catégorie
- sujet
- ultérieur
- Avec succès
- tel
- Combinaison
- convient
- suite
- résumé
- RÉSUMÉ
- Sunset
- Support
- Appareils
- Les soutiens
- sûr
- Durabilité
- synchronisation
- synopsis
- syntaxe
- combustion propre
- Système
- table
- tailleur
- Prenez
- prend
- objectifs
- Tâche
- tâches
- équipe
- équipes
- dire
- modèle
- modèles
- terminal
- terminologie
- conditions
- tester
- Essais
- texte
- que
- Merci
- qui
- La
- Les bases
- le hub
- les informations
- The New York Times
- Les projets
- La Source
- le monde
- leur
- Les
- puis
- Là.
- Ces
- l'ont
- des choses
- this
- ceux
- bien que?
- Avec
- tout au long de
- fiable
- long
- fois
- Titre
- à
- ensemble
- jeton
- tokenization
- Tokens
- trop
- outil
- Boîte à outils
- les outils
- top
- sujet
- Les sujets
- Total
- ville
- Traçant
- suivre
- traditionnel
- Formation
- Transformer
- transformations
- transformateur
- transformateurs
- transition
- procès
- oui
- vraiment
- Essai
- réglage
- TOUR
- Tournant
- tutoriel
- Twice
- deux
- type
- types
- Manuscrit
- typiquement
- ui
- En fin de compte
- non affecté
- sous
- sous-jacent
- comprendre
- compréhension
- comprend
- unifiée
- expérience unique et authentique
- Uni
- Universel
- contrairement à
- jusqu'à
- Mises à jour
- Actualités
- téléchargé
- URL
- us
- convivialité
- Utilisation
- utilisé
- cas d'utilisation
- d'utiliser
- Utilisateur
- Interface utilisateur
- utilisateurs
- Usages
- en utilisant
- les services publics
- utiliser
- utilisé
- utilise
- Utilisant
- v1
- validation
- Validateur
- Précieux
- Plus-value
- Valeurs
- variable
- variété
- divers
- Ve
- polyvalente
- version
- très
- via
- Vidéo
- Voir
- Violations
- visible
- visualiser
- vital
- vs
- marcher
- walkthrough
- souhaitez
- était
- Montres
- Façon..
- façons
- we
- Météo
- web
- navigateur web
- services Web
- sites Internet
- WELL
- bien connu
- ont été
- Quoi
- Qu’est ce qu'
- Quoi
- quand
- que
- qui
- tout en
- WHO
- la totalité
- why
- large
- largement
- un widget
- Wikipédia
- sera
- fenêtre
- Gagne
- comprenant
- dans les
- sans
- Word
- activités principales
- travaillé
- workflow
- workflows
- de travail
- vos contrats
- world
- pourra
- écrire
- écriture
- X
- encore
- york
- Vous n'avez
- Votre
- vous-même
- Youtube
- Zendesk
- zéphyrnet
- Zip