137 lines
4.4 KiB
Python
137 lines
4.4 KiB
Python
"""System prompts for RAG-based codebase Q&A."""
|
|
|
|
from app.embeddings.retriever import RetrievedChunk
|
|
from app.memory.conversation import Message
|
|
|
|
# For codebase questions WITH retrieved context
|
|
CODEBASE_SYSTEM_PROMPT = """You answer questions about the Tyndale trading system using ONLY the provided YAML artifacts.
|
|
|
|
HARD CONSTRAINTS:
|
|
- Do NOT assume access to source code
|
|
- Do NOT invent implementation details not in the artifacts
|
|
- Do NOT speculate about code mechanics beyond what artifacts describe
|
|
- If artifacts do not contain enough information, say so explicitly
|
|
|
|
RESPONSE STYLE:
|
|
- Prefer architectural and behavioral explanations over mechanics
|
|
- Reference source files by path (e.g., ./trader.py)
|
|
- Explain trading concepts for developers without finance background
|
|
- Keep responses focused and concise"""
|
|
|
|
# For general questions (no RAG context)
|
|
GENERAL_SYSTEM_PROMPT = """You are an assistant for the Tyndale trading system documentation.
|
|
You can answer general questions, but for specific codebase questions, you need artifact context.
|
|
If the user asks about specific code without context, ask them to rephrase or be more specific."""
|
|
|
|
# For clarification/follow-ups (uses conversation history)
|
|
CLARIFICATION_SYSTEM_PROMPT = """You are continuing a conversation about the Tyndale trading system.
|
|
Use the conversation history to answer follow-up questions.
|
|
If you need to look up new information, ask the user to rephrase as a standalone question."""
|
|
|
|
|
|
def select_system_prompt(intent: str, has_context: bool) -> str:
|
|
"""Select appropriate system prompt based on intent and context.
|
|
|
|
Args:
|
|
intent: Classified intent (codebase, general, clarification)
|
|
has_context: Whether RAG context was retrieved
|
|
|
|
Returns:
|
|
System prompt string
|
|
"""
|
|
if intent == "codebase" and has_context:
|
|
return CODEBASE_SYSTEM_PROMPT
|
|
elif intent == "codebase" and not has_context:
|
|
return CODEBASE_SYSTEM_PROMPT + "\n\nNOTE: No relevant artifacts were found for this question. Acknowledge this limitation in your response."
|
|
elif intent == "clarification":
|
|
return CLARIFICATION_SYSTEM_PROMPT
|
|
else:
|
|
return GENERAL_SYSTEM_PROMPT
|
|
|
|
|
|
def format_context(chunks: list[RetrievedChunk]) -> str:
|
|
"""Format retrieved chunks as context for the LLM.
|
|
|
|
Args:
|
|
chunks: List of retrieved chunks
|
|
|
|
Returns:
|
|
Formatted context string
|
|
"""
|
|
if not chunks:
|
|
return ""
|
|
|
|
context_parts = ["## Retrieved Artifact Context\n"]
|
|
|
|
for i, chunk in enumerate(chunks, 1):
|
|
context_parts.append(f"### Source {i}: {chunk.source_file} ({chunk.chunk_type})")
|
|
context_parts.append(chunk.content)
|
|
context_parts.append("") # Empty line separator
|
|
|
|
return "\n".join(context_parts)
|
|
|
|
|
|
def format_history(history: list[Message], max_messages: int = 10) -> str:
|
|
"""Format conversation history for the LLM.
|
|
|
|
Args:
|
|
history: List of conversation messages
|
|
max_messages: Maximum messages to include
|
|
|
|
Returns:
|
|
Formatted history string
|
|
"""
|
|
if not history:
|
|
return ""
|
|
|
|
# Take most recent messages
|
|
recent = history[-max_messages:] if len(history) > max_messages else history
|
|
|
|
history_parts = ["## Conversation History\n"]
|
|
|
|
for msg in recent:
|
|
role = "User" if msg.role == "user" else "Assistant"
|
|
history_parts.append(f"**{role}**: {msg.content}")
|
|
history_parts.append("")
|
|
|
|
return "\n".join(history_parts)
|
|
|
|
|
|
def build_rag_prompt(
|
|
user_message: str,
|
|
intent: str,
|
|
chunks: list[RetrievedChunk],
|
|
history: list[Message],
|
|
) -> tuple[str, str]:
|
|
"""Build complete RAG prompt with system message and user content.
|
|
|
|
Args:
|
|
user_message: Current user message
|
|
intent: Classified intent
|
|
chunks: Retrieved context chunks
|
|
history: Conversation history
|
|
|
|
Returns:
|
|
Tuple of (system_prompt, user_content)
|
|
"""
|
|
# Select system prompt
|
|
system_prompt = select_system_prompt(intent, bool(chunks))
|
|
|
|
# Build user content
|
|
parts = []
|
|
|
|
# Add context if available
|
|
if chunks:
|
|
parts.append(format_context(chunks))
|
|
|
|
# Add history for clarification intent
|
|
if intent == "clarification" and history:
|
|
parts.append(format_history(history))
|
|
|
|
# Add current question
|
|
parts.append(f"## Current Question\n{user_message}")
|
|
|
|
user_content = "\n\n".join(parts)
|
|
|
|
return system_prompt, user_content
|