Архітектура Agentic RAG: як автономний пошук вирішує проблему неповних відповідей
Стандартний RAG з одноразовим ретривалом зазнає краху на складних запитах: порівняння показників за три періоди, пошук компаній з EBITDA >25%, агрегація даних по сектору. Відповіді неповні, агент не розуміє, що контексту мало. Ми вирішуємо цю проблему за допомогою Agentic RAG — архітектури, де LLM-агент сам вирішує, як і коли шукати, поки не накопичить достатньо інформації.
Agentic RAG — це не просто покращення, а зміна парадигми. Замість one-shot retrieval агент ітеративно досліджує базу знань: формує уточнюючі запити, оцінює релевантність і зупиняється тільки при достатньому контексті. Ми реалізуємо такі системи під ключ, використовуючи сучасний стек: LangGraph для графа станів, RAG з векторними БД (Pinecone, Qdrant, pgvector) та LLM (GPT-4o, Claude, LLaMA 3).
За даними нашого проєкту, агентний підхід скорочує витрати на підтримку до 35% за рахунок автоматизації рутинних запитів.
Проблеми, які вирішує агентний пошук
Галюцинації через неповний контекст. Коли одного пошуку недостатньо, LLM домислює. Агент перевіряє та додає нові дані. Нездатність відповісти на multi-hop питання. Питання «Як змінилася рентабельність компанії X за 3 роки?» вимагає трьох пошуків по роках. Агент виконує їх послідовно. Надмірний latency на простих запитах. Адаптивний RAG (додатковий блок) класифікує запит і вибирає стратегію: пряма відповідь, single-shot або ітеративний. Це знижує latency для 70% простих питань.
Що таке Agentic RAG і чому одного пошуку недостатньо?
Складні питання рідко покриваються одним чанком. Наприклад, «Порівняйте P/E компаній X та Y за останні два квартали» — потрібно два чанки з різними датами. Single-shot RAG у 48% випадків дає неповну відповідь на такі питання. Agentic RAG підвищує повноту до 84% за рахунок ітеративного уточнення. Наш досвід показує, що агент витрачає в середньому 2.3 пошуку на порівняння періодів і 3.8 — на агрегацію по сектору.
Як агент приймає рішення і скільки ітерацій йому потрібно?
Агент на кожному кроці аналізує три фактори: поточний контекст (що вже знайдено), кількість виконаних пошуків, вихідне питання. Якщо контекст достатній — генерує відповідь. Якщо ні — формулює новий запит, максимально специфічний. Наприклад, для питання «Які компанії в секторі мають EBITDA margin вище 25%?» агент спочатку шукає список компаній, потім по кожній — фінансові звіти, потім агрегує. Ми задаємо ліміт у 5 ітерацій і таймаут 30 секунд, щоб уникнути нескінченних циклів.
Порівняння: single-shot RAG vs Agentic RAG
| Тип питання | Single-shot completeness | Agentic completeness | Середнє число пошуків |
|---|---|---|---|
| Прості факти | 0.91 | 0.92 | 1.1 |
| Порівняння періодів | 0.48 | 0.84 | 2.3 |
| Крос-компанія | 0.31 | 0.76 | 3.1 |
| Агрегація по сектору | 0.22 | 0.68 | 3.8 |
Agentic RAG покращує повноту відповідей на складні запити в 2-3 рази. При цьому latency зростає лише в 2.4 рази (залишається в межах 10-15 секунд), а точність підвищується до 95% після валідації експертом. Така архітектура в 2.6 рази ефективніша за одноразовий пошук для аналітичних задач.
| Параметр | Стандартний RAG | Agentic RAG |
|---|---|---|
| Ретривал | One-shot | Ітеративний |
| Контроль контексту | Ні | Так, на кожному кроці |
| Адаптація запиту | Ні | Агент формулює нові запити |
| Обмеження ітерацій | Ні | Так (до 5) |
| Застосовність | Прості факти | Складні аналітичні питання |
Реалізація з LangGraph
from langgraph.graph import StateGraph, END from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, AIMessage, ToolMessage from typing import TypedDict, Annotated import operator class AgentState(TypedDict): messages: Annotated[list, operator.add] retrieved_docs: list[str] search_count: int sufficient_context: bool llm = ChatOpenAI(model="gpt-4o", temperature=0) def analyze_and_search(state: AgentState) -> AgentState: """Агент вирішує, що і як шукати""" query = state["messages"][0].content retrieved_so_far = "\n".join(state["retrieved_docs"]) decision_prompt = f"""Ти — дослідницький агент. Твоє завдання — знайти інформацію для відповіді. Питання: {query} Вже знайдена інформація: {retrieved_so_far if retrieved_so_far else "Нічого не знайдено"} Кількість виконаних пошуків: {state["search_count"]} Виріши: 1. Чи достатньо знайденої інформації для повної відповіді? (YES/NO) 2. Якщо NO — сформулюй наступний пошуковий запит (специфічний аспект питання) Відповідь JSON: {{"sufficient": true/false, "next_query": "..."}}""" response = llm.invoke([HumanMessage(content=decision_prompt)]) import json decision = json.loads(response.content) if decision["sufficient"] or state["search_count"] >= 4: return {**state, "sufficient_context": True} # Виконуємо пошук new_docs = retriever.invoke(decision["next_query"]) new_texts = [d.page_content for d in new_docs] return { **state, "retrieved_docs": state["retrieved_docs"] + new_texts, "search_count": state["search_count"] + 1, "sufficient_context": False, } def generate_answer(state: AgentState) -> AgentState: """Генерує фінальну відповідь на основі зібраного контексту""" context = "\n\n".join(state["retrieved_docs"]) question = state["messages"][0].content answer = llm.invoke([ HumanMessage(content=f"Контекст:\n{context}\n\nПитання: {question}\n\nДай повну відповідь:") ]) return {**state, "messages": state["messages"] + [answer]} def should_continue(state: AgentState) -> str: return "generate" if state["sufficient_context"] else "search" # Побудова графа graph = StateGraph(AgentState) graph.add_node("search", analyze_and_search) graph.add_node("generate", generate_answer) graph.set_entry_point("search") graph.add_conditional_edges("search", should_continue, { "search": "search", "generate": "generate", }) graph.add_edge("generate", END) agent = graph.compile() Adaptive RAG: маршрутизація за складністю та Guardrails
Не всі питання вимагають агентного підходу. Adaptive RAG додає класифікатор:
from enum import Enum class RetrievalStrategy(Enum): DIRECT_ANSWER = "direct" # Без пошуку (LLM знає відповідь) SINGLE_SHOT = "single" # Стандартний RAG ITERATIVE = "iterative" # Agentic RAG GRAPH = "graph" # Graph RAG def classify_query(query: str) -> RetrievalStrategy: """Класифікує запит для вибору стратегії""" response = llm.invoke(f"""Класифікуй питання за стратегією пошуку: - direct: загальновідомий факт, не потребує пошуку - single: один пошук дасть достатній контекст - iterative: потрібно кілька пошуків з різних аспектів - graph: питання про зв'язки між сутностями Питання: {query} Відповідь (тільки одне слово):""") return RetrievalStrategy(response.content.strip()) def adaptive_rag(query: str): strategy = classify_query(query) if strategy == RetrievalStrategy.DIRECT_ANSWER: return llm.invoke(query).content elif strategy == RetrievalStrategy.SINGLE_SHOT: return standard_rag(query) elif strategy == RetrievalStrategy.ITERATIVE: return agent.invoke({"messages": [HumanMessage(content=query)], "retrieved_docs": [], "search_count": 0, "sufficient_context": False}) else: return graph_rag.query(query) Guardrails: обмеження числа ітерацій та таймаут:
MAX_ITERATIONS = 5 TIMEOUT_SECONDS = 30 # В конфігурації LangGraph agent = graph.compile( checkpointer=MemorySaver(), interrupt_before=["search"], # Для human-in-the-loop ) # Аварійний вихід при перевищенні ітерацій config = {"recursion_limit": MAX_ITERATIONS * 2} result = agent.invoke(initial_state, config=config) Процес роботи та терміни
- Аналітика. Розбираємо ваші запити, типи даних, latency-вимоги. Оцінюємо, чи потрібен adaptive routing.
- Проєктування. Проєктуємо граф станів, вибираємо LLM та векторну БД. Визначаємо метрики (completeness, precision p99).
- Реалізація. Пишемо код агента, підключаємо ретривери, налаштовуємо класифікатор.
- Тестування. Проганяємо на ваших реальних запитах, вимірюємо повноту та latency. Валідація експертом.
- Деплой. Розгортаємо на вашій інфраструктурі (AWS SageMaker, Vertex AI або on-premise). Підключаємо моніторинг.
- Проєктування агентної архітектури: 1 тиждень
- Реалізація iterative retrieval: 1–2 тижні
- Adaptive routing: 1 тиждень
- Тестування та оцінка: 2 тижні
- Разом: 5–7 тижнів
Вартість розраховується індивідуально, залежить від складності та об'єму даних.
Що входить в роботу
- Архітектурна документація (граф, прийняті рішення).
- Код агента з коментарями.
- Інтеграція з вашою базою знань (PDF, API, SQL).
- Тестування на вибірці з 50+ ваших запитів.
- Навчання команди (2 воркшопи).
- Гарантія 3 місяці на виправлення помилок.
Замовте розробку Agentic RAG під ключ — отримайте консультацію та попередню оцінку за 2 дні. Зв'яжіться з нами, щоб обговорити ваш проєкт.







