Projektowanie pipeline’u RAG, dzięki któremu agenci AI rozumują, a nie tylko wyszukują informacje.
Pipeline RAG dla agentów AI powinien udostępniać informacje o poziomie pewności, różnorodności źródeł oraz zakresie informacji, aby agent mógł zauważyć luki, zadać ponowne pytanie i wyjaśnić, jak do tego doszło.
Źródła: How to Design a RAG Pipeline So AI Agents Reason, Not Just Query It
Agent wywołuje pipeline RAG i otrzymuje listę dokumentów. Co dzieje się dalej?
W większości konfiguracji agentowych RAG jest traktowane jak pole wyszukiwania: wysyła się zapytanie, bierze się to, co wraca, i kontynuuje się. Agent nie może stwierdzić, czy wyniki były przydatne, czy obejmowały wszystkie aspekty pytania, czy druga próba z bardziej precyzyjną hipotezą mogłaby ujawnić coś ważnego. Działa w ciemno.
To ma znaczenie, ponieważ agenci działają na podstawie niepełnych informacji. Detektor halucynacji może wykryć sfabrykowane fakty, ale niewidzialne punkty słabości w procesie wyszukiwania są znacznie trudniejsze do zauważenia. Agent wyciąga pewne wnioski na podstawie niekompletnego obrazu, a nikt nie dowiaduje się, co przeoczył. Zwykły proces rozwoju – pobieranie danych, następnie wyszukiwanie, a potem generowanie – w ogóle nie zawiera sygnału zwrotnego.
Uczynienie procesu wyszukiwania widocznym dla agenta
Rozwiązaniem jest cienka obudowa wokół pipeline RAG, która udostępnia ustrukturyzowane sygnały, na podstawie których agent może rozumować, a nie tylko je konsumować.
Zamiast zwracać zwykły list dokumentów, obudowa zwraca bardziej złożony obiekt. Zawiera on dokumenty, ocenę pewności, miarę różnorodności źródeł (ile różnych domen i jaki zakres dat), sygnały dotyczące zakresu odpowiedzi, które aspekty pytania zostały omówione, a które brakuje, oraz metadane związane z wyszukiwaniem, takie jak model embedding, rozmiar fragmentów, parametr top-k oraz informację o tym, czy uruchomiono ponowne sortowanie.
{
"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
}
}
Dzięki temu agent ma kanał informacji zwrotnej. Może zauważyć, że zakres jest częściowy, a źródła ograniczone. Może zdecydować się na ponowne zapytanie z innej perspektywy, skontaktować się z osobą lub odnotować braki w swoim rozumowaniu.
Trzy warstwy
Warstwa 1: pozyskiwanie narzędzi
Najpierw należy zebrać to, co system już oblicza. Bazy danych wektorowych zwracają wyniki podobieństwa, narzędzia do ponownego rankowania podają poziom pewności, a fragmenty danych zawierają daty i adresy URL źródeł. Ta pierwsza warstwa gromadzi te wartości bez modyfikowania logiki wyszukiwania: wykonuje standardowe zapytanie, pobiera wyniki, źródła i daty, oblicza średnią wartości jako przybliżony poziom pewności i liczy unikalne źródła.
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))
}
}
Jest to metoda niewtrącająca się w proces, ponieważ odczytuje się jedynie dane, które już tam istniały.
Warstwa 2: wykrywanie zakresu pokrycia
Następnie pojawia się warstwa, która powiązuje uzyskany treść z pierwotnym pytaniem. Wystarczy proste porównanie semantyczne, nie ma potrzeby dokonywania pełnej ponownej sortowania.
Podziel pytanie na poszczególne aspekty. W przypadku pytania „Jak wdrożyć model przy ograniczeniach kosztowych?”, aspektami mogą być wdrożenie, koszt oraz ograniczenia. Następnie sprawdza się, które z nich pojawiają się w uzyskanej treści. Model językowy lub prosta ekstrakcja słów kluczowych może dostarczyć listę aspektów, a sprawdzenie może polegać na prostym wyszukiwaniu każdego z nich w połączonym tekście dokumentu. Funkcja podaje, które aspekty zostały objęte, które brakuje oraz wskaźnik zakresu pokrycia.
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
}
Tutaj agent otrzymuje informacje zwrotne, na których może się oprzeć w swoich działaniach. Brakujące aspekty powinny skutkować wysłaniem nowego zapytania. Aby udoskonalić ten podejście, należy podczas przetwarzania oznaczyć każdy dokument odpowiednimi aspektami i porównać te oznaczenia podczas wyszukiwania.
Warstwa 3: przekazanie zadań agentowi
Na koniec należy dać agentowi narzędzie, które zwraca wyniki przetwarzania. Narzędzie to przyjmuje zapytanie oraz opcjonalny aspekt, na którym należy się skupić, przeprowadza wyszukiwanie z wykorzystaniem odpowiednich sygnałów, dodaje informacje o stopniu pokrycia i dołącza rekomendację: ponownie wysłać zapytanie, gdy stopień pokrycia spadnie poniżej 0,7, w przeciwnym razie kontynuować.
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"
)
}
Agent otrzymuje tę rekomendację i może ją zaakceptować lub zignorować, korzystając z wiedzy specjalistycznej w danej dziedzinie.
Sprawdź, czy sygnały są godne zaufania
Urządzenie jest przydatne tylko wtedy, gdy jego sygnały są dokładne, dlatego sprawdź trzy aspekty.
- Dokładność sygnałów. Czy wartość pewności rzeczywiście przewiduje jakość wyników? Wykonaj około dwudziestu zapytań, ocenij wyniki ręcznie od jednego do pięciu i sprawdź związek pomiędzy ocenami a tą wartością. Rozsądnym celem jest korelacja powyżej około 0,75.
- Detekcja zakresu odpowiedzi. Ręcznie zaznacz, które aspekty każdego pytania są odpowiadane przez dokumenty, a następnie porównaj to z wynikami detektora przy około dziesięciu różnych zapytaniach. Celuj w precyzję powyżej 85%.
- Behawior agenta. Rejestruj każdą decyzję o ponownym złożeniu zapytania. Jeśli wskaźnik zakresu odpowiedzi poniżej 0,7 w większości przypadków skutkuje nowym zapytaniem, oznacza to, że agent zwraca uwagę na ten sygnał.
Koszty i ograniczenia
Pojawia się dodatkowy opóźnienie. Aby uzyskać pełną obsługę, konieczna jest druga analiza semantyczna, a przy wyszukiwaniu pięciu dokumentów może to dodać od 50 do 100 milisekund. Jeśli to zbyt wiele, należy zapamiętywać te dane w pamięci podręcznej lub obliczać je asynchronicznie.
To rozwiązanie zakłada również, że warstwa wyszukiwania jest wystarczająco sprawna, aby być dostępna. Jeśli magazyn wektorowy nie zwraca wyników lub fragmenty danych nie zawierają metadanych, najpierw trzeba zaimplementować narzędzia do ich analizy.
Ponadto te wskaźniki są heurystycznymi metodami. Wysoki wynik pewności nie gwarantuje poprawnego rozumowania. Rozwiązanie to dostarcza agentowi lepszych, ale nie doskonałych danych, dlatego nadal konieczne są dodatkowe kontrole na wypadek halucynacji.
Dlaczego to się opłaca
Agenci, którzy potrafią zajrzeć do procesu wyszukiwania, są bardziej przejrzysti i bardziej niezawodni. Mogą wyjaśnić, dlaczego przeprowadzili ponowną wyszukiwkę, zaznaczyć braki pewności i przekazać zadanie człowiekowi, gdy stopień pokrycia jest niski. To właśnie różnica pomiędzy silnikiem wyszukiwania a asystentem badawczym: jeden z nich zwraca wyniki, a drugi zwraca wyniki i mówi, w czym ma wątpliwości.
Pierwsze kroki
- W tym tygodniu wykonaj zadanie z warstwy 1. Ujawnij poziom pewności i różnorodność źródeł, rejestruj je przez jeden dzień i obserwuj występujące wzorce.
- Dodaj funkcję wykrywania stopnia pokrycia dla najczęściej używanych typów zapytań i sprawdź ją ręcznie na dziesięciu przykładach.
- Włącz tę funkcję do agenta i zmierz, czy ten przeprowadza ponowne zapytania, gdy stopień pokrycia jest niski, oraz czy jego rozumowanie się poprawia.
Gdy już istnieje ten zestaw narzędzi, łatwiej jest dodać kolejne sygnały: wykrywanie odchyleń semantycznych, sprawdzanie aktualności, mechanizmy weryfikacji faktów. Każdy z nich daje agencie więcej informacji do analizy. Zacznij od małych kroków, stwórz kanał informacji zwrotnej i pozwól agencie nauczyć się go słuchać.