W jego rdzeniu LangChain to innowacyjna platforma dostosowana do tworzenia aplikacji wykorzystujących możliwości modeli językowych. Jest to zestaw narzędzi przeznaczony dla programistów do tworzenia aplikacji świadomych kontekstu i zdolnych do wyrafinowanego rozumowania.
Oznacza to, że aplikacje LangChain mogą rozumieć kontekst, taki jak podpowiedzi lub odpowiedzi oparte na treści, i wykorzystywać modele językowe do złożonych zadań rozumowania, takich jak podejmowanie decyzji, jak odpowiedzieć lub jakie działania podjąć. LangChain reprezentuje ujednolicone podejście do tworzenia inteligentnych aplikacji, upraszczając drogę od koncepcji do realizacji dzięki różnorodnym komponentom.
Zrozumienie LangChaina
LangChain to znacznie więcej niż tylko framework; to pełnoprawny ekosystem składający się z kilku integralnych części.
- Po pierwsze, istnieją biblioteki LangChain, dostępne zarówno w Pythonie, jak i JavaScript. Biblioteki te stanowią szkielet LangChain, oferując interfejsy i integracje dla różnych komponentów. Zapewniają podstawowy środowisko uruchomieniowe umożliwiające łączenie tych komponentów w spójne łańcuchy i agenty, wraz z gotowymi implementacjami do natychmiastowego użycia.
- Następnie mamy szablony LangChain. Jest to zbiór możliwych do wdrożenia architektur referencyjnych dostosowanych do szerokiej gamy zadań. Niezależnie od tego, czy budujesz chatbota, czy złożone narzędzie analityczne, te szablony stanowią solidny punkt wyjścia.
- LangServe wkracza jako wszechstronna biblioteka do wdrażania łańcuchów LangChain jako interfejsów API REST. To narzędzie jest niezbędne do przekształcenia projektów LangChain w dostępne i skalowalne usługi internetowe.
- Wreszcie LangSmith służy jako platforma programistyczna. Został zaprojektowany do debugowania, testowania, oceny i monitorowania łańcuchów zbudowanych na dowolnym frameworku LLM. Bezproblemowa integracja z LangChain czyni go niezbędnym narzędziem dla programistów chcących udoskonalać i doskonalić swoje aplikacje.
Razem te komponenty umożliwiają łatwe tworzenie, produkcję i wdrażanie aplikacji. Dzięki LangChain zaczynasz od pisania aplikacji przy użyciu bibliotek, odwołując się do szablonów w celu uzyskania wskazówek. Następnie LangSmith pomaga Ci w inspekcji, testowaniu i monitorowaniu łańcuchów, zapewniając, że Twoje aplikacje są stale ulepszane i gotowe do wdrożenia. Wreszcie, dzięki LangServe możesz łatwo przekształcić dowolny łańcuch w interfejs API, dzięki czemu wdrożenie staje się proste.
W następnych sekcjach zagłębimy się w konfigurację LangChain i rozpoczniemy Twoją podróż w tworzeniu inteligentnych aplikacji opartych na modelach językowych.
Zautomatyzuj ręczne zadania i przepływy pracy za pomocą naszego narzędzia do tworzenia przepływów pracy opartego na sztucznej inteligencji, zaprojektowanego przez Nanonets dla Ciebie i Twoich zespołów.
Instalacja i konfiguracja
Czy jesteś gotowy, aby zanurzyć się w świecie LangChain? Konfiguracja jest prosta, a ten przewodnik przeprowadzi Cię przez ten proces krok po kroku.
Pierwszym krokiem w Twojej podróży z LangChain jest jego instalacja. Możesz to łatwo zrobić za pomocą pip lub conda. Uruchom następujące polecenie w swoim terminalu:
pip install langchain
Dla tych, którzy wolą najnowsze funkcje i czują się komfortowo z nieco większą ilością przygód, możesz zainstalować LangChain bezpośrednio ze źródła. Sklonuj repozytorium i przejdź do pliku langchain/libs/langchain
informator. Następnie uruchomić:
pip install -e .
W przypadku funkcji eksperymentalnych rozważ instalację langchain-experimental
. Jest to pakiet zawierający najnowocześniejszy kod, przeznaczony do celów badawczych i eksperymentalnych. Zainstaluj go za pomocą:
pip install langchain-experimental
LangChain CLI to przydatne narzędzie do pracy z szablonami LangChain i projektami LangServe. Aby zainstalować interfejs CLI LangChain, użyj:
pip install langchain-cli
LangServe jest niezbędny do wdrażania łańcuchów LangChain jako interfejsu API REST. Jest instalowany razem z interfejsem CLI LangChain.
LangChain często wymaga integracji z dostawcami modeli, magazynami danych, interfejsami API itp. W tym przykładzie użyjemy interfejsów API modeli OpenAI. Zainstaluj pakiet OpenAI Python, używając:
pip install openai
Aby uzyskać dostęp do interfejsu API, ustaw klucz API OpenAI jako zmienną środowiskową:
export OPENAI_API_KEY="your_api_key"
Alternatywnie przekaż klucz bezpośrednio w środowisku Pythona:
import os
os.environ['OPENAI_API_KEY'] = 'your_api_key'
LangChain umożliwia tworzenie aplikacji modeli językowych poprzez moduły. Moduły te mogą być samodzielne lub komponowane z myślą o złożonych przypadkach użycia. Moduły te to –
- Model we/wy: Ułatwia interakcję z różnymi modelami językowymi, efektywnie obsługując ich dane wejściowe i wyjściowe.
- Wyszukiwanie: Umożliwia dostęp i interakcję z danymi specyficznymi dla aplikacji, kluczowymi dla dynamicznego wykorzystania danych.
- Agenci: Umożliwienie aplikacjom wyboru odpowiednich narzędzi w oparciu o dyrektywy wysokiego poziomu, zwiększając możliwości podejmowania decyzji.
- Więzy: Oferuje predefiniowane kompozycje do wielokrotnego użytku, które służą jako elementy składowe do tworzenia aplikacji.
- Pamięć: Utrzymuje stan aplikacji w wielu wykonaniach łańcucha, co jest niezbędne w przypadku interakcji kontekstowych.
Każdy moduł jest ukierunkowany na konkretne potrzeby programistyczne, dzięki czemu LangChain jest kompleksowym zestawem narzędzi do tworzenia zaawansowanych aplikacji modeli językowych.
Oprócz powyższych komponentów posiadamy również Język wyrażeń LangChain (LCEL), który jest deklaratywnym sposobem łatwego komponowania modułów, co umożliwia łączenie komponentów przy użyciu uniwersalnego interfejsu Runnable.
LCEL wygląda mniej więcej tak –
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import BaseOutputParser # Example chain
chain = ChatPromptTemplate() | ChatOpenAI() | CustomOutputParser()
Skoro omówiliśmy podstawy, przejdźmy do:
- Przyjrzyj się szczegółowo każdemu modułowi Langchain.
- Dowiedz się, jak używać języka wyrażeń LangChain.
- Przeglądaj typowe przypadki użycia i wdrażaj je.
- Wdróż kompleksową aplikację za pomocą LangServe.
- Sprawdź LangSmith do debugowania, testowania i monitorowania.
Zacznijmy!
Moduł I: Model we/wy
W LangChain główny element każdej aplikacji kręci się wokół modelu językowego. Moduł ten zapewnia podstawowe elementy umożliwiające efektywną komunikację z dowolnym modelem językowym, zapewniając bezproblemową integrację i komunikację.
Kluczowe elementy modelu we/wy
- LLM i modele czatu (używane zamiennie):
- LLM:
- Definicja: Modele uzupełniania czystego tekstu.
- Wejście wyjście: Weź ciąg tekstowy jako wejście i zwróć ciąg tekstowy jako wynik.
- Modele czatu
- LLM:
- Definicja: Modele wykorzystujące model językowy jako podstawę, ale różniące się formatami wejściowymi i wyjściowymi.
- Wejście wyjście: Zaakceptuj listę wiadomości czatu jako dane wejściowe i zwróć wiadomość czatu.
- Monity: Szablonuj, dynamicznie wybieraj i zarządzaj danymi wejściowymi modelu. Umożliwia tworzenie elastycznych i dostosowanych do kontekstu podpowiedzi, które kierują odpowiedziami modelu językowego.
- Parsery wyjściowe: Wyodrębnianie i formatowanie informacji z wyników modelu. Przydatne do konwertowania surowych wyników modeli językowych na dane strukturalne lub określone formaty wymagane przez aplikację.
LLM
Integracja LangChain z dużymi modelami językowymi (LLM), takimi jak OpenAI, Cohere i Hugging Face, jest podstawowym aspektem jego funkcjonalności. Sam LangChain nie obsługuje LLM, ale oferuje jednolity interfejs do interakcji z różnymi LLM.
Ta sekcja zawiera przegląd korzystania z opakowania OpenAI LLM w LangChain, mającego zastosowanie również do innych typów LLM. Zainstalowaliśmy to już w sekcji „Pierwsze kroki”. Zainicjujmy LLM.
from langchain.llms import OpenAI
llm = OpenAI()
- LLM wdrażają Funkcjonalny interfejs, podstawowy element budulcowy Język wyrażeń LangChain (LCEL). Oznacza to, że wspierają
invoke
,ainvoke
,stream
,astream
,batch
,abatch
,astream_log
wzywa. - LLM akceptują smyczki jako dane wejściowe lub obiekty, które można wymusić na wyświetlaniu podpowiedzi w postaci ciągów znaków, w tym
List[BaseMessage]
iPromptValue
. (więcej na ten temat później)
Spójrzmy na kilka przykładów.
response = llm.invoke("List the seven wonders of the world.")
print(response)
Alternatywnie możesz wywołać metodę stream, aby przesłać strumieniowo odpowiedź tekstową.
for chunk in llm.stream("Where were the 2012 Olympics held?"): print(chunk, end="", flush=True)
Modele czatu
Integracja LangChain z modelami czatu, wyspecjalizowaną odmianą modeli językowych, jest niezbędna do tworzenia interaktywnych aplikacji do czatowania. Chociaż wewnętrznie wykorzystują modele językowe, modele czatów prezentują odrębny interfejs skupiony wokół wiadomości czatu jako danych wejściowych i wyjściowych. Ta sekcja zawiera szczegółowy przegląd korzystania z modelu czatu OpenAI w LangChain.
from langchain.chat_models import ChatOpenAI
chat = ChatOpenAI()
Modele czatu w LangChain współpracują z różnymi typami wiadomości, takimi jak AIMessage
, HumanMessage
, SystemMessage
, FunctionMessage
, ChatMessage
(z dowolnym parametrem roli). Ogólnie, HumanMessage
, AIMessage
, SystemMessage
są najczęściej używane.
Modele czatu przede wszystkim akceptują List[BaseMessage]
jako wejścia. Stringi można konwertować na HumanMessage
, PromptValue
jest również obsługiwane.
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)
Monity
Podpowiedzi są niezbędne w prowadzeniu modeli językowych w celu generowania odpowiednich i spójnych wyników. Mogą obejmować zarówno proste instrukcje, jak i złożone przykłady składające się z kilku strzałów. W LangChain obsługa podpowiedzi może być bardzo usprawniona, dzięki kilku dedykowanym klasom i funkcjom.
LangChaina PromptTemplate
class to wszechstronne narzędzie do tworzenia podpowiedzi ciągów znaków. Używa Pythona str.format
składnia, umożliwiająca dynamiczne generowanie podpowiedzi. Można zdefiniować szablon z symbolami zastępczymi i w razie potrzeby wypełnić je określonymi wartościami.
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)
W przypadku modeli czatu podpowiedzi są bardziej uporządkowane i obejmują wiadomości o określonych rolach. Oferta LangChain ChatPromptTemplate
w tym celu.
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)
Takie podejście pozwala na tworzenie interaktywnych, angażujących chatbotów z dynamicznymi odpowiedziami.
Obie PromptTemplate
i ChatPromptTemplate
bezproblemowo integrują się z językiem LangChain Expression Language (LCEL), dzięki czemu mogą być częścią większych, złożonych przepływów pracy. Więcej na ten temat omówimy później.
Niestandardowe szablony podpowiedzi są czasami niezbędne w przypadku zadań wymagających unikalnego formatowania lub szczegółowych instrukcji. Tworzenie niestandardowego szablonu podpowiedzi obejmuje zdefiniowanie zmiennych wejściowych i niestandardowej metody formatowania. Ta elastyczność pozwala LangChain zaspokoić szeroki zakres wymagań specyficznych dla aplikacji. Czytaj więcej tutaj.
LangChain obsługuje także podpowiedzi w postaci kilku strzałów, umożliwiając modelowi uczenie się na przykładach. Ta funkcja jest niezbędna w przypadku zadań wymagających zrozumienia kontekstu lub określonych wzorców. Szablony podpowiedzi zawierające kilka strzałów można zbudować na podstawie zestawu przykładów lub przy użyciu obiektu Selektor przykładów. Czytaj więcej tutaj.
Parsery wyjściowe
Parsery wyjściowe odgrywają kluczową rolę w Langchain, umożliwiając użytkownikom strukturalizację odpowiedzi generowanych przez modele językowe. W tej sekcji zbadamy koncepcję parserów wyjściowych i przedstawimy przykłady kodu przy użyciu PydanticOutputParser, SimpleJsonOutputParser, CommaSeparatedListOutputParser, DatetimeOutputParser i XMLOutputParser firmy Langchain.
PydanticOutputParser
Langchain udostępnia PydanticOutputParser do analizowania odpowiedzi w strukturach danych Pydantic. Poniżej znajduje się przykład krok po kroku, jak z niego korzystać:
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)
Wyjście będzie:
SimpleJsonOutputParser
SimpleJsonOutputParser firmy Langchain jest używany, gdy chcesz analizować dane wyjściowe w stylu JSON. Oto przykład:
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
CommaSeparatedListOutputParser jest przydatny, gdy chcesz wyodrębnić listy rozdzielane przecinkami z odpowiedzi modelu. Oto przykład:
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 firmy Langchain został zaprojektowany do analizowania informacji typu datetime. Oto jak z niego korzystać:
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)
Te przykłady pokazują, jak parsery wyjściowe Langchain mogą być wykorzystywane do strukturyzacji różnych typów odpowiedzi modeli, dzięki czemu nadają się do różnych zastosowań i formatów. Parsery wyjściowe są cennym narzędziem zwiększającym użyteczność i interpretowalność wyników modelu językowego w Langchain.
Zautomatyzuj ręczne zadania i przepływy pracy za pomocą naszego narzędzia do tworzenia przepływów pracy opartego na sztucznej inteligencji, zaprojektowanego przez Nanonets dla Ciebie i Twoich zespołów.
Moduł II: Odzyskiwanie
Pobieranie w LangChain odgrywa kluczową rolę w aplikacjach wymagających danych specyficznych dla użytkownika, nieuwzględnionych w zbiorze szkoleniowym modelu. Proces ten, znany jako generowanie rozszerzone wyszukiwania (RAG), obejmuje pobieranie danych zewnętrznych i integrowanie ich z procesem generowania modelu językowego. LangChain zapewnia kompleksowy zestaw narzędzi i funkcjonalności ułatwiających ten proces, obsługując zarówno proste, jak i złożone aplikacje.
LangChain umożliwia wyszukiwanie poprzez szereg komponentów, które omówimy jeden po drugim.
Ładowarki dokumentów
Ładowarki dokumentów w LangChain umożliwiają ekstrakcję danych z różnych źródeł. Dzięki ponad 100 dostępnym modułom ładującym obsługują szereg typów dokumentów, aplikacji i źródeł (prywatne zasobniki s3, publiczne strony internetowe, bazy danych).
Możesz wybrać moduł ładowania dokumentów w oparciu o swoje wymagania tutaj.
Wszystkie te moduły ładujące pobierają dane do dokument zajęcia. Później dowiemy się, jak korzystać z danych pozyskanych w klasach dokumentów.
Moduł ładowania plików tekstowych: Załaduj prosty .txt
plik do dokumentu.
from langchain.document_loaders import TextLoader loader = TextLoader("./sample.txt")
document = loader.load()
Moduł ładujący CSV: Załaduj plik CSV do dokumentu.
from langchain.document_loaders.csv_loader import CSVLoader loader = CSVLoader(file_path='./example_data/sample.csv')
documents = loader.load()
Możemy dostosować analizę, określając nazwy pól –
loader = CSVLoader(file_path='./example_data/mlb_teams_2012.csv', csv_args={ 'delimiter': ',', 'quotechar': '"', 'fieldnames': ['MLB Team', 'Payroll in millions', 'Wins']
})
documents = loader.load()
Programy ładujące PDF: Moduły ładujące PDF w LangChain oferują różne metody analizowania i wyodrębniania treści z plików PDF. Każdy moduł ładujący spełnia inne wymagania i korzysta z różnych bibliotek bazowych. Poniżej znajdują się szczegółowe przykłady dla każdego modułu ładującego.
PyPDFLoader służy do podstawowego analizowania plików PDF.
from langchain.document_loaders import PyPDFLoader loader = PyPDFLoader("example_data/layout-parser-paper.pdf")
pages = loader.load_and_split()
MathPixLoader jest idealny do wyodrębniania treści matematycznych i diagramów.
from langchain.document_loaders import MathpixPDFLoader loader = MathpixPDFLoader("example_data/math-content.pdf")
data = loader.load()
PyMuPDFLoader jest szybki i umożliwia szczegółową ekstrakcję metadanych.
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 służy do bardziej szczegółowej kontroli nad ekstrakcją tekstu.
from langchain.document_loaders import PDFMinerLoader loader = PDFMinerLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
AmazonTextractPDFParser wykorzystuje AWS Textract do OCR i innych zaawansowanych funkcji analizowania plików PDF.
from langchain.document_loaders import AmazonTextractPDFLoader # Requires AWS account and configuration
loader = AmazonTextractPDFLoader("example_data/complex-layout.pdf")
documents = loader.load()
PDFMinerPDFasHTMLLoader generuje HTML z pliku PDF w celu analizy semantycznej.
from langchain.document_loaders import PDFMinerPDFasHTMLLoader loader = PDFMinerPDFasHTMLLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
PDFPlumberLoader udostępnia szczegółowe metadane i obsługuje jeden dokument na stronę.
from langchain.document_loaders import PDFPlumberLoader loader = PDFPlumberLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
Zintegrowane ładowarki: LangChain oferuje szeroką gamę niestandardowych modułów ładujących do bezpośredniego ładowania danych z aplikacji (takich jak Slack, Sigma, Notion, Confluence, Google Drive i wiele innych) oraz baz danych i wykorzystywania ich w aplikacjach LLM.
Pełna lista jest tutaj.
Poniżej znajduje się kilka przykładów ilustrujących to –
Przykład I – Slack
Slack, szeroko stosowaną platformę komunikatorów internetowych, można zintegrować z przepływami pracy i aplikacjami LLM.
- Przejdź do strony Zarządzanie obszarem roboczym Slack.
- Nawigować do
{your_slack_domain}.slack.com/services/export
. - Wybierz żądany zakres dat i rozpocznij eksport.
- Slack powiadamia e-mailem i wiadomością prywatną, gdy eksport jest gotowy.
- Wynikiem eksportu jest a
.zip
plik znajdujący się w folderze Pobrane lub wyznaczonej ścieżce pobierania. - Przypisz ścieżkę pobranego pliku
.zip
złożyć doLOCAL_ZIPFILE
. - Użyj
SlackDirectoryLoader
zlangchain.document_loaders
pakiet.
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)
Przykład II – Figma
Figma, popularne narzędzie do projektowania interfejsów, oferuje REST API do integracji danych.
- Uzyskaj klucz pliku Figma z formatu adresu URL:
https://www.figma.com/file/{filekey}/sampleFilename
. - Identyfikatory węzłów znajdują się w parametrze URL
?node-id={node_id}
. - Wygeneruj token dostępu, postępując zgodnie z instrukcjami na stronie Centrum pomocy Figmy.
- Połączenia
FigmaFileLoader
klasa odlangchain.document_loaders.figma
służy do ładowania danych Figma. - Różne moduły LangChain, takie jak
CharacterTextSplitter
,ChatOpenAI
itp. są wykorzystywane do przetwarzania.
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()
- Połączenia
generate_code
funkcja wykorzystuje dane Figma do tworzenia kodu HTML/CSS. - Wykorzystuje szablonową rozmowę z modelem opartym na 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)
- Połączenia
generate_code
funkcja po wykonaniu zwraca kod HTML/CSS w oparciu o dane wejściowe projektu Figma.
Wykorzystajmy teraz naszą wiedzę do stworzenia kilku zestawów dokumentów.
Najpierw ładujemy plik PDF, roczny raport zrównoważonego rozwoju BCG.
Używamy do tego PyPDFLoader.
from langchain.document_loaders import PyPDFLoader loader = PyPDFLoader("bcg-2022-annual-sustainability-report-apr-2023.pdf")
pdfpages = loader.load_and_split()
Będziemy teraz przyjmować dane z Airtable. Mamy Airtable zawierający informacje o różnych modelach OCR i ekstrakcji danych –
Wykorzystajmy do tego AirtableLoader, znajdujący się na liście zintegrowanych ładowarek.
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()
Przejdźmy teraz dalej i nauczmy się, jak korzystać z tych klas dokumentów.
Dokument Transformers
Transformatory dokumentów w LangChain to niezbędne narzędzia służące do manipulacji dokumentami, które stworzyliśmy w poprzednim podrozdziale.
Służą do takich zadań, jak dzielenie długich dokumentów na mniejsze fragmenty, łączenie i filtrowanie, które są kluczowe dla dostosowania dokumentów do okna kontekstowego modelu lub spełnienia określonych potrzeb aplikacji.
Jednym z takich narzędzi jest RecursiveCharacterTextSplitter, wszechstronny narzędzie do rozdzielania tekstu, które do podziału wykorzystuje listę znaków. Umożliwia parametry takie jak rozmiar porcji, nakładanie się i indeks początkowy. Oto przykład jego użycia w Pythonie:
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])
Innym narzędziem jest CharacterTextSplitter, które dzieli tekst na podstawie określonego znaku i zawiera elementy sterujące rozmiarem fragmentu i nakładaniem się:
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 służy do dzielenia treści HTML na podstawie znaczników nagłówka, zachowując strukturę semantyczną:
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])
Bardziej złożoną manipulację można osiągnąć, łącząc HTMLHeaderTextSplitter z innym rozdzielaczem, takim jak rozdzielacz potokowy:
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 oferuje również specjalne rozdzielacze dla różnych języków programowania, takie jak rozdzielacz kodu Python i rozdzielacz kodu JavaScript:
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])
Do dzielenia tekstu na podstawie liczby tokenów, co jest przydatne w modelach językowych z limitami tokenów, używany jest TokenTextSplitter:
from langchain.text_splitter import TokenTextSplitter text_splitter = TokenTextSplitter(chunk_size=10)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
Na koniec LongContextReorder zmienia kolejność dokumentów, aby zapobiec pogorszeniu wydajności modeli z powodu długich kontekstów:
from langchain.document_transformers import LongContextReorder reordering = LongContextReorder()
reordered_docs = reordering.transform_documents(docs)
print(reordered_docs[0])
Narzędzia te demonstrują różne sposoby przekształcania dokumentów w LangChain, od prostego dzielenia tekstu po złożone zmiany kolejności i dzielenie specyficzne dla języka. W przypadku bardziej szczegółowych i konkretnych przypadków użycia należy zapoznać się z dokumentacją LangChain i sekcją Integracje.
W naszych przykładach programy ładujące utworzyły już dla nas dokumenty podzielone na fragmenty i ta część jest już obsługiwana.
Modele osadzania tekstu
Modele osadzania tekstu w LangChain zapewniają ustandaryzowany interfejs dla różnych dostawców modeli osadzania, takich jak OpenAI, Cohere i Hugging Face. Modele te przekształcają tekst w reprezentacje wektorowe, umożliwiając operacje takie jak wyszukiwanie semantyczne poprzez podobieństwo tekstu w przestrzeni wektorowej.
Aby rozpocząć korzystanie z modeli osadzania tekstu, zazwyczaj należy zainstalować określone pakiety i skonfigurować klucze API. Zrobiliśmy to już dla OpenAI
W LangChain, embed_documents
Metoda służy do osadzania wielu tekstów, zapewniając listę reprezentacji wektorowych. Na przykład:
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]))
Aby osadzić pojedynczy tekst, taki jak zapytanie, plik embed_query
stosowana jest metoda. Jest to przydatne do porównywania zapytania z zestawem osadzonych dokumentów. Na przykład:
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])
Zrozumienie tych osadów jest kluczowe. Każdy fragment tekstu konwertowany jest na wektor, którego wymiar zależy od użytego modelu. Na przykład modele OpenAI zazwyczaj tworzą wektory o 1536 wymiarach. Te osadzania są następnie wykorzystywane do pobierania odpowiednich informacji.
Funkcjonalność osadzania LangChain nie ogranicza się do OpenAI, ale jest zaprojektowana do współpracy z różnymi dostawcami. Konfiguracja i użycie mogą się nieznacznie różnić w zależności od dostawcy, ale podstawowa koncepcja osadzania tekstów w przestrzeni wektorowej pozostaje taka sama. W przypadku szczegółowego wykorzystania, w tym zaawansowanych konfiguracji i integracji z różnymi dostawcami modeli osadzania, cennym zasobem jest dokumentacja LangChain w sekcji Integracje.
Sklepy wektorowe
Magazyny wektorów w LangChain wspierają wydajne przechowywanie i wyszukiwanie osadzonych tekstów. LangChain integruje się z ponad 50 sklepami wektorowymi, zapewniając ustandaryzowany interfejs ułatwiający obsługę.
Przykład: przechowywanie i wyszukiwanie osadzania
Po osadzeniu tekstów możemy je przechowywać np. w sklepie wektorowym Chroma
i przeprowadź wyszukiwanie podobieństw:
from langchain.vectorstores import Chroma db = Chroma.from_texts(embedded_texts)
similar_texts = db.similarity_search("search query")
Alternatywnie skorzystajmy z magazynu wektorów FAISS, aby utworzyć indeksy dla naszych dokumentów.
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS pdfstore = FAISS.from_documents(pdfpages, embedding=OpenAIEmbeddings()) airtablestore = FAISS.from_documents(airtabledocs, embedding=OpenAIEmbeddings())
Retrievery
Retrievery w LangChain to interfejsy, które zwracają dokumenty w odpowiedzi na nieustrukturyzowane zapytanie. Są bardziej ogólne niż sklepy wektorowe i skupiają się na wyszukiwaniu, a nie na przechowywaniu. Chociaż magazyny wektorów mogą być używane jako kręgosłup aportera, istnieją również inne typy aporterów.
Aby skonfigurować moduł pobierania Chroma, najpierw zainstaluj go za pomocą pip install chromadb
. Następnie ładujesz, dzielisz, osadzasz i pobierasz dokumenty za pomocą szeregu poleceń Pythona. Oto przykładowy kod konfigurowania modułu pobierania 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)
MultiQueryRetriever automatyzuje dostrajanie podpowiedzi, generując wiele zapytań dla zapytania wejściowego użytkownika i łączy wyniki. Oto przykład jego prostego użycia:
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))
Kompresja kontekstowa w LangChain kompresuje pobrane dokumenty przy użyciu kontekstu zapytania, zapewniając zwrócenie tylko istotnych informacji. Wiąże się to z redukcją treści i odfiltrowaniem mniej istotnych dokumentów. Poniższy przykład kodu pokazuje, jak używać kontekstowego narzędzia do pobierania kompresji:
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)
EnsembleRetriever łączy różne algorytmy wyszukiwania, aby osiągnąć lepszą wydajność. Przykład połączenia BM25 i FAISS Retrieverów pokazano w poniższym kodzie:
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 w LangChain umożliwia wyszukiwanie dokumentów z wieloma wektorami na dokument, co jest przydatne do przechwytywania różnych aspektów semantycznych w dokumencie. Metody tworzenia wielu wektorów obejmują dzielenie na mniejsze części, podsumowywanie lub generowanie hipotetycznych pytań. Do dzielenia dokumentów na mniejsze części można zastosować następujący kod Pythona:
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)))
Inną metodą jest generowanie podsumowań w celu lepszego wyszukiwania dzięki bardziej skoncentrowanej reprezentacji treści. Oto przykład generowania podsumowań:
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)))
Innym podejściem jest generowanie hipotetycznych pytań istotnych dla każdego dokumentu za pomocą LLM. Można to zrobić za pomocą następującego kodu:
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)))
Parent Document Retriever to kolejny moduł pobierania, który zapewnia równowagę pomiędzy dokładnością osadzania a zachowaniem kontekstu poprzez przechowywanie małych fragmentów i pobieranie większych dokumentów nadrzędnych. Jego realizacja jest następująca:
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")
Samopytający moduł pobierający konstruuje ustrukturyzowane zapytania na podstawie danych wejściowych w języku naturalnym i stosuje je do bazowego magazynu VectorStore. Jego implementację pokazano w następującym kodzie:
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")
WebResearchRetriever przeprowadza badanie sieci na podstawie zadanego zapytania –
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")
W naszych przykładach możemy również użyć standardowego retrievera już zaimplementowanego jako część naszego obiektu magazynu wektorów w następujący sposób –
Możemy teraz przesłuchać retrievery. Wynikiem naszego zapytania będą obiekty dokumentu istotne dla zapytania. Zostaną one ostatecznie wykorzystane do stworzenia odpowiednich odpowiedzi w dalszych sekcjach.
Zautomatyzuj ręczne zadania i przepływy pracy za pomocą naszego narzędzia do tworzenia przepływów pracy opartego na sztucznej inteligencji, zaprojektowanego przez Nanonets dla Ciebie i Twoich zespołów.
Moduł III: Agenci
LangChain wprowadza potężną koncepcję zwaną „Agentami”, która przenosi ideę łańcuchów na zupełnie nowy poziom. Agenci wykorzystują modele językowe do dynamicznego określania sekwencji działań do wykonania, dzięki czemu są niezwykle wszechstronni i adaptacyjni. W przeciwieństwie do tradycyjnych łańcuchów, w których działania są zakodowane na stałe w kodzie, agenci wykorzystują modele językowe jako mechanizmy wnioskowania, aby decydować, jakie działania podjąć i w jakiej kolejności.
Agent jest głównym elementem odpowiedzialnym za podejmowanie decyzji. Wykorzystuje siłę modelu językowego i podpowiedzi do określenia kolejnych kroków, aby osiągnąć konkretny cel. Dane wejściowe agenta zazwyczaj obejmują:
- Narzędzia: Opisy dostępnych narzędzi (więcej o tym później).
- Dane wejściowe użytkownika: Cel wysokiego poziomu lub zapytanie od użytkownika.
- Kroki pośrednie: Historia par (akcja, wyjście narzędzia) wykonanych w celu osiągnięcia bieżących danych wejściowych użytkownika.
Dane wyjściowe agenta mogą być następne akcja podjąć działania (Akcje agenta) lub finał odpowiedź wysłać użytkownikowi (AgentZakończ). Na akcja określa a narzędzie oraz wkład dla tego narzędzia.
Tools
Narzędzia to interfejsy, których agent może używać do interakcji ze światem. Umożliwiają agentom wykonywanie różnych zadań, takich jak przeszukiwanie Internetu, uruchamianie poleceń powłoki lub uzyskiwanie dostępu do zewnętrznych interfejsów API. W LangChain narzędzia są niezbędne do poszerzania możliwości agentów i umożliwiania im realizacji różnorodnych zadań.
Aby korzystać z narzędzi w LangChain, możesz je załadować, korzystając z następującego fragmentu:
from langchain.agents import load_tools tool_names = [...]
tools = load_tools(tool_names)
Niektóre narzędzia mogą wymagać do zainicjowania podstawowego modelu języka (LLM). W takich przypadkach możesz również zdać LLM:
from langchain.agents import load_tools tool_names = [...]
llm = ...
tools = load_tools(tool_names, llm=llm)
Ta konfiguracja umożliwia dostęp do różnych narzędzi i integrację ich z przepływami pracy agenta. Pełna lista narzędzi wraz z dokumentacją użytkowania znajduje się na stronie tutaj.
Spójrzmy na kilka przykładów narzędzi.
DuckDuckGo
Narzędzie DuckDuckGo umożliwia wyszukiwanie w Internecie za pomocą swojej wyszukiwarki. Oto jak z niego korzystać:
from langchain.tools import DuckDuckGoSearchRun
search = DuckDuckGoSearchRun()
search.run("manchester united vs luton town match summary")
DataForSeo
Zestaw narzędzi DataForSeo umożliwia uzyskiwanie wyników wyszukiwania za pomocą DataForSeo API. Aby korzystać z tego zestawu narzędzi, musisz skonfigurować swoje dane uwierzytelniające API. Oto jak skonfigurować poświadczenia:
import os os.environ["DATAFORSEO_LOGIN"] = "<your_api_access_username>"
os.environ["DATAFORSEO_PASSWORD"] = "<your_api_access_password>"
Po ustawieniu poświadczeń możesz utworzyć plik DataForSeoAPIWrapper
narzędzie umożliwiające dostęp do API:
from langchain.utilities.dataforseo_api_search import DataForSeoAPIWrapper wrapper = DataForSeoAPIWrapper() result = wrapper.run("Weather in Los Angeles")
Połączenia DataForSeoAPIWrapper
narzędzie pobiera wyniki wyszukiwania z różnych źródeł.
Możesz dostosować typ wyników i pól zwracanych w odpowiedzi JSON. Na przykład możesz określić typy wyników, pola i ustawić maksymalną liczbę zwracanych najlepszych wyników:
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")
Ten przykład dostosowuje odpowiedź JSON, określając typy wyników, pola i ograniczając liczbę wyników.
Możesz także określić lokalizację i język wyników wyszukiwania, przekazując dodatkowe parametry do opakowania 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")
Podając parametry lokalizacji i języka, możesz dostosować wyniki wyszukiwania do konkretnych regionów i języków.
Masz swobodę wyboru wyszukiwarki, z której chcesz korzystać. Po prostu określ żądaną wyszukiwarkę:
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")
W tym przykładzie wyszukiwanie jest dostosowane tak, aby używać Bing jako wyszukiwarki.
Opakowanie API pozwala także określić typ wyszukiwania, które chcesz przeprowadzić. Możesz na przykład przeszukać mapy:
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")
Umożliwia to dostosowanie wyszukiwania w celu uzyskania informacji związanych z mapami.
Powłoka (bash)
Zestaw narzędzi Shell zapewnia agentom dostęp do środowiska powłoki, umożliwiając im wykonywanie poleceń powłoki. Ta funkcja jest potężna, ale należy jej używać ostrożnie, szczególnie w środowiskach piaskownicy. Oto jak możesz używać narzędzia Shell:
from langchain.tools import ShellTool shell_tool = ShellTool() result = shell_tool.run({"commands": ["echo 'Hello World!'", "time"]})
W tym przykładzie narzędzie Shell uruchamia dwa polecenia powłoki: powtarzając polecenie „Hello World!” i wyświetlanie aktualnego czasu.
Możesz udostępnić agentowi narzędzie Shell w celu wykonywania bardziej złożonych zadań. Oto przykład agenta pobierającego łącza ze strony internetowej za pomocą narzędzia 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."
)
W tym scenariuszu agent używa narzędzia Shell do wykonania sekwencji poleceń służących do pobierania, filtrowania i sortowania adresów URL ze strony internetowej.
Podane przykłady demonstrują niektóre narzędzia dostępne w LangChain. Narzędzia te ostatecznie rozszerzają możliwości agentów (omówione w następnym podrozdziale) i umożliwiają im efektywne wykonywanie różnych zadań. W zależności od wymagań możesz wybrać narzędzia i zestawy narzędzi, które najlepiej odpowiadają potrzebom Twojego projektu i zintegrować je z przepływami pracy agenta.
Wracając do agentów
Przejdźmy teraz do agentów.
AgentExecutor to środowisko wykonawcze agenta. Jest odpowiedzialny za wywołanie agenta, wykonanie wybranych akcji, przekazanie wyników akcji z powrotem do agenta i powtarzanie procesu aż do zakończenia działania agenta. W pseudokodzie AgentExecutor może wyglądać mniej więcej tak:
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 radzi sobie z różnymi złożonościami, takimi jak radzenie sobie z przypadkami, w których agent wybiera nieistniejące narzędzie, obsługa błędów narzędzia, zarządzanie wynikami generowanymi przez agenta oraz zapewnianie rejestrowania i obserwowalności na wszystkich poziomach.
Chociaż klasa AgentExecutor jest głównym środowiskiem wykonawczym agenta w LangChain, obsługiwane są inne, bardziej eksperymentalne środowiska wykonawcze, w tym:
- Agent planuj i wykonuj
- Dziecko AGI
- Automatyczne GPT
Aby lepiej zrozumieć strukturę agenta, zbudujmy podstawowego agenta od podstaw, a następnie przejdźmy do eksploracji gotowych agentów.
Zanim zajmiemy się tworzeniem agenta, konieczne jest ponowne zapoznanie się z niektórymi kluczowymi terminami i schematami:
- Akcja agenta: Jest to klasa danych reprezentująca akcję, którą powinien podjąć agent. Składa się z
tool
właściwość (nazwa narzędzia do wywołania) i atool_input
właściwość (wejście dla tego narzędzia). - Zakończenie agenta: Ta klasa danych wskazuje, że agent zakończył swoje zadanie i powinien zwrócić użytkownikowi odpowiedź. Zwykle zawiera słownik wartości zwracanych, często z kluczem „wyjściem” zawierającym tekst odpowiedzi.
- Kroki pośrednie: Są to zapisy poprzednich działań agenta i odpowiadających im wyników. Są one kluczowe dla przekazywania kontekstu przyszłym iteracjom agenta.
W naszym przykładzie użyjemy wywołania funkcji OpenAI do stworzenia naszego agenta. To podejście jest niezawodne przy tworzeniu agentów. Zaczniemy od stworzenia prostego narzędzia obliczającego długość słowa. To narzędzie jest przydatne, ponieważ modele językowe mogą czasami popełniać błędy z powodu tokenizacji podczas liczenia długości słów.
Najpierw załadujmy model języka, którego będziemy używać do sterowania agentem:
from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
Przetestujmy model za pomocą obliczenia długości słowa:
llm.invoke("how many letters in the word educa?")
W odpowiedzi należy podać liczbę liter w słowie „educa”.
Następnie zdefiniujemy prostą funkcję Pythona do obliczenia długości słowa:
from langchain.agents import tool @tool
def get_word_length(word: str) -> int: """Returns the length of a word.""" return len(word)
Stworzyliśmy narzędzie o nazwie get_word_length
która pobiera słowo jako dane wejściowe i zwraca jego długość.
Utwórzmy teraz zachętę dla agenta. Podpowiedź instruuje agenta, jak uzasadnić i sformatować dane wyjściowe. W naszym przypadku używamy wywołania funkcji OpenAI, które wymaga minimalnej liczby instrukcji. Zdefiniujemy zachętę z symbolami zastępczymi dla danych wprowadzanych przez użytkownika i notatnikiem agenta:
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"), ]
)
Skąd agent wie, z jakich narzędzi może skorzystać? Opieramy się na modelach językowych wywoływania funkcji OpenAI, które wymagają oddzielnego przekazywania funkcji. Aby udostępnić agentowi nasze narzędzia, sformatujemy je jako wywołania funkcji 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])
Teraz możemy utworzyć agenta, definiując mapowania wejściowe i łącząc komponenty:
To jest język LCEL. Omówimy to szczegółowo później.
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()
)
Stworzyliśmy naszego agenta, który rozumie dane wejściowe użytkownika, wykorzystuje dostępne narzędzia i formatuje dane wyjściowe. Teraz wejdźmy z nim w interakcję:
agent.invoke({"input": "how many letters in the word educa?", "intermediate_steps": []})
Agent powinien odpowiedzieć akcją AgentAction, wskazując następną akcję do wykonania.
Stworzyliśmy agenta, ale teraz musimy napisać dla niego środowisko wykonawcze. Najprostsze środowisko wykonawcze to takie, które w sposób ciągły wywołuje agenta, wykonuje akcje i powtarza aż do zakończenia działania agenta. Oto przykład:
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)
W tej pętli wielokrotnie wywołujemy agenta, wykonujemy akcje i aktualizujemy kroki pośrednie, aż do zakończenia działania agenta. Obsługujemy także interakcje narzędzi w pętli.
Aby uprościć ten proces, LangChain udostępnia klasę AgentExecutor, która hermetyzuje wykonywanie agenta i oferuje obsługę błędów, wcześniejsze zatrzymanie, śledzenie i inne ulepszenia. Użyjmy AgentExecutor do interakcji z agentem:
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 upraszcza proces wykonywania i zapewnia wygodny sposób interakcji z agentem.
Pamięć zostanie również omówiona szczegółowo później.
Stworzony do tej pory agent jest bezstanowy, co oznacza, że nie pamięta poprzednich interakcji. Aby umożliwić dalsze pytania i rozmowy, musimy dodać pamięć do agenta. Obejmuje to dwa kroki:
- Dodaj zmienną pamięci w monicie, aby przechowywać historię czatów.
- Śledź historię czatów podczas interakcji.
Zacznijmy od dodania symbolu zastępczego pamięci w wierszu zachęty:
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"), ]
)
Teraz utwórz listę, aby śledzić historię czatów:
from langchain.schema.messages import HumanMessage, AIMessage chat_history = []
Na etapie tworzenia agenta uwzględnimy również pamięć:
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()
)
Teraz, uruchamiając agenta, pamiętaj o zaktualizowaniu historii czatów:
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})
Umożliwia to agentowi prowadzenie historii rozmów i odpowiadanie na pytania uzupełniające w oparciu o poprzednie interakcje.
Gratulacje! Pomyślnie utworzyłeś i uruchomiłeś swojego pierwszego kompleksowego agenta w LangChain. Aby głębiej poznać możliwości LangChain, możesz odkryć:
- Obsługiwane różne typy agentów.
- Gotowi agenci
- Jak pracować z narzędziami i integracjami narzędzi.
Typy agentów
LangChain oferuje różne typy agentów, każdy dostosowany do konkretnych zastosowań. Oto niektórzy z dostępnych agentów:
- Reakcja zerowego strzału: Agent ten wykorzystuje framework ReAct do wybierania narzędzi wyłącznie na podstawie ich opisów. Wymaga opisu każdego narzędzia i jest bardzo uniwersalna.
- Dane wejściowe strukturalne ReAct: Agent ten obsługuje narzędzia z wieloma danymi wejściowymi i nadaje się do złożonych zadań, takich jak nawigacja w przeglądarce internetowej. Używa schematu argumentów narzędzi do wprowadzania strukturalnych danych.
- Funkcje OpenAI: Specjalnie zaprojektowany dla modeli dostosowanych do wywoływania funkcji, agent ten jest kompatybilny z modelami takimi jak gpt-3.5-turbo-0613 i gpt-4-0613. Wykorzystaliśmy to do stworzenia naszego pierwszego agenta powyżej.
- Konwersacyjny: Zaprojektowany do ustawień konwersacyjnych, agent ten wykorzystuje ReAct do wyboru narzędzia i wykorzystuje pamięć do zapamiętywania poprzednich interakcji.
- Zapytaj samodzielnie za pomocą wyszukiwania: Agent ten opiera się na jednym narzędziu „Odpowiedź pośrednia”, które wyszukuje oparte na faktach odpowiedzi na pytania. Jest to odpowiednik oryginalnego pytania samodzielnego z dokumentem wyszukiwania.
- Magazyn dokumentów ReAct: Agent ten współdziała z magazynem dokumentów przy użyciu platformy ReAct. Wymaga narzędzi „Wyszukaj” i „Wyszukaj” i jest podobny do przykładu z Wikipedii w oryginalnym artykule ReAct.
Zapoznaj się z tymi typami agentów, aby znaleźć w LangChain tego, który najlepiej odpowiada Twoim potrzebom. Agenci ci umożliwiają powiązanie w nich zestawu narzędzi do obsługi akcji i generowania odpowiedzi. Dowiedz się więcej na jak zbudować własnego agenta za pomocą narzędzi tutaj.
Wstępnie zbudowani agenci
Kontynuujmy naszą eksplorację agentów, koncentrując się na gotowych agentach dostępnych w LangChain.
gmail
LangChain oferuje zestaw narzędzi Gmail, który umożliwia połączenie poczty e-mail LangChain z interfejsem API Gmaila. Aby rozpocząć, musisz skonfigurować swoje dane uwierzytelniające, co opisano w dokumentacji interfejsu API Gmaila. Po pobraniu pliku credentials.json
możesz kontynuować korzystanie z interfejsu API Gmaila. Dodatkowo będziesz musiał zainstalować niektóre wymagane biblioteki za pomocą następujących poleceń:
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
Zestaw narzędzi Gmaila możesz utworzyć w następujący sposób:
from langchain.agents.agent_toolkits import GmailToolkit toolkit = GmailToolkit()
Możesz także dostosować uwierzytelnianie do swoich potrzeb. Za kulisami zasób Googleapi jest tworzony przy użyciu następujących metod:
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)
Zestaw narzędzi oferuje różne narzędzia, których można używać w agencie, w tym:
GmailCreateDraft
: utwórz wersję roboczą wiadomości e-mail z określonymi polami wiadomości.GmailSendMessage
: wysyłanie wiadomości e-mail.GmailSearch
: wyszukiwanie wiadomości e-mail lub wątków.GmailGetMessage
: pobierz wiadomość e-mail według identyfikatora wiadomości.GmailGetThread
: wyszukiwanie wiadomości e-mail.
Aby używać tych narzędzi w agencie, możesz zainicjować agenta w następujący sposób:
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,
)
Oto kilka przykładów wykorzystania tych narzędzi:
- Utwórz wersję roboczą Gmaila do edycji:
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."
)
- Wyszukaj najnowsze e-maile w swoich wersjach roboczych:
agent.run("Could you search in my drafts for the latest email?")
Te przykłady demonstrują możliwości zestawu narzędzi Gmail firmy LangChain w ramach agenta, umożliwiając programową interakcję z Gmailem.
Agent bazy danych SQL
Ta sekcja zawiera przegląd agenta zaprojektowanego do interakcji z bazami danych SQL, w szczególności z bazą danych Chinook. Agent ten może odpowiedzieć na ogólne pytania dotyczące bazy danych i odzyskać dane po błędach. Należy pamiętać, że jest on nadal w fazie aktywnego rozwoju i nie wszystkie odpowiedzi mogą być prawidłowe. Zachowaj ostrożność podczas uruchamiania go na wrażliwych danych, ponieważ może on wykonywać instrukcje DML w Twojej bazie danych.
Aby użyć tego agenta, możesz go zainicjować w następujący sposób:
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,
)
Agenta tego można zainicjować przy użyciu metody ZERO_SHOT_REACT_DESCRIPTION
typ agenta. Jego zadaniem jest odpowiadanie na pytania i dostarczanie opisów. Alternatywnie możesz zainicjować agenta za pomocą metody OPENAI_FUNCTIONS
typ agenta z modelem GPT-3.5-turbo OpenAI, którego używaliśmy w naszym wcześniejszym kliencie.
Odpowiedzialność
- Łańcuch zapytań może generować zapytania wstawiające/aktualizujące/usuwające. Zachowaj ostrożność i w razie potrzeby użyj niestandardowego monitu lub utwórz użytkownika SQL bez uprawnień do zapisu.
- Należy pamiętać, że uruchomienie niektórych zapytań, np. „uruchom możliwie największe zapytanie”, może przeciążyć bazę danych SQL, zwłaszcza jeśli zawiera ona miliony wierszy.
- Bazy danych zorientowane na hurtownie danych często obsługują przydziały na poziomie użytkownika, aby ograniczyć wykorzystanie zasobów.
Możesz poprosić agenta o opisanie tabeli, np. tabeli „ścieżka z listą odtwarzania”. Oto przykład, jak to zrobić:
agent_executor.run("Describe the playlisttrack table")
Agent przekaże informacje o schemacie tabeli i przykładowych wierszach.
Jeśli przez pomyłkę zapytasz o nieistniejącą tabelę, agent może ją odzyskać i dostarczyć informacje o najbliższej pasującej tabeli. Na przykład:
agent_executor.run("Describe the playlistsong table")
Agent znajdzie najbliższą pasującą tabelę i przekaże informacje na jej temat.
Możesz także poprosić agenta o wykonanie zapytań do bazy danych. Na przykład:
agent_executor.run("List the total sales per country. Which country's customers spent the most?")
Agent wykona zapytanie i poda wynik, np. kraj o najwyższej łącznej sprzedaży.
Aby uzyskać całkowitą liczbę utworów na każdej liście odtwarzania, możesz użyć następującego zapytania:
agent_executor.run("Show the total number of tracks in each playlist. The Playlist name should be included in the result.")
Agent zwróci nazwy list odtwarzania wraz z odpowiednią łączną liczbą utworów.
W przypadku, gdy agent napotka błędy, może je odzyskać i udzielić dokładnych odpowiedzi. Na przykład:
agent_executor.run("Who are the top 3 best selling artists?")
Nawet po napotkaniu początkowego błędu agent dostosuje się i poda poprawną odpowiedź, którą w tym przypadku jest 3 najlepiej sprzedających się artystów.
Agent ramki danych Pandy
W tej sekcji przedstawiono agenta zaprojektowanego do interakcji z Pandas DataFrames w celu odpowiadania na pytania. Należy pamiętać, że ten agent wykorzystuje ukrytego agenta Pythona do wykonywania kodu Pythona wygenerowanego przez model języka (LLM). Podczas korzystania z tego agenta należy zachować ostrożność, aby zapobiec potencjalnym szkodom powodowanym przez złośliwy kod Pythona wygenerowany przez LLM.
Możesz zainicjować agenta Pandas DataFrame w następujący sposób:
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,
# )
Możesz poprosić agenta o policzenie liczby wierszy w DataFrame:
agent.run("how many rows are there?")
Agent wykona kod df.shape[0]
i podaj odpowiedź, np. „W ramce danych znajduje się 891 wierszy”.
Możesz także poprosić agenta o filtrowanie wierszy na podstawie określonych kryteriów, takich jak znalezienie liczby osób mających więcej niż 3 rodzeństwa:
agent.run("how many people have more than 3 siblings")
Agent wykona kod df[df['SibSp'] > 3].shape[0]
i podaj odpowiedź, np. „30 osób ma więcej niż 3 rodzeństwa”.
Jeśli chcesz obliczyć pierwiastek kwadratowy średniego wieku, możesz zapytać agenta:
agent.run("whats the square root of the average age?")
Agent obliczy średni wiek korzystając df['Age'].mean()
a następnie oblicz pierwiastek kwadratowy za pomocą math.sqrt()
. Podaje odpowiedź, na przykład: „Pierwiastek kwadratowy średniego wieku to 5.449689683556195”.
Utwórzmy kopię DataFrame, a brakujące wartości wieku zostaną uzupełnione średnim wiekiem:
df1 = df.copy()
df1["Age"] = df1["Age"].fillna(df1["Age"].mean())
Następnie możesz zainicjować agenta obiema ramkami DataFrame i zadać mu pytanie:
agent = create_pandas_dataframe_agent(OpenAI(temperature=0), [df, df1], verbose=True)
agent.run("how many rows in the age column are different?")
Agent porówna kolumny wieku w obu ramkach danych i poda odpowiedź, na przykład „177 wierszy w kolumnie wieku jest różnych”.
Zestaw narzędzi Jira
W tej sekcji wyjaśniono, jak korzystać z zestawu narzędzi Jira, który umożliwia agentom interakcję z instancją Jira. Za pomocą tego zestawu narzędzi możesz wykonywać różne czynności, takie jak wyszukiwanie problemów i tworzenie problemów. Wykorzystuje bibliotekę atlassian-python-api. Aby korzystać z tego zestawu narzędzi, musisz ustawić zmienne środowiskowe dla swojej instancji Jira, w tym JIRA_API_TOKEN, JIRA_USERNAME i JIRA_INSTANCE_URL. Ponadto może być konieczne ustawienie klucza API OpenAI jako zmiennej środowiskowej.
Aby rozpocząć, zainstaluj bibliotekę atlassian-python-api i ustaw wymagane zmienne środowiskowe:
%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
)
Możesz zlecić agentowi utworzenie nowego wydania w konkretnym projekcie z podsumowaniem i opisem:
agent.run("make a new issue in project PW to remind me to make more fried rice")
Agent wykona niezbędne działania, aby utworzyć problem i udzieli odpowiedzi, np. „W projekcie PW utworzono nowy problem z podsumowaniem „Zrób więcej smażonego ryżu” i opisem „Przypomnienie o konieczności zrobienia większej ilości smażonego ryżu”.
Umożliwia to interakcję z instancją Jira przy użyciu instrukcji w języku naturalnym i zestawu narzędzi Jira.
Zautomatyzuj ręczne zadania i przepływy pracy za pomocą naszego narzędzia do tworzenia przepływów pracy opartego na sztucznej inteligencji, zaprojektowanego przez Nanonets dla Ciebie i Twoich zespołów.
Moduł IV: Łańcuchy
LangChain to narzędzie przeznaczone do wykorzystania modeli dużych języków (LLM) w złożonych aplikacjach. Zapewnia ramy do tworzenia łańcuchów komponentów, w tym LLM i innych typów komponentów. Dwa podstawowe frameworki
- Język wyrażeń LangChain (LCEL)
- Interfejs starszego łańcucha
Język wyrażeń LangChain (LCEL) to składnia pozwalająca na intuicyjne komponowanie łańcuchów. Obsługuje zaawansowane funkcje, takie jak przesyłanie strumieniowe, wywołania asynchroniczne, przetwarzanie wsadowe, równoległość, ponowne próby, rezerwy i śledzenie. Na przykład możesz utworzyć podpowiedzi, model i analizator wyników w języku LCEL, jak pokazano w następującym kodzie:
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)
Alternatywnie LLMCain jest opcją podobną do LCEL do komponowania komponentów. Przykład LLMCain wygląda następująco:
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")
Łańcuchy w LangChain mogą być również stanowe poprzez włączenie obiektu Memory. Pozwala to na trwałość danych między połączeniami, jak pokazano w tym przykładzie:
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 obsługuje również integrację z interfejsami API wywoływania funkcji OpenAI, co jest przydatne do uzyskiwania uporządkowanych wyników i wykonywania funkcji w łańcuchu. Aby uzyskać uporządkowane wyniki, możesz je określić za pomocą klas Pydantic lub JsonSchema, jak pokazano poniżej:
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"})
W przypadku wyników ustrukturyzowanych dostępne jest również starsze podejście wykorzystujące LLMChain:
from langchain.chains.openai_functions import create_structured_output_chain class Person(BaseModel): name: str = Field(..., description="The person's name") age: int = Field(..., description="The person's age") chain = create_structured_output_chain(Person, llm, prompt, verbose=True)
chain.run("Sally is 13")
LangChain wykorzystuje funkcje OpenAI do tworzenia różnych konkretnych łańcuchów do różnych celów. Należą do nich łańcuchy do ekstrakcji, tagowania, OpenAPI i kontroli jakości z cytatami.
W kontekście ekstrakcji proces jest podobny do ustrukturyzowanego łańcucha wyjściowego, ale koncentruje się na ekstrakcji informacji lub jednostek. W przypadku tagowania pomysł polega na oznakowaniu dokumentu klasami, takimi jak nastroje, język, styl, poruszane tematy lub tendencja polityczna.
Przykład działania tagowania w LangChain można zademonstrować za pomocą kodu Pythona. Proces rozpoczyna się od zainstalowania niezbędnych pakietów i skonfigurowania środowiska:
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
Zdefiniowano schemat tagowania, określając właściwości i ich oczekiwane typy:
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)
Przykłady uruchomienia łańcucha tagowania z różnymi danymi wejściowymi pokazują zdolność modelu do interpretowania nastrojów, języków i agresywności:
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'}
Aby uzyskać lepszą kontrolę, schemat można zdefiniować bardziej szczegółowo, łącznie z możliwymi wartościami, opisami i wymaganymi właściwościami. Przykład tej ulepszonej kontroli pokazano poniżej:
schema = { "properties": { # Schema definitions here }, "required": ["language", "sentiment", "aggressiveness"],
} chain = create_tagging_chain(schema, llm)
Schematy Pydantic mogą być również używane do definiowania kryteriów tagowania, zapewniając Pythoniczny sposób określania wymaganych właściwości i typów:
from enum import Enum
from pydantic import BaseModel, Field class Tags(BaseModel): # Class fields here chain = create_tagging_chain_pydantic(Tags, llm)
Dodatkowo, transformator dokumentów LangChain ze znacznikami metadanych może być używany do wyodrębniania metadanych z dokumentów LangChain, oferując podobną funkcjonalność jak łańcuch tagowania, ale zastosowany do dokumentu LangChain.
Cytowanie źródeł wyszukiwania to kolejna funkcja LangChain, która wykorzystuje funkcje OpenAI do wyodrębniania cytatów z tekstu. Pokazano to w następującym kodzie:
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
W LangChain łączenie w aplikacje Large Language Model (LLM) zazwyczaj obejmuje połączenie szablonu podpowiedzi z LLM i opcjonalnie parserem wyjściowym. Zalecanym sposobem na to jest użycie języka LangChain Expression Language (LCEL), chociaż obsługiwane jest również starsze podejście LLMChain.
Korzystając z LCEL, BasePromptTemplate, BaseLanguageModel i BaseOutputParser implementują interfejs Runnable i można je łatwo łączyć ze sobą. Oto przykład ilustrujący to:
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'
Routing w LangChain pozwala na tworzenie niedeterministycznych łańcuchów, w których wynik poprzedniego kroku determinuje następny krok. Pomaga to w strukturyzacji i utrzymaniu spójności w interakcjach z LLM. Na przykład, jeśli masz dwa szablony zoptymalizowane pod kątem różnych typów pytań, możesz wybrać szablon na podstawie danych wprowadzonych przez użytkownika.
Oto jak można to osiągnąć za pomocą LCEL z RunnableBranch, który jest inicjowany listą par (stanów, możliwych do uruchomienia) i domyślnym uruchamialnym:
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
Następnie tworzony jest końcowy łańcuch przy użyciu różnych komponentów, takich jak klasyfikator tematu, gałąź podpowiedzi i parser wyjściowy, aby określić przepływ na podstawie tematu danych wejściowych:
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
To podejście ilustruje elastyczność i możliwości LangChain w obsłudze złożonych zapytań i odpowiednim kierowaniu nimi na podstawie danych wejściowych.
W dziedzinie modeli językowych powszechną praktyką jest podążanie za pierwszym wywołaniem serią kolejnych, wykorzystując wynik jednego wywołania jako dane wejściowe dla następnego. To sekwencyjne podejście jest szczególnie korzystne, gdy chcesz opierać się na informacjach wygenerowanych podczas poprzednich interakcji. Chociaż zalecaną metodą tworzenia tych sekwencji jest język LangChain Expression Language (LCEL), metoda SequentialChain jest nadal udokumentowana pod kątem jej kompatybilności wstecznej.
Aby to zilustrować, rozważmy scenariusz, w którym najpierw generujemy streszczenie spektaklu, a następnie na jego podstawie recenzję. Korzystanie z Pythona langchain.prompts
, tworzymy dwa PromptTemplate
przypadkach: jedno do streszczenia, drugie do recenzji. Oto kod umożliwiający skonfigurowanie tych szablonów:
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:"
)
W podejściu LCEL łączymy te podpowiedzi z ChatOpenAI
i StrOutputParser
stworzyć sekwencję, która najpierw wygeneruje streszczenie, a następnie recenzję. Fragment kodu jest następujący:
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"})
Jeśli potrzebujemy zarówno streszczenia, jak i recenzji, możemy skorzystać RunnablePassthrough
aby utworzyć dla każdego oddzielny łańcuch, a następnie połączyć je:
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"})
W przypadku scenariuszy obejmujących bardziej złożone sekwencje, SequentialChain
metoda wchodzi w grę. Pozwala to na wiele wejść i wyjść. Rozważmy przypadek, w którym potrzebujemy streszczenia opartego na tytule i epoce sztuki. Oto jak możemy to skonfigurować:
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"})
W scenariuszach, w których chcesz zachować kontekst w całym łańcuchu lub w dalszej części łańcucha, SimpleMemory
może być użyte. Jest to szczególnie przydatne do zarządzania złożonymi relacjami wejście/wyjście. Na przykład w scenariuszu, w którym chcemy generować posty w mediach społecznościowych na podstawie tytułu, epoki, streszczenia i recenzji sztuki, SimpleMemory
może pomóc w zarządzaniu tymi zmiennymi:
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"})
Oprócz łańcuchów sekwencyjnych istnieją wyspecjalizowane łańcuchy do pracy z dokumentami. Każdy z tych łańcuchów służy innemu celowi, od łączenia dokumentów po udoskonalanie odpowiedzi w oparciu o iteracyjną analizę dokumentów, po mapowanie i redukowanie treści dokumentów w celu podsumowania lub zmiany rankingu na podstawie punktowanych odpowiedzi. Łańcuchy te można odtworzyć za pomocą LCEL, aby zapewnić dodatkową elastyczność i dostosowanie.
-
StuffDocumentsChain
łączy listę dokumentów w jeden monit przekazywany do LLM. -
RefineDocumentsChain
aktualizuje swoją odpowiedź iteracyjnie dla każdego dokumentu, odpowiednią dla zadań, w których dokumenty przekraczają pojemność kontekstu modelu. -
MapReduceDocumentsChain
stosuje łańcuch do każdego dokumentu indywidualnie, a następnie łączy wyniki. -
MapRerankDocumentsChain
ocenia każdą odpowiedź opartą na dokumencie i wybiera tę, która uzyskała najwyższy wynik.
Oto przykład konfiguracji pliku MapReduceDocumentsChain
przy użyciu 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")
Taka konfiguracja pozwala na szczegółową i wszechstronną analizę treści dokumentu, wykorzystując mocne strony LCEL i leżący u jego podstaw model językowy.
Zautomatyzuj ręczne zadania i przepływy pracy za pomocą naszego narzędzia do tworzenia przepływów pracy opartego na sztucznej inteligencji, zaprojektowanego przez Nanonets dla Ciebie i Twoich zespołów.
Moduł V: Pamięć
W LangChain pamięć jest podstawowym aspektem interfejsów konwersacyjnych, umożliwiającym systemom odwoływanie się do przeszłych interakcji. Osiąga się to poprzez przechowywanie informacji i odpytywanie o nie, wykonując dwie podstawowe czynności: czytanie i pisanie. System pamięci dwukrotnie podczas cyklu współdziała z łańcuchem, zwiększając dane wejściowe użytkownika i przechowując dane wejściowe i wyjściowe do wykorzystania w przyszłości.
Budowanie pamięci w systemie
- Przechowywanie wiadomości czatu: Moduł pamięci LangChain integruje różne metody przechowywania wiadomości czatu, od list w pamięci po bazy danych. Dzięki temu wszystkie interakcje na czacie są rejestrowane do wykorzystania w przyszłości.
- Wysyłanie zapytań do wiadomości czatu: Oprócz przechowywania wiadomości czatowych LangChain wykorzystuje struktury danych i algorytmy do tworzenia użytecznego widoku tych wiadomości. Proste systemy pamięci mogą zwracać najnowsze wiadomości, podczas gdy bardziej zaawansowane systemy mogą podsumowywać przeszłe interakcje lub skupiać się na jednostkach wspomnianych w bieżącej interakcji.
Aby zademonstrować wykorzystanie pamięci w LangChain, rozważ ConversationBufferMemory
class, prosta forma pamięci przechowująca wiadomości czatu w buforze. Oto przykład:
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?")
Integrując pamięć z łańcuchem, niezwykle ważne jest zrozumienie zmiennych zwracanych z pamięci i sposobu ich wykorzystania w łańcuchu. Na przykład load_memory_variables
Metoda pomaga dopasować zmienne odczytane z pamięci do oczekiwań łańcucha.
Kompleksowy przykład z LangChain
Rozważ użycie ConversationBufferMemory
w sposób LLMChain
. Łańcuch w połączeniu z odpowiednim szablonem podpowiedzi i pamięcią zapewnia płynną konwersację. Oto uproszczony przykład:
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?"})
Ten przykład ilustruje, jak system pamięci LangChain integruje się ze swoimi łańcuchami, aby zapewnić spójne i świadome kontekstowo doświadczenie konwersacyjne.
Typy pamięci w Langchain
Langchain oferuje różne typy pamięci, które można wykorzystać w celu usprawnienia interakcji z modelami AI. Każdy typ pamięci ma swoje własne parametry i typy zwracanych danych, dzięki czemu nadają się do różnych scenariuszy. Przyjrzyjmy się niektórym typom pamięci dostępnym w Langchain wraz z przykładami kodu.
1. Pamięć bufora rozmów
Ten typ pamięci umożliwia przechowywanie i wyodrębnianie wiadomości z rozmów. Możesz wyodrębnić historię jako ciąg znaków lub listę wiadomości.
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={})]}
Możesz także użyć pamięci bufora konwersacji w łańcuchu, aby uzyskać interakcje przypominające czat.
2. Pamięć okna bufora konwersacji
Ten typ pamięci przechowuje listę ostatnich interakcji i wykorzystuje K ostatnich interakcji, zapobiegając nadmiernemu zwiększeniu bufora.
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'}
Podobnie jak pamięć bufora konwersacji, tego typu pamięci można również używać w łańcuchu do interakcji przypominających czat.
3. Pamięć jednostki rozmowy
Ten typ pamięci zapamiętuje fakty dotyczące określonych podmiotów w rozmowie i wydobywa informacje za pomocą 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. Pamięć Grafu Wiedzy Rozmowy
Ten typ pamięci wykorzystuje wykres wiedzy do odtworzenia pamięci. Możesz wyodrębnić bieżące jednostki i trojaczki wiedzy z wiadomości.
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.'}
Możesz także użyć tego typu pamięci w łańcuchu do wyszukiwania wiedzy w oparciu o konwersację.
5. Pamięć podsumowania rozmowy
Ten typ pamięci tworzy podsumowanie rozmowy w czasie, przydatne do kondensowania informacji z dłuższych rozmów.
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. Pamięć buforowa podsumowania rozmów
Ten typ pamięci łączy podsumowanie rozmowy i bufor, zachowując równowagę pomiędzy ostatnimi interakcjami a podsumowaniem. Używa długości tokena, aby określić, kiedy opróżnić interakcje.
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'}
Możesz używać tych typów pamięci, aby usprawnić interakcje z modelami AI w Langchain. Każdy typ pamięci służy określonemu celowi i można go wybrać w zależności od wymagań.
7. Pamięć buforowa tokenów konwersacji
ConversationTokenBufferMemory to kolejny typ pamięci, który przechowuje w pamięci bufor ostatnich interakcji. W przeciwieństwie do poprzednich typów pamięci, które skupiają się na liczbie interakcji, ten wykorzystuje długość tokenu do określenia, kiedy należy opróżnić interakcje.
Korzystanie z pamięci w 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'}
W tym przykładzie pamięć jest ustawiona tak, aby ograniczać interakcje na podstawie długości tokenu, a nie liczby interakcji.
Jeśli używasz tego typu pamięci, możesz także uzyskać historię w postaci listy wiadomości.
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"})
Używanie w łańcuchu:
Możesz użyć ConversationTokenBufferMemory w łańcuchu, aby ulepszyć interakcje z modelem AI.
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?")
W tym przykładzie ConversationTokenBufferMemory jest używany w ConversationChain do zarządzania konwersacją i ograniczania interakcji na podstawie długości tokenu.
8. Pamięć VectorStoreRetriever
VectorStoreRetrieverMemory przechowuje wspomnienia w magazynie wektorów i przy każdym wywołaniu wysyła zapytania do najważniejszych dokumentów z najwyższej półki. Ten typ pamięci nie śledzi bezpośrednio kolejności interakcji, ale wykorzystuje pobieranie wektorów w celu pobrania odpowiednich wspomnień.
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"])
W tym przykładzie pamięć VectorStoreRetrieverMemory służy do przechowywania i pobierania odpowiednich informacji z konwersacji w oparciu o pobieranie wektorów.
Możesz także użyć VectorStoreRetrieverMemory w łańcuchu do wyszukiwania wiedzy w oparciu o konwersację, jak pokazano w poprzednich przykładach.
Te różne typy pamięci w Langchain zapewniają różne sposoby zarządzania informacjami z rozmów i wyszukiwania ich, zwiększając możliwości modeli sztucznej inteligencji w zakresie rozumienia zapytań użytkowników i kontekstu oraz odpowiadania na nie. Każdy typ pamięci można wybrać w oparciu o specyficzne wymagania aplikacji.
Teraz nauczymy się korzystać z pamięci w łańcuchu LLMCain. Pamięć w LLMChain pozwala modelowi zapamiętać poprzednie interakcje i kontekst, aby zapewnić bardziej spójne i świadome kontekstu odpowiedzi.
Aby skonfigurować pamięć w LLMChain, musisz utworzyć klasę pamięci, taką jak ConversationBufferMemory. Oto jak możesz to skonfigurować:
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")
W tym przykładzie ConversationBufferMemory służy do przechowywania historii konwersacji. The memory_key
Parametr określa klucz używany do przechowywania historii rozmów.
Jeśli używasz modelu czatu zamiast modelu w stylu uzupełniania, możesz inaczej strukturyzować podpowiedzi, aby lepiej wykorzystać pamięć. Oto przykład konfiguracji LLMCain opartego na modelu czatu z pamięcią:
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")
W tym przykładzie ChatPromptTemplate służy do strukturyzowania podpowiedzi, a ConversationBufferMemory służy do przechowywania i pobierania historii konwersacji. To podejście jest szczególnie przydatne w przypadku rozmów w stylu czatu, w których kontekst i historia odgrywają kluczową rolę.
Pamięć można także dodać do łańcucha zawierającego wiele danych wejściowych, takiego jak łańcuch pytań/odpowiedzi. Oto przykład konfiguracji pamięci w łańcuchu pytań/odpowiedzi:
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)
W tym przykładzie odpowiedź na pytanie jest udzielana przy użyciu dokumentu podzielonego na mniejsze części. ConversationBufferMemory służy do przechowywania i pobierania historii konwersacji, umożliwiając modelowi dostarczanie odpowiedzi uwzględniających kontekst.
Dodanie pamięci do agenta pozwala mu zapamiętać i wykorzystać poprzednie interakcje do udzielenia odpowiedzi na pytania i zapewnienia odpowiedzi uwzględniających kontekst. Oto jak skonfigurować pamięć w agencie:
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)
W tym przykładzie do agenta dodawana jest pamięć, która umożliwia mu zapamiętywanie historii poprzednich rozmów i dostarczanie odpowiedzi uwzględniających kontekst. Umożliwia to agentowi dokładne odpowiadanie na pytania uzupełniające w oparciu o informacje przechowywane w pamięci.
Język wyrażeń LangChain
W świecie przetwarzania języka naturalnego i uczenia maszynowego tworzenie złożonych łańcuchów operacji może być trudnym zadaniem. Na szczęście z pomocą przychodzi LangChain Expression Language (LCEL), zapewniając deklaratywny i skuteczny sposób budowania i wdrażania wyrafinowanych potoków przetwarzania języka. LCEL został zaprojektowany, aby uprościć proces komponowania łańcuchów, umożliwiając łatwe przejście od prototypu do produkcji. Na tym blogu dowiemy się, czym jest LCEL i dlaczego warto go używać, wraz z praktycznymi przykładami kodu ilustrującymi jego możliwości.
LCEL, czyli LangChain Expression Language, to potężne narzędzie do tworzenia łańcuchów przetwarzania języka. Został zaprojektowany specjalnie, aby płynnie wspierać przejście od prototypu do produkcji, bez konieczności rozległych zmian w kodzie. Niezależnie od tego, czy budujesz prosty łańcuch „prompt + LLM”, czy złożony potok składający się z setek kroków, LCEL zapewni Ci wszystko.
Oto kilka powodów, dla których warto używać języka LCEL w projektach przetwarzania języka:
- Szybkie przesyłanie tokenów: LCEL dostarcza tokeny z modelu języka do parsera wyjściowego w czasie rzeczywistym, poprawiając czas reakcji i wydajność.
- Wszechstronne interfejsy API: LCEL obsługuje zarówno synchroniczne, jak i asynchroniczne interfejsy API do prototypowania i zastosowań produkcyjnych, skutecznie obsługując wiele żądań.
- Automatyczna równoległość: LCEL optymalizuje wykonywanie równoległe, jeśli to możliwe, zmniejszając opóźnienia zarówno w interfejsach synchronizacyjnych, jak i asynchronicznych.
- Niezawodne konfiguracje: konfiguruj ponowne próby i awarie, aby zwiększyć niezawodność łańcucha na dużą skalę, z obsługą przesyłania strumieniowego w fazie rozwoju.
- Przesyłaj wyniki pośrednie: uzyskaj dostęp do wyników pośrednich podczas przetwarzania w celu aktualizacji użytkowników lub celów debugowania.
- Generowanie schematu: LCEL generuje schematy Pydantic i JSONSchema do sprawdzania poprawności danych wejściowych i wyjściowych.
- Kompleksowe śledzenie: LangSmith automatycznie śledzi wszystkie etapy złożonych łańcuchów w celu umożliwienia ich obserwacji i debugowania.
- Łatwe wdrażanie: wdrażaj łańcuchy utworzone za pomocą LCEL bez wysiłku, korzystając z LangServe.
Przyjrzyjmy się teraz praktycznym przykładom kodu, które demonstrują możliwości LCEL. Przyjrzymy się typowym zadaniom i scenariuszom, w których LCEL wyróżnia się.
Podpowiedź + LLM
Najbardziej podstawowa kompozycja polega na połączeniu podpowiedzi i modelu językowego w celu utworzenia łańcucha, który pobiera dane wejściowe użytkownika, dodaje je do podpowiedzi, przekazuje je do modelu i zwraca surowe dane wyjściowe modelu. Oto przykład:
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)
W tym przykładzie sieć generuje żart na temat niedźwiedzi.
Możesz dołączyć sekwencje zatrzymujące do swojego łańcucha, aby kontrolować sposób przetwarzania tekstu. Na przykład:
chain = prompt | model.bind(stop=["n"])
result = chain.invoke({"foo": "bears"})
print(result)
Ta konfiguracja zatrzymuje generowanie tekstu po napotkaniu znaku nowego wiersza.
LCEL obsługuje dołączanie informacji o wywołaniach funkcji do łańcucha. Oto przykład:
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)
W tym przykładzie załączono informacje o wywołaniu funkcji w celu wygenerowania żartu.
Podpowiedź + LLM + Parser wyjściowy
Możesz dodać analizator wyjściowy, aby przekształcić dane wyjściowe modelu surowego w bardziej wykonalny format. Oto jak możesz to zrobić:
from langchain.schema.output_parser import StrOutputParser chain = prompt | model | StrOutputParser()
result = chain.invoke({"foo": "bears"})
print(result)
Dane wyjściowe mają teraz format ciągu, co jest wygodniejsze w przypadku dalszych zadań.
Określając funkcję do zwrócenia, możesz ją przeanalizować bezpośrednio za pomocą języka LCEL. Na przykład:
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)
W tym przykładzie bezpośrednio analizujemy dane wyjściowe funkcji „żart”.
To tylko kilka przykładów tego, jak LCEL upraszcza złożone zadania przetwarzania języka. Niezależnie od tego, czy budujesz chatboty, generujesz treść, czy przeprowadzasz złożone transformacje tekstu, LCEL może usprawnić przepływ pracy i sprawić, że Twój kod będzie łatwiejszy w utrzymaniu.
RAG (generacja wspomagana odzyskiwaniem)
LCEL można wykorzystać do tworzenia łańcuchów generacji wspomaganych wyszukiwaniem, które łączą etapy wyszukiwania i generowania języka. Oto przykład:
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)
W tym przykładzie łańcuch wyszukuje istotne informacje z kontekstu i generuje odpowiedź na pytanie.
Łańcuch odzyskiwania konwersacji
Możesz łatwo dodać historię rozmów do swoich sieci. Oto przykład konwersacyjnego łańcucha wyszukiwania:
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)
W tym przykładzie sieć odpowiada na pytanie uzupełniające w kontekście konwersacyjnym.
Z pamięcią i powracającymi dokumentami źródłowymi
LCEL obsługuje także pamięć i zwrot dokumentów źródłowych. Oto jak możesz wykorzystać pamięć w łańcuchu:
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)
W tym przykładzie pamięć służy do przechowywania i pobierania historii rozmów oraz dokumentów źródłowych.
Wiele łańcuchów
Możesz połączyć wiele łańcuchów za pomocą Runnables. Oto przykład:
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)
W tym przykładzie dwa łańcuchy są łączone w celu wygenerowania informacji o mieście i jego kraju w określonym języku.
Rozgałęzianie i łączenie
LCEL umożliwia dzielenie i łączenie łańcuchów za pomocą RunnableMaps. Oto przykład rozgałęziania i łączenia:
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)
W tym przykładzie łańcuch rozgałęziania i łączenia służy do generowania argumentu i oceny jego zalet i wad przed wygenerowaniem ostatecznej odpowiedzi.
Pisanie kodu w Pythonie za pomocą LCEL
Jednym z potężnych zastosowań języka LangChain Expression Language (LCEL) jest pisanie kodu w języku Python w celu rozwiązywania problemów użytkowników. Poniżej znajduje się przykład użycia LCEL do napisania kodu w Pythonie:
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)
W tym przykładzie użytkownik wprowadza dane wejściowe, a LCEL generuje kod w języku Python w celu rozwiązania problemu. Kod jest następnie wykonywany przy użyciu języka Python REPL, a powstały kod języka Python jest zwracany w formacie Markdown.
Należy pamiętać, że użycie Pythona REPL może spowodować wykonanie dowolnego kodu, więc używaj go ostrożnie.
Dodawanie pamięci do łańcucha
Pamięć jest niezbędna w wielu konwersacyjnych zastosowaniach sztucznej inteligencji. Oto jak dodać pamięć do dowolnego łańcucha:
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({})
W tym przykładzie pamięć służy do przechowywania i pobierania historii rozmów, umożliwiając chatbotowi zachowanie kontekstu i odpowiednią reakcję.
Używanie narzędzi zewnętrznych z plikami wykonywalnymi
LCEL umożliwia bezproblemową integrację narzędzi zewnętrznych z Runnables. Oto przykład użycia narzędzia wyszukiwania 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)
W tym przykładzie LCEL integruje narzędzie DuckDuckGo Search z łańcuchem, umożliwiając wygenerowanie zapytania na podstawie danych wprowadzonych przez użytkownika i pobranie wyników wyszukiwania.
Elastyczność LCEL ułatwia włączanie różnych zewnętrznych narzędzi i usług do potoków przetwarzania języka, zwiększając ich możliwości i funkcjonalność.
Dodawanie moderacji do aplikacji LLM
Aby mieć pewność, że Twoja aplikacja LLM jest zgodna z polityką treści i zawiera zabezpieczenia moderacji, możesz zintegrować kontrole moderacji ze swoim łańcuchem. Oto jak dodać moderację za pomocą 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)
W tym przykładzie OpenAIModerationChain
służy do moderowania odpowiedzi generowanej przez LLM. Łańcuch moderacji sprawdza odpowiedź pod kątem treści naruszających politykę treści OpenAI. W przypadku wykrycia jakichkolwiek naruszeń odpowiedź zostanie odpowiednio oznaczona.
Routing według podobieństwa semantycznego
LCEL umożliwia implementację niestandardowej logiki routingu w oparciu o semantyczne podobieństwo danych wejściowych użytkownika. Oto przykład dynamicznego określania logiki łańcucha na podstawie danych wejściowych użytkownika:
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"}))
W tym przykładzie prompt_router
funkcja oblicza cosinus podobieństwa między danymi wprowadzonymi przez użytkownika a predefiniowanymi szablonami podpowiedzi dla pytań z fizyki i matematyki. Na podstawie wyniku podobieństwa sieć dynamicznie wybiera najodpowiedniejszy szablon podpowiedzi, zapewniając, że chatbot odpowiednio odpowie na pytanie użytkownika.
Korzystanie z agentów i obiektów wykonawczych
LangChain umożliwia tworzenie agentów poprzez łączenie elementów Runnable, podpowiedzi, modeli i narzędzi. Oto przykład budowania agenta i korzystania z niego:
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)
W tym przykładzie agent jest tworzony poprzez połączenie modelu, narzędzi, podpowiedzi i niestandardowej logiki dla etapów pośrednich i konwersji narzędzi. Następnie uruchamiany jest agent, który dostarcza odpowiedź na zapytanie użytkownika.
Zapytanie do bazy danych SQL
Możesz używać LangChain do wysyłania zapytań do bazy danych SQL i generowania zapytań SQL na podstawie pytań użytkowników. Oto przykład:
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)
W tym przykładzie LangChain służy do generowania zapytań SQL na podstawie pytań użytkowników i pobierania odpowiedzi z bazy danych SQL. Podpowiedzi i odpowiedzi są sformatowane tak, aby zapewnić interakcję z bazą danych w języku naturalnym.
Zautomatyzuj ręczne zadania i przepływy pracy za pomocą naszego narzędzia do tworzenia przepływów pracy opartego na sztucznej inteligencji, zaprojektowanego przez Nanonets dla Ciebie i Twoich zespołów.
LangServe i LangSmith
LangServe pomaga programistom wdrażać elementy uruchamialne i łańcuchy LangChain jako interfejs API REST. Ta biblioteka jest zintegrowana z FastAPI i wykorzystuje pydantic do sprawdzania poprawności danych. Dodatkowo zapewnia klienta, którego można używać do wywoływania elementów uruchamialnych wdrożonych na serwerze, a klient JavaScript jest dostępny w LangChainJS.
Korzyści
- Schematy wejściowe i wyjściowe są automatycznie pobierane z obiektu LangChain i egzekwowane przy każdym wywołaniu API, z rozbudowanymi komunikatami o błędach.
- Dostępna jest strona dokumentacji API z JSONSchema i Swagger.
- Wydajne punkty końcowe /invoke, /batch i /stream z obsługą wielu jednoczesnych żądań na jednym serwerze.
- Punkt końcowy /stream_log do przesyłania strumieniowego wszystkich (lub niektórych) kroków pośrednich z Twojego łańcucha/agenta.
- Strona placu zabaw w /playground z wyjściem przesyłania strumieniowego i etapami pośrednimi.
- Wbudowane (opcjonalne) śledzenie do LangSmith; po prostu dodaj swój klucz API (zobacz Instrukcje).
- Wszystko zbudowane przy użyciu sprawdzonych w boju bibliotek Pythona typu open source, takich jak FastAPI, Pydantic, uvloop i asyncio.
Ograniczenia
- Wywołania zwrotne klienta nie są jeszcze obsługiwane w przypadku zdarzeń pochodzących z serwera.
- Dokumenty OpenAPI nie będą generowane podczas korzystania z Pydantic V2. FastAPI nie obsługuje mieszania przestrzeni nazw Pythona v1 i v2. Więcej szczegółów znajdziesz w poniższej sekcji.
Użyj interfejsu CLI LangChain, aby szybko uruchomić projekt LangServe. Aby korzystać z interfejsu CLI langchain, upewnij się, że masz zainstalowaną najnowszą wersję langchain-cli. Możesz go zainstalować za pomocą pip install -U langchain-cli.
langchain app new ../path/to/directory
Szybko uruchom instancję LangServe dzięki szablonom LangChain. Więcej przykładów znajdziesz w indeksie szablonów lub w katalogu przykładów.
Oto serwer, który wdraża model czatu OpenAI, model czatu Anthropic i łańcuch, który wykorzystuje model Anthropic do opowiadania dowcipów na dany temat.
#!/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)
Po wdrożeniu powyższego serwera możesz przeglądać wygenerowane dokumenty OpenAPI, korzystając z:
curl localhost:8000/docs
Pamiętaj o dodaniu przyrostka /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" }])
W TypeScript (wymaga LangChain.js w wersji 0.0.166 lub nowszej):
import { RemoteRunnable } from "langchain/runnables/remote"; const chain = new RemoteRunnable({ url: `http://localhost:8000/chain/invoke/`,
});
const result = await chain.invoke({ topic: "cats",
});
Python używający żądań:
import requests
response = requests.post( "http://localhost:8000/chain/invoke/", json={'input': {'topic': 'cats'}}
)
response.json()
Możesz także użyć curl:
curl --location --request POST 'http://localhost:8000/chain/invoke/' --header 'Content-Type: application/json' --data-raw '{ "input": { "topic": "cats" } }'
Poniższy kod:
...
add_routes( app, runnable, path="/my_runnable",
)
dodaje te punkty końcowe do serwera:
- POST /my_runnable/invoke – wywołaj element uruchamialny na jednym wejściu
- POST /my_runnable/batch – wywołaj plik wykonywalny na partii danych wejściowych
- POST /my_runnable/stream – wywołaj na pojedynczym wejściu i przesyłaj strumieniowo wyjście
- POST /my_runnable/stream_log – wywołaj pojedyncze wejście i przesyłaj strumieniowo dane wyjściowe, w tym dane wyjściowe kroków pośrednich w miarę ich generowania
- GET /my_runnable/input_schema – schemat json dla danych wejściowych do pliku uruchamialnego
- GET /my_runnable/output_schema – schemat json dla wyjścia uruchamialnego
- GET /my_runnable/config_schema – schemat json do konfiguracji pliku uruchamialnego
Stronę placu zabaw dla swojego elementu uruchamialnego możesz znaleźć pod adresem /my_runnable/playground. Udostępnia to prosty interfejs użytkownika do konfigurowania i wywoływania elementu uruchamialnego z danymi wyjściowymi przesyłania strumieniowego i krokami pośrednimi.
Zarówno dla klienta, jak i serwera:
pip install "langserve[all]"
lub pip install „langserve[client]” dla kodu klienta i pip install „langserve[server]” dla kodu serwera.
Jeśli chcesz dodać uwierzytelnianie do swojego serwera, zapoznaj się z dokumentacją bezpieczeństwa FastAPI i dokumentacją oprogramowania pośredniego.
Możesz wdrożyć usługę w GCP Cloud Run za pomocą następującego polecenia:
gcloud run deploy [your-service-name] --source . --port 8001 --allow-unauthenticated --region us-central1 --set-env-vars=OPENAI_API_KEY=your_key
LangServe zapewnia obsługę Pydantic 2 z pewnymi ograniczeniami. Dokumenty OpenAPI nie będą generowane dla invoke/batch/stream/stream_log podczas korzystania z Pydantic V2. Fast API nie obsługuje mieszania przestrzeni nazw pydantic v1 i v2. LangChain używa przestrzeni nazw v1 w Pydantic v2. Prosimy o zapoznanie się z poniższymi wytycznymi, aby zapewnić kompatybilność z LangChain. Z wyjątkiem tych ograniczeń oczekujemy, że punkty końcowe interfejsu API, plac zabaw i wszelkie inne funkcje będą działać zgodnie z oczekiwaniami.
Aplikacje LLM często zajmują się plikami. Istnieją różne architektury, które można zastosować w celu wdrożenia przetwarzania plików; na wysokim poziomie:
- Plik może zostać przesłany na serwer poprzez dedykowany punkt końcowy i przetworzony na oddzielnym punkcie końcowym.
- Plik może zostać przesłany albo poprzez wartość (bajty pliku), albo przez odniesienie (np. adres URL s3 do zawartości pliku).
- Punkt końcowy przetwarzania może blokować lub nie blokować.
- Jeśli wymagane jest znaczące przetwarzanie, przetwarzanie można przenieść do dedykowanej puli procesów.
Powinieneś określić, która architektura jest odpowiednia dla Twojej aplikacji. Obecnie, aby przesłać pliki według wartości do pliku uruchamialnego, użyj dla pliku kodowania Base64 (dane wieloczęściowe/formularze nie są jeszcze obsługiwane).
Oto przykład który pokazuje, jak używać kodowania base64 do wysyłania pliku do zdalnego uruchomienia. Pamiętaj, że zawsze możesz przesłać pliki przez odniesienie (np. adres URL s3) lub przesłać je jako dane wieloczęściowe/formularz do dedykowanego punktu końcowego.
Typy wejść i wyjść są zdefiniowane dla wszystkich elementów uruchamialnych. Dostęp do nich można uzyskać poprzez właściwości input_schema i Output_schema. LangServe używa tych typów do sprawdzania poprawności i dokumentacji. Jeśli chcesz zastąpić domyślne wywnioskowane typy, możesz użyć metody with_types.
Oto przykład zabawki ilustrujący ten pomysł:
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)
Dziedzicz z CustomUserType, jeśli chcesz, aby dane deserializowały się do modelu pydantycznego, a nie do równoważnej reprezentacji dyktowanej. W tej chwili ten typ działa tylko po stronie serwera i służy do określenia pożądanego zachowania dekodowania. Jeśli dziedziczysz z tego typu, serwer zachowa zdekodowany typ jako model pydantyczny, zamiast konwertować go na dyktando.
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")
Plac zabaw umożliwia definiowanie niestandardowych widżetów dla uruchamianych z poziomu zaplecza. Widget jest określany na poziomie pola i dostarczany jako część schematu JSON typu wejściowego. Widżet musi zawierać klucz o nazwie type, którego wartość znajduje się na dobrze znanej liście widżetów. Inne klucze widgetu zostaną powiązane z wartościami opisującymi ścieżki w obiekcie JSON.
Schemat ogólny:
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;
};
Umożliwia utworzenie danych wejściowych przesyłania plików na placu zabaw interfejsu użytkownika dla plików przesyłanych jako ciągi zakodowane w standardzie Base64. Oto pełny przykład.
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
Zautomatyzuj ręczne zadania i przepływy pracy za pomocą naszego narzędzia do tworzenia przepływów pracy opartego na sztucznej inteligencji, zaprojektowanego przez Nanonets dla Ciebie i Twoich zespołów.
Wprowadzenie do LangSmitha
LangChain ułatwia prototypowanie aplikacji i agentów LLM. Jednak dostarczanie aplikacji LLM do produkcji może być zwodniczo trudne. Prawdopodobnie będziesz musiał w dużym stopniu dostosowywać i powtarzać monity, łańcuchy i inne komponenty, aby stworzyć produkt wysokiej jakości.
Aby wspomóc ten proces, wprowadzono LangSmith – ujednoliconą platformę do debugowania, testowania i monitorowania aplikacji LLM.
Kiedy może się to przydać? Może się to okazać przydatne, gdy chcesz szybko debugować nowy łańcuch, agenta lub zestaw narzędzi, wizualizować, w jaki sposób komponenty (łańcuchy, llm, retrievery itp.) są ze sobą powiązane i są używane, oceniać różne podpowiedzi i LLM dla pojedynczego komponentu, przeprowadź dany łańcuch kilka razy na zbiorze danych, aby upewnić się, że konsekwentnie spełnia on pasek jakości, lub przechwyć ślady użytkowania i wykorzystaj LLM lub potoki analityczne do wygenerowania spostrzeżeń.
Wymagania wstępne:
- Utwórz konto LangSmith i utwórz klucz API (patrz lewy dolny róg).
- Zapoznaj się z platformą przeglądając dokumentację.
A teraz zaczynajmy!
Najpierw skonfiguruj zmienne środowiskowe, aby poinformować LangChain o rejestrowaniu śladów. Odbywa się to poprzez ustawienie zmiennej środowiskowej LANGCHAIN_TRACING_V2 na wartość true. Możesz powiedzieć LangChainowi, do którego projektu ma się logować, ustawiając zmienną środowiskową LANGCHAIN_PROJECT (jeśli nie jest ona ustawiona, uruchomienia będą rejestrowane w projekcie domyślnym). Spowoduje to automatyczne utworzenie projektu dla Ciebie, jeśli nie istnieje. Musisz także ustawić zmienne środowiskowe LANGCHAIN_ENDPOINT i LANGCHAIN_API_KEY.
UWAGA: Możesz także użyć menedżera kontekstu w Pythonie do rejestrowania śladów za pomocą:
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?")
Jednak w tym przykładzie użyjemy zmiennych środowiskowych.
%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>"
Utwórz klienta LangSmith do interakcji z API:
from langsmith import Client client = Client()
Utwórz komponent LangChain i zarejestruj przebiegi na platformie. W tym przykładzie utworzymy agenta w stylu ReAct z dostępem do ogólnego narzędzia wyszukiwania (DuckDuckGo). Podpowiedzi agenta można wyświetlić w Hubie tutaj:
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
)
Aby zmniejszyć opóźnienia, uruchamiamy agenta jednocześnie na wielu wejściach. Uruchomienia są rejestrowane w LangSmith w tle, więc nie ma to wpływu na opóźnienie wykonania:
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]
Zakładając, że środowisko zostało pomyślnie skonfigurowane, ślady agenta powinny pojawić się w aplikacji w sekcji Projekty. Gratulacje!
Wygląda jednak na to, że agent nie wykorzystuje skutecznie narzędzi. Oceńmy to, abyśmy mieli punkt odniesienia.
Oprócz rejestrowania przebiegów LangSmith umożliwia także testowanie i ocenę aplikacji LLM.
W tej sekcji wykorzystasz LangSmith do utworzenia zbioru danych porównawczych i uruchomienia na agencie narzędzi ewaluacyjnych wspomaganych sztuczną inteligencją. Zrobisz to w kilku krokach:
- Utwórz zbiór danych LangSmith:
Poniżej używamy klienta LangSmith do utworzenia zestawu danych na podstawie powyższych pytań wejściowych i etykiet list. Wykorzystasz je później do pomiaru wydajności nowego agenta. Zbiór danych to zbiór przykładów, które są niczym więcej niż parami wejścia-wyjścia, których możesz użyć jako przypadków testowych swojej aplikacji:
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 )
- Zainicjuj nowego agenta w celu przeprowadzenia testu porównawczego:
LangSmith pozwala ocenić dowolną LLM, łańcuch, agenta, a nawet funkcję niestandardową. Agenci konwersacyjni są stanowi (mają pamięć); aby mieć pewność, że ten stan nie będzie współdzielony pomiędzy uruchomieniami zestawu danych, przekażemy chain_factory (
czyli konstruktor) do inicjowania każdego wywołania:
# 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)
- Skonfiguruj ocenę:
Ręczne porównywanie wyników łańcuchów w interfejsie użytkownika jest skuteczne, ale może być czasochłonne. Pomocne może być użycie zautomatyzowanych wskaźników i informacji zwrotnych wspomaganych sztuczną inteligencją do oceny wydajności komponentu:
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=[],
)
- Uruchom agenta i ewaluatory:
Użyj funkcji run_on_dataset (lub asynchronicznej arun_on_dataset), aby ocenić swój model. To będzie:
- Pobierz przykładowe wiersze z określonego zestawu danych.
- Uruchom agenta (lub dowolną funkcję niestandardową) w każdym przykładzie.
- Zastosuj ewaluatory do powstałych śladów przebiegów i odpowiednich przykładów referencyjnych, aby wygenerować automatyczną informację zwrotną.
Wyniki będą widoczne w aplikacji 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", ],
)
Teraz, gdy mamy już wyniki testów, możemy wprowadzić zmiany w naszym agencie i przeprowadzić dla nich testy porównawcze. Spróbujmy jeszcze raz z innym monitem i zobaczmy rezultaty:
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 umożliwia eksport danych do popularnych formatów, takich jak CSV lub JSONL, bezpośrednio w aplikacji internetowej. Możesz także użyć klienta do pobrania przebiegów do dalszej analizy, przechowywania we własnej bazie danych lub udostępniania innym. Pobierzmy ślady przebiegu z przebiegu ewaluacyjnego:
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
Był to krótki przewodnik na początek, ale istnieje wiele innych sposobów wykorzystania LangSmith w celu przyspieszenia pracy programistów i uzyskania lepszych wyników.
Aby uzyskać więcej informacji na temat maksymalnego wykorzystania możliwości LangSmith, zapoznaj się z dokumentacją LangSmith.
Zwiększ poziom dzięki Nanonets
Chociaż LangChain jest cennym narzędziem do integracji modeli językowych (LLM) z aplikacjami, może napotkać ograniczenia w przypadku zastosowań korporacyjnych. Przyjrzyjmy się, w jaki sposób Nanonets wykracza poza LangChain, aby sprostać tym wyzwaniom:
1. Kompleksowa łączność danych:
LangChain oferuje złącza, ale może nie obejmować wszystkich aplikacji obszaru roboczego i formatów danych, z których korzystają firmy. Nanonets zapewnia łączniki danych dla ponad 100 powszechnie używanych aplikacji do pracy, w tym Slack, Notion, Google Suite, Salesforce, Zendesk i wielu innych. Obsługuje także wszystkie nieustrukturyzowane typy danych, takie jak pliki PDF, TXT, obrazy, pliki audio i pliki wideo, a także ustrukturyzowane typy danych, takie jak pliki CSV, arkusze kalkulacyjne, MongoDB i bazy danych SQL.
2. Automatyzacja zadań dla aplikacji Workspace:
O ile generowanie tekstu/odpowiedzi działa świetnie, możliwości LangChaina są ograniczone, jeśli chodzi o używanie języka naturalnego do wykonywania zadań w różnych aplikacjach. Nanonets oferuje agenty wyzwalające/akcji dla najpopularniejszych aplikacji obszaru roboczego, umożliwiając konfigurowanie przepływów pracy, które nasłuchują zdarzeń i wykonują akcje. Na przykład możesz zautomatyzować odpowiedzi na e-mail, wpisy CRM, zapytania SQL i inne, a wszystko to za pomocą poleceń w języku naturalnym.
3. Synchronizacja danych w czasie rzeczywistym:
LangChain pobiera dane statyczne za pomocą łączników danych, które mogą nie nadążać za zmianami danych w źródłowej bazie danych. Natomiast Nanonets zapewnia synchronizację w czasie rzeczywistym ze źródłami danych, dzięki czemu zawsze pracujesz z najnowszymi informacjami.
3. Uproszczona konfiguracja:
Konfigurowanie elementów potoku LangChain, takich jak retrievery i syntezatory, może być procesem złożonym i czasochłonnym. Nanonets usprawnia to, zapewniając zoptymalizowane pozyskiwanie i indeksowanie danych dla każdego typu danych, a wszystko to obsługiwane w tle przez Asystenta AI. Zmniejsza to obciążenie związane z dostrajaniem i ułatwia konfigurację i użytkowanie.
4. Ujednolicone rozwiązanie:
W przeciwieństwie do LangChain, który może wymagać unikalnych implementacji dla każdego zadania, Nanonets służy jako kompleksowe rozwiązanie do łączenia danych z LLM. Niezależnie od tego, czy chcesz tworzyć aplikacje LLM, czy przepływy pracy AI, Nanonets oferuje ujednoliconą platformę dla Twoich różnorodnych potrzeb.
Przepływy pracy związane z sztuczną inteligencją Nanonets
Nanonets Workflows to bezpieczny, wielofunkcyjny asystent AI, który upraszcza integrację wiedzy i danych z LLM oraz ułatwia tworzenie aplikacji i przepływów pracy bez kodu. Oferuje łatwy w użyciu interfejs użytkownika, dzięki czemu jest dostępny zarówno dla osób prywatnych, jak i organizacji.
Na początek możesz umówić się na rozmowę z jednym z naszych ekspertów ds. sztucznej inteligencji, który może zapewnić spersonalizowaną wersję demonstracyjną i wersję próbną przepływów pracy Nanonets dostosowanych do konkretnego przypadku użycia.
Po skonfigurowaniu możesz używać języka naturalnego do projektowania i wykonywania złożonych aplikacji i przepływów pracy obsługiwanych przez LLM, płynnie integrując się z aplikacjami i danymi.
Wzmocnij swoje zespoły dzięki Nanonets AI, aby tworzyć aplikacje i integrować dane z aplikacjami i przepływami pracy opartymi na sztucznej inteligencji, dzięki czemu Twoje zespoły mogą skupić się na tym, co naprawdę ważne.
Zautomatyzuj ręczne zadania i przepływy pracy za pomocą naszego narzędzia do tworzenia przepływów pracy opartego na sztucznej inteligencji, zaprojektowanego przez Nanonets dla Ciebie i Twoich zespołów.
- Dystrybucja treści i PR oparta na SEO. Uzyskaj wzmocnienie już dziś.
- PlatoData.Network Pionowe generatywne AI. Wzmocnij się. Dostęp tutaj.
- PlatoAiStream. Inteligencja Web3. Wiedza wzmocniona. Dostęp tutaj.
- PlatonESG. Węgiel Czysta technologia, Energia, Środowisko, Słoneczny, Gospodarowanie odpadami. Dostęp tutaj.
- Platon Zdrowie. Inteligencja w zakresie biotechnologii i badań klinicznych. Dostęp tutaj.
- Źródło: https://nanonets.com/blog/langchain/
- :ma
- :Jest
- :nie
- :Gdzie
- $W GÓRĘ
- 1
- 10
- 100
- 114
- 13
- 15%
- 2000
- 2012
- 2023
- 25
- 30
- 32
- 36
- 40
- 400
- 408
- 50
- 500
- 7
- 8
- a
- ABC
- zdolność
- Zdolny
- O nas
- o tym
- powyżej
- Akceptuj
- Akceptuje
- dostęp
- dostępny
- Dostęp
- wykonać
- odpowiednio
- Konto
- precyzja
- dokładny
- dokładnie
- Osiągać
- osiągnięty
- Osiąga
- w poprzek
- działać
- Działania
- działania
- aktywny
- adaptacja
- adaptive
- Dodaj
- w dodatku
- dodanie
- dodatek
- Dodatkowy
- do tego
- adres
- Dodaje
- przyznać
- zaawansowany
- Szosowe
- Po
- ponownie
- wiek
- Agent
- agentów
- AI
- Asystent AI
- Modele AI
- AID
- Cel
- Algorytmy
- wyrównać
- Wyrównuje
- Wszystkie kategorie
- dopuszczać
- Pozwalać
- pozwala
- sam
- wzdłuż
- wzdłuż
- już
- również
- Chociaż
- zawsze
- an
- analiza
- Analityczny
- analityka
- i
- Angeles
- Ogłosić
- roczny
- Inne
- odpowiedź
- odpowiedzi
- hymn
- Antropiczny
- każdy
- wszystko
- api
- KLUCZE API
- Pszczoła
- Aplikacja
- odpowiedni
- Zastosowanie
- Application Development
- aplikacje
- stosowany
- dotyczy
- podejście
- awanse
- właściwy
- odpowiednio
- mobilne i webowe
- architektura
- SĄ
- argument
- argumenty
- Armstrong
- na około
- Szyk
- Artyści
- AS
- zapytać
- aspekt
- aspekty
- pomagać
- Asystent
- powiązany
- At
- dołączać
- Uwaga
- audio
- zwiększona
- Uwierzytelnianie
- zautomatyzować
- zautomatyzowane
- automaty
- automatycznie
- Automatyzacja
- dostępny
- średni
- oczekiwać
- świadomy
- AWS
- z powrotem
- Kręgosłup
- Backend
- tło
- źle
- Bilans
- bar
- baza
- na podstawie
- Baseline
- bash
- podstawowy
- Podstawy
- BCG
- BE
- Plaża
- Niedźwiedzie
- bo
- być
- zanim
- rozpocząć
- zachowanie
- za
- za kulisami
- jest
- poniżej
- Benchmark
- korzystny
- BEST
- Ulepsz Swój
- pomiędzy
- Poza
- Najwyższa
- Rachunek
- Bill Gates
- związania
- Bing
- Bit
- Czarny
- Black Hole
- Blokować
- bloking
- Bloki
- Blog
- bob
- Bootstrap
- urodzony
- Bot
- obie
- Dolny
- Oddział
- przerwa
- wiatr
- krótko
- szerszy
- brązowy
- przeglądarka
- bufor
- budować
- budowniczy
- Budowanie
- wybudowany
- ciężar
- biznes
- ale
- by
- obliczać
- oblicza
- obliczenie
- obliczenie
- wezwanie
- oddzwanianie
- nazywa
- powołanie
- Połączenia
- CAN
- Może uzyskać
- Kanada
- możliwości
- zdolny
- Pojemność
- zdobyć
- Przechwytywanie
- walizka
- Etui
- CAT
- zaopatrywać
- catering
- caters
- koty
- ostrożność
- ostrożny
- wyśrodkowany
- pewien
- łańcuch
- więzy
- wyzwania
- Zmiany
- charakter
- chatbot
- nasze chatboty
- ZOBACZ
- Wykrywanie urządzeń szpiegujących
- Dodaj
- wybrany
- okoliczności
- Miasto
- klasa
- Klasy
- klient
- Chmura
- kod
- Kodowanie
- Kawa
- ZGODNY
- spoisty
- współpracować
- Zawalić się
- kolekcja
- kolorowy
- Kolumna
- kolumny
- COM
- połączyć
- połączony
- kombajny
- łączenie
- jak
- byliśmy spójni, od początku
- wygodny
- wspólny
- Komunikacja
- sukcesy firma
- porównać
- porównanie
- zgodność
- zgodny
- kompletny
- całkowicie
- ukończenia
- kompleks
- złożoności
- składnik
- składniki
- w składzie
- skład
- wszechstronny
- obejmujący
- pojęcie
- zwięzły
- równoległy
- warunek
- systemu
- zbieg
- Skontaktuj się
- Podłączanie
- Łączność
- Wady
- Rozważać
- konsekwentnie
- składa się
- Konsola
- stale
- konstrukty
- zawierać
- zawiera
- zawartość
- kontekst
- konteksty
- kontekstowy
- kontynuować
- bez przerwy
- kontrast
- kontrola
- kontroli
- Wygodny
- Rozmowa
- konwersacyjny
- konwersacyjna sztuczna inteligencja
- rozmowy
- Konwersja
- przeliczone
- 轉換
- rdzeń
- Corner
- skorygowania
- Odpowiedni
- mógłby
- rachunkowość
- kraj
- Para
- pokrywa
- pokryty
- Stwórz
- stworzony
- tworzy
- Tworzenie
- tworzenie
- Listy uwierzytelniające
- Kryteria
- Krytyk
- CRM
- istotny
- Aktualny
- Obecnie
- zwyczaj
- Klientów
- dostosowywanie
- dostosować
- dostosowane
- pionierski nowatorski
- dane
- Struktura danych
- Baza danych
- Bazy danych
- Data
- data i godzina
- sprawa
- czynienia
- grudzień
- zdecydować
- Decydowanie
- Podejmowanie decyzji
- Rozszyfrowanie
- dedykowane
- głębiej
- Domyślnie
- określić
- zdefiniowane
- definiowanie
- definicje
- dostarczanie
- dostarcza
- sięgać
- próbny
- wykazać
- wykazać
- demonstrowanie
- zależeć
- W zależności
- zależy
- rozwijać
- wdrażane
- wdrażanie
- Wdrożenie
- wdraża się
- opisać
- opis
- Wnętrze
- wyznaczony
- zaprojektowany
- życzenia
- detal
- szczegółowe
- detale
- Ustalać
- określa
- rozwijać
- Deweloper
- deweloperzy
- rozwijanie
- oprogramowania
- schematy
- DICT
- ZROBIŁ
- różnić się
- różne
- różnie
- trudny
- Wymiary
- Wymiary
- Dyrektywy
- bezpośrednio
- dyskutować
- omówione
- wyświetlanie
- odrębny
- nurkować
- inny
- DM
- do
- dokument
- dokumentacja
- dokumenty
- robi
- robi
- robi
- darowizna
- zrobić
- Podwójna
- na dół
- pobieranie
- pliki do pobrania
- projekt
- napęd
- z powodu
- podczas
- dynamiczny
- dynamicznie
- e
- każdy
- Wcześniej
- Wcześnie
- łatwość
- łatwość użycia
- łatwiej
- z łatwością
- łatwo
- łatwy w użyciu
- przegapić
- Ekosystem
- Efektywne
- faktycznie
- efektywność
- wydajny
- skutecznie
- bez wysiłku
- bądź
- element
- Elementy
- Elon
- Elon Musk
- więcej
- osadzać
- osadzone
- osadzanie
- zatrudniony
- pracowników
- zatrudnia
- upoważniać
- umożliwiać
- Umożliwia
- umożliwiając
- kapsułkuje
- spotkanie
- koniec końców
- Punkt końcowy
- ujmujący
- silnik
- silniki
- Anglia
- Angielski
- Angielska Premier League
- wzmacniać
- wzmocnione
- wzmocnienie
- zapewnić
- zapewnia
- zapewnienie
- Enterprise
- podmioty
- jednostka
- Środowisko
- środowiska
- Równoważny
- Era
- błąd
- Błędy
- szczególnie
- niezbędny
- wyobcowany
- itp
- oceniać
- ewaluację
- Parzyste
- wydarzenia
- Każdy
- przykład
- przykłady
- przekraczać
- Z wyjątkiem
- wykonać
- wykonany
- Wykonuje
- wykonywania
- egzekucja
- stanowi przykład
- Ćwiczenie
- istnieć
- oczekiwać
- oczekiwania
- spodziewany
- oczekuje
- doświadczenie
- eksperymentalny
- eksperci
- wyjaśnione
- Objaśnia
- wyraźnie
- eksploracja
- odkryj
- zbadane
- eksport
- wyrażenie
- rozciągać się
- rozsuwalny
- rozległy
- zewnętrzny
- dodatkowy
- wyciąg
- ekstrakcja
- Wyciągi
- Twarz
- ułatwiać
- ułatwia
- fabryka
- fakty
- daleko
- FAST
- Moja lista
- Cecha
- Korzyści
- informacja zwrotna
- kilka
- pole
- Łąka
- figa
- Postać
- filet
- Akta
- wypełniać
- wypełniony
- Nadzienie
- filtrować
- filtracja
- finał
- W końcu
- Znajdź
- znalezieniu
- i terminów, a
- pięć
- Elastyczność
- elastyczne
- pływ
- Skupiać
- koncentruje
- koncentruje
- skupienie
- obserwuj
- następujący
- następujący sposób
- jedzenie
- W razie zamówieenia projektu
- Nasz formularz
- format
- utworzony
- na szczęście
- znaleziono
- Framework
- Ramy
- często
- przyjaciel
- przyjaciele
- od
- pełny
- pełnoprawny
- funkcjonować
- funkcjonalności
- Funkcjonalność
- Funkcje
- fundamentalny
- zabawny
- dalej
- przyszłość
- Wzrost
- Games
- Bramy
- Ogólne
- ogólnie
- Generować
- wygenerowane
- generuje
- generujący
- generacja
- rodzaj
- Niemcy
- otrzymać
- miejsce
- gif
- GitHub
- dany
- GMT
- Go
- Goes
- będzie
- dobry
- ziarnisty
- wykres
- wspaniały
- większy
- poradnictwo
- poprowadzi
- wytyczne
- hackathon
- uchwyt
- Uchwyty
- Prowadzenie
- poręczny
- Ciężko
- zaszkodzić
- uprzęże
- Have
- mający
- ciężko
- Trzymany
- pomoc
- pomocny
- pomaga
- jej
- tutaj
- hi
- Wysoki
- na wysokim szczeblu
- wysokiej jakości
- Najwyższa
- wysoko
- historyczny
- historia
- Otwór
- kaptur
- gospodarz
- W jaki sposób
- How To
- Jednak
- HTML
- http
- HTTPS
- Piasta
- człowiek
- Setki
- i
- ID
- pomysł
- idealny
- ids
- if
- ii
- iii
- zilustrować
- ilustruje
- zdjęcia
- Natychmiastowy
- wdrożenia
- realizacja
- wdrożenia
- realizowane
- importować
- ulepszenia
- poprawy
- in
- informacje
- zawierać
- włączony
- obejmuje
- Włącznie z
- włączać
- włączenie
- niewiarygodnie
- wskaźnik
- indeksy
- wskazać
- wskazuje
- Indywidualnie
- osób
- Informacja
- początkowy
- zainicjować
- Innowacyjny
- wkład
- Wejścia
- spostrzeżenia
- zainstalować
- zainstalowany
- Instalacja
- przykład
- natychmiastowy
- zamiast
- instrukcje
- integralny
- integrować
- zintegrowany
- Integruje się
- Integracja
- integracja
- integracje
- Inteligentny
- zamierzony
- interakcji
- wzajemne oddziaływanie
- Interakcje
- interaktywne
- współdziała
- Interfejs
- interfejsy
- wewnętrznie
- Internet
- najnowszych
- wprowadzono
- Przedstawia
- intuicyjny
- z udziałem
- ISN
- problem
- problemy
- IT
- szt
- iteracje
- JEGO
- samo
- Jackson
- JAVASCRIPT
- Praca
- Jordania
- podróż
- json
- lipiec
- właśnie
- PRAWO
- Trzymać
- utrzymuje
- Klawisz
- Klawisze
- Uprzejmy
- Wiedzieć
- wiedza
- Wykres Wiedza
- znany
- Etykieta
- Etykiety
- Kraj
- język
- Języki
- duży
- większe
- Nazwisko
- Utajenie
- później
- firmy
- Liga
- UCZYĆ SIĘ
- nauka
- lewo
- Dziedzictwo
- Długość
- mniej
- niech
- pozwala
- list
- poziom
- poziomy
- Dźwignia
- wykorzystuje
- lewarowanie
- biblioteki
- Biblioteka
- lubić
- Prawdopodobnie
- LIMIT
- Ograniczenia
- Ograniczony
- ograniczenie
- Limity
- linki
- Lista
- słuchać
- wykazy
- relacja na żywo
- ll
- LLM
- załadować
- ładowarka
- usytuowany
- lokalizacja
- log
- zalogowany
- zalogowaniu
- logika
- długo
- dłużej
- Popatrz
- poszukuje
- WYGLĄD
- wyszukiwania
- im
- Los Angeles
- niski
- maszyna
- uczenie maszynowe
- zrobiony
- utrzymać
- Utrzymywane w utrzymaniu
- Utrzymywanie
- utrzymuje
- robić
- WYKONUJE
- Dokonywanie
- zarządzanie
- i konserwacjami
- kierownik
- zarządzający
- Manchester
- Manchester United
- Manipulacja
- sposób
- podręcznik
- Producent
- wiele
- wielu ludzi
- mapa
- mapowanie
- Mapy
- Mecz
- dopasowywanie
- matematyka
- matematyczny
- Matters
- maksymalny
- Może..
- me
- oznaczać
- znaczenie
- znaczy
- zmierzyć
- Media
- Spotkanie
- Spełnia
- wspomnienia
- Pamięć
- wzmiankowany
- Łączyć
- połączenie
- wiadomość
- wiadomości
- wiadomości
- Metadane
- metoda
- metody
- Metryka
- może
- miliony
- minimalny
- moll
- brakujący
- błędy
- Mieszanie
- MLB
- Aplikacje mobilne
- model
- modele
- umiar
- Moduł
- Moduły
- moment
- MongoDB
- monitor
- monitorowanie
- Księżyc
- jeszcze
- większość
- Najbardziej popularne posty
- ruch
- film
- dużo
- wielokrotność
- wiele łańcuchów
- Piżmo
- musi
- my
- Nazwa
- O imieniu
- Nazwy
- narodowy
- Naturalny
- Przetwarzanie języka naturalnego
- Nawigacja
- żeglujący
- Blisko
- niezbędny
- Potrzebować
- potrzebne
- wymagania
- ujemny
- Nowości
- I Love New York
- New York Times
- Następny
- Nie
- żaden
- nic
- Pojęcie
- już dziś
- numer
- Obama
- przedmiot
- cel
- obiekty
- obserwacja
- uzyskać
- uzyskiwanie
- OCR
- of
- oferta
- oferuje
- Oferty
- często
- oh
- W porządku
- Igrzyska Olimpijskie
- on
- pewnego razu
- ONE
- tylko
- open source
- OpenAI
- operacje
- operator
- zoptymalizowane
- Optymalizuje
- Option
- or
- zamówienie
- organiczny
- organizacji
- oryginalny
- OS
- Inne
- Pozostałe
- Inaczej
- ludzkiej,
- na zewnątrz
- wydajność
- Wyjścia
- koniec
- Zastąp
- przegląd
- własny
- pakiet
- Pakiety
- strona
- stron
- par
- pandy
- Papier
- Parallel
- parametr
- parametry
- Park
- część
- szczególnie
- strony
- przechodzić
- minęło
- przebiegi
- Przechodzący
- Przeszłość
- ścieżka
- ścieżki
- wzory
- Lista płac
- Ludzie
- dla
- doskonały
- doskonale
- wykonać
- jest gwarancją najlepszej jakości, które mogą dostarczyć Ci Twoje monitory,
- wykonywania
- wykonuje
- uprawnienia
- uporczywość
- osoba
- Personalizowany
- perspektywa
- Fizyka
- kawałek
- rurociąg
- Pizza
- zastępczy
- Platforma
- plato
- Analiza danych Platona
- PlatoDane
- Grać
- plac zabaw dla dzieci
- odgrywa
- Proszę
- plus
- punkt
- polityka
- polityka
- polityczny
- basen
- Popularny
- zaludniony
- pozytywny
- możliwy
- Post
- Wiadomości
- potencjał
- power
- powered
- mocny
- Praktyczny
- praktyka
- woleć
- premier
- teraźniejszość
- prezydent
- zapobiec
- zapobieganie
- poprzedni
- głównie
- pierwotny
- premia
- prywatny
- Problem
- problemy
- kontynuować
- wygląda tak
- Obrobiony
- procesów
- przetwarzanie
- produkować
- Produkt
- Produkcja
- Profesor
- Programowanie
- języki programowania
- projekt
- projektowanie
- niska zabudowa
- własność
- PROS
- prototyp
- prototypowanie
- zapewniać
- pod warunkiem,
- dostawca
- dostawców
- zapewnia
- że
- publiczny
- cel
- cele
- położyć
- Python
- Q & A
- jakość
- zapytania
- pytanie
- pytania
- Szybki
- szybko
- cytaty
- R
- podnieść
- zasięg
- nośny
- raczej
- ocena
- Surowy
- RE
- dosięgnąć
- React
- Czytaj
- Czytający
- gotowy
- real
- w czasie rzeczywistym
- dane w czasie rzeczywistym
- królestwo
- powód
- Przyczyny
- niedawny
- Zalecana
- nagrany
- dokumentacja
- Recover
- zmniejszyć
- zmniejsza
- redukcja
- redukcja
- odniesienie
- odwoływanie się
- oczyścić
- rafinacja
- regiony
- Relacje
- wydany
- mających znaczenie
- niezawodność
- rzetelny
- polegać
- opierając się
- szczątki
- pamiętać
- przypomnienie
- zdalny
- oddać
- powtarzać
- WIELOKROTNIE
- przeformułowanie
- obsługi produkcji rolnej, która zastąpiła
- raport
- składnica
- reprezentacja
- reprezentowanie
- reprezentuje
- zażądać
- wywołań
- wymagać
- wymagany
- wymagania
- Wymaga
- ratowanie
- Badania naukowe
- rozwiązać
- Zasób
- Odpowiadać
- odpowiadanie
- odpowiedź
- Odpowiedzi
- odpowiedzialny
- czuły
- REST
- dalsze
- wynikły
- Efekt
- wspornikowy
- retencja
- powrót
- powrót
- powraca
- wielokrotnego użytku
- przeglądu
- kręci się
- Ryż
- Bogaty
- roboty
- Rola
- role
- korzeń
- Routing
- RZĄD
- run
- bieganie
- działa
- Czas
- s
- zabezpieczenia
- sole
- sprzedawca
- Sam
- taki sam
- Zapisz
- powiedzieć
- mówią
- skalowalny
- Skala
- scenariusz
- scenariusze
- Sceny
- rozkład
- wynik
- zadraśnięcie
- bezszwowy
- płynnie
- Szukaj
- Wyszukiwarka
- wyszukiwania
- poszukiwania
- Sekcja
- działy
- bezpieczne
- bezpieczeństwo
- widzieć
- wybrany
- wybór
- Sprzedawanie
- wysłać
- wrażliwy
- sentyment
- uczucia
- oddzielny
- wrzesień
- Sekwencja
- Serie
- służyć
- serwer
- służy
- Usługi
- zestaw
- Zestawy
- ustawienie
- w panelu ustawień
- ustawienie
- siedem
- kilka
- Share
- shared
- Powłoka
- Świeci
- wysłane
- powinien
- pokazać
- prezentacja
- pokazane
- Targi
- Sigma
- znaczący
- podobny
- Prosty
- uproszczony
- upraszczać
- upraszczanie
- po prostu
- ponieważ
- pojedynczy
- Rozmiar
- luźny
- mały
- mniejszy
- mądry
- skrawek
- So
- dotychczas
- Piłka nożna
- Obserwuj Nas
- Media społecznościowe
- Posty w mediach społecznościowych
- Wyłącznie
- solidny
- rozwiązanie
- ROZWIĄZANIA
- kilka
- coś
- czasami
- wyrafinowany
- Dźwięki
- Źródło
- Źródła
- Typ przestrzeni
- hiszpański
- wyspecjalizowanym
- specyficzny
- swoiście
- specyfika
- określony
- prędkość
- spędził
- dzielić
- Dzieli
- Sport
- Kwadratowa
- stoisko
- standalone
- standard
- początek
- rozpoczęty
- Startowy
- Stan
- oświadczenia
- statyczny
- Ewolucja krok po kroku
- Cel
- Nadal
- Stop
- zatrzymanie
- Zatrzymuje
- przechowywanie
- sklep
- przechowywany
- sklep
- przechowywania
- Historia
- bezpośredni
- strumień
- Streaming
- opływowy
- usprawniony
- silne strony
- Strajki
- sznur
- Struktura
- zbudowany
- Struktury
- strukturyzacja
- styl
- przedmiot
- kolejny
- Z powodzeniem
- taki
- Garnitur
- odpowiedni
- apartament
- streszczać
- PODSUMOWANIE
- Zachód słońca
- wsparcie
- Utrzymany
- podpory
- pewnie
- Zrównoważony rozwój
- synchronizacja
- streszczenie
- składnia
- system
- systemy
- stół
- krawiec
- dostosowane
- Brać
- trwa
- cele
- Zadanie
- zadania
- zespół
- Zespoły
- powiedzieć
- szablon
- Szablony
- terminal
- terminologia
- REGULAMIN
- test
- Testowanie
- XNUMX
- niż
- Podziękowania
- że
- Połączenia
- Podstawy
- Centrum
- Informacje
- The New York Times
- Projekty
- Źródło
- świat
- ich
- Im
- następnie
- Tam.
- Te
- one
- rzeczy
- to
- tych
- chociaż?
- Przez
- poprzez
- czas
- czasochłonne
- czasy
- Tytuł
- do
- razem
- żeton
- tokenizacja
- Żetony
- także
- narzędzie
- Zestaw narzędzi
- narzędzia
- Top
- aktualny
- tematy
- Kwota produktów:
- miasto
- Rysunek kalkowy
- śledzić
- tradycyjny
- Trening
- Przekształcać
- przemiany
- transformator
- Transformatory
- przejście
- próba
- prawdziwy
- naprawdę
- próbować
- strojenie
- SKRĘCAĆ
- Obrócenie
- Tutorial
- Dwa razy
- drugiej
- rodzaj
- typy
- Maszynopis
- zazwyczaj
- ui
- Ostatecznie
- nieporuszony
- dla
- zasadniczy
- zrozumieć
- zrozumienie
- rozumie
- Ujednolicony
- wyjątkowy
- Zjednoczony
- uniwersalny
- w odróżnieniu
- aż do
- Aktualizacja
- Nowości
- przesłanych
- URL
- us
- użyteczność
- Stosowanie
- posługiwać się
- przypadek użycia
- używany
- Użytkownik
- Interfejs użytkownika
- Użytkownicy
- zastosowania
- za pomocą
- Użytkowe
- wykorzystać
- wykorzystany
- wykorzystuje
- Wykorzystując
- v1
- uprawomocnienie
- Validator
- Cenny
- wartość
- Wartości
- zmienna
- różnorodność
- różnorodny
- Ve
- wszechstronny
- wersja
- początku.
- przez
- Wideo
- Zobacz i wysłuchaj
- Naruszenia
- widoczny
- wyobrażać sobie
- istotny
- vs
- spacer
- solucja
- chcieć
- była
- Oglądaj
- Droga..
- sposoby
- we
- Pogoda
- sieć
- przeglądarka internetowa
- usługi internetowe
- strony internetowe
- DOBRZE
- znane
- były
- Co
- Co to jest
- Whats
- jeśli chodzi o komunikację i motywację
- czy
- który
- Podczas
- KIM
- cały
- dlaczego
- szeroki
- szeroko
- widget
- Wikipedia
- będzie
- okno
- Zwycięstwa
- w
- w ciągu
- bez
- słowo
- Praca
- pracował
- workflow
- przepływów pracy
- pracujący
- działa
- świat
- by
- napisać
- pisanie
- X
- jeszcze
- york
- You
- Twój
- siebie
- youtube
- Zendesk
- zefirnet
- Zamek błyskawiczny