В основі LangChain це інноваційний фреймворк, призначений для створення програм, які використовують можливості мовних моделей. Це набір інструментів, розроблений для розробників для створення програм, які залежать від контексту та здатні до складних міркувань.
Це означає, що додатки LangChain можуть розуміти контекст, наприклад швидкі інструкції чи відповіді, що ґрунтуються на вмісті, і використовувати мовні моделі для складних завдань міркування, як-от рішення про те, як відповісти або які дії виконати. LangChain представляє уніфікований підхід до розробки інтелектуальних програм, спрощуючи шлях від концепції до виконання за допомогою різноманітних компонентів.
Розуміння LangChain
LangChain — це набагато більше, ніж просто фреймворк; це повноцінна екосистема, що складається з кількох невід’ємних частин.
- По-перше, є бібліотеки LangChain, доступні як на Python, так і на JavaScript. Ці бібліотеки є основою LangChain, пропонуючи інтерфейси та інтеграцію для різних компонентів. Вони забезпечують базове середовище виконання для об’єднання цих компонентів у зв’язані ланцюжки та агенти разом із готовими реалізаціями для негайного використання.
- Далі у нас є шаблони LangChain. Це набір еталонних архітектур, що розгортаються, розроблених для широкого спектру завдань. Незалежно від того, створюєте ви чат-бота чи складний аналітичний інструмент, ці шаблони пропонують надійну відправну точку.
- LangServe виступає як універсальна бібліотека для розгортання ланцюжків LangChain як REST API. Цей інструмент необхідний для перетворення ваших проектів LangChain на доступні та масштабовані веб-сервіси.
- Нарешті, LangSmith служить платформою для розробників. Він призначений для налагодження, тестування, оцінки та моніторингу ланцюжків, побудованих на будь-якому фреймворку LLM. Повна інтеграція з LangChain робить його незамінним інструментом для розробників, які прагнуть удосконалити та вдосконалити свої програми.
Разом ці компоненти дають змогу з легкістю розробляти, створювати та розгортати програми. З LangChain ви починаєте з написання програм за допомогою бібліотек, посилаючись на шаблони для вказівок. Потім LangSmith допоможе вам перевіряти, тестувати та контролювати ваші ланцюги, гарантуючи, що ваші програми постійно вдосконалюються та готові до розгортання. Нарешті, за допомогою LangServe ви можете легко перетворити будь-який ланцюжок на API, що полегшить розгортання.
У наступних розділах ми глибше розглянемо, як налаштувати LangChain і розпочнемо вашу подорож у створенні інтелектуальних додатків на основі мовної моделі.
Автоматизуйте ручні завдання та робочі процеси за допомогою нашого конструктора робочих процесів на основі ШІ, розробленого Nanonets для вас і ваших команд.
Встановлення та налаштування
Ви готові поринути у світ LangChain? Налаштувати це просто, і цей посібник крок за кроком проведе вас через процес.
Першим кроком у вашій подорожі LangChain є його встановлення. Ви можете легко зробити це за допомогою pip або conda. Виконайте таку команду у вашому терміналі:
pip install langchain
Для тих, хто віддає перевагу найновішим функціям і готовий отримати більше пригод, ви можете встановити LangChain безпосередньо з початкового коду. Клонуйте репозиторій і перейдіть до langchain/libs/langchain
каталог. Потім запустіть:
pip install -e .
Розгляньте можливість встановлення експериментальних функцій langchain-experimental
. Це пакет, який містить передовий код і призначений для дослідницьких і експериментальних цілей. Встановіть його за допомогою:
pip install langchain-experimental
LangChain CLI — це зручний інструмент для роботи з шаблонами LangChain і проектами LangServe. Щоб установити LangChain CLI, використовуйте:
pip install langchain-cli
LangServe необхідний для розгортання ваших ланцюжків LangChain як REST API. Його встановлюють разом із LangChain CLI.
LangChain часто вимагає інтеграції з постачальниками моделей, сховищами даних, API тощо. Для цього прикладу ми використаємо API моделі OpenAI. Встановіть пакет OpenAI Python за допомогою:
pip install openai
Щоб отримати доступ до API, установіть ключ OpenAI API як змінну середовища:
export OPENAI_API_KEY="your_api_key"
Крім того, передайте ключ безпосередньо у своєму середовищі python:
import os
os.environ['OPENAI_API_KEY'] = 'your_api_key'
LangChain дозволяє створювати програми мовної моделі за допомогою модулів. Ці модулі можуть стояти окремо або складатися для складних випадків використання. Ці модулі –
- Модель I/O: полегшує взаємодію з різними мовними моделями, ефективно обробляючи їхні вхідні та вихідні дані.
- Пошук: Забезпечує доступ до даних конкретної програми та взаємодію з ними, що має вирішальне значення для динамічного використання даних.
- Агенти: Дозвольте програмам вибирати відповідні інструменти на основі директив високого рівня, покращуючи можливості прийняття рішень.
- Ланцюги: Пропонує попередньо визначені багаторазові композиції, які служать будівельними блоками для розробки програм.
- пам'ять: підтримує стан програми під час кількох ланцюжків виконання, необхідне для контекстно-залежної взаємодії.
Кожен модуль націлений на конкретні потреби розробки, що робить LangChain комплексним набором інструментів для створення розширених програм мовної моделі.
Поряд з вищевказаними компонентами, ми також маємо Мова експресії LangChain (LCEL), що є декларативним способом легкого складання модулів разом, і це дозволяє об’єднувати компоненти за допомогою універсального інтерфейсу Runnable.
LCEL виглядає приблизно так –
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import BaseOutputParser # Example chain
chain = ChatPromptTemplate() | ChatOpenAI() | CustomOutputParser()
Тепер, коли ми розглянули основи, ми продовжимо:
- Розгляньте докладніше кожен модуль Langchain.
- Дізнайтеся, як використовувати мову виразів LangChain.
- Досліджуйте загальні випадки використання та впроваджуйте їх.
- Розгорніть наскрізну програму за допомогою LangServe.
- Перегляньте LangSmith для налагодження, тестування та моніторингу.
Давайте розпочнемо!
Модуль I: Модель введення/виведення
У LangChain основний елемент будь-якої програми обертається навколо мовної моделі. Цей модуль надає основні будівельні блоки для ефективного інтерфейсу з будь-якою мовною моделлю, забезпечуючи бездоганну інтеграцію та спілкування.
Ключові компоненти моделі I/O
- LLM і моделі чату (взаємозамінні):
- LLM:
- Визначення: Моделі завершення чистого тексту.
- Введення-виведення: приймати текстовий рядок як вхідні дані та повертати текстовий рядок як вихідні дані.
- Моделі чату
- LLM:
- Визначення: моделі, які використовують мовну модель як основу, але відрізняються форматами введення та виведення.
- Введення-виведення: прийняти список повідомлень чату як вхідні дані та повернути повідомлення чату.
- Підказки: створення шаблонів, динамічний вибір і керування входами моделі. Дозволяє створювати гнучкі контекстно-залежні підказки, які керують відповідями мовної моделі.
- Парсери виводу: вилучення та форматування інформації з вихідних даних моделі. Корисно для перетворення вихідних даних мовних моделей у структуровані дані або спеціальні формати, необхідні програмі.
LLM
Інтеграція LangChain із великими мовними моделями (LLM), такими як OpenAI, Cohere та Hugging Face, є фундаментальним аспектом його функціональності. Сам LangChain не розміщує LLM, але пропонує єдиний інтерфейс для взаємодії з різними LLM.
У цьому розділі наведено огляд використання оболонки OpenAI LLM у LangChain, яка також застосовується до інших типів LLM. Ми вже встановили це в розділі «Початок роботи». Давайте ініціалізуємо LLM.
from langchain.llms import OpenAI
llm = OpenAI()
- LLM реалізують Запуск інтерфейсу, основний будівельний блок Мова експресії LangChain (LCEL). Це означає, що вони підтримують
invoke
,ainvoke
,stream
,astream
,batch
,abatch
,astream_log
дзвінки - LLM приймають струни як вхідні дані або об’єкти, які можуть бути примусово створені для рядкових підказок, у тому числі
List[BaseMessage]
таPromptValue
. (докладніше про це пізніше)
Давайте розглянемо кілька прикладів.
response = llm.invoke("List the seven wonders of the world.")
print(response)
Ви також можете викликати метод потоку для потокової передачі текстової відповіді.
for chunk in llm.stream("Where were the 2012 Olympics held?"): print(chunk, end="", flush=True)
Моделі чату
Інтеграція LangChain із моделями чату, спеціалізованим варіантом мовних моделей, є важливою для створення інтерактивних додатків для чату. Хоча вони використовують внутрішньо мовні моделі, моделі чату представляють окремий інтерфейс, зосереджений навколо повідомлень чату як вхідних і вихідних даних. Цей розділ містить детальний огляд використання моделі чату OpenAI у LangChain.
from langchain.chat_models import ChatOpenAI
chat = ChatOpenAI()
Моделі чату в LangChain працюють з різними типами повідомлень, наприклад AIMessage
, HumanMessage
, SystemMessage
, FunctionMessage
та ChatMessage
(з довільним параметром ролі). загалом, HumanMessage
, AIMessage
та SystemMessage
є найбільш часто використовуваними.
Моделі чату переважно приймають List[BaseMessage]
як входи. Рядки можна конвертувати в HumanMessage
та PromptValue
також підтримується.
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)
Підказки
Підказки мають важливе значення для скерування мовних моделей для створення відповідних і узгоджених результатів. Вони можуть варіюватися від простих інструкцій до складних невеликих прикладів. У LangChain обробка підказок може бути дуже спрощеним процесом завдяки кільком спеціальним класам і функціям.
LangChain PromptTemplate
class — це універсальний інструмент для створення рядкових підказок. Він використовує Python str.format
синтаксис, що дозволяє генерувати динамічні підказки. Ви можете визначити шаблон із заповнювачами та заповнити їх певними значеннями за потреби.
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)
Для моделей чату підказки більш структуровані, містять повідомлення з певними ролями. Пропозиції LangChain ChatPromptTemplate
Для цієї мети.
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)
Цей підхід дозволяє створювати інтерактивні, захоплюючі чат-боти з динамічними відповідями.
обидві PromptTemplate
та ChatPromptTemplate
бездоганно інтегруються з мовою виразів LangChain (LCEL), що дозволяє їм бути частиною більших складних робочих процесів. Ми обговоримо це пізніше.
Спеціальні шаблони підказок іноді необхідні для завдань, які вимагають унікального форматування або спеціальних інструкцій. Створення спеціального шаблону підказки передбачає визначення вхідних змінних і спеціального методу форматування. Ця гнучкість дозволяє LangChain задовольняти широкий спектр вимог до конкретних програм. Подробиці читайте тут.
LangChain також підтримує кілька підказок, дозволяючи моделі навчатися на прикладах. Ця функція життєво необхідна для завдань, які потребують розуміння контексту або певних шаблонів. Шаблони підказок із кількома випадками можна створювати з набору прикладів або за допомогою об’єкта вибору прикладу. Подробиці читайте тут.
Парсери виводу
Синтаксичні аналізатори виводу відіграють вирішальну роль у Langchain, дозволяючи користувачам структурувати відповіді, створені мовними моделями. У цьому розділі ми розглянемо концепцію аналізаторів виводу та надамо приклади коду з використанням PydanticOutputParser, SimpleJsonOutputParser, CommaSeparatedListOutputParser, DatetimeOutputParser і XMLOutputParser Langchain.
PydanticOutputParser
Langchain надає PydanticOutputParser для аналізу відповідей у структурах даних Pydantic. Нижче наведено покроковий приклад його використання.
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)
Вихідний сигнал буде:
SimpleJsonOutputParser
SimpleJsonOutputParser від Langchain використовується, коли ви хочете проаналізувати JSON-подібні виходи. Ось приклад:
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 зручний, якщо ви хочете отримати списки, розділені комами, із відповідей моделі. Ось приклад:
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
Langchain DatetimeOutputParser призначений для аналізу інформації про дату та час. Ось як ним користуватися:
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)
Ці приклади демонструють, як парсери вихідних даних Langchain можна використовувати для структурування різних типів відповідей моделі, що робить їх придатними для різних програм і форматів. Синтаксичні аналізатори вихідних даних є цінним інструментом для підвищення зручності використання та інтерпретації виходів мовної моделі в Langchain.
Автоматизуйте ручні завдання та робочі процеси за допомогою нашого конструктора робочих процесів на основі ШІ, розробленого Nanonets для вас і ваших команд.
Модуль II: Пошук
Отримання в LangChain відіграє вирішальну роль у програмах, які вимагають специфічних для користувача даних, які не входять до навчального набору моделі. Цей процес, відомий як Retrieval Augmented Generation (RAG), передбачає отримання зовнішніх даних та їх інтеграцію в процес генерації мовної моделі. LangChain надає повний набір інструментів і функціональних можливостей для полегшення цього процесу, обслуговуючи як прості, так і складні програми.
LangChain забезпечує пошук за допомогою серії компонентів, які ми обговоримо один за іншим.
Завантажувачі документів
Завантажувачі документів у LangChain дозволяють отримувати дані з різних джерел. Маючи понад 100 доступних завантажувачів, вони підтримують низку типів документів, програм і джерел (приватні сегменти s3, загальнодоступні веб-сайти, бази даних).
Ви можете вибрати завантажувач документів на основі ваших вимог тут.
Усі ці завантажувачі завантажують дані Документ класи. Пізніше ми дізнаємося, як використовувати дані, отримані в класах Document.
Завантажувач текстових файлів: Завантажити простий .txt
файл у документ.
from langchain.document_loaders import TextLoader loader = TextLoader("./sample.txt")
document = loader.load()
Завантажувач CSV: Завантажте файл CSV у документ.
from langchain.document_loaders.csv_loader import CSVLoader loader = CSVLoader(file_path='./example_data/sample.csv')
documents = loader.load()
Ми можемо налаштувати розбір, вказавши назви полів –
loader = CSVLoader(file_path='./example_data/mlb_teams_2012.csv', csv_args={ 'delimiter': ',', 'quotechar': '"', 'fieldnames': ['MLB Team', 'Payroll in millions', 'Wins']
})
documents = loader.load()
Завантажувачі PDF: Завантажувачі PDF у LangChain пропонують різні методи аналізу та вилучення вмісту з файлів PDF. Кожен завантажувач задовольняє різні вимоги та використовує різні базові бібліотеки. Нижче наведено докладні приклади для кожного завантажувача.
PyPDFLoader використовується для базового аналізу PDF.
from langchain.document_loaders import PyPDFLoader loader = PyPDFLoader("example_data/layout-parser-paper.pdf")
pages = loader.load_and_split()
MathPixLoader ідеально підходить для отримання математичного вмісту та діаграм.
from langchain.document_loaders import MathpixPDFLoader loader = MathpixPDFLoader("example_data/math-content.pdf")
data = loader.load()
PyMuPDFLoader є швидким і включає детальне вилучення метаданих.
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 використовується для більш детального контролю над вилученням тексту.
from langchain.document_loaders import PDFMinerLoader loader = PDFMinerLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
AmazonTextractPDFParser використовує AWS Texttract для OCR та інші розширені функції аналізу PDF.
from langchain.document_loaders import AmazonTextractPDFLoader # Requires AWS account and configuration
loader = AmazonTextractPDFLoader("example_data/complex-layout.pdf")
documents = loader.load()
PDFMinerPDFasHTMLLoader генерує HTML із PDF для семантичного аналізу.
from langchain.document_loaders import PDFMinerPDFasHTMLLoader loader = PDFMinerPDFasHTMLLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
PDFPlumberLoader надає детальні метадані та підтримує один документ на сторінку.
from langchain.document_loaders import PDFPlumberLoader loader = PDFPlumberLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
Інтегровані завантажувачі: LangChain пропонує широкий вибір користувальницьких завантажувачів для безпосереднього завантаження даних із ваших додатків (таких як Slack, Sigma, Notion, Confluence, Google Drive та багатьох інших) і баз даних і використання їх у програмах LLM.
Повний список такий тут.
Нижче наведено пару прикладів, щоб проілюструвати це –
Приклад I – Slack
Slack, широко поширену платформу обміну миттєвими повідомленнями, можна інтегрувати в робочі процеси та програми LLM.
- Перейдіть на сторінку керування робочим простором Slack.
- перейдіть до
{your_slack_domain}.slack.com/services/export
. - Виберіть потрібний діапазон дат і запустіть експорт.
- Slack сповіщає електронною поштою та DM, коли експорт готовий.
- Результатом експорту є a
.zip
файл, який знаходиться у вашій папці завантажень або в указаному вами шляху завантаження. - Призначте шлях до завантаженого
.zip
файл вLOCAL_ZIPFILE
. - Використовувати
SlackDirectoryLoader
відlangchain.document_loaders
пакет.
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)
Приклад II – Figma
Figma, популярний інструмент для розробки інтерфейсів, пропонує REST API для інтеграції даних.
- Отримайте ключ файлу Figma з формату URL:
https://www.figma.com/file/{filekey}/sampleFilename
. - Ідентифікатори вузлів можна знайти в параметрі URL
?node-id={node_id}
. - Згенеруйте маркер доступу, дотримуючись інструкцій на сторінці Довідковий центр Figma.
- Команда
FigmaFileLoader
клас відlangchain.document_loaders.figma
використовується для завантаження даних Figma. - Різні модулі LangChain, наприклад
CharacterTextSplitter
,ChatOpenAI
, тощо, використовуються для обробки.
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()
- Команда
generate_code
функція використовує дані Figma для створення коду HTML/CSS. - Він використовує шаблонну розмову з моделлю на основі 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)
- Команда
generate_code
Функція під час виконання повертає код HTML/CSS на основі вхідних даних дизайну Figma.
Давайте тепер використаємо наші знання для створення кількох наборів документів.
Спочатку ми завантажуємо PDF, щорічний звіт про сталий розвиток BCG.
Для цього ми використовуємо PyPDFLoader.
from langchain.document_loaders import PyPDFLoader loader = PyPDFLoader("bcg-2022-annual-sustainability-report-apr-2023.pdf")
pdfpages = loader.load_and_split()
Зараз ми завантажимо дані з Airtable. У нас є Airtable, що містить інформацію про різні моделі оптичного розпізнавання та вилучення даних –
Скористаємося для цього AirtableLoader, який можна знайти у списку інтегрованих завантажувачів.
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()
Давайте тепер продовжимо і навчимося використовувати ці класи документів.
Трансформери документів
Перетворювачі документів у LangChain є основними інструментами, призначеними для роботи з документами, які ми створили в попередньому підрозділі.
Вони використовуються для таких завдань, як розбиття довгих документів на менші частини, об’єднання та фільтрація, які мають вирішальне значення для адаптації документів до контекстного вікна моделі або задоволення конкретних потреб програми.
Одним із таких інструментів є RecursiveCharacterTextSplitter, універсальний роздільник тексту, який використовує список символів для розділення. Він дозволяє такі параметри, як розмір блоку, перекриття та початковий індекс. Ось приклад того, як це використовується в Python:
from langchain.text_splitter import RecursiveCharacterTextSplitter state_of_the_union = "Your long text here..." text_splitter = RecursiveCharacterTextSplitter( chunk_size=100, chunk_overlap=20, length_function=len, add_start_index=True,
) texts = text_splitter.create_documents([state_of_the_union])
print(texts[0])
print(texts[1])
Іншим інструментом є CharacterTextSplitter, який розділяє текст на основі заданого символу та містить елементи керування розміром фрагмента та накладенням:
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 призначений для розділення вмісту HTML на основі тегів заголовків, зберігаючи семантичну структуру:
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])
Більш складну маніпуляцію можна досягти, об’єднавши HTMLHeaderTextSplitter з іншим роздільником, наприклад Pipelined Splitter:
from langchain.text_splitter import HTMLHeaderTextSplitter, RecursiveCharacterTextSplitter url = "https://example.com"
headers_to_split_on = [("h1", "Header 1"), ("h2", "Header 2")]
html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
html_header_splits = html_splitter.split_text_from_url(url) chunk_size = 500
text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size)
splits = text_splitter.split_documents(html_header_splits)
print(splits[0])
LangChain також пропонує спеціальні роздільники для різних мов програмування, як-от Python Code Splitter і JavaScript Code Splitter:
from langchain.text_splitter import RecursiveCharacterTextSplitter, Language python_code = """
def hello_world(): print("Hello, World!")
hello_world() """ python_splitter = RecursiveCharacterTextSplitter.from_language( language=Language.PYTHON, chunk_size=50
)
python_docs = python_splitter.create_documents([python_code])
print(python_docs[0]) js_code = """
function helloWorld() { console.log("Hello, World!");
}
helloWorld(); """ js_splitter = RecursiveCharacterTextSplitter.from_language( language=Language.JS, chunk_size=60
)
js_docs = js_splitter.create_documents([js_code])
print(js_docs[0])
Для розділення тексту на основі кількості токенів, що корисно для мовних моделей з обмеженнями токенів, використовується 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])
Нарешті, LongContextReorder змінює порядок документів, щоб запобігти зниженню продуктивності в моделях через довгі контексти:
from langchain.document_transformers import LongContextReorder reordering = LongContextReorder()
reordered_docs = reordering.transform_documents(docs)
print(reordered_docs[0])
Ці інструменти демонструють різні способи трансформації документів у LangChain, від простого поділу тексту до складного перевпорядкування та поділу для певної мови. Щоб отримати докладніші та конкретні випадки використання, ознайомтеся з розділом документації та інтеграції LangChain.
У наших прикладах завантажувачі вже створили для нас фрагментовані документи, і ця частина вже оброблена.
Моделі вбудовування тексту
Моделі вбудовування тексту в LangChain забезпечують стандартизований інтерфейс для різних постачальників моделей вбудовування, таких як OpenAI, Cohere та Hugging Face. Ці моделі перетворюють текст у векторне представлення, уможливлюючи такі операції, як семантичний пошук через подібність тексту у векторному просторі.
Щоб розпочати роботу з моделями вбудовування тексту, зазвичай потрібно інсталювати певні пакети та налаштувати ключі API. Ми вже зробили це для OpenAI
У LangChain, embed_documents
метод використовується для вбудовування кількох текстів, надаючи список векторних зображень. Наприклад:
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]))
Для вбудовування окремого тексту, наприклад пошукового запиту, embed_query
використовується метод. Це корисно для порівняння запиту з набором вбудованих документів. Наприклад:
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])
Розуміння цих вкладень має вирішальне значення. Кожен фрагмент тексту перетворюється на вектор, розмірність якого залежить від використовуваної моделі. Наприклад, моделі OpenAI зазвичай створюють 1536-вимірні вектори. Потім ці вбудовування використовуються для отримання відповідної інформації.
Функціональність вбудовування LangChain не обмежується OpenAI, але розроблена для роботи з різними постачальниками. Налаштування та використання можуть дещо відрізнятися залежно від постачальника, але основна концепція вбудовування текстів у векторний простір залишається незмінною. Для детального використання, включаючи розширені конфігурації та інтеграцію з різними постачальниками моделі вбудовування, документація LangChain у розділі «Інтеграції» є цінним ресурсом.
Векторні магазини
Векторні магазини в LangChain підтримують ефективне зберігання та пошук вбудованих текстів. LangChain інтегрується з понад 50 векторними магазинами, забезпечуючи стандартизований інтерфейс для зручності використання.
Приклад: Зберігання та пошук вбудованих елементів
Після вбудовування текстів ми можемо зберігати їх у векторному сховищі, наприклад Chroma
і виконати пошук подібності:
from langchain.vectorstores import Chroma db = Chroma.from_texts(embedded_texts)
similar_texts = db.similarity_search("search query")
Скористаємось векторним сховищем FAISS для створення індексів для наших документів.
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS pdfstore = FAISS.from_documents(pdfpages, embedding=OpenAIEmbeddings()) airtablestore = FAISS.from_documents(airtabledocs, embedding=OpenAIEmbeddings())
ретривери
Ретривери в LangChain — це інтерфейси, які повертають документи у відповідь на неструктурований запит. Вони більш загальні, ніж векторні сховища, зосереджені на пошуку, а не на зберіганні. Хоча векторні магазини можна використовувати як основу ретривера, існують також інші типи ретриверів.
Щоб налаштувати Chroma Retriever, спочатку встановіть його за допомогою pip install chromadb
. Потім ви завантажуєте, розділяєте, вставляєте та отримуєте документи за допомогою ряду команд Python. Ось приклад коду для налаштування Chroma Retriever:
from langchain.embeddings import OpenAIEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import Chroma full_text = open("state_of_the_union.txt", "r").read()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
texts = text_splitter.split_text(full_text) embeddings = OpenAIEmbeddings()
db = Chroma.from_texts(texts, embeddings)
retriever = db.as_retriever() retrieved_docs = retriever.invoke("What did the president say about Ketanji Brown Jackson?")
print(retrieved_docs[0].page_content)
MultiQueryRetriever автоматизує швидку настройку, генеруючи кілька запитів для запиту, введеного користувачем, і об’єднує результати. Ось приклад його простого використання:
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))
Контекстне стиснення в LangChain стискає отримані документи з використанням контексту запиту, забезпечуючи повернення лише релевантної інформації. Це передбачає зменшення вмісту та фільтрування менш релевантних документів. У наступному прикладі коду показано, як використовувати Contextual Compression Retriever:
from langchain.llms import OpenAI
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor llm = OpenAI(temperature=0)
compressor = LLMChainExtractor.from_llm(llm)
compression_retriever = ContextualCompressionRetriever(base_compressor=compressor, base_retriever=retriever) compressed_docs = compression_retriever.get_relevant_documents("What did the president say about Ketanji Jackson Brown")
print(compressed_docs[0].page_content)
EnsembleRetriever поєднує різні алгоритми пошуку для досягнення кращої продуктивності. Приклад поєднання BM25 і FAISS Retrievers показано в наступному коді:
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 у LangChain дозволяє запитувати документи з кількома векторами на документ, що корисно для захоплення різних семантичних аспектів у документі. Методи створення кількох векторів включають поділ на менші фрагменти, узагальнення або генерування гіпотетичних запитань. Для поділу документів на менші частини можна використовувати наступний код Python:
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)))
Іншим методом є створення підсумків для кращого пошуку завдяки більш сфокусованому представленню вмісту. Ось приклад створення підсумків:
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)))
Іншим підходом є створення гіпотетичних запитань, що стосуються кожного документа за допомогою LLM. Це можна зробити за допомогою такого коду:
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 — це ще один засіб відновлення, який досягає балансу між точністю вбудовування та збереженням контексту, зберігаючи невеликі фрагменти та витягаючи їх більші батьківські документи. Його реалізація полягає в наступному:
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")
Самозапитувальний ретривер створює структуровані запити з вхідних даних природною мовою та застосовує їх до основного VectorStore. Його реалізацію показано в наступному коді:
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 виконує веб-дослідження на основі заданого запиту –
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")
Для наших прикладів ми також можемо використати стандартний ретривер, уже реалізований як частина нашого об’єкта векторної сховища, як показано нижче –
Тепер ми можемо запитати ретриверів. Результатом нашого запиту будуть об’єкти документа, що відповідають запиту. Зрештою вони будуть використані для створення відповідних відповідей у наступних розділах.
Автоматизуйте ручні завдання та робочі процеси за допомогою нашого конструктора робочих процесів на основі ШІ, розробленого Nanonets для вас і ваших команд.
Модуль III: Агенти
LangChain представляє потужну концепцію під назвою «Агенти», яка виводить ідею ланцюгів на абсолютно новий рівень. Агенти використовують мовні моделі для динамічного визначення послідовності дій для виконання, що робить їх неймовірно універсальними та адаптивними. На відміну від традиційних ланцюжків, де дії жорстко закодовані в коді, агенти використовують мовні моделі як механізми міркування, щоб вирішити, які дії виконувати та в якому порядку.
Агент є основним компонентом, відповідальним за прийняття рішень. Він використовує силу мовної моделі та підказку для визначення наступних кроків для досягнення конкретної мети. Вхідні дані для агента зазвичай включають:
- Інструменти: Опис доступних інструментів (про це пізніше).
- Введення користувача: Мета високого рівня або запит від користувача.
- Проміжні кроки: Історія пар (дій, вихід інструменту), виконаних для досягнення поточного введення користувача.
Вихід агента може бути наступним дію вжити заходів (AgentActions) або фінал відповідь надіслати користувачеві (AgentFinish). Ан дію вказує a інструмент і вхід для цього інструменту.
Tools
Інструменти — це інтерфейси, які агент може використовувати для взаємодії зі світом. Вони дозволяють агентам виконувати різні завдання, такі як пошук в Інтернеті, виконання команд оболонки або доступ до зовнішніх API. У LangChain інструменти необхідні для розширення можливостей агентів і надання їм можливості виконувати різноманітні завдання.
Щоб використовувати інструменти в LangChain, ви можете завантажити їх за допомогою такого фрагмента:
from langchain.agents import load_tools tool_names = [...]
tools = load_tools(tool_names)
Для ініціалізації деяких інструментів може знадобитися базова мовна модель (LLM). У таких випадках ви також можете пройти LLM:
from langchain.agents import load_tools tool_names = [...]
llm = ...
tools = load_tools(tool_names, llm=llm)
Це налаштування дозволяє отримати доступ до різноманітних інструментів та інтегрувати їх у робочі процеси вашого агента. Повний список інструментів із документацією щодо використання є тут.
Давайте розглянемо кілька прикладів інструментів.
DuckDuckGo
Інструмент DuckDuckGo дає змогу здійснювати веб-пошук за допомогою його пошукової системи. Ось як ним користуватися:
from langchain.tools import DuckDuckGoSearchRun
search = DuckDuckGoSearchRun()
search.run("manchester united vs luton town match summary")
DataForSeo
Набір інструментів DataForSeo дозволяє отримувати результати пошукової системи за допомогою DataForSeo API. Щоб використовувати цей інструментарій, вам потрібно налаштувати свої облікові дані API. Ось як налаштувати облікові дані:
import os os.environ["DATAFORSEO_LOGIN"] = "<your_api_access_username>"
os.environ["DATAFORSEO_PASSWORD"] = "<your_api_access_password>"
Після встановлення облікових даних ви можете створити a DataForSeoAPIWrapper
інструмент для доступу до API:
from langchain.utilities.dataforseo_api_search import DataForSeoAPIWrapper wrapper = DataForSeoAPIWrapper() result = wrapper.run("Weather in Los Angeles")
Команда DataForSeoAPIWrapper
інструмент отримує результати пошукової системи з різних джерел.
Ви можете налаштувати тип результатів і полів, що повертаються у відповіді JSON. Наприклад, ви можете вказати типи результатів, поля та встановити максимальну кількість для повернення найпопулярніших результатів:
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")
У цьому прикладі налаштовується відповідь JSON, вказуючи типи результатів, поля та обмежуючи кількість результатів.
Ви також можете вказати розташування та мову для результатів пошуку, передавши додаткові параметри в оболонку 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")
Надавши параметри розташування та мови, ви можете адаптувати результати пошуку до певних регіонів і мов.
У вас є можливість вибрати пошукову систему, яку ви хочете використовувати. Просто вкажіть потрібну пошукову систему:
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")
У цьому прикладі пошук налаштовано для використання Bing як пошукової системи.
Обгортка API також дозволяє вказати тип пошуку, який ви хочете виконати. Наприклад, ви можете виконати пошук на картах:
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")
Це налаштовує пошук для отримання інформації, пов’язаної з картами.
Shell (баш)
Набір інструментів Shell надає агентам доступ до середовища оболонки, дозволяючи їм виконувати команди оболонки. Ця функція потужна, але її слід використовувати з обережністю, особливо в пісочниці. Ось як ви можете використовувати інструмент Shell:
from langchain.tools import ShellTool shell_tool = ShellTool() result = shell_tool.run({"commands": ["echo 'Hello World!'", "time"]})
У цьому прикладі інструмент Shell виконує дві команди оболонки: повторюючи «Hello World!» і відображення поточного часу.
Ви можете надати агенту інструмент Shell для виконання більш складних завдань. Ось приклад агента, який отримує посилання з веб-сторінки за допомогою інструмента 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."
)
У цьому сценарії агент використовує інструмент Shell для виконання послідовності команд для отримання, фільтрування та сортування URL-адрес із веб-сторінки.
Наведені приклади демонструють деякі інструменти, доступні в LangChain. Ці інструменти зрештою розширюють можливості агентів (досліджено в наступному підрозділі) і дають їм змогу ефективно виконувати різні завдання. Залежно від ваших вимог ви можете вибрати інструменти та набори інструментів, які найкраще відповідають потребам вашого проекту, і інтегрувати їх у робочі процеси вашого агента.
Повернутися до Агентів
Тепер перейдемо до агентів.
AgentExecutor — це середовище виконання для агента. Він відповідає за виклик агента, виконання вибраних ним дій, передачу результатів дії назад агенту та повторення процесу, доки агент не завершить роботу. У псевдокоді AgentExecutor може виглядати приблизно так:
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 справляється з різними складнощами, такими як робота з випадками, коли агент вибирає неіснуючий інструмент, обробка помилок інструменту, керування створеними агентом виходами та забезпечення журналювання та спостереження на всіх рівнях.
Хоча клас AgentExecutor є основним середовищем виконання агента в LangChain, підтримуються інші, більш експериментальні середовища виконання, зокрема:
- Плануй і виконуй агент
- Baby AGI
- Авто GPT
Щоб краще зрозуміти структуру агента, давайте створимо базовий агент з нуля, а потім перейдемо до вивчення готових агентів.
Перш ніж ми заглибимося в створення агента, важливо переглянути деякі ключові термінології та схеми:
- AgentAction: Це клас даних, що представляє дію, яку повинен виконати агент. Він складається з a
tool
властивість (назва інструменту для виклику) і atool_input
властивість (вхід для цього інструменту). - AgentFinish: Цей клас даних вказує на те, що агент виконав своє завдання і повинен повернути відповідь користувачеві. Зазвичай він включає словник значень, що повертаються, часто з ключовим «виводом», що містить текст відповіді.
- Проміжні кроки: Це записи попередніх дій агента та відповідних виходів. Вони мають вирішальне значення для передачі контексту майбутнім ітераціям агента.
У нашому прикладі ми використаємо виклик функцій OpenAI для створення нашого агента. Цей підхід надійний для створення агента. Ми почнемо зі створення простого інструменту, який обчислює довжину слова. Цей інструмент корисний, оскільки мовні моделі іноді можуть допускати помилки через токенізацію під час підрахунку довжини слів.
По-перше, давайте завантажимо мовну модель, яку будемо використовувати для керування агентом:
from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
Перевіримо модель за допомогою обчислення довжини слова:
llm.invoke("how many letters in the word educa?")
У відповіді має бути вказано кількість літер у слові «educa».
Далі ми визначимо просту функцію Python для обчислення довжини слова:
from langchain.agents import tool @tool
def get_word_length(word: str) -> int: """Returns the length of a word.""" return len(word)
Ми створили інструмент під назвою get_word_length
який приймає слово як вхідні дані та повертає його довжину.
Тепер давайте створимо підказку для агента. Підказка вказує агенту, як міркувати та форматувати вихідні дані. У нашому випадку ми використовуємо OpenAI Function Calling, який вимагає мінімум інструкцій. Ми визначимо запит із заповнювачами для введення користувача та блокнота агента:
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"), ]
)
Тепер, як агент дізнається, які інструменти він може використовувати? Ми покладаємося на мовні моделі виклику функцій OpenAI, які потребують окремої передачі функцій. Щоб надати наші інструменти агенту, ми відформатуємо їх як виклики функцій 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])
Тепер ми можемо створити агента, визначивши відображення вхідних даних і підключивши компоненти:
Це мова LCEL. Ми обговоримо це пізніше детально.
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()
)
Ми створили нашого агента, який розуміє дані користувача, використовує доступні інструменти та форматує вихідні дані. Тепер давайте взаємодіяти з ним:
agent.invoke({"input": "how many letters in the word educa?", "intermediate_steps": []})
Агент має відповісти AgentAction, що вказує на наступну дію.
Ми створили агента, але тепер нам потрібно написати для нього середовище виконання. Найпростішим середовищем виконання є те, що безперервно викликає агента, виконує дії та повторює, доки агент не завершить роботу. Ось приклад:
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)
У цьому циклі ми неодноразово викликаємо агента, виконуємо дії та оновлюємо проміжні кроки, доки агент не завершить роботу. Ми також керуємо взаємодією інструментів у циклі.
Щоб спростити цей процес, LangChain надає клас AgentExecutor, який інкапсулює виконання агента та пропонує обробку помилок, ранню зупинку, трасування та інші вдосконалення. Давайте використаємо AgentExecutor для взаємодії з агентом:
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 спрощує процес виконання та забезпечує зручний спосіб взаємодії з агентом.
Пам'ять також детально обговорюється пізніше.
Агент, який ми наразі створили, не має статусу, тобто він не пам’ятає попередні взаємодії. Щоб увімкнути додаткові запитання та розмови, нам потрібно додати пам’ять для агента. Це включає два кроки:
- Додайте змінну пам’яті в запит, щоб зберігати історію чату.
- Відстежуйте історію чату під час взаємодії.
Почнемо з додавання заповнювача пам’яті в підказку:
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"), ]
)
Тепер створіть список для відстеження історії чату:
from langchain.schema.messages import HumanMessage, AIMessage chat_history = []
На етапі створення агента ми також включимо пам’ять:
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()
)
Тепер, коли запускаєте агент, не забудьте оновити історію чату:
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})
Це дає змогу агенту зберігати історію розмов і відповідати на додаткові запитання на основі попередніх взаємодій.
Щиро вітаю! Ви успішно створили та запустили свій перший наскрізний агент у LangChain. Щоб глибше ознайомитись із можливостями LangChain, ви можете дослідити:
- Підтримуються різні типи агентів.
- Попередньо створені агенти
- Як працювати з інструментами та інтеграціями інструментів.
Типи агентів
LangChain пропонує різні типи агентів, кожен з яких підходить для конкретних випадків використання. Ось деякі з доступних агентів:
- Zero-shot ReAct: Цей агент використовує фреймворк ReAct для вибору інструментів виключно на основі їхніх описів. Він вимагає описів для кожного інструменту та є надзвичайно універсальним.
- Структурований вхід ReAct: Цей агент працює з інструментами багаторазового введення та підходить для таких складних завдань, як навігація веб-переглядачем. Він використовує схему аргументів інструментів для структурованого введення.
- Функції OpenAI: Спеціально розроблений для моделей, налаштованих на виклик функцій, цей агент сумісний із такими моделями, як gpt-3.5-turbo-0613 і gpt-4-0613. Ми використали це для створення нашого першого агента вище.
- Розмова: Розроблений для розмовних налаштувань, цей агент використовує ReAct для вибору інструментів і використовує пам’ять для запам’ятовування попередніх взаємодій.
- Самозапитуйте з пошуком: Цей агент покладається на єдиний інструмент «Проміжна відповідь», який шукає фактичні відповіді на запитання. Це еквівалент оригінального самозапитання з пошуковим папером.
- Сховище документів ReAct: Цей агент взаємодіє зі сховищем документів за допомогою фреймворку ReAct. Він вимагає інструментів «Пошук» і «Пошук» і схожий на оригінальний приклад статті ReAct у Вікіпедії.
Вивчіть ці типи агентів, щоб знайти той, який найкраще відповідає вашим потребам у LangChain. Ці агенти дозволяють прив’язувати набір інструментів у них для обробки дій і генерування відповідей. Дізнайтеся більше на як створити власного агента за допомогою інструментів тут.
Готові агенти
Давайте продовжимо наше дослідження агентів, зосередившись на готових агентах, доступних у LangChain.
Gmail
LangChain пропонує набір інструментів Gmail, який дозволяє підключити вашу електронну пошту LangChain до API Gmail. Щоб розпочати, вам потрібно буде налаштувати свої облікові дані, які пояснюються в документації Gmail API. Після завантаження файлу credentials.json
файл, ви можете продовжити використання Gmail API. Крім того, вам потрібно буде інсталювати деякі необхідні бібліотеки за допомогою таких команд:
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
Ви можете створити набір інструментів Gmail таким чином:
from langchain.agents.agent_toolkits import GmailToolkit toolkit = GmailToolkit()
Ви також можете налаштувати автентифікацію відповідно до своїх потреб. За лаштунками ресурс googleapi створюється за допомогою таких методів:
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)
Набір інструментів пропонує різні інструменти, які можна використовувати в агенті, зокрема:
GmailCreateDraft
: створити чернетку електронного листа з указаними полями повідомлення.GmailSendMessage
: надсилання електронних листів.GmailSearch
: пошук повідомлень електронної пошти або ланцюжків.GmailGetMessage
: отримати електронний лист за ідентифікатором повідомлення.GmailGetThread
: пошук повідомлень електронної пошти.
Щоб використовувати ці інструменти в агенті, ви можете ініціалізувати агента таким чином:
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,
)
Ось кілька прикладів того, як можна використовувати ці інструменти:
- Створіть чернетку Gmail для редагування:
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."
)
- Знайдіть останній електронний лист у чернетках:
agent.run("Could you search in my drafts for the latest email?")
Ці приклади демонструють можливості набору інструментів Gmail від LangChain в агенті, що дозволяє вам взаємодіяти з Gmail програмно.
Агент бази даних SQL
У цьому розділі наведено огляд агента, призначеного для взаємодії з базами даних SQL, зокрема базою даних Chinook. Цей агент може відповідати на загальні запитання про базу даних і відновлювати помилки. Зверніть увагу, що він все ще знаходиться в активній розробці, і не всі відповіді можуть бути правильними. Будьте обережні, запускаючи його з конфіденційними даними, оскільки він може виконувати оператори DML у вашій базі даних.
Щоб використовувати цей агент, ви можете ініціалізувати його таким чином:
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,
)
Цей агент можна ініціалізувати за допомогою ZERO_SHOT_REACT_DESCRIPTION
тип агента. Він призначений для відповідей на запитання та надання описів. Крім того, ви можете ініціалізувати агента за допомогою OPENAI_FUNCTIONS
тип агента з моделлю OpenAI GPT-3.5-turbo, яку ми використовували в нашому попередньому клієнті.
відмова
- Ланцюжок запитів може генерувати запити на вставку/оновлення/видалення. Будьте обережні та скористайтеся спеціальним запитом або створіть користувача SQL без прав на запис, якщо це необхідно.
- Майте на увазі, що виконання певних запитів, як-от «запустити максимально великий запит», може перевантажити вашу базу даних SQL, особливо якщо вона містить мільйони рядків.
- Бази даних, орієнтовані на сховище даних, часто підтримують квоти на рівні користувача, щоб обмежити використання ресурсів.
Ви можете попросити агента описати таблицю, наприклад таблицю «playlisttrack». Ось приклад того, як це зробити:
agent_executor.run("Describe the playlisttrack table")
Агент надасть інформацію про схему таблиці та зразки рядків.
Якщо ви помилково запитаєте про таблицю, яка не існує, агент може відновити та надати інформацію про найближчу відповідну таблицю. Наприклад:
agent_executor.run("Describe the playlistsong table")
Агент знайде найближчий відповідний стіл і надасть інформацію про нього.
Ви також можете попросити агента виконати запити до бази даних. Наприклад:
agent_executor.run("List the total sales per country. Which country's customers spent the most?")
Агент виконає запит і надасть результат, наприклад країну з найбільшим загальним обсягом продажів.
Щоб отримати загальну кількість треків у кожному списку відтворення, ви можете скористатися таким запитом:
agent_executor.run("Show the total number of tracks in each playlist. The Playlist name should be included in the result.")
Агент поверне назви списків відтворення разом із відповідною загальною кількістю треків.
У випадках, коли агент стикається з помилками, він може відновити та надати точні відповіді. Наприклад:
agent_executor.run("Who are the top 3 best selling artists?")
Навіть зіткнувшись з початковою помилкою, агент скорегує та надасть правильну відповідь, яка в даному випадку є ТОП-3 найбільш продаваних виконавців.
Агент Pandas DataFrame
У цьому розділі представлено агент, призначений для взаємодії з Pandas DataFrames для отримання відповідей на запитання. Зверніть увагу, що цей агент використовує агент Python під капотом для виконання коду Python, згенерованого мовною моделлю (LLM). Будьте обережні, використовуючи цей агент, щоб запобігти потенційній шкоді від шкідливого коду Python, створеного LLM.
Ви можете ініціалізувати агент Pandas DataFrame наступним чином:
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,
# )
Ви можете попросити агента підрахувати кількість рядків у DataFrame:
agent.run("how many rows are there?")
Агент виконає код df.shape[0]
і надайте відповідь, наприклад «У кадрі даних 891 рядок».
Ви також можете попросити агента відфільтрувати рядки на основі конкретних критеріїв, наприклад знайти кількість людей, які мають більше ніж 3 братів і сестер:
agent.run("how many people have more than 3 siblings")
Агент виконає код df[df['SibSp'] > 3].shape[0]
і дайте відповідь, наприклад «30 людей мають більше ніж 3 братів і сестер».
Якщо ви хочете обчислити квадратний корінь із середнього віку, ви можете запитати агента:
agent.run("whats the square root of the average age?")
Агент розрахує середній вік за допомогою df['Age'].mean()
а потім обчисліть квадратний корінь за допомогою math.sqrt()
. Він дасть відповідь, наприклад «Квадратний корінь із середнього віку дорівнює 5.449689683556195».
Давайте створимо копію DataFrame, а відсутні значення віку заповнимо середнім віком:
df1 = df.copy()
df1["Age"] = df1["Age"].fillna(df1["Age"].mean())
Потім ви можете ініціалізувати агент обома DataFrames і поставити йому запитання:
agent = create_pandas_dataframe_agent(OpenAI(temperature=0), [df, df1], verbose=True)
agent.run("how many rows in the age column are different?")
Агент порівнює вікові стовпці в обох DataFrames і надасть відповідь, наприклад «177 рядків у віковому стовпці різні».
Jira Toolkit
У цьому розділі пояснюється, як використовувати набір інструментів Jira, який дозволяє агентам взаємодіяти з примірником Jira. Ви можете виконувати різні дії, наприклад шукати проблеми та створювати проблеми за допомогою цього набору інструментів. Він використовує бібліотеку atlassian-python-api. Щоб використовувати цей набір інструментів, вам потрібно встановити змінні середовища для вашого екземпляра Jira, зокрема JIRA_API_TOKEN, JIRA_USERNAME та JIRA_INSTANCE_URL. Крім того, вам може знадобитися встановити ключ OpenAI API як змінну середовища.
Для початку встановіть бібліотеку atlassian-python-api і встановіть необхідні змінні середовища:
%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
)
Ви можете доручити агенту створити нову проблему в конкретному проекті зі зведенням і описом:
agent.run("make a new issue in project PW to remind me to make more fried rice")
Агент виконає необхідні дії для створення проблеми та надасть відповідь, як-от «У проекті PW створено нову проблему зі зведенням «Зробіть більше смаженого рису» та описом «Нагадування про необхідність зробити більше смаженого рису».
Це дозволяє вам взаємодіяти з примірником Jira за допомогою інструкцій природною мовою та набору інструментів Jira.
Автоматизуйте ручні завдання та робочі процеси за допомогою нашого конструктора робочих процесів на основі ШІ, розробленого Nanonets для вас і ваших команд.
Модуль IV: Ланцюги
LangChain — це інструмент, призначений для використання великих мовних моделей (LLM) у складних програмах. Він надає рамки для створення ланцюжків компонентів, включаючи LLM та інші типи компонентів. Дві основні рамки
- Мова виразів LangChain (LCEL)
- Застарілий інтерфейс Chain
Мова виразів LangChain (LCEL) — це синтаксис, який дозволяє інтуїтивно зрозуміло створювати ланцюжки. Він підтримує розширені функції, як-от потокове передавання, асинхронні виклики, пакетування, розпаралелювання, повторні спроби, резервні варіанти та трасування. Наприклад, ви можете створити підказку, модель і аналізатор виводу в LCEL, як показано в наступному коді:
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)
Крім того, LLMChain є опцією, подібною до LCEL для створення компонентів. Приклад LLMChain такий:
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")
Ланцюжки в LangChain також можуть мати стан шляхом включення об’єкта Memory. Це дозволяє зберігати дані між викликами, як показано в цьому прикладі:
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 також підтримує інтеграцію з API виклику функцій OpenAI, що корисно для отримання структурованих виходів і виконання функцій у ланцюжку. Щоб отримати структуровані результати, ви можете вказати їх за допомогою класів Pydantic або JsonSchema, як показано нижче:
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"})
Для структурованих виходів також доступний застарілий підхід із використанням 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 використовує функції OpenAI для створення різних конкретних ланцюжків для різних цілей. До них належать ланцюжки для вилучення, тегування, OpenAPI та QA з цитуваннями.
У контексті вилучення процес подібний до структурованого ланцюга виведення, але зосереджений на вилученні інформації або сутності. Для додавання тегів ідея полягає в тому, щоб позначити документ такими класами, як настрої, мова, стиль, охоплені теми або політичні тенденції.
Приклад того, як працює тегування в LangChain, можна продемонструвати за допомогою коду Python. Процес починається з встановлення необхідних пакетів і налаштування середовища:
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
Визначається схема для тегування, вказуючи властивості та їх очікувані типи:
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)
Приклади запуску ланцюжка тегів з різними вхідними даними показують здатність моделі інтерпретувати почуття, мови та агресивність:
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'}
Для більш точного контролю схему можна визначити більш конкретно, включаючи можливі значення, описи та необхідні властивості. Приклад цього розширеного контролю показано нижче:
schema = { "properties": { # Schema definitions here }, "required": ["language", "sentiment", "aggressiveness"],
} chain = create_tagging_chain(schema, llm)
Схеми Pydantic також можна використовувати для визначення критеріїв тегів, забезпечуючи Pythonic спосіб визначення необхідних властивостей і типів:
from enum import Enum
from pydantic import BaseModel, Field class Tags(BaseModel): # Class fields here chain = create_tagging_chain_pydantic(Tags, llm)
Крім того, засіб трансформації тегів метаданих LangChain можна використовувати для вилучення метаданих із документів LangChain, пропонуючи подібні функції до ланцюжка тегів, але застосовуючи їх до документа LangChain.
Посилання на джерела пошуку є ще однією функцією LangChain, яка використовує функції OpenAI для отримання цитат із тексту. Це показано в наступному коді:
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
У LangChain ланцюжок у програмах великої мовної моделі (LLM) зазвичай передбачає поєднання шаблону підказки з LLM і необов’язково синтаксичним аналізатором виводу. Рекомендований спосіб зробити це за допомогою мови виразів LangChain (LCEL), хоча також підтримується застарілий підхід LLMChain.
Використовуючи LCEL, BasePromptTemplate, BaseLanguageModel і BaseOutputParser реалізують інтерфейс Runnable і можуть легко передаватись один в одного. Ось приклад, який демонструє це:
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'
Маршрутизація в LangChain дозволяє створювати недетерміновані ланцюжки, де результат попереднього кроку визначає наступний крок. Це допомагає структурувати та підтримувати узгодженість у взаємодії з LLM. Наприклад, якщо у вас є два шаблони, оптимізовані для різних типів питань, ви можете вибрати шаблон на основі введення користувача.
Ось як ви можете досягти цього за допомогою LCEL з RunnableBranch, який ініціалізується списком пар (умова, виконуваний) і за замовчуванням виконуваним:
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
Остаточний ланцюжок потім будується з використанням різних компонентів, таких як класифікатор теми, гілка підказки та аналізатор виводу, щоб визначити потік на основі теми введення:
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
Цей підхід є прикладом гнучкості та потужності LangChain у обробці складних запитів та їх належній маршрутизації на основі вхідних даних.
У сфері мовних моделей поширеною практикою є продовження початкового виклику серією наступних викликів, використовуючи вихід одного виклику як вхід для наступного. Цей послідовний підхід особливо корисний, коли ви хочете спиратися на інформацію, отриману під час попередніх взаємодій. Хоча LangChain Expression Language (LCEL) є рекомендованим методом для створення цих послідовностей, метод SequentialChain все ще задокументований для його зворотної сумісності.
Щоб проілюструвати це, давайте розглянемо сценарій, коли ми спочатку генеруємо короткий опис гри, а потім огляд на основі цього короткого опису. Використання Python langchain.prompts
, створюємо два PromptTemplate
екземпляри: один для конспекту, інший для огляду. Ось код для налаштування цих шаблонів:
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:"
)
У підході LCEL ми об’єднуємо ці підказки ChatOpenAI
та StrOutputParser
щоб створити послідовність, яка спочатку генерує короткий опис, а потім огляд. Фрагмент коду виглядає наступним чином:
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"})
Якщо нам потрібні і синопсис, і огляд, ми можемо скористатися RunnablePassthrough
щоб створити окремий ланцюжок для кожного, а потім об’єднати їх:
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"})
Для сценаріїв, що включають більш складні послідовності, SequentialChain
метод вступає в дію. Це дозволяє використовувати кілька входів і виходів. Розглянемо випадок, коли нам потрібен синопсис на основі назви п’єси та епохи. Ось як ми можемо це налаштувати:
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"})
У сценаріях, коли ви хочете зберегти контекст у всьому ланцюжку або для наступної частини ланцюжка, SimpleMemory
може бути використаний. Це особливо корисно для керування складними взаємозв’язками введення/виведення. Наприклад, у сценарії, коли ми хочемо створити публікації в соціальних мережах на основі назви п’єси, епохи, короткого опису та рецензії, SimpleMemory
може допомогти керувати цими змінними:
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"})
Крім послідовних ланцюжків існують спеціалізовані ланцюжки для роботи з документами. Кожен із цих ланцюжків служить різним цілям: від об’єднання документів до уточнення відповідей на основі ітераційного аналізу документів до відображення та скорочення вмісту документів для підсумовування чи переранжування на основі оцінених відповідей. Ці ланцюжки можна відтворити за допомогою LCEL для додаткової гнучкості та налаштування.
-
StuffDocumentsChain
об’єднує список документів в єдину підказку, що передається LLM. -
RefineDocumentsChain
оновлює свою відповідь ітераційно для кожного документа, що підходить для завдань, де документи перевищують контекстну ємність моделі. -
MapReduceDocumentsChain
застосовує ланцюжок до кожного документа окремо, а потім об’єднує результати. -
MapRerankDocumentsChain
оцінює кожну відповідь на основі документа та вибирає відповідь із найвищим балом.
Ось приклад того, як можна налаштувати a MapReduceDocumentsChain
за допомогою 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")
Ця конфігурація дозволяє проводити детальний і комплексний аналіз вмісту документа, використовуючи переваги LCEL і базової мовної моделі.
Автоматизуйте ручні завдання та робочі процеси за допомогою нашого конструктора робочих процесів на основі ШІ, розробленого Nanonets для вас і ваших команд.
Модуль V: Пам'ять
У LangChain пам'ять є фундаментальним аспектом розмовних інтерфейсів, що дозволяє системам посилатися на минулі взаємодії. Це досягається шляхом зберігання та запиту інформації з двома основними діями: читанням і записом. Система пам’яті взаємодіє з ланцюгом двічі під час запуску, доповнюючи вхідні дані користувача та зберігаючи вхідні та вихідні дані для подальшого використання.
Вбудовування пам'яті в систему
- Зберігання повідомлень чату: Модуль пам’яті LangChain об’єднує різні методи для зберігання повідомлень чату, починаючи від списків у пам’яті до баз даних. Це гарантує, що всі взаємодії в чаті записуються для використання в майбутньому.
- Запит повідомлень чату: Окрім зберігання повідомлень чату, LangChain використовує структури даних і алгоритми для створення корисного перегляду цих повідомлень. Прості системи пам’яті можуть повертати нещодавні повідомлення, тоді як більш просунуті системи можуть узагальнювати минулі взаємодії або зосереджуватися на об’єктах, згаданих у поточній взаємодії.
Щоб продемонструвати використання пам’яті в LangChain, розглянемо ConversationBufferMemory
клас, проста форма пам'яті, яка зберігає повідомлення чату в буфері. Ось приклад:
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?")
Під час об’єднання пам’яті в ланцюжок дуже важливо розуміти змінні, що повертаються з пам’яті, і те, як вони використовуються в ланцюжку. Наприклад, load_memory_variables
метод допомагає узгодити змінні, зчитані з пам’яті, з очікуваннями ланцюжка.
Наскрізний приклад із LangChain
Подумайте про використання ConversationBufferMemory
в LLMChain
. Ланцюжок у поєднанні з відповідним шаблоном підказки та пам’яттю забезпечує безперебійну розмову. Ось спрощений приклад:
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?"})
Цей приклад ілюструє, як система пам’яті LangChain інтегрується з його ланцюжками, щоб забезпечити узгоджену розмову з урахуванням контексту.
Типи пам'яті в Langchain
Langchain пропонує різні типи пам’яті, які можна використовувати для покращення взаємодії з моделями ШІ. Кожен тип пам’яті має власні параметри та типи повернення, що робить їх придатними для різних сценаріїв. Давайте розглянемо деякі типи пам’яті, доступні в Langchain, разом із прикладами коду.
1. Буферна пам'ять розмов
Цей тип пам’яті дозволяє зберігати та отримувати повідомлення з розмов. Ви можете витягти історію як рядок або як список повідомлень.
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={})]}
Ви також можете використовувати пам’ять буфера розмов у ланцюжку для взаємодії, подібної до чату.
2. Пам'ять вікна буфера розмов
Цей тип пам’яті зберігає список останніх взаємодій і використовує останні K взаємодій, запобігаючи тому, щоб буфер став занадто великим.
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'}
Подібно до пам’яті буфера розмов, ви також можете використовувати цей тип пам’яті в ланцюжку для взаємодії, подібної до чату.
3. Пам'ять сутності розмови
Цей тип пам’яті запам’ятовує факти про конкретні сутності в розмові та витягує інформацію за допомогою 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. Розмова Граф пам'яті знань
Цей тип пам’яті використовує граф знань для відтворення пам’яті. Ви можете витягувати поточні сутності та триплети знань із повідомлень.
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.'}
Ви також можете використовувати цей тип пам’яті в ланцюжку для пошуку знань на основі розмови.
5. Розмова Підсумкова пам'ять
Цей тип пам’яті створює підсумок розмови протягом певного часу, корисний для ущільнення інформації з тривалих розмов.
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. Буферна пам'ять підсумкової розмови
Цей тип пам’яті поєднує підсумок розмови та буфер, зберігаючи баланс між останніми взаємодіями та підсумком. Він використовує довжину маркера, щоб визначити, коли скидати взаємодії.
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'}
Ви можете використовувати ці типи пам’яті для покращення взаємодії з моделями ШІ в Langchain. Кожен тип пам’яті служить певній меті та може бути обраний відповідно до ваших вимог.
7. Буферна пам'ять маркера розмови
ConversationTokenBufferMemory — ще один тип пам’яті, який зберігає в пам’яті буфер останніх взаємодій. На відміну від попередніх типів пам’яті, які зосереджуються на кількості взаємодій, цей використовує довжину маркера, щоб визначити, коли скидати взаємодії.
Використання пам'яті з 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'}
У цьому прикладі пам’ять налаштована на обмеження взаємодій на основі довжини маркера, а не кількості взаємодій.
При використанні цього типу пам’яті ви також можете отримати історію як список повідомлень.
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"})
Використання в ланцюжку:
Ви можете використовувати ConversationTokenBufferMemory у ланцюжку, щоб покращити взаємодію з моделлю ШІ.
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?")
У цьому прикладі ConversationTokenBufferMemory використовується в ConversationChain для керування бесідою та обмеження взаємодії на основі довжини маркера.
8. VectorStoreRetrieverMemory
VectorStoreRetrieverMemory зберігає спогади у векторному сховищі та запитує перші K найбільш «важливих» документів під час кожного виклику. Цей тип пам’яті явно не відстежує порядок взаємодій, але використовує векторний пошук для отримання відповідних спогадів.
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"])
У цьому прикладі VectorStoreRetrieverMemory використовується для зберігання та отримання відповідної інформації з розмови на основі векторного пошуку.
Ви також можете використовувати VectorStoreRetrieverMemory у ланцюжку для пошуку знань на основі розмови, як показано в попередніх прикладах.
Ці різні типи пам’яті в Langchain надають різні способи керування та отримання інформації з розмов, покращуючи можливості моделей штучного інтелекту щодо розуміння запитів користувачів і контексту та відповідей на них. Кожен тип пам'яті можна вибрати на основі конкретних вимог вашої програми.
Тепер ми навчимося використовувати пам’ять за допомогою LLMChain. Пам’ять у LLMChain дозволяє моделі запам’ятовувати попередні взаємодії та контекст, щоб надавати більш узгоджені відповіді з урахуванням контексту.
Щоб налаштувати пам’ять у LLMChain, вам потрібно створити клас пам’яті, наприклад ConversationBufferMemory. Ось як це можна налаштувати:
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")
У цьому прикладі ConversationBufferMemory використовується для зберігання історії розмов. The memory_key
Параметр визначає ключ, який використовується для зберігання історії розмов.
Якщо ви використовуєте модель чату замість моделі стилю завершення, ви можете по-іншому структурувати свої підказки, щоб краще використовувати пам’ять. Ось приклад того, як налаштувати LLMChain на основі моделі чату з пам’яттю:
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")
У цьому прикладі ChatPromptTemplate використовується для структурування підказки, а ConversationBufferMemory використовується для зберігання та отримання історії розмов. Цей підхід особливо корисний для розмов у стилі чату, де контекст і історія відіграють вирішальну роль.
Пам’ять також можна додати до ланцюжка з декількома входами, наприклад до ланцюжка запитань/відповідей. Ось приклад того, як налаштувати пам’ять у ланцюжку запитань/відповідей:
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)
У цьому прикладі відповідь на запитання надається за допомогою документа, розділеного на менші частини. ConversationBufferMemory використовується для зберігання та отримання історії розмов, що дозволяє моделі надавати відповіді з урахуванням контексту.
Додавання пам’яті до агента дозволяє йому запам’ятовувати та використовувати попередні взаємодії, щоб відповідати на запитання та надавати відповіді з урахуванням контексту. Ось як можна налаштувати пам’ять в агенті:
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)
У цьому прикладі до агента додається пам’ять, що дозволяє йому запам’ятовувати історію попередніх розмов і надавати контекстно-залежні відповіді. Це дозволяє агенту точно відповідати на додаткові запитання на основі інформації, що зберігається в пам’яті.
Мова експресії LangChain
У світі обробки природної мови та машинного навчання складання складних ланцюжків операцій може бути складним завданням. На щастя, мова LangChain Expression Language (LCEL) приходить на допомогу, забезпечуючи декларативний і ефективний спосіб створення та розгортання складних конвеєрів обробки мови. LCEL розроблено для спрощення процесу складання ланцюжків, дозволяючи легко переходити від створення прототипу до виробництва. У цьому блозі ми дослідимо, що таке LCEL і чому ви можете його використовувати, а також практичні приклади коду, щоб проілюструвати його можливості.
LCEL, або мова виразів LangChain, є потужним інструментом для створення ланцюжків обробки мови. Він був спеціально створений для підтримки переходу від прототипування до виробництва без проблем, не вимагаючи значних змін коду. Незалежно від того, створюєте ви простий ланцюжок «підказка + LLM» або складний конвеєр із сотнями кроків, LCEL допоможе вам.
Ось кілька причин використовувати LCEL у ваших проектах обробки мови:
- Швидка потокова передача маркерів: LCEL доставляє маркери з мовної моделі до вихідного синтаксичного аналізатора в режимі реального часу, покращуючи швидкість реагування та ефективність.
- Універсальні API: LCEL підтримує як синхронні, так і асинхронні API для створення прототипів і виробництва, ефективно обробляючи численні запити.
- Автоматичне розпаралелювання: LCEL оптимізує паралельне виконання, коли це можливо, зменшуючи затримку в інтерфейсах синхронізації та асинхронізації.
- Надійні конфігурації: налаштуйте повторні спроби та резервні варіанти для підвищення надійності ланцюга в масштабі з підтримкою потокового передавання в розробці.
- Потік проміжних результатів: доступ до проміжних результатів під час обробки для оновлень користувача або з метою налагодження.
- Генерація схем: LCEL генерує схеми Pydantic і JSONSchema для перевірки вхідних і вихідних даних.
- Комплексне відстеження: LangSmith автоматично відстежує всі кроки в складних ланцюжках для спостереження та налагодження.
- Легке розгортання: легко розгортайте ланцюжки, створені LCEL, за допомогою LangServe.
Тепер давайте зануримося в практичні приклади коду, які демонструють потужність LCEL. Ми досліджуватимемо загальні завдання та сценарії, де LCEL сяє.
Підказка + LLM
Найфундаментальніша композиція передбачає поєднання підказки та мовної моделі для створення ланцюжка, який приймає введені користувачем дані, додає їх до підказки, передає в модель і повертає необроблений вихід моделі. Ось приклад:
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)
У цьому прикладі ланцюжок генерує жарт про ведмедів.
Ви можете прикріпити до свого ланцюжка послідовності зупинок, щоб контролювати, як він обробляє текст. Наприклад:
chain = prompt | model.bind(stop=["n"])
result = chain.invoke({"foo": "bears"})
print(result)
Ця конфігурація зупиняє створення тексту, коли зустрічається символ нового рядка.
LCEL підтримує додавання інформації про виклик функції до вашого ланцюжка. Ось приклад:
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)
Цей приклад додає інформацію про виклик функції, щоб створити жарт.
Підказка + LLM + OutputParser
Ви можете додати синтаксичний аналізатор виводу, щоб перетворити необроблений вихід моделі в більш зручний формат. Ось як ви можете це зробити:
from langchain.schema.output_parser import StrOutputParser chain = prompt | model | StrOutputParser()
result = chain.invoke({"foo": "bears"})
print(result)
Вихідні дані тепер у форматі рядка, що зручніше для подальших завдань.
Указуючи функцію для повернення, ви можете проаналізувати її безпосередньо за допомогою LCEL. Наприклад:
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)
У цьому прикладі безпосередньо аналізується вихід функції «joke».
Це лише кілька прикладів того, як LCEL спрощує складні завдання обробки мови. Незалежно від того, створюєте ви чат-ботів, генеруєте вміст або виконуєте складні текстові перетворення, LCEL може оптимізувати ваш робочий процес і зробити ваш код більш зручним для обслуговування.
RAG (генерація з доповненим пошуком)
LCEL можна використовувати для створення ланцюжків генерації з доповненим пошуком, які поєднують етапи пошуку та генерації мови. Ось приклад:
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)
У цьому прикладі ланцюжок отримує релевантну інформацію з контексту та генерує відповідь на запитання.
Розмовний ланцюжок пошуку
Ви можете легко додати історію розмов до своїх ланцюжків. Ось приклад ланцюжка розмовного пошуку:
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)
У цьому прикладі ланцюжок обробляє наступне запитання в контексті розмови.
З пам'яттю та поверненням вихідних документів
LCEL також підтримує пам'ять і повернення вихідних документів. Ось як ви можете використовувати пам'ять у ланцюжку:
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)
У цьому прикладі пам’ять використовується для зберігання та отримання історії розмов і вихідних документів.
Кілька ланцюгів
Ви можете об’єднати кілька ланцюжків за допомогою Runnables. Ось приклад:
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)
У цьому прикладі два ланцюжки об’єднані для створення інформації про місто та його країну визначеною мовою.
Розгалуження та злиття
LCEL дозволяє розділяти та об’єднувати ланцюжки за допомогою RunnableMaps. Ось приклад розгалуження та злиття:
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)
У цьому прикладі ланцюжок розгалуження та злиття використовується для генерації аргументу та оцінки його плюсів і мінусів перед тим, як генерувати остаточну відповідь.
Написання коду Python за допомогою LCEL
Одним із потужних застосувань LangChain Expression Language (LCEL) є написання коду Python для вирішення проблем користувачів. Нижче наведено приклад використання LCEL для написання коду Python:
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain_experimental.utilities import PythonREPL template = """Write some python code to solve the user's problem. Return only python code in Markdown format, e.g.: ```python
....
```"""
prompt = ChatPromptTemplate.from_messages([("system", template), ("human", "{input}")]) model = ChatOpenAI() def _sanitize_output(text: str): _, after = text.split("```python") return after.split("```")[0] chain = prompt | model | StrOutputParser() | _sanitize_output | PythonREPL().run result = chain.invoke({"input": "what's 2 plus 2"})
print(result)
У цьому прикладі користувач вводить дані, а LCEL створює код Python для вирішення проблеми. Потім код виконується за допомогою Python REPL, і отриманий код Python повертається у форматі Markdown.
Зверніть увагу, що використання Python REPL може виконувати довільний код, тому використовуйте його з обережністю.
Додавання пам'яті до ланцюга
Пам'ять має важливе значення для багатьох розмовних програм ШІ. Ось як додати пам’ять до довільного ланцюжка:
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({})
У цьому прикладі пам’ять використовується для зберігання та отримання історії розмов, що дозволяє чат-боту підтримувати контекст і відповідати належним чином.
Використання зовнішніх інструментів із Runnables
LCEL дозволяє легко інтегрувати зовнішні інструменти з Runnables. Ось приклад використання інструмента DuckDuckGo Search:
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain.tools import DuckDuckGoSearchRun search = DuckDuckGoSearchRun() template = """Turn the following user input into a search query for a search engine: {input}"""
prompt = ChatPromptTemplate.from_template(template) model = ChatOpenAI() chain = prompt | model | StrOutputParser() | search search_result = chain.invoke({"input": "I'd like to figure out what games are tonight"})
print(search_result)
У цьому прикладі LCEL інтегрує інструмент DuckDuckGo Search у ланцюжок, дозволяючи йому генерувати пошуковий запит на основі введення користувача та отримувати результати пошуку.
Гнучкість LCEL дозволяє легко включати різноманітні зовнішні інструменти та служби у ваші конвеєри обробки мови, покращуючи їхні можливості та функціональність.
Додавання модерації до програми LLM
Щоб переконатися, що ваша програма LLM відповідає політикам щодо вмісту та включає засоби захисту модерації, ви можете інтегрувати перевірки модерації у свій ланцюжок. Ось як додати модерацію за допомогою 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)
У цьому прикладі файл OpenAIModerationChain
використовується для додавання модерації до відповіді, створеної LLM. Ланцюжок модерації перевіряє відповіді на вміст, який порушує політику щодо вмісту OpenAI. Якщо буде виявлено будь-які порушення, відповідним чином буде позначено відповідь.
Маршрутизація за семантичною подібністю
LCEL дозволяє реалізувати спеціальну логіку маршрутизації на основі семантичної подібності введених користувачем даних. Ось приклад того, як динамічно визначати логіку ланцюга на основі введення користувача:
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"}))
У цьому прикладі файл prompt_router
функція обчислює косинусну подібність між введенням користувача та попередньо визначеними шаблонами запитань із фізики та математики. На основі оцінки подібності ланцюжок динамічно вибирає найбільш релевантний шаблон підказки, забезпечуючи належну відповідь чат-бота на запитання користувача.
Використання агентів і Runnables
LangChain дозволяє створювати агентів, поєднуючи Runnables, підказки, моделі та інструменти. Ось приклад створення агента та його використання:
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)
У цьому прикладі агент створюється шляхом поєднання моделі, інструментів, підказки та спеціальної логіки для проміжних кроків і перетворення інструментів. Після цього агент виконується, надаючи відповідь на запит користувача.
Запит до бази даних SQL
Ви можете використовувати LangChain для запитів до бази даних SQL і створення запитів SQL на основі запитань користувача. Ось приклад:
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)
У цьому прикладі LangChain використовується для створення SQL-запитів на основі запитань користувача та отримання відповідей із бази даних SQL. Підказки та відповіді відформатовано для забезпечення природної взаємодії мови з базою даних.
Автоматизуйте ручні завдання та робочі процеси за допомогою нашого конструктора робочих процесів на основі ШІ, розробленого Nanonets для вас і ваших команд.
LangServe & LangSmith
LangServe допомагає розробникам розгортати виконувані модулі та ланцюжки LangChain як REST API. Ця бібліотека інтегрована з FastAPI та використовує pydantic для перевірки даних. Крім того, він надає клієнт, який можна використовувати для виклику runnables, розгорнутих на сервері, а клієнт JavaScript доступний у LangChainJS.
риси
- Схеми введення та виведення автоматично виводяться з вашого об’єкта LangChain і застосовуються під час кожного виклику API із багатими повідомленнями про помилки.
- Доступна сторінка документів API з JSONSchema та Swagger.
- Ефективні кінцеві точки /invoke, /batch і /stream з підтримкою багатьох одночасних запитів на одному сервері.
- Кінцева точка /stream_log для потокової передачі всіх (або деяких) проміжних кроків від вашого ланцюга/агента.
- Сторінка ігрового майданчика за адресою /playground із потоковим виведенням і проміжними кроками.
- Вбудована (додаткова) трасування в LangSmith; просто додайте свій ключ API (див. Інструкції).
- Усі вони створені з перевіреними в боях бібліотеками Python з відкритим кодом, такими як FastAPI, Pydantic, uvloop і asyncio.
Недоліки
- Клієнтські зворотні виклики ще не підтримуються для подій, які виникають на сервері.
- Під час використання Pydantic V2 документи OpenAPI не створюватимуться. FastAPI не підтримує змішування пидантичних просторів імен v1 і v2. Додаткову інформацію див. у розділі нижче.
Використовуйте LangChain CLI для швидкого завантаження проекту LangServe. Щоб використовувати langchain CLI, переконайтеся, що у вас встановлено останню версію langchain-cli. Ви можете встановити його за допомогою pip install -U langchain-cli.
langchain app new ../path/to/directory
Швидко запустіть свій екземпляр LangServe за допомогою шаблонів LangChain. Більше прикладів дивіться в покажчику шаблонів або каталозі прикладів.
Ось сервер, який розгортає модель чату OpenAI, модель чату Anthropic і мережу, яка використовує модель Anthropic, щоб розповісти анекдот на тему.
#!/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)
Після того, як ви розгорнули сервер вище, ви можете переглянути згенеровані документи OpenAPI за допомогою:
curl localhost:8000/docs
Обов’язково додайте суфікс /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" }])
У TypeScript (потрібна версія LangChain.js 0.0.166 або новіша):
import { RemoteRunnable } from "langchain/runnables/remote"; const chain = new RemoteRunnable({ url: `http://localhost:8000/chain/invoke/`,
});
const result = await chain.invoke({ topic: "cats",
});
Python використовує запити:
import requests
response = requests.post( "http://localhost:8000/chain/invoke/", json={'input': {'topic': 'cats'}}
)
response.json()
Ви також можете використовувати curl:
curl --location --request POST 'http://localhost:8000/chain/invoke/' --header 'Content-Type: application/json' --data-raw '{ "input": { "topic": "cats" } }'
Наступний код:
...
add_routes( app, runnable, path="/my_runnable",
)
додає ці кінцеві точки на сервер:
- POST /my_runnable/invoke – викликати runnable на один вхід
- POST /my_runnable/batch – викликати runnable для пакету вхідних даних
- POST /my_runnable/stream – виклик на одному вході та потік виведення
- POST /my_runnable/stream_log – виклик на одному вході та потік виводу, включно з виведенням проміжних кроків у міру його створення
- GET /my_runnable/input_schema – схема json для введення в runnable
- GET /my_runnable/output_schema – json-схема для виведення runnable
- GET /my_runnable/config_schema – схема json для конфігурації runnable
Ви можете знайти сторінку ігрового майданчика для свого runnable за адресою /my_runnable/playground. Це відкриває простий інтерфейс користувача для налаштування та виклику вашого runnable із потоковим виведенням і проміжними кроками.
Як для клієнта, так і для сервера:
pip install "langserve[all]"
або pip install “langserve[client]” для клієнтського коду та pip install “langserve[server]” для серверного коду.
Якщо вам потрібно додати автентифікацію на свій сервер, зверніться до документації щодо безпеки та проміжного програмного забезпечення FastAPI.
Ви можете розгорнути GCP Cloud Run за допомогою такої команди:
gcloud run deploy [your-service-name] --source . --port 8001 --allow-unauthenticated --region us-central1 --set-env-vars=OPENAI_API_KEY=your_key
LangServe забезпечує підтримку Pydantic 2 з деякими обмеженнями. Під час використання Pydantic V2 документи OpenAPI не створюватимуться для invoke/batch/stream/stream_log. Швидкий API не підтримує змішування підантичних просторів імен v1 і v2. LangChain використовує простір імен v1 у Pydantic v2. Прочитайте наведені нижче вказівки, щоб переконатися в сумісності з LangChain. За винятком цих обмежень, ми очікуємо, що кінцеві точки API, ігровий майданчик і будь-які інші функції працюватимуть належним чином.
Програми LLM часто мають справу з файлами. Існують різні архітектури, які можна створити для реалізації обробки файлів; на високому рівні:
- Файл може бути завантажений на сервер через виділену кінцеву точку та оброблений за допомогою окремої кінцевої точки.
- Файл може бути завантажений або за значенням (байти файлу), або за посиланням (наприклад, URL-адреса s3 для вмісту файлу).
- Кінцева точка обробки може бути блокуючою або неблокуючою.
- Якщо потрібна значна обробка, обробку можна перенести на спеціальний пул процесів.
Ви повинні визначити, яка архітектура підходить для вашої програми. Наразі, щоб завантажити файли за значенням у runnable, використовуйте кодування base64 для файлу (multipart/form-data ще не підтримується).
Ось такий приклад який показує, як використовувати кодування base64 для надсилання файлу на віддалений запуск. Пам’ятайте, що ви завжди можете завантажувати файли за посиланням (наприклад, URL-адреса s3) або завантажувати їх як багатокомпонентні дані/дані форми до спеціальної кінцевої точки.
Типи входу та виводу визначені для всіх запущених файлів. Ви можете отримати до них доступ через властивості input_schema та output_schema. LangServe використовує ці типи для перевірки та документації. Якщо ви бажаєте перевизначити стандартні типи, ви можете використати метод with_types.
Ось приклад іграшки, щоб проілюструвати цю ідею:
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)
Успадкуйте від CustomUserType, якщо ви хочете, щоб дані десеріалізувалися в підантичну модель, а не в еквівалентне представлення dict. На даний момент цей тип працює лише на стороні сервера та використовується для визначення бажаної поведінки декодування. У разі успадкування від цього типу сервер зберігатиме декодований тип як підантичну модель замість того, щоб перетворювати його на dict.
from fastapi import FastAPI
from langchain.schema.runnable import RunnableLambda
from langserve import add_routes
from langserve.schema import CustomUserType app = FastAPI() class Foo(CustomUserType): bar: int def func(foo: Foo) -> int: """Sample function that expects a Foo type which is a pydantic model""" assert isinstance(foo, Foo) return foo.bar add_routes(app, RunnableLambda(func), path="/foo")
Ігровий майданчик дозволяє вам визначати користувацькі віджети для вашого runnable із серверної частини. Віджет вказується на рівні поля та надсилається як частина схеми JSON типу введення. Віджет повинен містити ключ під назвою type зі значенням одного з добре відомого списку віджетів. Інші ключі віджета будуть пов’язані зі значеннями, які описують шляхи в об’єкті JSON.
Загальна схема:
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;
};
Дозволяє створювати вхідні дані для завантаження файлів у ігровому майданчику інтерфейсу користувача для файлів, які завантажуються як рядки в кодуванні base64. Ось повний приклад.
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
Автоматизуйте ручні завдання та робочі процеси за допомогою нашого конструктора робочих процесів на основі ШІ, розробленого Nanonets для вас і ваших команд.
Знайомство з LangSmith
LangChain дозволяє легко створювати прототипи LLM-додатків і агентів. Однак доставка програм LLM до виробництва може бути оманливо складною. Щоб створити високоякісний продукт, вам, імовірно, доведеться ретельно налаштовувати та повторювати свої підказки, ланцюжки та інші компоненти.
Щоб допомогти в цьому процесі, було представлено LangSmith, уніфіковану платформу для налагодження, тестування та моніторингу ваших програм LLM.
Коли це може стати в нагоді? Це може бути корисним, коли ви хочете швидко налагодити новий ланцюжок, агента або набір інструментів, візуалізувати зв’язок і використання компонентів (ланцюги, LLMS, ретривери тощо), оцінити різні підказки та LLM для одного компонента, кілька разів перевірте певний ланцюжок над набором даних, щоб переконатися, що він постійно відповідає планці якості, або зафіксуйте сліди використання та використовуйте LLM або конвеєри аналітики для отримання інформації.
Необхідні умови:
- Створіть обліковий запис LangSmith і створіть ключ API (див. нижній лівий кут).
- Ознайомтеся з платформою, переглянувши документи.
Тепер давайте почнемо!
По-перше, налаштуйте змінні середовища, щоб наказати LangChain реєструвати трасування. Це робиться шляхом встановлення значення true для змінної середовища LANGCHAIN_TRACING_V2. Ви можете вказати LangChain, який проект реєструвати, встановивши змінну середовища LANGCHAIN_PROJECT (якщо це значення не встановлено, запуски реєструватимуться в проекті за замовчуванням). Це автоматично створить для вас проект, якщо він не існує. Ви також повинні встановити змінні середовища LANGCHAIN_ENDPOINT і LANGCHAIN_API_KEY.
ПРИМІТКА. Ви також можете використовувати диспетчер контексту в python, щоб реєструвати трасування за допомогою:
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?")
Однак у цьому прикладі ми будемо використовувати змінні середовища.
%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>"
Створіть клієнт LangSmith для взаємодії з API:
from langsmith import Client client = Client()
Створіть компонент LangChain і зареєструйте запуски на платформі. У цьому прикладі ми створимо агента в стилі ReAct із доступом до загального інструменту пошуку (DuckDuckGo). Підказку агента можна переглянути в Хабі тут:
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
)
Ми запускаємо агент одночасно на кількох входах, щоб зменшити затримку. Запуски реєструються в LangSmith у фоновому режимі, тому затримка виконання не впливає:
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]
Якщо ви успішно налаштували своє середовище, трасування вашого агента мають відображатися в розділі «Проекти» програми. Вітаю!
Схоже, що агент неефективно використовує інструменти. Давайте оцінимо це, щоб у нас була базова лінія.
На додаток до журналювання, LangSmith також дозволяє тестувати та оцінювати ваші програми LLM.
У цьому розділі ви використаєте LangSmith, щоб створити набір даних порівняння та запустити на агенті оцінювачі за допомогою ШІ. Ви зробите це за кілька кроків:
- Створіть набір даних LangSmith:
Нижче ми використовуємо клієнт LangSmith для створення набору даних із введених вище запитань і міток списку. Ви використовуватимете їх пізніше для вимірювання ефективності нового агента. Набір даних — це набір прикладів, які є не чим іншим, як парами введення-виведення, які можна використовувати як тестові випадки для вашої програми:
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 )
- Ініціалізація нового агента для тестування:
LangSmith дозволяє оцінити будь-яку LLM, мережу, агента або навіть спеціальну функцію. Розмовні агенти мають стан (вони мають пам'ять); щоб переконатися, що цей стан не розподіляється між запусками набору даних, ми передамо chain_factory (
також конструктор) для ініціалізації для кожного виклику:
# 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)
- Налаштувати оцінку:
Ручне порівняння результатів ланцюжків в інтерфейсі користувача є ефективним, але може зайняти багато часу. Може бути корисно використовувати автоматичні показники та зворотній зв’язок за допомогою штучного інтелекту, щоб оцінити продуктивність вашого компонента:
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=[],
)
- Запустіть агента та оцінювачі:
Використовуйте функцію run_on_dataset (або асинхронну arun_on_dataset), щоб оцінити свою модель. Це буде:
- Отримати зразки рядків із указаного набору даних.
- Запустіть свій агент (або будь-яку спеціальну функцію) для кожного прикладу.
- Застосуйте оцінювачі до отриманих трасувань запуску та відповідних еталонних прикладів для створення автоматичного зворотного зв’язку.
Результати буде видно в додатку 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", ],
)
Тепер, коли ми маємо результати тестування, ми можемо внести зміни в наш агент і порівняти їх. Давайте спробуємо це знову з іншою підказкою та побачимо результати:
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 дозволяє експортувати дані у типові формати, наприклад CSV або JSONL, безпосередньо у веб-програмі. Ви також можете використовувати клієнт, щоб отримати прогони для подальшого аналізу, зберегти у власній базі даних або поділитися з іншими. Давайте виберемо траси виконання з оцінювального запуску:
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
Це був короткий посібник для початку, але є багато інших способів використання LangSmith, щоб пришвидшити роботу розробника та отримати кращі результати.
Для отримання додаткової інформації про те, як отримати максимальну віддачу від LangSmith, перегляньте документацію LangSmith.
Підвищуйте рівень за допомогою Nanonets
Незважаючи на те, що LangChain є цінним інструментом для інтеграції мовних моделей (LLM) із вашими програмами, він може зіткнутися з обмеженнями, коли мова заходить про випадки корпоративного використання. Давайте дослідимо, як Nanonets виходить за рамки LangChain для вирішення цих проблем:
1. Комплексне підключення даних:
LangChain пропонує з’єднувачі, але вони можуть охоплювати не всі робочі програми та формати даних, на які покладаються компанії. Nanonets надає з’єднувачі даних для понад 100 широко використовуваних програм робочого середовища, включаючи Slack, Notion, Google Suite, Salesforce, Zendesk та багато інших. Він також підтримує всі неструктуровані типи даних, як-от PDF-файли, TXT-файли, зображення, аудіо- та відеофайли, а також структуровані типи даних, як-от CSV, електронні таблиці, бази даних MongoDB і SQL.
2. Автоматизація завдань для програм Workspace:
Хоча генерація тексту/відповіді працює чудово, можливості LangChain обмежені, коли йдеться про використання природної мови для виконання завдань у різних програмах. Nanonets пропонує агенти тригерів/дій для найпопулярніших програм робочого простору, що дозволяє вам налаштовувати робочі процеси, які відстежують події та виконують дії. Наприклад, ви можете автоматизувати відповіді електронною поштою, записи CRM, запити SQL тощо за допомогою команд природною мовою.
3. Синхронізація даних у реальному часі:
LangChain отримує статичні дані за допомогою конекторів даних, які можуть не встигати за змінами даних у вихідній базі даних. Навпаки, Nanonets забезпечує синхронізацію в реальному часі з джерелами даних, гарантуючи, що ви завжди працюєте з найновішою інформацією.
3. Спрощена конфігурація:
Налаштування елементів конвеєра LangChain, таких як ретривери та синтезатори, може бути складним і трудомістким процесом. Nanonets спрощує це, забезпечуючи оптимізоване надходження та індексування даних для кожного типу даних, і все це обробляється у фоновому режимі за допомогою AI Assistant. Це зменшує навантаження на тонке налаштування та полегшує налаштування та використання.
4. Уніфіковане рішення:
На відміну від LangChain, який може потребувати унікальних реалізацій для кожного завдання, Nanonets служить універсальним рішенням для підключення ваших даних до LLM. Незалежно від того, чи потрібно вам створювати програми LLM або робочі процеси AI, Nanonets пропонує єдину платформу для ваших різноманітних потреб.
Робочі процеси Nanonets AI
Nanonets Workflows — це безпечний багатоцільовий помічник штучного інтелекту, який спрощує інтеграцію ваших знань і даних із магістрами права та полегшує створення додатків і робочих процесів без використання коду. Він пропонує простий у використанні інтерфейс користувача, що робить його доступним як для окремих осіб, так і для організацій.
Щоб розпочати роботу, ви можете запланувати телефонну розмову з одним із наших експертів зі штучного інтелекту, який може надати персоналізовану демонстрацію та пробну версію робочих процесів Nanonets відповідно до вашого конкретного випадку використання.
Після налаштування ви можете використовувати природну мову для розробки та виконання складних програм і робочих процесів на базі LLM, бездоганно інтегруючись із вашими програмами та даними.
Зарядіть свої команди за допомогою Nanonets AI, щоб створювати програми та інтегрувати свої дані з додатками та робочими процесами на основі штучного інтелекту, дозволяючи вашим командам зосередитися на тому, що справді важливо.
Автоматизуйте ручні завдання та робочі процеси за допомогою нашого конструктора робочих процесів на основі ШІ, розробленого Nanonets для вас і ваших команд.
- Розповсюдження контенту та PR на основі SEO. Отримайте посилення сьогодні.
- PlatoData.Network Vertical Generative Ai. Додайте собі сили. Доступ тут.
- PlatoAiStream. Web3 Intelligence. Розширення знань. Доступ тут.
- ПлатонЕСГ. вуглець, CleanTech, Енергія, Навколишнє середовище, Сонячна, Поводження з відходами. Доступ тут.
- PlatoHealth. Розвідка про біотехнології та клінічні випробування. Доступ тут.
- джерело: https://nanonets.com/blog/langchain/
- : має
- :є
- : ні
- :де
- $UP
- 1
- 10
- 100
- 114
- 13
- 15%
- 2000
- 2012
- 2023
- 25
- 30
- 32
- 36
- 40
- 400
- 408
- 50
- 500
- 7
- 8
- a
- азбука
- здатність
- Здатний
- МЕНЮ
- про це
- вище
- Прийняти
- Приймає
- доступ
- доступною
- доступ до
- виконувати
- відповідно
- рахунки
- точність
- точний
- точно
- Achieve
- досягнутий
- Досягає
- через
- Діяти
- дію
- дії
- активний
- пристосування
- адаптивний
- додавати
- доданий
- додати
- доповнення
- Додатковий
- Додатково
- адреса
- Додає
- визнати
- просунутий
- пригода
- після
- знову
- вік
- Агент
- агенти
- AI
- AI помічник
- Моделі AI
- Aid
- прицілювання
- алгоритми
- вирівнювати
- Вирівнює
- ВСІ
- дозволяти
- Дозволити
- дозволяє
- тільки
- по
- пліч-о-пліч
- вже
- Також
- хоча
- завжди
- an
- аналіз
- Аналітичний
- аналітика
- та
- -Анджелесі
- Оголосити
- щорічний
- Інший
- відповідь
- Відповіді
- гімн
- Антропний
- будь-який
- все
- API
- КЛЮЧІ API
- Інтерфейси
- додаток
- застосовно
- додаток
- Розробка додатка
- застосування
- прикладної
- застосовується
- підхід
- підходи
- відповідний
- відповідним чином
- додатка
- архітектура
- ЕСТЬ
- аргумент
- аргументація
- Армстронг
- навколо
- масив
- Художники
- AS
- запитати
- зовнішній вигляд
- аспекти
- допомогу
- Помічник
- асоційований
- At
- приєднувати
- увагу
- аудіо
- збільшено
- Authentication
- автоматизувати
- Автоматизований
- автоматизує
- автоматично
- Автоматизація
- доступний
- середній
- чекати
- знати
- AWS
- назад
- Хребет
- Backend
- фон
- погано
- Balance
- бар
- база
- заснований
- Базова лінія
- бити
- основний
- Основи
- БЦЖ
- BE
- Пляж
- ведмеді
- оскільки
- було
- перед тим
- починати
- поведінка
- за
- за лаштунками
- буття
- нижче
- еталонний тест
- корисний
- КРАЩЕ
- Краще
- між
- За
- найбільший
- Білл
- Білл Гейтс
- пов'язувати
- Bing
- Біт
- Black
- Чорна діра
- Блокувати
- блокування
- блоки
- Блог
- боб
- Bootstrap
- народжений
- Бот
- обидва
- дно
- Філія
- Перерва
- вітер
- коротко
- ширше
- коричневий
- браузер
- буфера
- будувати
- будівельник
- Створюємо
- побудований
- тягар
- підприємства
- але
- by
- обчислювати
- обчислює
- розрахунок
- розрахунок
- call
- зворотні дзвінки
- званий
- покликання
- Виклики
- CAN
- Може отримати
- Канада
- можливості
- здатний
- потужність
- захоплення
- захопивши
- випадок
- випадків
- КПП
- догоджати
- громадське харчування
- обслуговує
- коти
- обережність
- обережний
- центр
- певний
- ланцюг
- ланцюга
- проблеми
- Зміни
- характер
- Chatbot
- chatbots
- перевірка
- Перевірки
- Вибирати
- вибраний
- обставин
- Місто
- клас
- класів
- клієнт
- хмара
- код
- Кодування
- кави
- КОГЕРЕНТНИЙ
- згуртований
- співпрацювати
- колапс
- збір
- барвистий
- Колонка
- Колони
- COM
- об'єднувати
- комбінований
- комбінати
- об'єднання
- Приходити
- приходить
- зручний
- загальний
- Комунікація
- компанія
- порівняти
- порівняння
- сумісність
- сумісний
- повний
- повністю
- завершення
- комплекс
- складності
- компонент
- Компоненти
- складається
- склад
- всеосяжний
- що включає
- концепція
- лаконічний
- одночасно
- стан
- конфігурація
- злиття
- З'єднуватися
- З'єднувальний
- зв'язок
- мінуси
- Вважати
- послідовно
- складається
- Консоль
- постійно
- конструкти
- містити
- містить
- зміст
- контекст
- контексти
- контекстуальний
- продовжувати
- постійно
- контрастність
- контроль
- управління
- Зручний
- Розмова
- діалоговий
- розмовний ШІ
- розмови
- Перетворення
- перероблений
- перетворення
- Core
- Кут
- виправити
- Відповідний
- може
- підрахунок
- країна
- Пара
- обкладинка
- покритий
- створювати
- створений
- створює
- створення
- створення
- Повноваження
- Критерії
- Критик
- CRM
- вирішальне значення
- Поточний
- В даний час
- виготовлений на замовлення
- Клієнти
- настройка
- налаштувати
- налаштувати
- передовий
- дані
- Структура даних
- Database
- базами даних
- Дата
- дата, час
- угода
- справу
- Грудень
- вирішувати
- Вирішивши
- Прийняття рішень
- Декодування
- присвячених
- глибше
- дефолт
- визначати
- певний
- визначаючи
- Визначення
- надання
- постачає
- заглиблюватися
- демонстрація
- демонструвати
- продемонстрований
- демонстрація
- залежати
- Залежно
- залежить
- розгортання
- розгорнути
- розгортання
- розгортання
- розгортає
- описувати
- description
- дизайн
- призначені
- призначений
- бажаний
- деталь
- докладно
- деталі
- Визначати
- визначає
- розвивати
- Розробник
- розробників
- розвивається
- розробка
- діаграми
- DICT
- DID
- відрізняються
- різний
- інакше
- важкий
- Розмір
- розміри
- директиви
- безпосередньо
- обговорювати
- обговорювалися
- показ
- чіткий
- занурення
- Різне
- DM
- do
- документ
- документація
- документація
- робить
- байдуже
- справи
- Дон
- зроблений
- подвійний
- вниз
- скачати
- завантажень
- проект
- управляти
- два
- під час
- динамічний
- динамічно
- e
- кожен
- Раніше
- Рано
- простота
- простота використання
- легше
- легко
- легко
- легкий у використанні
- нудьгувати
- екосистема
- Ефективний
- фактично
- ефективність
- ефективний
- продуктивно
- легко
- або
- елемент
- елементи
- Елон
- Елон Маск
- ще
- Вставляти
- вбудований
- вбудовування
- працевлаштований
- співробітників
- працює
- уповноважувати
- включіть
- дозволяє
- дозволяє
- інкапсулює
- стикаючись
- кінець в кінець
- Кінцева точка
- залучення
- двигун
- Двигуни
- England
- англійська
- Англійська прем'єр-ліга
- підвищувати
- підвищена
- підвищення
- забезпечувати
- гарантує
- забезпечення
- підприємство
- юридичні особи
- суб'єкта
- Навколишнє середовище
- середовищах
- Еквівалент
- Епоха
- помилка
- помилки
- особливо
- істотний
- відсторонений
- і т.д.
- оцінювати
- оцінка
- Навіть
- Події
- Кожен
- приклад
- Приклади
- перевищувати
- Крім
- виконувати
- виконано
- Виконує
- виконання
- виконання
- ілюструє
- Здійснювати
- існувати
- очікувати
- очікування
- очікуваний
- чекає
- досвід
- експериментальний
- experts
- пояснені
- Пояснює
- явно
- дослідження
- дослідити
- Розвіданий
- експорт
- вираз
- продовжити
- розширення
- обширний
- зовнішній
- додатково
- витяг
- видобуток
- Виписки
- Face
- фасилітувати
- полегшує
- завод
- Факти
- далеко
- ШВИДКО
- Улюблений
- особливість
- риси
- зворотний зв'язок
- кілька
- поле
- Поля
- фігма
- Рисунок
- філе
- Файли
- заповнювати
- заповнений
- наповнення
- фільтрувати
- фільтрація
- остаточний
- в кінці кінців
- знайти
- виявлення
- Перший
- п'ять
- Гнучкість
- гнучкий
- потік
- Сфокусувати
- увагу
- фокусується
- фокусування
- стежити
- після
- слідує
- харчування
- для
- форма
- формат
- сформований
- На щастя
- знайдений
- Рамки
- каркаси
- часто
- друг
- друзі
- від
- Повний
- повноцінний
- функція
- функціональні можливості
- функціональність
- Функції
- фундаментальний
- смішний
- далі
- майбутнє
- Отримувати
- Games
- Гейтс
- Загальне
- в цілому
- породжувати
- генерується
- генерує
- породжує
- покоління
- жанр
- Німеччина
- отримати
- отримання
- GIF
- GitHub
- даний
- GMT
- Go
- йде
- буде
- добре
- зернистий
- графік
- великий
- великий
- керівництво
- керівництво
- керівні вказівки
- Hackathon
- обробляти
- Ручки
- Обробка
- мобільний
- Жорсткий
- шкодити
- джгути
- Мати
- має
- сильно
- Герой
- допомога
- корисний
- допомагає
- її
- тут
- hi
- Високий
- на вищому рівні
- високоякісний
- найвищий
- дуже
- історичний
- історія
- Hole
- капот
- господар
- Як
- How To
- Однак
- HTML
- HTTP
- HTTPS
- Концентратор
- людина
- Сотні
- i
- ID
- ідея
- ідеальний
- ідентифікатори
- if
- ii
- III
- ілюструвати
- ілюструє
- зображень
- Негайний
- здійснювати
- реалізація
- реалізації
- реалізовані
- імпорт
- поліпшення
- поліпшення
- in
- поглиблений
- включати
- включені
- includes
- У тому числі
- включати
- включення
- неймовірно
- індекс
- покажчики
- вказувати
- вказує
- Індивідуально
- осіб
- інформація
- початковий
- ініціювати
- інноваційний
- вхід
- витрати
- розуміння
- встановлювати
- встановлений
- установка
- екземпляр
- мить
- замість
- інструкції
- інтегральний
- інтегрувати
- інтегрований
- Інтеграція
- Інтеграція
- інтеграція
- інтеграцій
- Розумний
- призначених
- взаємодіяти
- взаємодія
- Взаємодії
- інтерактивний
- взаємодіє
- інтерфейс
- Інтерфейси
- внутрішньо
- інтернет
- в
- введені
- Вводить
- інтуїтивний
- за участю
- isn
- питання
- питання
- IT
- пунктів
- ітерації
- ЙОГО
- сам
- Джексон
- JavaScript
- робота
- Jordan
- подорож
- json
- липень
- просто
- юстиція
- тримати
- тримає
- ключ
- ключі
- Дитина
- Знати
- знання
- Графік знань
- відомий
- етикетка
- етикетки
- земля
- мова
- мови
- великий
- більше
- останній
- Затримка
- пізніше
- останній
- Ліга
- УЧИТЬСЯ
- вивчення
- залишити
- Legacy
- довжина
- менше
- дозволяти
- дозволяє
- лист
- рівень
- рівні
- Важіль
- важелі
- використання
- libraries
- бібліотека
- як
- Ймовірно
- МЕЖА
- недоліки
- обмеженою
- обмежуючий
- рамки
- зв'язку
- список
- слухати
- списки
- жити
- ll
- LLM
- загрузка
- завантажувач
- розташований
- розташування
- журнал
- увійшли
- каротаж
- логіка
- Довго
- довше
- подивитися
- шукати
- ВИГЛЯДИ
- пошук
- в
- Лос-Анджелес
- низький
- машина
- навчання за допомогою машини
- made
- підтримувати
- Підлягає ремонту
- Підтримка
- підтримує
- зробити
- РОБОТИ
- Робить
- управляти
- управління
- менеджер
- управління
- Манчестер
- Манчестер Юнайтед
- Маніпуляція
- манера
- керівництво
- виробник
- багато
- багато людей
- карта
- відображення
- карти
- матч
- узгодження
- математики
- математичний
- Питання
- максимальний
- Може..
- me
- значити
- сенс
- засоби
- вимір
- Медіа
- засідання
- відповідає
- пам'яті
- пам'ять
- згаданий
- Злиття
- злиття
- повідомлення
- повідомлення
- обмін повідомленнями
- метадані
- метод
- методика
- Метрика
- може бути
- мільйони
- мінімальний
- незначний
- відсутній
- помилки
- Змішування
- MLB
- Mobile
- модель
- Моделі
- помірність
- Модулі
- Модулі
- момент
- MongoDB
- монітор
- моніторинг
- Moon
- більше
- найбільш
- Найбільш популярний
- рухатися
- фільм
- багато
- множинний
- кілька ланцюгів
- Маск
- повинен
- my
- ім'я
- Названий
- Імена
- National
- Природний
- Обробка природних мов
- Переміщення
- навігація
- Близько
- необхідно
- Необхідність
- необхідний
- потреби
- негативний
- Нові
- Нью-Йорк
- Нью-Йорк Таймс
- наступний
- немає
- ніхто
- нічого
- поняття
- зараз
- номер
- Обама
- об'єкт
- мета
- об'єкти
- спостереження
- отримувати
- отримання
- OCR
- of
- пропонувати
- пропонує
- Пропозиції
- часто
- oh
- добре
- Олімпійські ігри
- on
- один раз
- ONE
- тільки
- з відкритим вихідним кодом
- OpenAI
- операції
- оператор
- оптимізований
- Оптимізує
- варіант
- or
- порядок
- органічний
- організації
- оригінал
- OS
- Інше
- інші
- інакше
- наші
- з
- вихід
- виходи
- над
- перевизначення
- огляд
- власний
- пакет
- пакети
- сторінка
- сторінок
- пар
- панди
- Папір
- Паралельні
- параметр
- параметри
- Парк
- частина
- особливо
- частини
- проходити
- Пройшов
- проходить
- Проходження
- Минуле
- шлях
- стежки
- моделі
- Платіжна відомість
- Люди
- для
- ідеальний
- відмінно
- Виконувати
- продуктивність
- виконанні
- виступає
- Дозволи
- наполегливість
- людина
- Персоналізовані
- перспектива
- Фізика
- частина
- трубопровід
- Піца
- заповнювач
- платформа
- plato
- Інформація про дані Платона
- PlatoData
- Play
- дитячий майданчик
- відіграє
- будь ласка
- плюс
- точка
- Політика
- політика
- політичний
- басейн
- популярний
- заселений
- позитивний
- це можливо
- пошта
- Пости
- потенціал
- влада
- Харчування
- потужний
- Практичний
- практика
- надавати перевагу
- прем'єр-міністр
- представити
- президент
- запобігати
- попередження
- попередній
- в першу чергу
- первинний
- Prime
- приватний
- Проблема
- проблеми
- продовжити
- процес
- Оброблено
- процеси
- обробка
- виробляти
- Product
- Production
- Професор
- Програмування
- мови програмування
- проект
- проектів
- властивості
- власність
- PROS
- прототип
- макетування
- забезпечувати
- за умови
- Постачальник
- провайдери
- забезпечує
- забезпечення
- громадськість
- мета
- цілей
- put
- Python
- Питання та відповіді
- якість
- запити
- питання
- питань
- Швидко
- швидко
- лапки
- R
- підвищення
- діапазон
- ранжування
- швидше
- рейтинг
- Сировина
- RE
- досягати
- Реагувати
- Читати
- читання
- готовий
- реальний
- реального часу
- дані в режимі реального часу
- царство
- причина
- Причини
- останній
- рекомендований
- записаний
- облік
- Відновлювати
- зменшити
- знижує
- зниження
- скорочення
- посилання
- посилання
- удосконалювати
- рафінування
- райони
- Відносини
- випущений
- актуальність
- доречний
- надійність
- надійний
- покладатися
- покладаючись
- залишається
- запам'ятати
- нагадування
- віддалений
- надавати
- повторювати
- ПОВТОРНО
- перефразування
- замінювати
- звітом
- Сховище
- подання
- представляє
- представляє
- запросити
- запитів
- вимагати
- вимагається
- Вимога
- Вимагається
- рятувати
- дослідження
- рішення
- ресурс
- Реагувати
- відповідаючи
- відповідь
- відповіді
- відповідальний
- реагувати
- REST
- результат
- в результаті
- результати
- утримує
- утримання
- повертати
- повернення
- Умови повернення
- багаторазовий
- огляд
- обертається
- рис
- Багаті
- роботи
- Роль
- ролі
- корінь
- Маршрутизація
- ROW
- прогін
- біг
- пробіжки
- час виконання
- s
- гарантії
- продажів
- Salesforce
- Сем
- то ж
- зберегти
- say
- говорить
- масштабовані
- шкала
- сценарій
- сценарії
- сцени
- розклад
- рахунок
- подряпати
- безшовні
- плавно
- Пошук
- Пошукова система
- пошук
- Грати короля карти - безкоштовно Nijumi логічна гра гри
- розділ
- розділам
- безпечний
- безпеку
- побачити
- обраний
- вибір
- Продаж
- послати
- чутливий
- настрій
- почуття
- окремий
- Вересень
- Послідовність
- Серія
- служити
- сервер
- служить
- Послуги
- комплект
- набори
- установка
- налаштування
- установка
- сім
- кілька
- Поділитись
- загальні
- Склад
- світить
- занурено
- Повинен
- Показувати
- демонстрації
- показаний
- Шоу
- Сигма
- значний
- аналогічний
- простий
- спрощений
- спростити
- спрощення
- просто
- з
- один
- Розмір
- слабкий
- невеликий
- менше
- розумний
- уривок
- So
- так далеко
- Футбол
- соціальна
- соціальні медіа
- Повідомлення в соціальних мережах
- виключно
- solid
- рішення
- ВИРІШИТИ
- деякі
- що в сім'ї щось
- іноді
- складний
- звуки
- Source
- Джерела
- Простір
- іспанська
- спеціалізований
- конкретний
- конкретно
- специфіка
- зазначений
- швидкість
- відпрацьований
- розкол
- Розколи
- Спорт
- площа
- стояти
- автономні
- standard
- старт
- почалася
- Починаючи
- стан
- заяви
- статичний
- Крок
- заходи
- Як і раніше
- Стоп
- зупинка
- Зупиняє
- зберігання
- зберігати
- зберігати
- магазинів
- зберігання
- Історія
- просто
- потік
- потоковий
- раціоналізувати
- обтічний
- сильні сторони
- страйки
- рядок
- структура
- структурований
- структур
- структурування
- стиль
- тема
- наступні
- Успішно
- такі
- костюм
- підходящий
- набір
- підсумовувати
- РЕЗЮМЕ
- захід
- підтримка
- Підтриманий
- Опори
- Переконайтеся
- Sustainability
- синхронізація
- конспект
- синтаксис
- система
- Systems
- таблиця
- кравець
- з урахуванням
- Приймати
- приймає
- цілі
- Завдання
- завдання
- команда
- команди
- сказати
- шаблон
- Шаблони
- термінал
- термінологія
- terms
- тест
- Тестування
- текст
- ніж
- Дякую
- Що
- Команда
- Основи
- концентратор
- інформація
- The New York Times
- Проекти
- Джерело
- світ
- їх
- Їх
- потім
- Там.
- Ці
- вони
- речі
- це
- ті
- хоча?
- через
- по всьому
- час
- трудомісткий
- times
- назва
- до
- разом
- знак
- Токенізація
- Жетони
- занадто
- інструмент
- Інструментарій
- інструменти
- топ
- тема
- теми
- Усього:
- місто
- Простеження
- трек
- традиційний
- Навчання
- Перетворення
- перетворень
- трансформатор
- Трансформатори
- перехід
- суд
- правда
- по-справжньому
- намагатися
- настройка
- ПЕРЕГЛЯД
- Поворот
- підручник
- Двічі
- два
- тип
- Типи
- Машинопис
- типово
- ui
- Зрештою
- неушкоджений
- при
- що лежить в основі
- розуміти
- розуміння
- розумієш
- єдиний
- створеного
- United
- Universal
- на відміну від
- до
- Оновити
- Updates
- завантажено
- URL
- us
- юзабіліті
- Використання
- використання
- використання випадку
- використовуваний
- користувач
- Інтерфейс користувача
- користувачі
- використовує
- використання
- комунальні послуги
- використовувати
- використовувати
- використовує
- використовує
- v1
- перевірка достовірності
- Валідатор
- Цінний
- значення
- Цінності
- змінна
- різноманітність
- різний
- Ve
- різнобічний
- версія
- дуже
- через
- Відео
- вид
- Порушення
- видимий
- візуалізувати
- життєво важливий
- vs
- ходити
- покрокове керівництво
- хотіти
- було
- годинник
- шлях..
- способи
- we
- погода
- Web
- веб-браузер
- веб-сервіси
- веб-сайти
- ДОБРЕ
- добре відомі
- були
- Що
- Що таке
- що
- коли
- Чи
- який
- в той час як
- ВООЗ
- всі
- чому
- широкий
- широко
- віджет
- Вікіпедія
- волі
- вікно
- Перемоги
- з
- в
- без
- слово
- Work
- працював
- робочий
- Робочі процеси
- робочий
- працює
- світ
- б
- запис
- лист
- X
- ще
- йорк
- Ти
- вашу
- себе
- YouTube
- Zendesk
- зефірнет
- Zip