Разработка Agentic RAG с автономным поиском под ключ

Стандартный RAG часто даёт неполные ответы на сложные запросы, когда одного поиска недостаточно. Мы разрабатываем Agentic RAG с автономным поиском, где LLM-агент сам решает, как и когда искать, пока не накопит достаточно информации. Реализуем проект под ключ — от концепции до сопровождения, с многолетним опытом и последующей поддержкой.
Часто задаваемые вопросы

Архитектура 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)

Процесс работы и сроки

  1. Аналитика. Разбираем ваши запросы, типы данных, latency-требования. Оцениваем, нужен ли adaptive routing.
  2. Проектирование. Проектируем граф состояний, выбираем LLM и векторную БД. Определяем метрики (completeness, precision p99).
  3. Реализация. Пишем код агента, подключаем ретриверы, настраиваем классификатор.
  4. Тестирование. Прогоняем на ваших реальных запросах, измеряем полноту и latency. Валидация экспертом.
  5. Деплой. Разворачиваем на вашей инфраструктуре (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 дня. Свяжитесь с нами, чтобы обсудить ваш проект.

Расшифровка метрик: что измеряемCompleteness — доля фактов, которые агент извлёк из базы знаний, от идеально полного ответа (проверяется экспертом). Precision — доля релевантных чанков среди всех полученных. Latency p99 — время ответа для 99% запросов. Все метрики фиксируем до и после внедрения.

Направления AI-разработки

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1394
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1369
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    816
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1141