Optimize context prompts

This commit is contained in:
Yiorgis Gozadinos 2026-01-16 11:39:57 +02:00
parent dff489f75f
commit d82e1f95c1
No known key found for this signature in database
3 changed files with 73 additions and 56 deletions

View file

@ -30,49 +30,51 @@ from haiku.rag.utils import build_prompt, get_model
def format_context_for_prompt(context: ResearchContext) -> str: def format_context_for_prompt(context: ResearchContext) -> str:
"""Format the research context as XML for inclusion in prompts.""" """Format the research context as XML for planning prompts."""
context_data: dict[str, object] = { context_data: dict[str, object] = {}
"original_question": context.original_question,
"unanswered_questions": context.sub_questions, if context.initial_context:
"qa_responses": [ context_data["background"] = context.initial_context
context_data["question"] = context.original_question
if context.sub_questions:
context_data["pending_questions"] = context.sub_questions
if context.qa_responses:
context_data["prior_answers"] = [
{ {
"question": qa.query, "question": qa.query,
"answer": qa.answer, "answer": qa.answer,
"confidence": qa.confidence, "confidence": qa.confidence,
"sources": [ "source": qa.citations[0].document_title or qa.citations[0].document_uri
{ if qa.citations
"document_uri": c.document_uri, else None,
"document_title": c.document_title,
"page_numbers": c.page_numbers,
"headings": c.headings,
}
for c in qa.citations
],
} }
for qa in context.qa_responses for qa in context.qa_responses
], ]
}
if context.initial_context: return format_as_xml(context_data, root_tag="context")
context_data["initial_context"] = context.initial_context
return format_as_xml(context_data, root_tag="research_context")
def format_conversational_context_for_prompt(context: ResearchContext) -> str: def format_conversational_context_for_prompt(context: ResearchContext) -> str:
"""Format context for conversational mode - excludes unanswered_questions.""" """Format context for synthesis prompts."""
context_data: dict[str, object] = { context_data: dict[str, object] = {}
"question": context.original_question,
}
if context.initial_context: if context.initial_context:
context_data["initial_context"] = context.initial_context context_data["background"] = context.initial_context
context_data["question"] = context.original_question
# Only include conversation_history if there are qa_responses
if context.qa_responses: if context.qa_responses:
context_data["conversation_history"] = [ context_data["prior_answers"] = [
{ {
"question": qa.query, "question": qa.query,
"answer": qa.answer, "answer": qa.answer,
"sources": [c.document_title or c.document_uri for c in qa.citations], "confidence": qa.confidence,
"source": qa.citations[0].document_title or qa.citations[0].document_uri
if qa.citations
else None,
} }
for qa in context.qa_responses for qa in context.qa_responses
] ]
@ -95,9 +97,12 @@ async def _plan_step_logic(
model_config = config.research.model model_config = config.research.model
# Use context-aware prompt if we have existing qa_responses # Use context-aware prompt if we have existing qa_responses
has_context = bool(state.context.qa_responses) has_prior_answers = bool(state.context.qa_responses)
has_background = bool(state.context.initial_context)
effective_plan_prompt = ( effective_plan_prompt = (
build_prompt(PLAN_PROMPT_WITH_CONTEXT, config) if has_context else plan_prompt build_prompt(PLAN_PROMPT_WITH_CONTEXT, config)
if has_prior_answers
else plan_prompt
) )
plan_agent = Agent( plan_agent = Agent(
@ -124,13 +129,20 @@ async def _plan_step_logic(
return "\n\n".join(r.content for r in results) return "\n\n".join(r.content for r in results)
# Build prompt with existing context if available # Build prompt with existing context if available
if has_context: if has_prior_answers:
context_xml = format_context_for_prompt(state.context) context_xml = format_context_for_prompt(state.context)
prompt = ( prompt = (
f"Review existing context and plan additional research if needed.\n\n" f"Review existing context and plan additional research if needed.\n\n"
f"{context_xml}\n\n" f"{context_xml}\n\n"
f"Main question: {state.context.original_question}" f"Main question: {state.context.original_question}"
) )
elif has_background:
context_xml = format_context_for_prompt(state.context)
prompt = (
f"Plan a focused approach for the main question.\n\n"
f"{context_xml}\n\n"
f"Main question: {state.context.original_question}"
)
else: else:
prompt = ( prompt = (
"Plan a focused approach for the main question.\n\n" "Plan a focused approach for the main question.\n\n"

View file

@ -1,10 +1,11 @@
PLAN_PROMPT = """You are the research orchestrator for a focused, iterative workflow. PLAN_PROMPT = """You are the research orchestrator for a focused workflow.
If a <background> section is provided, use it to understand the domain context.
Responsibilities: Responsibilities:
1. Understand and decompose the main question 1. Understand and decompose the main question
2. Propose a minimal, high-leverage plan 2. Propose a minimal, high-leverage plan
3. Coordinate specialized agents to gather evidence 3. Coordinate specialized agents to gather evidence
4. Iterate based on gaps and new findings
Plan requirements: Plan requirements:
- Produce at most 3 sub_questions that together cover the main question. - Produce at most 3 sub_questions that together cover the main question.
@ -22,19 +23,22 @@ Use the gather_context tool once on the main question before planning."""
PLAN_PROMPT_WITH_CONTEXT = """You are the research orchestrator for a focused workflow. PLAN_PROMPT_WITH_CONTEXT = """You are the research orchestrator for a focused workflow.
You have access to PREVIOUS CONVERSATION CONTEXT in the qa_responses section below. You have access to context that may include:
Review this context first - if it already answers the question, generate minimal - <background>: Domain context for the conversation
or no sub-questions. Only create sub-questions to fill gaps in the existing context. - <prior_answers>: Previous Q&A pairs with confidence scores
Review this first - if prior answers already answer the question completely,
you may return an empty sub_questions list. Only create sub-questions to
fill genuine gaps.
Responsibilities: Responsibilities:
1. Review existing qa_responses to understand what's already known 1. Review prior_answers to understand what's already known
2. Identify gaps that need additional research 2. Identify gaps that need additional research
3. Propose minimal sub-questions only for missing information 3. Propose minimal sub-questions only for missing information
Plan requirements: Plan requirements:
- If existing context fully answers the question, return a SINGLE sub-question - If prior answers fully answer the question, return an empty sub_questions list.
to verify or slightly expand the answer. - Only create new sub-questions for genuine gaps in existing knowledge.
- Only create new sub-questions for genuine gaps in the existing knowledge.
- sub_questions must be a list of plain strings (max 3). - sub_questions must be a list of plain strings (max 3).
- Each sub_question must be standalone and self-contained. - Each sub_question must be standalone and self-contained.
- Prioritize the highest-value gaps first. - Prioritize the highest-value gaps first.
@ -145,7 +149,8 @@ Output:
- confidence: Score from 0.0 to 1.0 indicating answer quality. - confidence: Score from 0.0 to 1.0 indicating answer quality.
Guidelines: Guidelines:
- Base your answer solely on the collected evidence in qa_responses. - Base your answer solely on the evidence provided in the context.
- If a <background> section is provided, use it to frame your answer appropriately.
- Be thorough - include all relevant information from the evidence. - Be thorough - include all relevant information from the evidence.
- Use formatting (bullet points, numbered lists) when it improves clarity. - Use formatting (bullet points, numbered lists) when it improves clarity.
- Do NOT use meta-commentary like "Based on the research..." or "The evidence shows..." - Do NOT use meta-commentary like "Based on the research..." or "The evidence shows..."

View file

@ -61,45 +61,45 @@ def test_research_context_initial_context_defaults_to_none():
assert context.initial_context is None assert context.initial_context is None
def test_format_context_for_prompt_includes_initial_context(): def test_format_context_for_prompt_includes_background():
"""Test format_context_for_prompt includes initial_context in output.""" """Test format_context_for_prompt includes background in output."""
from haiku.rag.agents.research.graph import format_context_for_prompt from haiku.rag.agents.research.graph import format_context_for_prompt
context = ResearchContext( context = ResearchContext(
original_question="What is X?", original_question="What is X?",
initial_context="Background: X is a concept in domain Y.", initial_context="X is a concept in domain Y.",
) )
result = format_context_for_prompt(context) result = format_context_for_prompt(context)
assert "Background: X is a concept in domain Y." in result assert "X is a concept in domain Y." in result
assert "initial_context" in result assert "<background>" in result
def test_format_context_for_prompt_excludes_initial_context_when_none(): def test_format_context_for_prompt_excludes_background_when_none():
"""Test format_context_for_prompt excludes initial_context when None.""" """Test format_context_for_prompt excludes background when None."""
from haiku.rag.agents.research.graph import format_context_for_prompt from haiku.rag.agents.research.graph import format_context_for_prompt
context = ResearchContext(original_question="What is X?") context = ResearchContext(original_question="What is X?")
result = format_context_for_prompt(context) result = format_context_for_prompt(context)
assert "initial_context" not in result assert "<background>" not in result
def test_format_conversational_context_for_prompt_includes_initial_context(): def test_format_conversational_context_for_prompt_includes_background():
"""Test format_conversational_context_for_prompt includes initial_context.""" """Test format_conversational_context_for_prompt includes background."""
from haiku.rag.agents.research.graph import format_conversational_context_for_prompt from haiku.rag.agents.research.graph import format_conversational_context_for_prompt
context = ResearchContext( context = ResearchContext(
original_question="What is X?", original_question="What is X?",
initial_context="Background: X is a concept in domain Y.", initial_context="X is a concept in domain Y.",
) )
result = format_conversational_context_for_prompt(context) result = format_conversational_context_for_prompt(context)
assert "Background: X is a concept in domain Y." in result assert "X is a concept in domain Y." in result
assert "initial_context" in result assert "<background>" in result
def test_format_conversational_context_for_prompt_excludes_initial_context_when_none(): def test_format_conversational_context_for_prompt_excludes_background_when_none():
"""Test format_conversational_context_for_prompt excludes initial_context when None.""" """Test format_conversational_context_for_prompt excludes background when None."""
from haiku.rag.agents.research.graph import format_conversational_context_for_prompt from haiku.rag.agents.research.graph import format_conversational_context_for_prompt
context = ResearchContext(original_question="What is X?") context = ResearchContext(original_question="What is X?")
result = format_conversational_context_for_prompt(context) result = format_conversational_context_for_prompt(context)
assert "initial_context" not in result assert "<background>" not in result