LlamaIndex і LangGraph: акуратны патэрн для RAG-агентаў
Як пабудаваць базу ведаў на LlamaIndex і падаць яе агенту LangGraph як інструмент: захаванне стану, Chroma і рэжым толькі з рэтрыверам.
Крыніцы: RAG Without the Guesswork: A Standardized LangGraph + LlamaIndex Pattern.
Абсцынт і разпад працы
Агент LangGraph знае толькі тое, што ўсваяў яго LLM пад час навчання. На запытанні пра внутрэшню політыку цэнавання, фінансавы абзвястак за пасляпэўдні квартал або інструкцыю, завершаную ў празылуце, агент або зізнаецца ў незнаёмцы, або, што горш, дае впэўненую, але неправдзівую адпаведзь.
Retrieval-Augmented Generation (RAG) закрывае гэты прыем. Пад час адпаведы ён выкарыстоўвае рэлевантныя фрагменты з вашых сабеўных дакументаў і перэдае іх LLM як кантэкст, тады мадэль чытае, а не здагадваецца. RAG — гэта можнасць, якая дадаецца адзінаму агенту. Гэта не новы патэрн оркестрацыі, таму керавальнікі, падграфы і Send не беруць удзеле ў гэтым процэсе. Усё, што трэба, — гэта певная знаёмасць з структурой агента LangGraph і спосабам надання яму інструментаў.
Магчымае стварыць такую лінію апрацоўкі рукамі ўнутрь LangGraph: трэба напісаць савой чанкер, код для стварэння эмбедынгаў, індэкса вектараў і ўзяць інфармацыі з індэкса. Багато команд так і робяць, але гэта вельмі складна задача для таго, што ўжо ёсць рашаным праблемам. LlamaIndex створаны, каб перадзеяць гэту працу. Ён, без сумневу, ўжо ўвесь час ўважаецца найболей зробленым і популярным выборам для апрацоўкі дадзэнняў у AI-застосунках — ён включае завантажэнне, чанкаванне, стварэння эмбедынгаў, індэксаванне і выкарыстоўванне інфармацыі. Частка, якая карыстуецца оркестрацыяй, тыя-то стан, прабег кантролю і багатыя крокі аналізу, належыць LangGraph.
З гэтага падзелу выйшае структура, якую вікорыстоўвае большасць прымэнных сістэм RAG: LlamaIndex стварае і аддае ў спраўу базу знанняў. LangGraph спрацьвоўвае яе як інструмент і сам выбірае, калі яго запускаты.
Ментальная мадэль LlamaIndex
Уявіце LlamaIndex як бібліятэкара для вашага LLM. LLM падае на аднаго талантаванага асістэнта-даследніка, які прачытаў вялікі частак інтэрнэту, але ніколі не ачынаў файлы вашай кампаніі, і ніхто не можа прабавіць змусіць яго запам’ятаваць збірнік з 10 000 стороніц. Таму вступае бібліятэкар: ён чытае кожны дакумент, разбівае яго на маленькіе карточкі-індэксы, якія можна шукаты (фрагменты), зберагае гэтыя карточкі там, дзе пошук па тэме ведаецца быстра (вектарны індэкс), і выбірае толькі 3–5 найболей рэлевантных карточак, калі асістэнт задае запыт. Асістэнт ніколі нічога не запам’ятавае. Прыходзяць калькі фрагментав і на іхней аднойчы ведаецца логіка.
Пяцьступеневы працэс
Кожная сістэма RAG, незалежна ад фрэймворку, праходзіць праз тыя ж пяць ступеняў, і LlamaIndex прысвячае кожнаму з іх чыстую абстракцыю.
1. LOAD → Read raw files (PDF, Word, web pages, databases) into Documents
2. CHUNK → Split Documents into small, retrievable Nodes
3. EMBED → Convert each Node's text into a vector (a list of numbers
representing meaning)
4. STORE → Save those vectors in a Vector Index for fast lookup
5. RETRIEVE → At query time, embed the user's question, find the most
similar Nodes, and return them as context
Першыя чатыры этапы выконваюцца аднакрэт, калі ствараецца база знанняя, і гэта называецца індэксаваннем. Пятая стадыя выконваецца кожны раз, калі корыстувач задае запіт, і гэта называецца запітаваннем. Співвярэнне часу індэксавання і часу запітавання, верагацейна, ёсць найважлівейшым ментальным мадэлем у RAG, і варта яго памятаць.
Словнік
Дакумент— гэта неапдэтаваны фрагмент вучальнага кантэнту, такі як адзін PDF, адзіна веб-стороніца або адзін радок базы дадзеных, плюс яго метаданы. Гэта неапдэтаваная, цэлая едыніца.Вузел— гэта фрагмент, вырваны зДакумента. Мадэлі LLM і мадэлі embedding працуюць лепшая з фокусаваным, маленькім за розмерам тэкстам, чым з цэлымі дакументамі, таму LlamaIndex дзельніцяе кожныДакументна многа об’ектыВузела. Вузелі перадаюць метаданы своему вышэйшаму родніку, таму кожны фрагмент можна праследаваць да яго вучальнага кантэнту.
SimpleDirectoryReader — гэта стандартны вычытальнік: яго можна нацэсіць на папку, і ён чытае PDF-файлы, тэкст, файлы Word і іншыя фарматы, ствараючы адзін або калькі Document об’ектаў на кожны файл.VectorStoreIndex — галоўны клас для стварэння індэкса. Пры наявнасці Document або Node об’ектаў ён іх уключае і стварае індэкс вектараў, які можна шукаты, аднойчы ў памяці або ў зовнішній базе дадзенаў вектараў, калі такая ўстановлена.Settings — глобальны об’ект налашоўкаў. На яму аднойчы задаюцца налашоўкі LLM і модэлю уключэння, і кожны компонент іх бера, таму іх не трэба перадаваць у кожны вызов.QueryEngine — гэта тое, каму вы фактычна ставіце запытанні. Ён выкалікаецца з .as_query_engine() на індэксе, і адна вызовка включае запыт, адрабатвае пошук на адпоўненасць і падае атрыманы кантэкст у LLM для фінальнай адпаведзі.Retriever выкалікаецца з .as_retriever() на індэксе і адпрацоўвае толькі крок пошуку. Ён вяртае неапдэтаваныя об’екты Node, якія падходзяць, і не генеруе адпаведзі, што падходзіць для сітуацыяў, калі пошук і генераванне павінны быць аддзельнымі, керованымі крокамі. Гэта самэ і сітуацыя, калі прыходзіць LangGraph.Пайплайн спачатку будуецца сам, без LangGraph.
Рабочы пайплайн у апошніх дзесяці лініях
Спачатку выконваецца інсталяцыя.
# Core package + OpenAI LLM and embedding integrations (the common starting setup)
pip install llama-index-core llama-index-llms-openai llama-index-embeddings-openai
# Readers for common file types (PDF, Word, etc.)
pip install llama-index-readers-file pypdf
LlamaIndex намеравана выдаваць як магчыма большае лічба маленькіх пакетаў. llama-index-core містыць логіку фрэймворку, а выбор LLM, модэлю эмбедынгу, базы вектарных дадзеных і чытальніка файлаў знаходзіцца ў адным з окрэмых пакетаў, якія інсталююцца толькі калі гэта неабходна. Чыгуча гэта спакойвае працэс інсталляцыі.
Маленькі файл налаштавання задае глобальныя стандартныя значэнні.
# ── llamaindex_config.py ─────────────────────────────────────
import os
from llama_index.core import Settings
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
# Settings is global - configure once, used everywhere in LlamaIndex
Settings.llm = OpenAI(
model="gpt-4o-mini", # Used for generating final answers from retrieved context
temperature=0.1, # Low temperature: factual, not creative
)
Settings.embed_model = OpenAIEmbedding(
model="text-embedding-3-small", # Used to convert text into vectors
)
# Controls how documents are split into Nodes (chunks)
Settings.chunk_size = 512 # Max tokens per chunk
Settings.chunk_overlap = 50 # Overlap between consecutive chunks, to preserve context across boundaries
Па параметры chunk_size: занадта большыя часткі маюць так много тэксту, што ўзяць яго стае складна, адтолькі ўзятая частка можа быць рэлевантной лішае 10%. Занадта маленькія часткі выкарыстоўваюць не всю кантэкстную інфармацыю, якая трэба ІІ-мадэлі, каб ёй было зрозумела праблема. Звычайна і разумна пачынак з 512 токенав, з перакрыццем у 50 токенав, пасля чаго правіляцца ў залежнасці ад дакументаў.
А потым сама база знанняў:
# ── build_knowledge_base.py ──────────────────────────────────
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
# ── LOAD: Read all files in a folder into Document objects ──
documents = SimpleDirectoryReader("./data").load_data()
print(f"Loaded {len(documents)} documents")
# ── CHUNK + EMBED + STORE: all three happen inside this one call ──
# VectorStoreIndex automatically:
# 1. Splits each Document into Nodes (using Settings.chunk_size)
# 2. Embeds each Node (using Settings.embed_model)
# 3. Stores the vectors in an in-memory index
index = VectorStoreIndex.from_documents(documents, show_progress=True)
# ── RETRIEVE + GENERATE: ask a question ──────────────────────
query_engine = index.as_query_engine(
similarity_top_k=3, # Retrieve the 3 most relevant chunks for each query
)
response = query_engine.query("What is our refund policy for enterprise customers?")
print(response)
Прыгаючы прыблізна дзесяць ліній коду, можна стварыць працюючую сістэму RAG, якая ўособлівае сябе як „hello world“ для гэтай парадыгмы і ўсёяснае прычыну ўсстановлення такіх рашэнняў. Выкананне гэтага вручную апяроцьваецца неабходнасцю стварэння спецыяльнага скаладчыка дадзеных, цыклу, які запускае мадэль укладання, пошуку найбліжэйшага суседа і шаблона запіту.
Зберагчыць індэкс
Кожны фрагмент дадзеных праходзіць праз мадэль укладання пад час стварэння індэкса, што коштае грошы і час, таму перзапуск стварэння індэкса з кожным запускам прыкладнага програмы ёсць нерацыональным. Зберагчыць індэкс на дыску і запускіць яго пазней дапамагае ухіліцца ад гэтага.
# ── Save the index after building it ─────────────────────────
index.storage_context.persist(persist_dir="./storage")
# ── Load it back later without re-embedding anything ──────────
from llama_index.core import StorageContext, load_index_from_storage
storage_context = StorageContext.from_defaults(persist_dir="./storage")
index = load_index_from_storage(storage_context)
storage_context.persist() зберагае вектарныя даны, метаданы вузлаў і дакументы ў локальной папцы, а load_index_from_storage() стварае аднаковы індэкс з гэтых файлоў без павторнага включэння дадзеных і без вызоў API. Ён следуе той жа ідэі «стварыць раз, зберагчы, практычна перзаваначыць» як і чэкпойнтар LangGraph.
Праўdziва вектарная база дадзеных
Індэкс у памяці падходзіць для пратыпаў. У працоўных умовах зазвычай патрэбна спецыяльная вектарная база дадзеных, прызначаная для мільйонав вектароў, адночасных чытанняў і фільтрацыі метаданых у велікых масштабах. Chroma ўсьмо тут прыклад.
# ── Using Chroma as a persistent, production-grade vector store ──
# pip install llama-index-vector-stores-chroma chromadb
import chromadb
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.core import StorageContext, VectorStoreIndex
chroma_client = chromadb.PersistentClient(path="./chroma_db")
chroma_collection = chroma_client.get_or_create_collection("my_knowledge_base")
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
# Build the index directly into Chroma
index = VectorStoreIndex.from_documents(
documents,
storage_context=storage_context
)
# Later, in a different process, reconnect without re-indexing:
index = VectorStoreIndex.from_vector_store(vector_store=vector_store)
Этот механізм адаптавання падобныся к апаратам перапрацоўкі дадзеных. Вы заменяеце адні разы об’ект (буфер памяці для ChromaVectorStore), так сама як MemorySaver заменяецца на SqliteSaver), а механізм запітаў і логіка пошуку застаюцца без змян. Pinecone, Qdrant, Weaviate і большасць іншых базаў вектарных дадзеных, якія падтрымлівае LlamaIndex, працуюць аднойчы.
Спаянне двух фрэймворкаў
У гэтым і справа. Фрэймворкі вікорыстоўваюць разныя мовы: QueryEngine з LlamaIndex не ўзьмецца як інструмент для LangGraph, адтолькі ўпрабовач LangGraph чакае інструменты, створаныя з дэкоратара @tool з LangChain.
Мост аплявання просты. Задаюце звычную функцыю на Python, ставяце на яе атрыбут @tool, і прымушваеце яе тэлы вызваць query_engine.query(...). Гэта ўсё, што трэба для інтэграцыі. LangGraph не патрэбна ніякая інфармацыя пра внутрэшню структуру LlamaIndex, адколі ён бачыць толькі інструмент, які прымее строку і верне строку, як і будзь-яны іншы інструмент.
# ── MODULE 3: TOOLS (LlamaIndex-backed) ─────────────────────
from langchain_core.tools import tool
# The query_engine built in Part B - created once, at startup
# (In a real app, you'd load this from persisted storage, not rebuild it every time)
@tool
def search_knowledge_base(query: str) -> str:
"""Search the internal knowledge base for company policies, product
documentation, and internal procedures. Use this whenever the user asks
a question that might be answered by internal company documents rather
than general knowledge.
Args:
query: A natural-language question to search for.
Returns:
A synthesized answer based on the most relevant retrieved documents.
"""
response = query_engine.query(query)
return str(response)
Докстрынг мае такое ж самае значэнне, як і для будзь-каго інструмента. LLM агента чытае яго, каб адначыце з’ясавіць, колі вызваць гэты інструмент, замест таго, каб адказаць на базе сябе-ж знаёмасцей або вызваць іншы інструмент.
Полны агент
Ёсць цэлы шаблон агента з інструментам RAG, падтрымваным LlamaIndex, які розмішаны ў модулі інструментаў. Нічога іншага не змінілася.
# ============================================================
# LANGGRAPH + LLAMAINDEX RAG AGENT — COMPLETE TEMPLATE
# Extends: Part 1 (core structure)
# ============================================================
# ── MODULE 1: IMPORTS & CONFIGURATION ───────────────────────
import os
from typing import Literal
# LangChain / LangGraph imports (the orchestration layer)
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage, BaseMessage
from langchain_core.tools import tool
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.prebuilt import ToolNode
from langgraph.checkpoint.memory import MemorySaver
# LlamaIndex imports (the retrieval / data layer)
from llama_index.core import (1
Settings, SimpleDirectoryReader, VectorStoreIndex,
StorageContext, load_index_from_storage
)
from llama_index.llms.openai import OpenAI as LlamaOpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
# LangGraph's chat model - used by the agent's reasoning
llm = ChatOpenAI(model="gpt-4o", temperature=0)
# LlamaIndex's model config - used internally by the query engine
# Note: these are SEPARATE from the LangGraph llm above. Each framework
# manages its own model instances; they don't share state.
Settings.llm = LlamaOpenAI(model="gpt-4o-mini", temperature=0.1)
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")
Settings.chunk_size = 512
# ── MODULE 2: STATE ──────────────────────────────────────────
class State(MessagesState):
pass # messages field inherited; extend if your agent needs more
# ── MODULE 3: TOOLS (RAG-backed) ─────────────────────────────
# Build or load the LlamaIndex knowledge base ONCE, at startup
PERSIST_DIR = "./storage"
if os.path.exists(PERSIST_DIR):
# Reload existing index - no re-embedding, fast startup
storage_context = StorageContext.from_defaults(persist_dir=PERSIST_DIR)
index = load_index_from_storage(storage_context)
else:
# First run - build the index and persist it
documents = SimpleDirectoryReader("./data").load_data()
index = VectorStoreIndex.from_documents(documents, show_progress=True)
index.storage_context.persist(persist_dir=PERSIST_DIR)
query_engine = index.as_query_engine(similarity_top_k=3)
@tool
def search_knowledge_base(query: str) -> str:
"""Search internal company documents for policies, product specs,
procedures, and other domain-specific information. Use this for any
question that requires knowledge specific to this organization rather
than general world knowledge."""
response = query_engine.query(query)
return str(response)
tools = [search_knowledge_base]
llm_with_tools = llm.bind_tools(tools)
tool_node = ToolNode(tools)
# ── MODULE 4: NODES ──────────────────────────────────────────
def agent_node(state: State) -> dict:
"""The reasoning node. Decides whether to answer directly or
search the knowledge base first."""
system_prompt = SystemMessage(content=(
"You are a helpful assistant with access to an internal knowledge base. "
"Use the search_knowledge_base tool when the user asks about company-specific "
"information. For general questions, answer directly."
))
messages = [system_prompt] + state["messages"]
response = llm_with_tools.invoke(messages)
return {"messages": [response]}
# ── MODULE 5: ROUTING ────────────────────────────────────────
def should_continue(state: State) -> Literal["tools", "__end__"]:
last_message = state["messages"][-1]
if hasattr(last_message, "tool_calls") and last_message.tool_calls:
return "tools"
return "__end__"
# ── MODULE 6: GRAPH ASSEMBLY ─────────────────────────────────
graph_builder = StateGraph(State)
graph_builder.add_node("agent", agent_node)
graph_builder.add_node("tools", tool_node)
graph_builder.add_edge(START, "agent")
graph_builder.add_conditional_edges(
"agent", should_continue,
{"tools": "tools", "__end__": END}
)
graph_builder.add_edge("tools", "agent")
graph = graph_builder.compile(checkpointer=MemorySaver())
# ── MODULE 7: ENTRYPOINT ──────────────────────────────────────
if __name__ == "__main__":
config = {"configurable": {"thread_id": "session-001"}}
print("RAG agent ready. Ask about your documents, or anything else.\n")
while True:
user_text = input("You: ").strip()
if not user_text or user_text.lower() == "exit":
break
response = graph.invoke(
{"messages": [HumanMessage(content=user_text)]},
config=config
)
print(f"Agent: {response['messages'][-1].content}\n")
Што адвараецца праз адзін запіт
Аналіз адзінаго запіту дапамагае чытная паказаць распад працы.
User: "What's our policy on remote work?"
↓
[agent_node] — LangGraph's LLM reads the message, recognizes this needs
internal info, decides to call search_knowledge_base
↓
[tools] — ToolNode executes search_knowledge_base("What's our policy on remote work?")
↓
Inside the tool: query_engine.query(...) runs —
this is 100% LlamaIndex, invisible to LangGraph:
1. Embeds the query
2. Searches the vector index for the 3 closest chunks
3. Feeds those chunks + the question to Settings.llm
4. Returns a synthesized answer string
↓
[agent_node] — LangGraph's LLM receives the tool's string result,
and crafts the final response shown to the user
↓
Response to user
Граніцы ўсё чыстыя. LangGraph ніколі не сталквіцца з Node, укладаннем чыста вектарам, а толькі з інструментам, які вяртаюць тэкст, не аднародным з search_web чыста calculate. LlamaIndex ніколі не сталквіцца з messages, state чыста thread_id, а толькі з запітам, які прыходзіць, і адказам, які выходзіць. Кожная платформа выкарыстоўвае свае сілы, і адна вызов функцыі стварае з’еднанне межаў.
Рэжым толькі для абтракцыі для большага кантролю
Шаблон query_engine.query() — гэта самая простая інтэграцыя, якая падходзіць для большасці случаў. Інодзе большы кантроль ўжыткавы, напрыклад, калі сам LLM агента LangGraph павінен напісаць заканчоўны адказ, выкарыстоўваючы існуючы сістэмны прыказ чыста кантэкст размовы, а не внутрашні Settings.llm LlamaIndex, які генеруе аддзельны, несувязаны адказ.
У такім случае выкорыстайце Retriever заместо QueryEngine. Ён выкананы толькі крок пошуку і вяртае необработаны фрагменты, а што будзе далей — гэта залежыць ад агента.
# ── Retriever-only tool: returns raw chunks, not a synthesized answer ──
retriever = index.as_retriever(similarity_top_k=3)
@tool
def retrieve_documents(query: str) -> str:
"""Retrieve relevant document excerpts from the internal knowledge base.
Returns raw excerpts for you to read and reason over yourself -
use this when you need to cite specific sources or combine information
from multiple documents."""
nodes = retriever.retrieve(query)
# Format each retrieved chunk with its source for transparency
formatted_chunks = []
for i, node in enumerate(nodes):
source = node.metadata.get("file_name", "unknown source")
formatted_chunks.append(f"[Excerpt {i+1} from {source}]\n{node.text}")
return "\n\n---\n\n".join(formatted_chunks)
За дапамою такой наладкі, власны вызов LLM у agent_node, які выкорыстоўвае llm_with_tools разам з усім історыям размовы і сістэмным запросам, чытае неапдэтаваныя фрагменты тэксту і пішае адпаведны адказ. Гэта дае рэальныя перады: агент можа пазначыць, з якога дакумента была взята інформацыя, можа сумешваць запрашаныя фрагменты з паканальнымі розмовамі, а корыстувачы чуюць аднаковы голас, а не два LLM у розных стылях.
Калькі выбраць
Выберыце QueryEngine для найпростэйшай інтэграцыі, калі дастатнька можлівасць LLM з LlamaIndex стварыць адказ, базаваны на пошуку, у віглядзе самастойнага строкі. Гэта падходзіць для большасці чат-ботаў і асістэнтав.
Выберыце Retriever, калі патрэбны ісхадныя цітаты, калі галоўны LLM агента павінен падтрымваць стабільны тон і стыль аргументаў як у атрыбутаваных, так і ў няатрыбутаваных адказах, або калі атрыбутаваныя часткі тэксту павінны быць сумаваны з рэзультатамі іншых інструментаў пры стварэнні фінальнага адказу.
Справака пра ключовыя словы
Завантажэнне і індэксаванне. Document — гэта завантажаныя выкладкі, тое ўзе адна файл або адна стораніца. Node — гэта частка яго, елемент, які можна выявіць, з метаданамі, які вядуць да яго выхаднага джэрага. SimpleDirectoryReader("./path").load_data() завантажае кожны падтрымваны файл у папцы як об’екты Document. Settings — гэта глобальны екземпляр налашоўкаў, а Settings.llm, Settings.embed_model і Settings.chunk_size настаўляюцца аднойчы для всіх компанентаў. VectorStoreIndex.from_documents(documents) адбівае часткі, вбудоввае іх і зберагае за адны вызов.
Запыткі. index.as_query_engine(similarity_top_k=3) стварае QueryEngine, які запошчае топ-k фрагментаў і таксама запісвае сінтэзаваны адказ. index.as_retriever(similarity_top_k=3) стварае Retriever, які запошчае толькі топ-k фрагментаў, што падходзіць для сцэнарыяў, дзе сінтэзацію выканае ваш сае LLM. query_engine.query("...") выкананае цэлы працэс запошчання і падготавкі адказу, і вяртае об’ект Response, а str(response) выкалывае тэкст. retriever.retrieve("...") выкананае толькі запошчання і вяртае об’екты Node, якія маюць атрыбуты .text і .metadata.
Стойкасць. index.storage_context.persist(persist_dir="./storage") зберагае індэкс, таму пасля перзапуску не трэба яго занова ствараць. StorageContext.from_defaults(persist_dir="./storage") у поўнай зусімнасці з load_index_from_storage(...) перзавантажвае яго. ChromaVectorStore, PineconeVectorStore і QdrantVectorStore — гэта зовнішні бэкенды, якія заменяюць стандартны внутрашній мэморыяны сховыш, па той жа прынцып, як і чэкпоінты LangGraph.
Мост. Функцыя @tool, тэлы каторой вызываюць query_engine.query(...), і ўсё, што неабходна для інтэграцыі: LangGraph бачыць звычны інструмент, а LlamaIndex застаецца інкапсульаваным. Таксама існуе два незалежныя канфігурацыі LLM. Settings.llm — гэта внутрэній модэль LlamaIndex, які вікорыстоўваецца толькі внутры ў механізме запытоў, а llm у LangGraph агента адпавядае за основную логіку. Адныя і другія працуюць незалежна і не дзеляцца ні історыяй, ні станам.
Чы трэба вам гэта?
- Калі агенту трэбны толькі загальныя знанні, матэматыка або пошук у інтэрнэтэ, LlamaIndex не патрэбен, і дастатнекі будзе базовы шаблон з стандартнымі інструментамі.
- Калі ён павінен адпавядаць на запыты на адной фіксаванай сэткі дакументаў, такіх як правілы, інструкцыі або адчыненнія, якія рэдка калі зміняюцца, тады выкорыстоўванне
QueryEngineяк інструмента — гэта самае правільнае рашэнне.
Retriever.interrupt() з LangGraph і размясціце вызов на атрымання дадзенаў у вузле, які чакае на падтверджэння, як і у разе з будзь-якім чутлівым інструментам.Два фрэймворкі і адна ўзлегласць
Гэты урок заключаецца ў тым, што наданне агенту рэальных знанняў — гэта не проблема LangGraph. Гэта проблема даных, і для ўсунення яе падходзіць фрэймворк для апрацоўкі даных. Складная мнагаагентная сістэма на самай працэў падлягае складанню з кальколькаякасці графаў адзінаго агента, і доступ да знанняў таксама адбываецца за модульным прынцыпам.
LlamaIndex адпавядае за індэксаванне і выкарыстоўванне даных, а LangGraph — за логіку выважвання і коордынацыю. Весь цыя працэс з’едынаецца ў адну функцыю, адзначаную тэгам @tool. Гэта не ўскладненне, а правільны ступень взаімазв’язку, адколі кожны фрэймворк застаецца у сваёй сферы, і кожную з сторон можна апдэйтаваць незалежна. Базу вектарных даных можна заменіць без вплыву на граф, а патэрн керавання можна дадаць без змян у логіцы выкарыстоўвання даных.
Спадневаная літэратура
- MCP для агентаў LangGraph, па шагах: серверы, срэдства перадачы дадзеных і мосты-адаптэры — Вы дазнаецеся пра протакол Model Context Protocol, які выкорыстоўваецца з роляў хоста, кліента і сервера, а таксама пра FastMCP сервер, разлікі межы stdio і HTTP, адаптэры langchain-mcp і распалохі пад час працы ў LangGraph.
- Стварэнне ShopBot: агента падтрымкі па прынцыпах LangGraph з можлівасцю зберагчання дадзеных, выкарыстоўвання інструментаў і затверджэння вярнення грошаў — Створыце агента падтрымкі кліента ў модулі LangGraph паэтапна: стан, інструменты, вузлы, маршрутызацыя, стварэнне кароткіх падсумкаў і механізм перэрыву, які чакае на затверджэння вярнення грошаў.