Startseite / Artikel

Agentic RAG mit Agno Teams: Abfragen umschreiben, ein Kritikzyklus und Qdrant

Agentic RAG mit einem Agno-Team: Ein Koordinator überarbeitet Anfragen, ein Kritiker wiederholt die Informationsbeschaffung, und die Antworten stammen ausschließlich aus dem genehmigten Kontext in der Qdrant-Hybridsuche.

Verlag: REACTAPP.TOP22 Min. Lesezeit5160 Wörter

Quellen: The Agent Coordinator Pattern: Orchestrating Query Rewriting, Retrieval, and Critique with Agno

Ein Such- und Kritik-Loop zwischen Agenten lässt sich leicht an einer Tafel skizzieren, ist aber überraschend schwierig in die Praxis umzusetzen. Das hier beschriebene System läuft auf Agno Teams und umfasst vier Rollen: einen Koordinator, einen Abfrageschreiber, einen Loop zur ständigen Verbesserung des Kontexts sowie einen Antwortagenten, der erst dann antwortet, wenn die Beweise ausreichen. Darunter kommt eine hybride Suche in Qdrant zum Einsatz, die dichte Vektoren, BM25 sowie die Kombination von Rückgriffsrängen miteinander verbindet.

Wie die Teamstruktur aussieht

Oben an der Hierarchie steht der Koordinator, ein Team im coordinate-Modus. Er erledigt keine eigenen Aufgaben. Stattdessen verteilt er Aufgaben, wartet und leitet jedes Ergebnis weiter die Kette entlang.

  1. Der Abfrageschreiberagent nimmt die ursprüngliche Frage entgegen und erzeugt drei bis fünf semantisch ähnliche Varianten. Andere Formulierungen liefern unterschiedliche Abschnitte, und eine einzige Formulierung findet selten alle relevanten Informationen.
  2. Der Such- und Bewertungsschleifen ist der Ort, an dem die eigentliche Arbeit stattfindet. Eine zweite Team-Instanz, die im tasks-Modus arbeitet und durch max_iterations begrenzt ist, wird als einzelnes Mitglied innerhalb des Koordinators platziert. Darin führt ein Suchagent eine hybride Suche für jede Variante gegen Qdrant durch, wobei dichte und spärliche Vektoren mithilfe einer nachträglichen Neubewertung kombiniert werden. Anschließend bewertet ein Bewertung agent die zurückgegebenen Ergebnisse hinsichtlich Relevanz und Abdeckung. Bei geringer Abdeckung wird die Anfrage in überarbeiteter Form erneut gesendet, während eine gute Abdeckung die Genehmigung zur Verwendung der Ergebnisse bewirkt. Der Zyklus endet, sobald der Bewertung agent zufrieden ist oder das Iterationsbudget aufgebraucht ist – je nachdem, was zuerst eintritt.
  3. Der Antwort agent sieht nur den genehmigten Kontext, niemals die rohe Suchausgabe. Er antwortet ausschließlich auf der Grundlage dieses Materials, gibt an, welcher Abschnitt welche Behauptung stützt, und macht klar, wann der Kontext unzureichend ist.
  4. Die endgültige Antwort kehrt unverändert über den Koordinator zurück, ohne Überarbeitung oder erneute Prüfung.

Warum eine Gruppe innerhalb einer Gruppe einsetzen? Dadurch wird die Idee der Kritik und des Feedback-Zyklus auf Agnos eigenes Iterationsmechanismus übertragen, sodass es im Anwendungscode keine manuell erstellten while-Schleifen gibt. Der Koordinator sieht nur ein einheitliches Element, und die gesamte Wiederholungslogik bleibt innerhalb dieses Elements.

Aufbau der Wissensbasis

Kein Agent kann etwas abrufen, solange die Wissensbasis noch nicht existiert, und es ist genauso wichtig, diesen Teil richtig umzusetzen, wie die Gestaltung des Agents selbst.

Das zugrundeliegende Datensatz ist MedQuAD_Context_GroupedQA – etwa 8.000 medizinische Texte, von denen jeder mit gruppierten Frage-Antwort-Paaren versehen ist. Bei der Aufnahme wird nur die context-Spalte beibehalten. Die QA-Paare bleiben im Datensatz unverändert, da das Experiment die Abfrage anhand der Rohtexte statt der Merkfähigkeit der Antworten überprüft.

Es gibt keine Aufteilung in Blöcke. Der vollständige Kontext jeder Zeile wird eingebettet und als ein einziger Qdrant-Punkt gespeichert. Das macht die Verarbeitung einfacher, kostet aber, dass bei langen Kontexten auf die eigene Trunkierungslogik der Embedding-APIs zurückgegriffen werden muss.

Jeder Punkt enthält drei Vektoren, jeweils in einem eigenen benannten Slot, wodurch eine Sammlung mit drei komplementären Ansichten desselben Textes entsteht:

  • dense: ein 768-dimensionaler Gemini-Embedding
  • sparse: BM25 über FastEmbed
  • late_interaction: ein ColBERT-Multivektor, der zur Neubewertung der Reihenfolge verwendet wird, nicht zur ersten Suchvorgangserfassung

Zuletzt kommt der Payload-Vertrag. Agnos Qdrant-Integration erwartet bestimmte Payload-Schlüssel (name, content, meta_data und content_id), damit sie zu Zeit der Suche ihre internen Document-Objekte neu erstellen kann.

Projektcode

Die Dateien befinden sich in einem kleinen Baum:

.
├── data_ingester.py
├── in-context-learning-agentic-team.py
├── pyproject.toml
├── .env
└── uv.lock

Die globale Konfiguration kommt zuerst, und umfasst Importe, das Modell sowie das Wissensobjekt:

import os

from agno.agent import Agent
from agno.knowledge.knowledge import Knowledge
from agno.models.openai import OpenAIChat
from agno.knowledge.embedder.google import GeminiEmbedder
from agno.team import Team
from agno.team.mode import TeamMode
from agno.vectordb.qdrant import Qdrant
from agno.vectordb.search import SearchType
from dotenv import load_dotenv, find_dotenv

# ---------------------------------------------------------------------------
# Shared config
# ---------------------------------------------------------------------------
load_dotenv(find_dotenv())

MODEL_ID = "gpt-4o"
COLLECTION_NAME = os.getenv("QDRANT_COLLECTION", "medquad_hybrid")

# Must match the ingestion script's model/dimensions exactly, or the query
# vector lands in the wrong embedding space entirely.
embedder = GeminiEmbedder(
    id=os.getenv("GEMINI_EMBEDDING_MODEL", "gemini-embedding-2-preview"),
    dimensions=768,
    api_key=os.getenv("GEMINI_API_KEY"),
)

vector_db = Qdrant(
    collection=COLLECTION_NAME,
    url=os.getenv("QDRANT_URL", "http://localhost:6333"),
    api_key=os.getenv("QDRANT_API_KEY"),
    embedder=embedder,
    search_type=SearchType.hybrid,
)

knowledge_base = Knowledge(
    vector_db=vector_db,
)

Abfrageschreiber

Dieser Agent verfügt über keine Tools, nur über Sprachfähigkeiten. Bei einer Frage erstellt er drei bis fünf Varianten, die sich in der Formulierung, Genauigkeit und Synonymen unterscheiden. Ziel ist es, bereits vor dem Suchvorgang ein etwas breiteres Suchfeld zu nutzen.

# ---------------------------------------------------------------------------
# 1. Query Rewriting Agent
# ---------------------------------------------------------------------------

query_rewriter = Agent(
    name="Query Rewriting Agent",
    role="Given a user query, generate N semantically similar reformulations",
    model=OpenAIChat(id=MODEL_ID),
    instructions=[
        "Given the user's query, produce 3 to 5 semantically similar variants.",
        "Vary phrasing, specificity, and synonyms so each variant could surface "
        "different but relevant passages during retrieval.",
        "Return the variants as a clean numbered list, nothing else.",
    ],
    add_datetime_to_context=True,
)

Retrieval Agent

Von allen Agenten ist dies derjenige, der direkt bei Qdrant nachfragt. Jede Abfragevariante erhält eine kombinierte dichte-plus-sparsame Suchmethode, und die gefundenen Ergebnisse werden mit Angaben dazu zurückgegeben, woher sie stammen und wie gut ihre Bewertung ausfällt; bei Bedarf steht ein Nachrangierer für späte Interaktionen zur Verfügung. Seine Anweisungen besagen, „nichts gefunden“ zu melden und niemals einen plausibel klingenden Text zu erfinden.

# ---------------------------------------------------------------------------
# 2. Retrieval Agent (Qdrant-backed knowledge)
# ---------------------------------------------------------------------------

retrieval_agent = Agent(
    name="Retrieval Agent",
    role="Search the Qdrant knowledge base for passages relevant to a query",
    model=OpenAIChat(id=MODEL_ID),
    knowledge=knowledge_base,
    search_knowledge=True,
    instructions=[
        "For each incoming query variant, search the knowledge base.",
        "Return the retrieved passages verbatim along with their source and "
        "similarity score so the Critique Agent can evaluate them.",
        "If nothing relevant is found for a variant, say so explicitly instead "
        "of fabricating context.",
    ],
    add_datetime_to_context=True,
)

Kritiker-Agent

Der Skeptiker der Gruppe antwortet selbst nicht. Er bewertet, wie relevant und umfassend der Abruf-Agent die Informationen gefunden hat, und genehmigt anschließend den Kontext oder schickt ihn mit einer Begründung zurück. Dadurch wird aus dem Vorgehen „einsammeln und hoffen“ ein echter Feedbackkreislauf.

# ---------------------------------------------------------------------------
# 3. Critique Agent
# ---------------------------------------------------------------------------

critique_agent = Agent(
    name="Critique Agent",
    role="Critique and self-evaluate retrieved context for relevance and coverage",
    model=OpenAIChat(id=MODEL_ID),
    instructions=[
        "Evaluate the retrieved passages against the original user query.",
        "Score relevance and coverage on a 1-5 scale and explain briefly.",
        "If coverage is weak (score below 4) or passages are off-topic, "
        "explicitly request the Retrieval Agent to retry with a refined query, "
        "narrower or broader scope, or different query variant.",
        "If coverage is adequate, clearly state that the context is approved "
        "and ready to be handed to the Response Generation Agent.",
    ],
    add_datetime_to_context=True,
)

# ---------------------------------------------------------------------------
# Retrieval <-> Critique loop, as a nested tasks-mode sub-team
# ---------------------------------------------------------------------------

retrieval_critique_loop = Team(
    name="Retrieval-Critique Loop",
    role=(
        "Iteratively retrieve context for each query variant and critique it "
        "until the context is approved or the iteration budget is exhausted"
    ),
    mode=TeamMode.tasks,
    model=OpenAIChat(id=MODEL_ID),
    members=[retrieval_agent, critique_agent],
    max_iterations=4,
    instructions=[
        "Run retrieval for every query variant received.",
        "After each retrieval pass, send the results to the Critique Agent.",
        "If the Critique Agent requests a retry, refine the query and retrieve "
        "again.",
        "Stop as soon as the Critique Agent approves the context, or when the "
        "iteration budget is reached -- whichever comes first.",
        "Return the final approved (or best-effort) fused context.",
    ],
)

Antwortagent

Nur dieser Agent spricht mit dem Benutzer. Er liest den vom Kritiker bereits genehmigten Kontext, begründet jede Behauptung darin mit Zitaten und greift bei Unklarheiten auf eine explizite Meldung über „unzureichenden Kontext“ zurück, anstatt zu raten.

# ---------------------------------------------------------------------------
# 4. Response Generation Agent
# ---------------------------------------------------------------------------

response_agent = Agent(
    name="Response Generation Agent",
    role="Generate the final answer from the fused, approved context",
    model=OpenAIChat(id=MODEL_ID),
    instructions=[
        "You will receive the original user query and the final fused context "
        "approved by the Retrieval-Critique Loop.",
        "Answer strictly grounded in the provided context.",
        "If the context is insufficient, say so rather than guessing.",
        "Cite which passage(s) support each claim where possible.",
    ],
    add_datetime_to_context=True,
)

Koordinator

Als Agent zu bezeichnen, überspannt den Begriff, denn er ähnelt eher einem Dirigenten. Er kennt die Reihenfolge (umschreiben, abrufen und kritisieren, antworten) und leitet die Ergebnisse unverändert weiter. Das gesamte Denken findet später statt, und der Koordinator sorgt lediglich dafür, dass die richtigen Dinge in der richtigen Reihenfolge erledigt werden.

# ---------------------------------------------------------------------------
# Top-level coordinator
# ---------------------------------------------------------------------------

agent_coordinator = Team(
    name="Agent Coordinator",
    mode=TeamMode.coordinate,
    model=OpenAIChat(id=MODEL_ID),
    members=[query_rewriter, retrieval_critique_loop, response_agent],
    instructions=[
        "You coordinate an agentic RAG pipeline.",
        "Step 1: send the user's query to the Query Rewriting Agent to obtain "
        "N semantically similar query variants.",
        "Step 2: send all query variants to the Retrieval-Critique Loop and "
        "wait for the final fused, approved context.",
        "Step 3: send the original user query plus the fused context to the "
        "Response Generation Agent.",
        "Step 4: return the Response Generation Agent's output as the final "
        "answer -- do not rewrite or second-guess it.",
    ],
    add_datetime_to_context=True,
    show_members_responses=True,
)

Ausführen

Das Einlesensskript verbindet das Datensatz, die drei Embedder und Qdrant miteinander:

import os
import time
import uuid

from datasets import load_dataset
from fastembed import LateInteractionTextEmbedding, SparseTextEmbedding
from google import genai
from google.genai.types import EmbedContentConfig, HttpOptions, HttpRetryOptions
from qdrant_client import QdrantClient
from qdrant_client.models import (
    Distance,
    HnswConfigDiff,
    Modifier,
    MultiVectorComparator,
    MultiVectorConfig,
    PointStruct,
    SparseVector,
    SparseVectorParams,
    VectorParams,
)
from dotenv import load_dotenv, find_dotenv

# ---------------------------------------------------------------------------
# Config
# ---------------------------------------------------------------------------
load_dotenv(find_dotenv())

DATASET_ID = "pavanmantha/MedQuAD_Context_GroupedQA"
COLLECTION_NAME = os.getenv("QDRANT_COLLECTION", "medquad_hybrid")

# Dense: Google Gemini embedding.
# gemini-embedding-2-preview is Google's newest (multimodal-capable) model;
# swap to "gemini-embedding-001" if you want the GA, text-only model instead.
GEMINI_MODEL = os.getenv("GEMINI_EMBEDDING_MODEL", "gemini-embedding-2-preview")
DENSE_DIM = int(os.getenv("GEMINI_EMBEDDING_DIM", "768"))  # Google's recommended sweet spot

# Sparse: BM25 (must be paired with Modifier.IDF on the Qdrant side)
SPARSE_MODEL_NAME = "Qdrant/bm25"

# Late interaction: ColBERT-style multivector, used later for reranking
LATE_INTERACTION_MODEL_NAME = "answerdotai/answerai-colbert-small-v1"
LATE_INTERACTION_DIM = 96  # matches answerai-colbert-small-v1

BATCH_SIZE = 16  # points per upsert batch

# Retry/backoff for Gemini calls (you were hitting 4xx rate limits and
# 5xx "not available" errors -- both are transient and worth retrying)
GEMINI_MAX_ATTEMPTS = int(os.getenv("GEMINI_MAX_ATTEMPTS", "6"))
GEMINI_RETRY_INITIAL_DELAY = float(os.getenv("GEMINI_RETRY_INITIAL_DELAY", "2.0"))
GEMINI_RETRY_MAX_DELAY = float(os.getenv("GEMINI_RETRY_MAX_DELAY", "64.0"))
GEMINI_RETRYABLE_STATUS_CODES = [408, 429, 500, 502, 503, 504]
GEMINI_REQUEST_DELAY_SECONDS = float(os.getenv("GEMINI_REQUEST_DELAY_SECONDS", "0.5"))

# ---------------------------------------------------------------------------
# Clients / models (initialized once)
# ---------------------------------------------------------------------------

genai_client = genai.Client(
    http_options=HttpOptions(
        retry_options=HttpRetryOptions(
            attempts=GEMINI_MAX_ATTEMPTS,
            initial_delay=GEMINI_RETRY_INITIAL_DELAY,
            max_delay=GEMINI_RETRY_MAX_DELAY,
            http_status_codes=GEMINI_RETRYABLE_STATUS_CODES,
        )
    )
)  # picks up GEMINI_API_KEY from env; auto-retries 429/5xx with backoff

qdrant_client = QdrantClient(
    url=os.getenv("QDRANT_URL", "http://localhost:6333"),
    api_key=os.getenv("QDRANT_API_KEY"),
)

sparse_model = SparseTextEmbedding(model_name=SPARSE_MODEL_NAME)
late_interaction_model = LateInteractionTextEmbedding(model_name=LATE_INTERACTION_MODEL_NAME)


# ---------------------------------------------------------------------------
# Embedding helpers
# ---------------------------------------------------------------------------

def embed_dense(texts: list[str]) -> list[list[float]]:
    vectors = []
    for text in texts:
        result = genai_client.models.embed_content(
            model=GEMINI_MODEL,
            contents=text,
            config=EmbedContentConfig(
                task_type="RETRIEVAL_DOCUMENT",
                output_dimensionality=DENSE_DIM,
            ),
        )
        vectors.append(result.embeddings[0].values)
        time.sleep(GEMINI_REQUEST_DELAY_SECONDS)  # spacing between calls, tune to your rate limit
    return vectors


def embed_sparse(texts: list[str]) -> list[SparseVector]:
    """Sparse BM25 embeddings via FastEmbed -> Qdrant SparseVector."""
    sparse_embeddings = list(sparse_model.embed(texts))
    return [
        SparseVector(indices=se.indices.tolist(), values=se.values.tolist())
        for se in sparse_embeddings
    ]


def embed_late_interaction(texts: list[str]) -> list[list[list[float]]]:
    multivectors = list(late_interaction_model.embed(texts))
    return [mv.tolist() for mv in multivectors]


# ---------------------------------------------------------------------------
# Collection setup
# ---------------------------------------------------------------------------

def create_collection():
    if qdrant_client.collection_exists(collection_name=COLLECTION_NAME):
        qdrant_client.delete_collection(collection_name=COLLECTION_NAME)

    qdrant_client.create_collection(
        collection_name=COLLECTION_NAME,
        vectors_config={
            "dense": VectorParams(
                size=DENSE_DIM,
                distance=Distance.COSINE,
            ),
            "late_interaction": VectorParams(
                size=LATE_INTERACTION_DIM,
                distance=Distance.COSINE,
                multivector_config=MultiVectorConfig(
                    comparator=MultiVectorComparator.MAX_SIM,
                ),
                hnsw_config=HnswConfigDiff(m=0),  # reranking-only, no ANN index needed
            ),
        },
        sparse_vectors_config={
            "sparse": SparseVectorParams(modifier=Modifier.IDF),
        },
    )


# ---------------------------------------------------------------------------
# Ingestion
# ---------------------------------------------------------------------------

def build_points(chunk_texts: list[str], payloads: list[dict]) -> list[PointStruct]:
    dense_vecs = embed_dense(chunk_texts)
    sparse_vecs = embed_sparse(chunk_texts)
    late_vecs = embed_late_interaction(chunk_texts)

    points = []
    for text, payload, dense_vec, sparse_vec, late_vec in zip(
            chunk_texts, payloads, dense_vecs, sparse_vecs, late_vecs
    ):
        row_idx = payload["source_row_id"]
        points.append(
            PointStruct(
                id=str(uuid.uuid4()),
                vector={
                    "dense": dense_vec,
                    "sparse": sparse_vec,
                    "late_interaction": late_vec,
                },
                payload={
                    # Required by Agno's Qdrant readback (Document reconstruction):
                    "name": f"MedQuAD context {row_idx}",
                    "meta_data": {"source_row_id": row_idx},
                    "content": text,  # the actual context
                    "usage": None,
                    "content_id": str(row_idx),
                },
            )
        )
    return points


def ingest():
    create_collection()

    dataset = load_dataset(DATASET_ID, split="train")

    batch_texts: list[str] = []
    batch_payloads: list[dict] = []
    total_ingested = 0

    for row_idx, row in enumerate(dataset):
        context = row["context"]

        batch_texts.append(context)
        batch_payloads.append({"source_row_id": row_idx})

        if len(batch_texts) >= BATCH_SIZE:
            points = build_points(batch_texts, batch_payloads)
            qdrant_client.upsert(collection_name=COLLECTION_NAME, points=points)
            total_ingested += len(points)
            print(f"Ingested {total_ingested} contexts...")
            batch_texts, batch_payloads = [], []

    # flush remaining
    if batch_texts:
        points = build_points(batch_texts, batch_payloads)
        qdrant_client.upsert(collection_name=COLLECTION_NAME, points=points)
        total_ingested += len(points)

    print(f"Done. Total contexts ingested: {total_ingested}")


if __name__ == "__main__":
    ingest()

Die Hauptskript kombiniert die Agenten und das Team:

import os

from agno.agent import Agent
from agno.knowledge.knowledge import Knowledge
from agno.models.openai import OpenAIChat
from agno.knowledge.embedder.google import GeminiEmbedder
from agno.team import Team
from agno.team.mode import TeamMode
from agno.vectordb.qdrant import Qdrant
from agno.vectordb.search import SearchType
from dotenv import load_dotenv, find_dotenv

# ---------------------------------------------------------------------------
# Shared config
# ---------------------------------------------------------------------------
load_dotenv(find_dotenv())

MODEL_ID = "gpt-4o"
COLLECTION_NAME = os.getenv("QDRANT_COLLECTION", "medquad_hybrid")

# Must match the ingestion script's model/dimensions exactly, or the query
# vector lands in the wrong embedding space entirely.
embedder = GeminiEmbedder(
    id=os.getenv("GEMINI_EMBEDDING_MODEL", "gemini-embedding-2-preview"),
    dimensions=768,
    api_key=os.getenv("GEMINI_API_KEY"),
)

vector_db = Qdrant(
    collection=COLLECTION_NAME,
    url=os.getenv("QDRANT_URL", "http://localhost:6333"),
    api_key=os.getenv("QDRANT_API_KEY"),
    embedder=embedder,
    search_type=SearchType.hybrid,
)

knowledge_base = Knowledge(
    vector_db=vector_db,
)


# ---------------------------------------------------------------------------
# 1. Query Rewriting Agent
# ---------------------------------------------------------------------------

query_rewriter = Agent(
    name="Query Rewriting Agent",
    role="Given a user query, generate N semantically similar reformulations",
    model=OpenAIChat(id=MODEL_ID),
    instructions=[
        "Given the user's query, produce 3 to 5 semantically similar variants.",
        "Vary phrasing, specificity, and synonyms so each variant could surface "
        "different but relevant passages during retrieval.",
        "Return the variants as a clean numbered list, nothing else.",
    ],
    add_datetime_to_context=True,
)

# ---------------------------------------------------------------------------
# 2. Retrieval Agent (Qdrant-backed knowledge)
# ---------------------------------------------------------------------------

retrieval_agent = Agent(
    name="Retrieval Agent",
    role="Search the Qdrant knowledge base for passages relevant to a query",
    model=OpenAIChat(id=MODEL_ID),
    knowledge=knowledge_base,
    search_knowledge=True,
    instructions=[
        "For each incoming query variant, search the knowledge base.",
        "Return the retrieved passages verbatim along with their source and "
        "similarity score so the Critique Agent can evaluate them.",
        "If nothing relevant is found for a variant, say so explicitly instead "
        "of fabricating context.",
    ],
    add_datetime_to_context=True,
)

# ---------------------------------------------------------------------------
# 3. Critique Agent
# ---------------------------------------------------------------------------

critique_agent = Agent(
    name="Critique Agent",
    role="Critique and self-evaluate retrieved context for relevance and coverage",
    model=OpenAIChat(id=MODEL_ID),
    instructions=[
        "Evaluate the retrieved passages against the original user query.",
        "Score relevance and coverage on a 1-5 scale and explain briefly.",
        "If coverage is weak (score below 4) or passages are off-topic, "
        "explicitly request the Retrieval Agent to retry with a refined query, "
        "narrower or broader scope, or different query variant.",
        "If coverage is adequate, clearly state that the context is approved "
        "and ready to be handed to the Response Generation Agent.",
    ],
    add_datetime_to_context=True,
)

# ---------------------------------------------------------------------------
# Retrieval <-> Critique loop, as a nested tasks-mode sub-team
# ---------------------------------------------------------------------------

retrieval_critique_loop = Team(
    name="Retrieval-Critique Loop",
    role=(
        "Iteratively retrieve context for each query variant and critique it "
        "until the context is approved or the iteration budget is exhausted"
    ),
    mode=TeamMode.tasks,
    model=OpenAIChat(id=MODEL_ID),
    members=[retrieval_agent, critique_agent],
    max_iterations=4,
    instructions=[
        "Run retrieval for every query variant received.",
        "After each retrieval pass, send the results to the Critique Agent.",
        "If the Critique Agent requests a retry, refine the query and retrieve "
        "again.",
        "Stop as soon as the Critique Agent approves the context, or when the "
        "iteration budget is reached -- whichever comes first.",
        "Return the final approved (or best-effort) fused context.",
    ],
)

# ---------------------------------------------------------------------------
# 4. Response Generation Agent
# ---------------------------------------------------------------------------

response_agent = Agent(
    name="Response Generation Agent",
    role="Generate the final answer from the fused, approved context",
    model=OpenAIChat(id=MODEL_ID),
    instructions=[
        "You will receive the original user query and the final fused context "
        "approved by the Retrieval-Critique Loop.",
        "Answer strictly grounded in the provided context.",
        "If the context is insufficient, say so rather than guessing.",
        "Cite which passage(s) support each claim where possible.",
    ],
    add_datetime_to_context=True,
)

# ---------------------------------------------------------------------------
# Top-level coordinator
# ---------------------------------------------------------------------------

agent_coordinator = Team(
    name="Agent Coordinator",
    mode=TeamMode.coordinate,
    model=OpenAIChat(id=MODEL_ID),
    members=[query_rewriter, retrieval_critique_loop, response_agent],
    instructions=[
        "You coordinate an agentic RAG pipeline.",
        "Step 1: send the user's query to the Query Rewriting Agent to obtain "
        "N semantically similar query variants.",
        "Step 2: send all query variants to the Retrieval-Critique Loop and "
        "wait for the final fused, approved context.",
        "Step 3: send the original user query plus the fused context to the "
        "Response Generation Agent.",
        "Step 4: return the Response Generation Agent's output as the final "
        "answer -- do not rewrite or second-guess it.",
    ],
    add_datetime_to_context=True,
    show_members_responses=True,
)

# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------

if __name__ == "__main__":
    # One-time setup: point the knowledge base at your source documents.
    # Example (uncomment and edit):
    # knowledge_base.add_content(url="https://example.com/your-document.pdf")
    # Q1. "What is (are) Small Intestine Cancer? give document citations as reference.",
    # Q2. "Who is at risk for Langerhans Cell Histiocytosis?",
    # Q3. "What is (are) Langerhans Cell Histiocytosis?",
    agent_coordinator.print_response(
        "Who is at risk for Langerhans Cell Histiocytosis?",
        stream=True,
    )

Ein vollständiger Ablauf erzeugt eine lange Spur mit Dokumentabfragen sowie den Nachrichtenfeldern jedes Agents:

INFO Found 10 documents
INFO Found 10 documents
INFO Found 10 documents
┏━ Message ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                              ┃
┃ What is (are) Small Intestine Cancer?                                        ┃
┃                                                                              ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━ Query Rewriting Agent Response ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                              ┃
┃ 1. What is the disease known as Small Intestine Cancer?                      ┃
┃ 2. Can you describe Small Intestine Cancer?                                  ┃
┃ 3. How would you define cancer of the small intestine?                       ┃
┃ 4. What are the characteristics of Small Intestine Cancer?                   ┃
┃ 5. Could you explain what Small Intestine Cancer entails?                    ┃
┃                                                                              ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━ Query Rewriting Agent Response ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                              ┃
┃ 1. What types of cancers affect the small intestine?                         ┃
┃ 2. Can you list the different forms of cancer found in the small intestine?  ┃
┃ 3. How many kinds of small intestine cancers are there?                      ┃
┃ 4. What are the various cancers of the small intestine?                      ┃
┃ 5. Could you explain the different types of small intestine cancers?         ┃
┃                                                                              ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━ retrieval-agent Tool Calls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                              ┃
┃ • search_knowledge_base(query=What is Small Intestine Cancer?)               ┃
┃                                                                              ┃
┃ • search_knowledge_base(query=What are Small Intestine Cancers?)             ┃
┃                                                                              ┃
┃ • search_knowledge_base(query=Small Intestine Cancer definition symptoms     ┃
┃ treatment options prognosis)                                                 ┃
┃                                                                              ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━ retrieval-agent Response ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                              ┃
┃ Here are the retrieved passages related to Small Intestine Cancer:           ┃
┃                                                                              ┃
┃ 1. **Passage from MedQuAD context 0:**                                       ┃
┃    - The small intestine is part of the body’s digestive system, which also  ┃
┃ includes the esophagus, stomach, and large intestine. The digestive system   ┃
┃ removes and processes nutrients (vitamins, minerals, carbohydrates, fats,    ┃
┃ proteins, and water) from foods and helps pass waste material out of the     ┃
┃ body. The small intestine is a long tube that connects the stomach to the    ┃
┃ large intestine. It folds many times to fit inside the abdomen. EnlargeThe   ┃
┃ small intestine connects the stomach and the colon. It includes the          ┃
┃ duodenum, jejunum, and ileum. The types of cancer found in the small         ┃
┃ intestine are adenocarcinoma, sarcoma, carcinoid tumors, gastrointestinal    ┃
┃ stromal tumor, and lymphoma. This summary discusses adenocarcinoma and       ┃
┃ leiomyosarcoma (a type of sarcoma). Adenocarcinoma starts in glandular cells ┃
┃ in the lining of the small intestine and is the most common type of small    ┃
┃ intestine cancer. Most of these tumors occur in the part of the small        ┃
┃ intestine near the stomach. They may grow and block the intestine.           ┃
┃ Leiomyosarcoma starts in the smooth muscle cells of the small intestine.     ┃
┃ Most of these tumors occur in the part of the small intestine near the large ┃
┃ intestine. For more information on small intestine cancer, see the           ┃
┃ following: Anything that increases your risk of getting a disease is called  ┃
┃ a risk factor. Having a risk factor does not mean that you will get cancer;  ┃
┃ not having risk factors doesn't mean that you will not get cancer. Talk with ┃
┃ your doctor if you think you may be at risk. [Source: PMID: 26389461]        ┃
┃                                                                              ┃
┃ 2. **Passage from MedQuAD context 121:**                                     ┃
┃    - You had surgery to remove all or part of your small intestine (small    ┃
┃ bowel). You may also have had an ileostomy. During and after surgery, you    ┃
┃ received intravenous (IV) fluids. You also may have had a tube placed        ┃
┃ through your nose and into your stomach. You may have received antibiotics.  ┃
┃ You may have these problems after you return home from the hospital: Follow  ┃
┃ your health care provider's instructions... [Source: Elmously A, Yeo HL.     ┃
┃ Management of small bowel obstruction.]                                      ┃
┃                                                                              ┃
┃ 3. **Passage from MedQuAD context 209:**                                     ┃
┃    - Radiation enteritis is damage to the lining of the intestines (bowels)  ┃
┃ caused by radiation therapy, which is used for some types of cancer          ┃
┃ treatment... When symptoms become long-term (chronic), other problems may    ┃
┃ include: The health care provider will do a physical exam and ask about your ┃
┃ medical history. Tests may include... [Source: Kuemmerle JF. Inflammatory    ┃
┃ and anatomic diseases of the intestine, peritoneum, mesentery, and omentum.] ┃
┃                                                                              ┃
┃ These passages were retrieved for both queries, "What is Small Intestine     ┃
┃ Cancer?" and "What are Small Intestine Cancers?" They cover an overview,     ┃
┃ treatment, and some related conditions and procedures.                       ┃
┃                                                                              ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━ critique-agent Response ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                              ┃
┃ **Relevance Score: 4/5**                                                     ┃
┃                                                                              ┃
┃ The passages include relevant information about Small Intestine Cancer,      ┃
┃ especially the types of cancers that can occur in the small intestine, such  ┃
┃ as adenocarcinoma and leiomyosarcoma, which directly addresses the query on  ┃
┃ what Small Intestine Cancer is. The passage provides important details about ┃
┃ where these cancers are likely to occur within the small intestine and some  ┃
┃ general information about risk factors.                                      ┃
┃                                                                              ┃
┃ **Coverage Score: 3/5**                                                      ┃
┃                                                                              ┃
┃ While the passages offer a brief overview and touch on significant points    ┃
┃ like types of cancers and risk factors, they do not thoroughly define Small  ┃
┃ Intestine Cancer or discuss characteristics, treatment options, symptoms,    ┃
┃ diagnosis, or prognosis, which would provide a more comprehensive            ┃
┃ understanding. The second and third passages primarily discuss specific      ┃
┃ surgical procedures and conditions related to cancer treatment rather than   ┃
┃ providing detailed insights into Small Intestinal Cancer itself.             ┃
┃                                                                              ┃
┃ **Recommendation:**                                                          ┃
┃                                                                              ┃
┃ The coverage is insufficient for delivering a complete response to the query ┃
┃ about Small Intestine Cancer. It's advisable to request the Retrieval Agent  ┃
┃ conduct a more focused search that includes information on defining Small    ┃
┃ Intestine Cancer, its symptoms, treatment options, and prognosis. This will  ┃
┃ ensure a more comprehensive answer can be given to the user.                 ┃
┃                                                                              ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━ retrieval-agent Tool Calls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                              ┃
┃ • search_knowledge_base(query=What is Small Intestine Cancer?)               ┃
┃                                                                              ┃
┃ • search_knowledge_base(query=What are Small Intestine Cancers?)             ┃
┃                                                                              ┃
┃ • search_knowledge_base(query=Small Intestine Cancer definition symptoms     ┃
┃ treatment options prognosis)                                                 ┃
┃                                                                              ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━ retrieval-agent Response ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                              ┃
┃ Here are the retrieved passages related to Small Intestine Cancer, including ┃
┃ its definition, symptoms, treatment options, and prognosis:                  ┃
┃                                                                              ┃
┃ 1. **Passage from MedQuAD context 0:**                                       ┃
┃    - The small intestine is part of the body’s digestive system, which also  ┃
┃ includes the esophagus, stomach, and large intestine. The digestive system   ┃
┃ removes and processes nutrients (vitamins, minerals, carbohydrates, fats,    ┃
┃ proteins, and water) from foods and helps pass waste material out of the     ┃
┃ body. The small intestine is a long tube that connects the stomach to the    ┃
┃ large intestine. It folds many times to fit inside the abdomen. EnlargeThe   ┃
┃ small intestine connects the stomach and the colon. It includes the          ┃
┃ duodenum, jejunum, and ileum. The types of cancer found in the small         ┃
┃ intestine are adenocarcinoma, sarcoma, carcinoid tumors, gastrointestinal    ┃
┃ stromal tumor, and lymphoma. Adenocarcinoma starts in glandular cells in the ┃
┃ lining of the small intestine and is the most common type of small intestine ┃
┃ cancer. Most of these tumors occur in the part of the small intestine near   ┃
┃ the stomach. They may grow and block the intestine. Leiomyosarcoma starts in ┃
┃ the smooth muscle cells of the small intestine. Most of these tumors occur   ┃
┃ in the part of the small intestine near the large intestine. Risk factors    ┃
┃ for small intestine cancer include various factors, but having a risk factor ┃
┃ does not mean definite development of cancer. Tests and procedures to        ┃
┃ detect, diagnose, and stage small intestine cancer are usually done at the   ┃
┃ same time. The prognosis and treatment options depend on the type of small   ┃
┃ intestine cancer and whether the tumor can be removed by surgery. Treatment  ┃
┃ depends on whether the cancer is being treated as a primary tumor or is      ┃
┃ metastatic cancer. Different types of treatments are available, including    ┃
┃ surgery, chemotherapy, radiation therapy, and participation in clinical      ┃
┃ trials. Many of today's standard treatments are based on earlier clinical    ┃
┃ trials, and patients who participate in clinical trials also help improve    ┃
┃ future treatments. [PMID: 26389461]                                          ┃
┃                                                                              ┃
┃ This passage is comprehensive in providing definitions, symptoms, risk       ┃
┃ factors, staging, treatment options, and prognosis regarding Small Intestine ┃
┃ Cancer. It describes different cancers that may affect the small intestine   ┃
┃ and the general treatment approach including surgery, chemotherapy, and      ┃
┃ clinical trials, offering a holistic understanding of Small Intestine        ┃
┃ Cancer.                                                                      ┃
┃                                                                              ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━ Response Generation Agent Response ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                              ┃
┃ Small Intestine Cancer is a type of cancer that occurs in the small          ┃
┃ intestine, which is part of the body’s digestive system connecting the       ┃
┃ stomach to the large intestine. The small intestine extracts and processes   ┃
┃ nutrients from foods and assists in passing waste material out of the body.  ┃
┃ It includes sections called the duodenum, jejunum, and ileum.                ┃
┃                                                                              ┃
┃ The types of cancer that can develop in the small intestine include          ┃
┃ adenocarcinoma, sarcoma (such as leiomyosarcoma), carcinoid tumors,          ┃
┃ gastrointestinal stromal tumors, and lymphoma. Adenocarcinoma, which starts  ┃
┃ in the glandular cells lining the small intestine, is the most common type.  ┃
┃ These tumors typically form in the part of the small intestine near the      ┃
┃ stomach and may grow to block the intestine. Leiomyosarcoma originates in    ┃
┃ the smooth muscle cells of the small intestine.                              ┃
┃                                                                              ┃
┃ Several factors may increase the risk of developing small intestine cancer,  ┃
┃ though having a risk factor does not guarantee that cancer will develop.     ┃
┃ Detection, diagnosis, and staging of small intestine cancer usually occur    ┃
┃ simultaneously through various tests and procedures.                         ┃
┃                                                                              ┃
┃ The prognosis and treatment for small intestine cancer depend on the cancer  ┃
┃ type and whether the tumor can be removed surgically. Treatment options      ┃
┃ include surgery, chemotherapy, radiation therapy, and participation in       ┃
┃ clinical trials. These trials are essential as many of today's standard      ┃
┃ treatments are based on earlier clinical trial results. Patients who         ┃
┃ participate in clinical trials contribute to the potential improvement of    ┃
┃ future cancer treatments.                                                    ┃
┃                                                                              ┃
┃ This comprehensive understanding of Small Intestine Cancer covers its        ┃
┃ definition, types, risk factors, diagnosis methods, and treatment practices, ┃
┃ providing an insightful perspective on managing this disease [Source: PMID:  ┃
┃ 26389461].                                                                   ┃
┃                                                                              ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━ Team Tool Calls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                              ┃
┃ • delegate_task_to_member(member_id=query-rewriting-agent, task=Generate     ┃
┃ five semantically similar                                                    ┃
┃   reformulations of the query: 'What is Small Intestine Cancer?')            ┃
┃                                                                              ┃
┃ • delegate_task_to_member(member_id=query-rewriting-agent, task=Generate     ┃
┃ five semantically similar                                                    ┃
┃   reformulations of the query: 'What are Small Intestine Cancers?')          ┃
┃                                                                              ┃
┃ • delegate_task_to_member(member_id=retrieval-agent, task=Retrieve           ┃
┃ information on Small Intestine Cancer from                                   ┃
┃   the knowledge base.)                                                       ┃
┃                                                                              ┃
┃ • delegate_task_to_member(member_id=critique-agent, task=Review the          ┃
┃ retrieved passages related to Small                                          ┃
┃   Intestine Cancer from MedQuAD context and evaluate for relevance and       ┃
┃ coverage. Confirm if additional                                              ┃
┃   retrieval is needed to comprehensively answer the user's query.)           ┃
┃                                                                              ┃
┃ • delegate_task_to_member(member_id=retrieval-agent, task=Conduct a more     ┃
┃ focused search in the knowledge base                                         ┃
┃   to obtain detailed information on Small Intestine Cancer, including its    ┃
┃ definition, symptoms, treatment                                              ┃
┃   options, and prognosis.)                                                   ┃
┃                                                                              ┃
┃ • delegate_task_to_member(member_id=response-generation-agent, task=Using    ┃
┃ the retrieved passage on Small                                               ┃
┃   Intestine Cancer from MedQuAD context 0, generate a comprehensive response ┃
┃ that defines Small Intestine                                                 ┃
┃   Cancer, its types, symptoms, treatment options, and prognosis. The         ┃
┃ response should cover what small                                             ┃
┃   intestine cancer is, associated risk factors, diagnosis, and available     ┃
┃ treatment practices.)                                                        ┃
┃                                                                              ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━ Response (50.2s) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                              ┃
┃ Small Intestine Cancer is a type of cancer occurring in the small intestine, ┃
┃ part of the digestive system that connects the stomach to the large          ┃
┃ intestine. It plays a key role in extracting nutrients from food and passing ┃
┃ waste material. The small intestine encompasses the duodenum, jejunum, and   ┃
┃ ileum.                                                                       ┃
┃                                                                              ┃
┃ Types of Small Intestine Cancer include adenocarcinoma, sarcoma (such as     ┃
┃ leiomyosarcoma), carcinoid tumors, gastrointestinal stromal tumors, and      ┃
┃ lymphoma. Adenocarcinoma starts in glandular cells lining the small          ┃
┃ intestine and is the most common type. It typically occurs near the stomach  ┃
┃ and can grow to block the intestine. Leiomyosarcoma originates in the smooth ┃
┃ muscle cells, often near the large intestine.                                ┃
┃                                                                              ┃
┃ Risk factors vary, but a risk factor does not guarantee cancer development.  ┃
┃ Diagnosis and staging usually involve simultaneous testing, and the          ┃
┃ prognosis and treatment options depend on the cancer type and tumor          ┃
┃ resectability. Treatments include surgery, chemotherapy, radiation, and      ┃
┃ clinical trials, which offer newer treatment avenues.                        ┃
┃                                                                              ┃
┃ This overview provides a detailed look at Small Intestine Cancer, including  ┃
┃ types, risks, diagnosis, and treatments based on clinical advancements       ┃
┃ [Source: PMID: 26389461].                                                    ┃
┃                                                                              ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Was dieses Design bietet

Das Ergebnis ist ein RAG-Pipeline-System, das sich selbst herausfordert, bevor es etwas ausspricht: Die Datenerfassung, Kritik und Erstellung erfolgen als getrennte Schritte, die jeweils überprüft werden können, anstatt durch einen einzigen unklaren Aufruf. Um dorthin zu gelangen, mussten Agno Teams verschachtelt werden, um iterative Verbesserungen vorzunehmen, eine echte hybride Suche aus dichten, spärlichen sowie spät interagierenden Vektoren in Qdrant erstellt werden, sowie kleine Details wie Payload-Schlüssel, Vektornamen und die Art und Weise, wie Kontext zwischen Agenten geteilt wird, sorgfältig abgestimmt werden. Rechnen Sie damit, dass die ersten Versuche fehlschlagen, da gerade diese kleinen Details den größten Teil der Debugging-Zeit in Anspruch nehmen.

Verwandte Artikel

  • Viele Hände, ein Stift: Sieben Regeln zur Steuerung von KI-Agenten — Warum Orchesterer nicht Tools in der Hand halten sollten, wenn ein Workflow einem Agenten überlegen ist, wie man die Rückgaben von Subagenten eingibt und Beendigungsbedingungen aufschreibt, mit Python-Beispielen zu jedem Punkt.