c889a57b6b
Test Suites / Build CI Environment (push) Has been cancelled
Test Suites / Basic Tests (push) Has been cancelled
Test Suites / End-to-End Tests (push) Has been cancelled
Test Suites / CLI Tests (push) Has been cancelled
Test Suites / Slow End-to-End Tests (push) Has been cancelled
Test Suites / Graph Database Tests (push) Has been cancelled
Test Suites / Vector DB Tests (push) Has been cancelled
Test Suites / Temporal Graph Test (push) Has been cancelled
Test Suites / Search Test on Different DBs (push) Has been cancelled
Test Suites / Example Tests (push) Has been cancelled
Test Suites / Notebook Tests (push) Has been cancelled
Test Suites / OS and Python Tests Ubuntu (push) Has been cancelled
Test Suites / OS and Python Tests Extended (push) Has been cancelled
Test Suites / LLM Test Suite (push) Has been cancelled
Test Suites / S3 File Storage Test (push) Has been cancelled
Test Suites / Run Integration Tests (push) Has been cancelled
Test Suites / MCP Tests (push) Has been cancelled
Test Suites / Docker Compose Test (push) Has been cancelled
Test Suites / Docker CI test (push) Has been cancelled
Test Suites / Relational DB Migration Tests (push) Has been cancelled
Test Suites / Distributed Cognee Test (push) Has been cancelled
Test Suites / DB Examples Tests (push) Has been cancelled
Test Suites / Test Completion Status (push) Has been cancelled
Test Suites / Claude Code Review (push) Has been cancelled
Test Suites / basic checks (push) Has been cancelled
build | Build and Push Cognee MCP Docker Image to dockerhub / docker-build-and-push (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
build | Build and Push Docker Image to dockerhub / docker-build-and-push (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Core Functionality (3.11) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Core Functionality (3.12) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges with Different Graph Databases (kuzu, kuzu) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges with Different Graph Databases (neo4j, neo4j) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Examples (push) Has been cancelled
Weighted Edges Tests / Code Quality for Weighted Edges (push) Has been cancelled
190 lines
7.8 KiB
Python
190 lines
7.8 KiB
Python
"""BEAM question-type router — routes probing questions to appropriate retrievers.
|
|
|
|
Each BEAM question type maps to a retriever + system prompt strategy.
|
|
The router classifies the question (using pre-labeled types from the dataset)
|
|
and delegates to the matching retrieval strategy.
|
|
"""
|
|
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
from cognee.modules.retrieval.base_retriever import BaseRetriever
|
|
from cognee.modules.retrieval.graph_completion_retriever import GraphCompletionRetriever
|
|
from cognee.modules.retrieval.graph_completion_cot_retriever import GraphCompletionCotRetriever
|
|
from cognee.modules.retrieval.graph_summary_completion_retriever import (
|
|
GraphSummaryCompletionRetriever,
|
|
)
|
|
from cognee.shared.logging_utils import get_logger
|
|
|
|
logger = get_logger()
|
|
|
|
|
|
# Prompt templates per question type — instruct the LLM on HOW to answer
|
|
_TYPE_PROMPTS: Dict[str, str] = {
|
|
"information_extraction": (
|
|
"You are answering a factual question about a conversation. "
|
|
"Extract the specific information requested. Be precise and concise. "
|
|
"If the information is not in the context, say so."
|
|
),
|
|
"temporal_reasoning": (
|
|
"You are answering a question that requires reasoning about time. "
|
|
"Pay attention to dates, time references, and the order of events. "
|
|
"Reference specific dates or time periods in your answer."
|
|
),
|
|
"multi_session_reasoning": (
|
|
"You are answering a question that requires combining information "
|
|
"from multiple conversation sessions. Think step by step: first identify "
|
|
"the relevant pieces of information from different sessions, then "
|
|
"synthesize them into a coherent answer."
|
|
),
|
|
"contradiction_resolution": (
|
|
"You are answering a question about contradictory information in a conversation. "
|
|
"Identify both the original statement and the contradicting one. "
|
|
"Explain which is more recent or authoritative, and resolve the contradiction."
|
|
),
|
|
"event_ordering": (
|
|
"You are answering a question about the order of events in a conversation. "
|
|
"List events in chronological order. Reference specific sessions or "
|
|
"time anchors when available."
|
|
),
|
|
"knowledge_update": (
|
|
"You are answering a question about updated information. "
|
|
"The conversation may contain both old and new versions of a fact. "
|
|
"Always use the most recent information unless specifically asked about history."
|
|
),
|
|
"summarization": (
|
|
"You are summarizing part of a conversation. "
|
|
"Cover all key points mentioned in the relevant sessions. "
|
|
"Be comprehensive but concise. Use bullet points if appropriate."
|
|
),
|
|
"abstention": (
|
|
"You are answering a question where the correct response may be to abstain. "
|
|
"If the conversation does not contain enough evidence to answer confidently, "
|
|
"say that the information is not available rather than guessing."
|
|
),
|
|
"preference_following": (
|
|
"You are answering a question about user preferences expressed in the conversation. "
|
|
"Pay attention to explicitly stated preferences, changes in preference over time, "
|
|
"and implicit preferences inferred from the user's behavior."
|
|
),
|
|
"instruction_following": (
|
|
"You are answering a question about instructions given during the conversation. "
|
|
"Check whether specific instructions were followed consistently. "
|
|
"Reference the original instruction and evidence of compliance or non-compliance."
|
|
),
|
|
}
|
|
|
|
# Map question types to retriever classes
|
|
_TYPE_RETRIEVERS: Dict[str, type] = {
|
|
"information_extraction": GraphCompletionRetriever,
|
|
"temporal_reasoning": GraphCompletionRetriever,
|
|
"event_ordering": GraphCompletionRetriever,
|
|
"knowledge_update": GraphCompletionRetriever,
|
|
"abstention": GraphCompletionRetriever,
|
|
"preference_following": GraphCompletionRetriever,
|
|
"instruction_following": GraphCompletionRetriever,
|
|
# These require multi-step reasoning
|
|
"multi_session_reasoning": GraphCompletionCotRetriever,
|
|
"contradiction_resolution": GraphCompletionCotRetriever,
|
|
# Summarization benefits from pre-computed summaries
|
|
"summarization": GraphSummaryCompletionRetriever,
|
|
}
|
|
|
|
_DEFAULT_PROMPT = (
|
|
"You are answering a question about a conversation. "
|
|
"Use the provided context to give an accurate answer."
|
|
)
|
|
|
|
|
|
class BEAMRouter:
|
|
"""Routes BEAM probing questions to the appropriate retriever and prompt.
|
|
|
|
Usage::
|
|
|
|
router = BEAMRouter()
|
|
answers = await router.answer_questions(questions)
|
|
"""
|
|
|
|
def __init__(self, fallback_retriever: Optional[type] = None):
|
|
self._fallback_retriever = fallback_retriever or GraphCompletionRetriever
|
|
self._retriever_cache: Dict[str, BaseRetriever] = {}
|
|
|
|
def _get_retriever(self, question_type: str) -> BaseRetriever:
|
|
"""Get or create a retriever instance for the given question type."""
|
|
retriever_cls = _TYPE_RETRIEVERS.get(question_type, self._fallback_retriever)
|
|
cls_name = retriever_cls.__name__
|
|
|
|
if cls_name not in self._retriever_cache:
|
|
self._retriever_cache[cls_name] = retriever_cls()
|
|
|
|
return self._retriever_cache[cls_name]
|
|
|
|
@staticmethod
|
|
def get_system_prompt(question_type: str) -> str:
|
|
"""Get the system prompt for a question type."""
|
|
return _TYPE_PROMPTS.get(question_type, _DEFAULT_PROMPT)
|
|
|
|
async def answer_questions(self, questions: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
"""Answer a list of BEAM probing questions using type-based routing.
|
|
|
|
Args:
|
|
questions: List of dicts with "question", "answer" (golden),
|
|
"question_type", and optionally "rubric".
|
|
|
|
Returns:
|
|
List of answer dicts compatible with the eval framework.
|
|
"""
|
|
answers = []
|
|
|
|
for instance in questions:
|
|
query_text = instance["question"]
|
|
question_type = instance.get("question_type", "information_extraction")
|
|
golden_answer = instance["answer"]
|
|
|
|
retriever = self._get_retriever(question_type)
|
|
system_prompt = self.get_system_prompt(question_type)
|
|
|
|
try:
|
|
retrieved_objects = await retriever.get_retrieved_objects(query=query_text)
|
|
retrieval_context = await retriever.get_context_from_objects(
|
|
query=query_text, retrieved_objects=retrieved_objects
|
|
)
|
|
search_results = await retriever.get_completion_from_context(
|
|
query=query_text,
|
|
retrieved_objects=retrieved_objects,
|
|
context=retrieval_context,
|
|
system_prompt=system_prompt,
|
|
)
|
|
|
|
if isinstance(search_results, str):
|
|
search_results = [search_results]
|
|
|
|
answer_text = search_results[0] if search_results else ""
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to answer '{query_text[:80]}...': {e}")
|
|
answer_text = f"ERROR: {e}"
|
|
retrieval_context = ""
|
|
|
|
answer = {
|
|
"question": query_text,
|
|
"answer": answer_text,
|
|
"golden_answer": golden_answer,
|
|
"retrieval_context": retrieval_context,
|
|
"question_type": question_type,
|
|
}
|
|
|
|
if "rubric" in instance:
|
|
answer["rubric"] = instance["rubric"]
|
|
if "golden_context" in instance:
|
|
answer["golden_context"] = instance["golden_context"]
|
|
if "difficulty" in instance:
|
|
answer["difficulty"] = instance["difficulty"]
|
|
|
|
answers.append(answer)
|
|
logger.info(
|
|
f"[{question_type}] Answered: '{query_text[:60]}...' "
|
|
f"(retriever: {type(retriever).__name__})"
|
|
)
|
|
|
|
return answers
|