diff --git a/RAGManager/app/agents/nodes/context_builder.py b/RAGManager/app/agents/nodes/context_builder.py index 79f2195..b550659 100644 --- a/RAGManager/app/agents/nodes/context_builder.py +++ b/RAGManager/app/agents/nodes/context_builder.py @@ -1,10 +1,19 @@ """Nodo 6: Context Builder - Enriches query with retrieved context.""" +import logging + from app.agents.state import AgentState -from langchain_core.messages import SystemMessage +from app.core.config import settings +from langchain_core.messages import HumanMessage, SystemMessage from langchain_openai import ChatOpenAI -llm = ChatOpenAI(model="gpt-5-nano") +logger = logging.getLogger(__name__) + +# Initialize Primary LLM with configuration from settings +llm = ChatOpenAI( + model="gpt-4.1-mini", # Primary LLM model for context-aware responses + openai_api_key=settings.openai_api_key, +) def context_builder(state: AgentState) -> AgentState: @@ -23,30 +32,82 @@ def context_builder(state: AgentState) -> AgentState: Returns: Updated state with enriched_query and primary_response set """ - # TODO: Implement context building and primary LLM call - # This should: - # 1. Combine paraphrased_text with relevant_chunks into enriched_query - # 2. Format the query appropriately (e.g., with system prompts, context sections) - # 3. Call Primary LLM with the enriched query - # 4. Store the LLM response in primary_response - - # Placeholder: For now, we'll create a simple enriched query updated_state = state.copy() + + # Get paraphrased text and relevant chunks from state paraphrased = state.get("paraphrased_text", "") chunks = state.get("relevant_chunks", []) - + + # Fallback if paraphrased_text is not available + if not paraphrased: + logger.warning("No paraphrased text found in state. Using original prompt.") + messages = state.get("messages", []) + if messages: + paraphrased = messages[-1].content if hasattr(messages[-1], "content") else str(messages[-1]) + else: + paraphrased = state.get("prompt", "") + # Build enriched query with context - context_section = "\n\n".join(chunks) if chunks else "No relevant context found." + if chunks: + context_section = "\n\n---\n\n".join([f"Context {i+1}:\n{chunk}" for i, chunk in enumerate(chunks)]) + else: + context_section = "No relevant context found in the knowledge base." + logger.warning("No relevant chunks found for context building") - system_content = f"""You are a helpful assistant. Use the following context to answer the user's question. -If the answer is not in the context, say you don't know. + # Create enriched query combining paraphrased text and context + enriched_query = f"""User Question: {paraphrased} -Context: -{context_section}""" +Relevant Context from Knowledge Base: +{context_section} - messages = [SystemMessage(content=system_content)] + state["messages"] +Please provide a comprehensive answer based on the context provided above. If the context does not contain enough information to answer the question, please indicate that clearly.""" + + # System prompt for the Primary LLM + system_content = """You are a helpful assistant specialized in providing accurate, context-based answers about nutrition and culinary topics. - # Call Primary LLM - response = llm.invoke(messages) +Your task is to: +1. Use the provided context to answer the user's question accurately +2. If the context contains relevant information, provide a comprehensive answer +3. If the context does not contain enough information, clearly state that you don't have sufficient information in the knowledge base +4. Always base your answer on the provided context - do not make up information +5. If the question is not related to the context, politely redirect the conversation - return {"messages": [response]} +Be concise, accurate, and helpful.""" + + # Prepare messages for LLM + messages_for_llm = [ + SystemMessage(content=system_content), + HumanMessage(content=enriched_query) + ] + + try: + # Call Primary LLM + logger.info("Calling Primary LLM with enriched query") + response = llm.invoke(messages_for_llm) + + # Extract response content + primary_response = response.content if hasattr(response, "content") else str(response) + + # Update state with enriched query and primary response (as defined in state.py) + updated_state["enriched_query"] = enriched_query + updated_state["primary_response"] = primary_response + + # Also set generated_response for guard_final (Nodo 7: Generator not yet implemented) + # For now, generated_response = primary_response + # This allows guard_final to validate the response + updated_state["generated_response"] = primary_response + + # Also update messages for LangGraph compatibility + updated_state["messages"] = state.get("messages", []) + [response] + + logger.info("Successfully generated primary response from LLM") + + except Exception as e: + logger.error(f"Error calling Primary LLM: {e}", exc_info=True) + # Set error state + updated_state["error_message"] = f"Error in context builder: {str(e)}" + updated_state["enriched_query"] = enriched_query + updated_state["primary_response"] = None + updated_state["generated_response"] = None + + return updated_state