Главная / Статьи

Проектирование конвейера RAG для того, чтобы ИИ-агенты рассуждали, а не просто делали запросы.

Пайплайн RAG для ИИ-агентов должен отображать уровень уверенности, разнообразие источников и степень охвата, чтобы агент мог заметить пробелы, снова сделать запрос и объяснить, как он пришел к своему выводу.

Издатель: REACTAPP.TOP5 мин чтения1252 слов

Источники: How to Design a RAG Pipeline So AI Agents Reason, Not Just Query It

Агент вызывает пайплайн RAG и получает список документов. Что происходит дальше?

В большинстве схем с агентами RAG рассматривается как поисковое поле: отправляется запрос, берутся полученные результаты, и процесс продолжается. Агент не может определить, хороши ли эти результаты, охватывают ли они все аспекты вопроса, или не привела бы вторая попытка с более точной гипотезой к важной информации. Он действует вслепую.

Это важно, потому что агенты принимают решения на основе неполной информации. Детектор галлюцинаций может выявить выдуманные факты, но слепые зоны в процессе поиска гораздо труднее обнаружить. Агент уверенно рассуждает, опираясь на неполную картину, и никто не узнает, что он упустил. Типичный пайплайн разработки — сначала загрузка данных, затем поиск, затем генерация — совершенно не содержит сигналов обратной связи.

Сделать процесс поиска видимым для агента

Решение заключается в тонком «креплении» вокруг пайплайна RAG, которое предоставляет структурированные сигналы, на основе которых агент может рассуждать, а не просто потреблять информацию.

Вместо простого списка документов это крепление возвращает более подробный объект. Он содержит сами документы, оценку уверенности, показатель разнообразия источников (сколько различных доменов и какой диапазон дат), сигналы охвата, указывающие, какие аспекты вопроса были рассмотрены, а какие отсутствуют, а также метаданные по поиску, такие как модель вживления, размер фрагментов, параметр top-k и информация о том, выполнялся ли процесс переупорядочивания результатов.

{
  "results": [Document, Document, Document],
  "confidence_score": 0.87,
  "source_diversity": {"domains": 3, "timestamps": ["2024-01", "2023-11", "2023-09"]},
  "coverage_signals": {
    "question_aspects_covered": ["technical", "cost"],
    "question_aspects_missing": ["compliance", "deployment"]
  },
  "retrieval_metadata": {
    "embedding_model": "text-embedding-3-large",
    "chunk_size": 512,
    "top_k": 5,
    "reranker_applied": true
  }
}

Благодаря этому у агента есть канал обратной связи. Он может увидеть, что охват информации неполный, а источники ограничены. Он может решить повторно выполнить поиск с другой точки зрения, обратиться за помощью к специалисту или задокументировать недостатки в своих рассуждениях.

Три уровня

Уровень 1: получение данных из инструментов

Начните с сбора тех данных, которые уже вычисляет система. Векторные базы данных возвращают оценки сходства, инструменты переранжирования выводят уровень уверенности, а фрагменты данных содержат временные метки и URL-адреса источников. На этом первом уровне собираются эти значения без изменения логики поиска: выполняется стандартный запрос, извлекаются оценки, источники и временные метки, оценки суммируются для получения приблизительного показателя уверенности, а также подсчитывается количество уникальных источников.

def retrieve_with_signals(query: str, top_k: int = 5):
    # Standard retrieval
    results = vector_db.query(query, top_k=top_k)

    # Capture raw signals
    similarity_scores = [r.score for r in results]
    sources = [r.metadata.get("source") for r in results]
    timestamps = [r.metadata.get("timestamp") for r in results]

    # Compute confidence as mean similarity
    confidence = sum(similarity_scores) / len(similarity_scores)

    return {
        "results": results,
        "confidence_score": confidence,
        "source_diversity": {
            "domains": len(set(sources)),
            "timestamps": sorted(set(timestamps))
        }
    }

Этот метод неинвазивен, поскольку вы считываете только те данные, которые уже там находились.

Уровень 2: определение охвата

Далее идет уровень, который связывает полученный контент с исходным вопросом. Достаточно простого семантического сравнения, полной переориентации рейтингов не требуется.

Разделите вопрос на аспекты. Для вопроса «Как развернуть модель с ограничениями по стоимости?» аспектами могут быть развертывание, стоимость и ограничения. Затем проверьте, какие из них присутствуют в полученном тексте. Для формирования списка аспектов можно использовать большую языковую модель или простой метод извлечения ключевых слов; проверка может заключаться в простом поиске каждого аспекта в объединенном тексте документа. Функция сообщает, какие аспекты были охвачены, какие отсутствуют, а также показывает коэффициент охвата.

def detect_coverage(query: str, documents: list) -> dict:
    # Extract query aspects (simple approach: use an LLM or keyword extraction)
    aspects = extract_query_aspects(query)  # ["deployment", "cost"]

    # Check document coverage
    doc_text = " ".join([d.content for d in documents])
    covered = [a for a in aspects if a.lower() in doc_text.lower()]
    missing = [a for a in aspects if a not in covered]

    return {
        "question_aspects_covered": covered,
        "question_aspects_missing": missing,
        "coverage_ratio": len(covered) / len(aspects) if aspects else 1.0
    }

Именно здесь агент получает обратную связь, на основе которой может принимать действия. Отсутствующие аспекты должны стимулировать отправку нового запроса. Для улучшения подхода необходимо при обработке данных помечать каждый документ аспектами и сравнивать эти метки во время поиска.

Уровень 3: передача агенту

Наконец, необходимо предоставить агенту инструмент, возвращающий результаты поиска. Этот инструмент принимает запрос и, при наличии, аспект, на котором следует сосредоточиться, выполняет поиск с использованием соответствующих сигналов, определяет степень покрытия и формирует рекомендацию: отправить новый запрос, если коэффициент покрытия падает ниже 0,7, в противном случае продолжить работу.

tools = [
    {
        "name": "search_with_reasoning",
        "description": "Search the knowledge base and receive coverage signals",
        "parameters": {
            "query": "str",
            "aspect_focus": "optional str (e.g., 'deployment' or 'cost')"
        }
    }
]

def search_with_reasoning(query: str, aspect_focus: str = None) -> dict:
    retrieval_output = retrieve_with_signals(query, top_k=5)
    coverage = detect_coverage(query, retrieval_output["results"])

    return {
        **retrieval_output,
        "coverage_signals": coverage,
        "recommendation": (
            "re-query" if coverage["coverage_ratio"] < 0.7 else "proceed"
        )
    }

Агент получает это рекомендование и может следовать ему или отклонить его, используя свои знания в данной области.

Проверьте, заслуживают ли сигналы доверия

Система полезна только тогда, когда её сигналы точны, поэтому необходимо протестировать три аспекта.

  • Точность сигналов. Действительно ли показатель уверенности предсказывает качество получаемых результатов? Выполните около двадцати запросов, оцените результаты вручную от одного до пяти и сверьте эти оценки с показателем уверенности. Разумной целью будет корреляция выше примерно 0,75.
  • Обнаружение охвата. Вручную отметьте, какие аспекты каждого вопроса покрывают документы, затем сравните это с результатами работы детектора для примерно десяти различных запросов. Цель — точность выше 85%.
  • Поведение агента. Фиксируйте каждое решение о повторном запросе. Если в большинстве случаев коэффициент охвата ниже 0,7 приводит к новому запросу, значит агент уделяет внимание сигналу.

Затраты и ограничения

Появляется дополнительная задержка. Для обработки данных требуется второй этап анализа семантики, и при поиске пяти документов может добавиться ещё от 50 до 100 миллисекунд. Если это слишком много, следует кэшировать сигналы или вычислять их асинхронно.

Кроме того, данная система предполагает, что слой поиска находится в достаточно хорошем состоянии для использования. Если хранилище векторов не возвращает оценки или блоки не содержат метаданных, сначала необходимо настроить инструменты для сбора информации.

Сигналы, используемые в системе, являются эвристиками. Высокий уровень уверенности не гарантирует правильности выводов. Система предоставляет агенту более качественные, но не идеальные входные данные, поэтому всё равно требуются проверки на галлюцинации на последующих этапах.

Почему это оправдано

Агенты, способные видеть процесс поиска, более прозрачны и надежны. Они могут объяснить, почему проводят поиск снова, отмечать неопределенность и передавать задачу человеку при низком уровне покрытия. В этом и заключается разница между поисковой системой и исследовательским ассистентом: одна просто возвращает результаты, а другая возвращает их и указывает, в чем она не уверена.

Начало работы

  1. В этой неделе выполните этап 1. Отобразите уровень уверенности и разнообразие источников, фиксируйте эти показатели в течение дня и ищите закономерности.
  2. Добавьте функцию обнаружения уровня покрытия для наиболее часто используемых типов запросов и проверьте ее вручную на десяти примерах.
  3. Интегрируйте эту функцию в агента и оцените, будет ли он проводить повторный поиск при низком уровне покрытия, а также улучшится ли его способность к логическим рассуждениям.

Как только появляется такой кронштейн, становится проще внедрять дополнительные сигналы: обнаружение семантического смещения, проверки свежести данных, механизмы верификации фактов. Каждый из них предоставляет агенту дополнительную информацию для анализа. Начните с малого, создайте канал обратной связи и позвольте агенту научиться его использовать.