текст перекладу
Коли йдеться про управління агентами в робочих процесах AI, LangGraph є потужним інструментом. У цій статті ми пропонуємо простий посібник, застосовуючи LangGraph до практичного випадку використання. Ми дослідимо його можливості, використовуючи Mistral. Це рішення дозволяє отримати доступ до безкоштовних великих мовних моделей (LLMs) без необхідності витрачати великі ресурси на обчислення.
Для всього вмісту та повного навчального зошита ознайомтеся з проєктом на GitHub → https://github.com/DanielPuentee/LangGraph-Mistral-CV-Evaluator/blob/main/tutorial.ipynb
Давайте почнемо!
1. Що таке LangGraph?
Перед тим як приступити до посібника, давайте спершу зрозуміємо, що таке LangGraph і чому він став таким популярним. LangGraph — це потужна бібліотека в екосистемі LangChain, спеціально розроблена для полегшення створення мульти-агентних додатків, що використовують великі мовні моделі (LLMs). Вона пропонує структурований фреймворк для визначення, координації та виконання кількох агентів або ланцюгів LLM, що дозволяє розробникам створювати складні, масштабовані та гнучкі AI-системи.
На відміну від традиційних фреймворків Directed Acyclic Graph (DAG), LangGraph вводить підтримку циклічних графів, що є ключовою особливістю для розробки складних середовищ для агентів. Ця можливість дозволяє інтегрувати цикли та умови, що робить додатки більш адаптивними та чуйними до різних сценаріїв.
У наступних розділах ми розглянемо практичні приклади та глибше вивчимо критичні аспекти LangGraph, ілюструючи його універсальність та важливість у сучасних робочих процесах AI.
2. Пакети
Тепер ми почнемо з посібника для Mistral і LangGraph, тому важливо мати наступні залежності:
# Використовувана версія Python: 3.10.15
langchain==0.3.10
langchain-mistralai==0.2.3
langgraph==0.2.60
3. Як використовувати Mistral
Mistral буде служити як LLM-двигун для цього посібника. Для початку важливо зрозуміти, як налаштувати та ефективно використовувати його. Почніть із входу на платформу Mistral та генерації API-ключа. Ви можете зробити це за наступним посиланням → https://console.mistral.ai/api-keys/
Після входу ви побачите екран, подібний до наведеного нижче. Клікніть на "Create new key", присвойте ім'я вашому ключу, і він буде готовий до використання.
Тепер, коли у вас є API-ключ, ви можете інтегрувати Mistral з LangChain для повного використання його можливостей. Для цього вам потрібно імпортувати бібліотеку LangChain Mistral, налаштувати її з вашим API-ключем та вказати бажану модель і параметри.
Для цього посібника ми використаємо модель mistral-small-latest з без температури та 5 максимальними спробами. Як приклад, ми створимо простий запит для перекладу фрази “I love programming” на іспанську.
### МОДЕЛЬ MISTRAL
from langchain_mistralai import ChatMistralAI
from langchain_core.messages import SystemMessage, HumanMessage
# Налаштування API-ключа Mistral
os.environ['MISTRAL_API_KEY'] = ""
# Налаштування LLM
llm = ChatMistralAI(
model="mistral-small-latest",
temperature=0,
max_retries=5
)
# Запити
sys_prompt = "You are a helpful assistant that translates English to Spanish"
hum_prompt = "Translate the user sentence without giving more details, just the translation: I love programming."
# Виклик LLM
response = llm.invoke([
SystemMessage(content=sys_prompt),
HumanMessage(content=hum_prompt)]
).content.strip()
print(response)
4. Використання LangGraph
Ми продемонструємо простий випадок використання, що включає 4 різних агенти.
текст перекладу
Мета полягає в тому, щоб створити систему, яка обробляє резюме (CV) та пропозицію роботи, оцінює, чи підходить кандидат для цієї позиції, і потім складає електронний лист з прийняттям або відмовою від пропозиції, а також відповідними коментарями. Процес виглядає наступним чином:
У цьому випадку кроки спроектовані таким чином, щоб спростити процес і допомогти вам швидко зрозуміти динаміку LangGraph.
Розпочнемо з посібника, перший крок — визначити State (стан). State визначає, як повідомлення передаються між агентами. Ця структура гарантує безперешкодний потік інформації по всій системі. Типізація важлива, оскільки вона допомагає зберігати чіткість і послідовність. У цьому випадку ми використовуємо словники через їхню простоту та зручність відслідковування.
# Визначення стану
from typing import Dict
class State(TypedDict):
messages: Dict
Ми починаємо з визначення простій функції для читання .txt
файлів:
# Функція для обробки
def read_file(file_path):
with open(file_path, 'r') as f:
return f.read()
4.1 Агенти та інструменти
У цьому розділі ми визначимо кожного агента і інструмент, який він використовуватиме. Тут кожен агент призначений одному інструменту, оскільки кожен агент працює незалежно, використовуючи свою спеціалізовану функцію. Це один до одного відповідність спрощує робочий процес і забезпечує чіткість реалізації.
# Бібліотеки
from langchain_core.messages import SystemMessage, ToolMessage, AIMessage, HumanMessage
from langgraph.graph import StateGraph, START, END
import uuid
Почнемо з визначення перших двох агентів, які будуть обробляти вміст резюме та вміст пропозиції роботи. Перший — це агент для читання резюме. Однак перед тим, як перейти до коду, важливо встановити початковий стан (start_state
), який бере участь у процесі.
текст перекладу
start_state
визначено наступним чином:
cv_path = "data/cv.txt"
job_path = "data/job_description.txt"
start_state = {"messages": {"cv_path": cv_path, "job_path": job_path}}
У цьому проєкті ми маємо наступні файли, що знаходяться в папці data
:
cv.txt
: цей файл містить інформацію про резюме, яке в клонованому репозиторії на GitHub є моїм резюме.job_description.txt
: цей файл містить вигадану опис вакансії від MAIgents, створену спеціально для цього посібника.
Якщо ви клонуватимете репозиторій на GitHub, ці зразки файлів дозволять вам відтворити та слідувати посібнику (https://github.com/DanielPuentee/LangGraph-Mistral-CV-Evaluator).
Після того, як визначено start_state
, ми можемо перейти до визначення агентів і їх відповідних інструментів.
# Читання CV
def get_cv_content(state: dict): # State тут -> {"messages": {"cv_path": cv_path, "job_path": job_path}}
print("***** get_cv_content *****")
# Отримуємо шлях до файлу CV з state
cv_path = state['messages']['cv_path']
cv_content = read_file(cv_path)
# Створюємо об'єкт ToolMessage з вмістом CV та унікальним ідентифікатором виклику інструменту
tool_call = ToolMessage(
content=cv_content,
tool_call_id=str(uuid.uuid4())
)
# Оновлюємо state з вмістом CV та зберігаємо шлях до файлу вакансії
new_state = {
"messages": {
"job_path": state['messages']['job_path'],
"cv_content": tool_call
}
}
return new_state
# Читання пропозиції роботи
def get_job_description(state: dict): # State тут буде результатом get_cv_content -> {"messages": {"job_path": job_path, "cv_content": ___}}
print("***** get_job_description *****")
# Отримуємо шлях до файлу опису вакансії з state
job_path = state['messages']['job_path']
# Читаємо вміст файлу опису вакансії
job_content = read_file(job_path)
# Створюємо об'єкт ToolMessage з вмістом опису вакансії та унікальним ідентифікатором виклику інструменту
tool_call = ToolMessage(
content=job_content,
tool_call_id=str(uuid.uuid4())
)
# Оновлюємо state з вмістом опису вакансії та зберігаємо вміст CV
new_state = {
"messages": {
"cv_content": state['messages']['cv_content'],
"job_content": tool_call
}
}
return new_state
Код простий і служить основою для перших двох агентів. Перша функція, get_cv_content
, приймає start_state
як вхід для початку процесу. Ця функція отримує шлях до файлу CV з початкового стану, читає вміст файлу і оновлює стан вмістом CV, зберігаючи шлях до файлу вакансії. Оновлений стан потім передається наступному агенту.
Порядок агентів буде вказано після того, як всі агенти та їх інструменти будуть повністю визначені. Однак, оскільки ми вже пройшли цей етап, ми знаємо, що після прочитання резюме логічно наступним кроком буде обробка опису вакансії. Ця послідовність є важливою, оскільки оновлений стан з get_cv_content
надає cv_content
і зберігає job_path
, який наступний агент, get_job_description
, потребує для виконання своєї мети.
Функція get_job_description
має схожу структуру.
текст перекладу
Функція evaluate_match
бере стан, повернений агентом get_job_description
, і застосовує свою власну логіку. Процес простий: вона витягує вміст резюме та опису вакансії зі стану, формує детальний запит і використовує його для оцінки можливого співвідношення кандидата до вакансії.
Логіка включає два типи запитів: системний запит, який визначає завдання оцінки, та людський запит, який містить вміст резюме та опису вакансії, надаючи професійне та детальне керівництво для оцінки. Об'єднані запити передаються в LLM для оцінки.
Після того, як LLM генерує відповідь, результат обгортається в AIMessage
, що служить стандартизованим способом передачі AI-генерованих відповідей наступному агенту. AIMessage
функціонує подібно до ToolMessage
, але явно вказує, що вміст був створений AI.
Нарешті, переходимо до останнього агента, який відповідатиме за створення чернетки електронного листа з рішенням щодо вибору на основі результатів оцінки.
# Генерація електронного листа
def generate_email(state: dict): # State тут буде результатом evaluate_match -> {"messages": {"evaluation": ___}}
print("***** generate_email *****")
# Витягнути результат оцінки з state
evaluation_result = state["messages"]["evaluation"].content
# Створення запитів для електронного листа
hum_email_template = """Оцінка заявки на роботу:
{evaluation}
===
На основі оцінки відповідності резюме кандидата та опису вакансії, створіть електронний лист кандидату, в якому повідомляється результат оцінки. Чітко вкажіть, чи був кандидат обраний на посаду, і надайте причини для цього рішення. Тон має бути ввічливим, професійним та поважним, починаючи лист із ввічливого визнання."""
текст перекладу
Функція `generate_email` є останнім кроком у робочому процесі і має схожу структуру з агентом `evaluate_match`. Її мета — отримати результат оцінки, створений попереднім агентом, сформувати добре структурований запит і згенерувати чернетку електронного листа, в якому повідомляється рішення щодо відбору кандидата.
Після того, як всі агенти будуть визначені, ми **переходимо до побудови графа**. Цей крок передбачає визначення кожного вузла в робочому процесі, визначення з'єднань між вузлами і створення візуального представлення процесу.
Початок графа з початковим станом
workflow = StateGraph(State)
Додаємо вузли, що відповідають функціям, які ми визначили. Ми маємо дати їм ім'я
workflow.addnode("readcv", getcvcontent)
workflow.addnode("getjobdescription", getjobdescription)
workflow.addnode("evaluatematch", evaluatematch)
workflow.addnode("generateemail", generate_email)
Додаємо ребра, що з'єднують вузли.
Починаємо з START і вказуємо наступний вузол, в цьому випадку "read_cv"
workflow.addedge(START, "readcv")
workflow.addedge("readcv", "getjobdescription")
workflow.addedge("getjobdescription", "evaluatematch")
workflow.addedge("evaluatematch", "generateemail")
workflow.addedge("generate_email", END)
Компілюємо граф
graph = workflow.compile()
Можемо візуалізувати граф
from IPython.display import Image, display
display(Image(graph.getgraph().drawmermaid_png()))
```
Для завершення робочого процесу ми створюємо StateGraph
на основі класу State
, який ми визначили на початку.
- Для вузлів ми просто додаємо функції, які ми визначили, надаючи кожній функції ім'я для позначення її відповідного агента.
- Для ребер ми вказуємо з'єднання між агентами. Перший аргумент вказує на поточного агента, а другий — на наступного в послідовності.
Нарешті, ми компілюємо граф і візуалізуємо його. Отримана візуалізація виглядатиме приблизно так:
Тепер нам просто потрібно запустити граф, починаючи з уже визначеного старту:
# Ітеруємо через граф
for output in graph.stream(start_state):
print("Current Output:", output)
print("\n***** Процес успішно завершено!! *****\n")
print(output['generate_email']['messages']['email'].content)
Це покаже результат кожного етапу робочого процесу, а в кінці буде представлений результат чернетки електронного листа.
Дякуємо за прочитання!
Щиро дякую за прочитання статті. Якщо вам сподобалося, не соромтесь слідкувати за мною на LinkedIn.
aiagents #langchain #ai
Перекладено з: LangGraph + Mistral: CV Evaluator agent system