ask-the-web-agent / src /feedback /refinement.py
debashis2007's picture
Upload folder using huggingface_hub
75bea1c verified
from __future__ import annotations
"""Refinement strategies for improving responses."""
from dataclasses import dataclass
from typing import Any
from src.feedback.gaps import InformationGap
@dataclass
class RefinementAction:
"""An action to refine the response."""
action_type: str # "search", "verify", "expand", "clarify", "restructure"
description: str
parameters: dict[str, Any]
priority: int # 1-5, lower is higher priority
class RefinementStrategy:
"""Determines strategies for refining responses."""
def __init__(self, max_iterations: int = 3):
"""Initialize the refinement strategy.
Args:
max_iterations: Maximum refinement iterations allowed
"""
self.max_iterations = max_iterations
self._current_iteration = 0
def analyze(
self,
query: str,
answer: str,
gaps: list[InformationGap],
quality_score: float,
) -> list[RefinementAction]:
"""Analyze response and determine refinement actions.
Args:
query: Original query
answer: Current answer
gaps: Identified information gaps
quality_score: Overall quality score
Returns:
List of refinement actions
"""
actions = []
# If quality is already high, minimal refinement needed
if quality_score >= 0.8:
return []
# Handle each gap type
for gap in gaps:
if gap.gap_type == "missing_fact":
actions.append(RefinementAction(
action_type="search",
description=f"Search for missing information: {gap.description}",
parameters={
"search_query": gap.suggested_search or query,
"gap_description": gap.description,
},
priority=1 if gap.severity == "high" else 2,
))
elif gap.gap_type == "unverified":
actions.append(RefinementAction(
action_type="verify",
description=f"Verify claim: {gap.description}",
parameters={
"claim": gap.description,
},
priority=2,
))
elif gap.gap_type == "unclear":
actions.append(RefinementAction(
action_type="clarify",
description=f"Clarify: {gap.description}",
parameters={
"unclear_part": gap.description,
},
priority=3,
))
elif gap.gap_type == "outdated":
actions.append(RefinementAction(
action_type="search",
description=f"Find recent information: {gap.description}",
parameters={
"search_query": gap.suggested_search or f"{query} latest recent",
"temporal": True,
},
priority=1,
))
# General improvements based on quality score
if quality_score < 0.5:
actions.append(RefinementAction(
action_type="expand",
description="Expand answer with more detail",
parameters={"reason": "Low quality score"},
priority=2,
))
# Sort by priority
actions.sort(key=lambda a: a.priority)
# Limit number of actions
return actions[:5]
def should_continue(self, quality_score: float) -> bool:
"""Determine if refinement should continue.
Args:
quality_score: Current quality score
Returns:
True if refinement should continue
"""
if self._current_iteration >= self.max_iterations:
return False
# Continue if quality is below threshold
return quality_score < 0.7
def increment_iteration(self) -> int:
"""Increment the iteration counter.
Returns:
Current iteration number
"""
self._current_iteration += 1
return self._current_iteration
def reset(self) -> None:
"""Reset the iteration counter."""
self._current_iteration = 0
def get_iteration(self) -> int:
"""Get current iteration number.
Returns:
Current iteration
"""
return self._current_iteration
def create_refined_query(
self,
original_query: str,
action: RefinementAction,
) -> str:
"""Create a refined query for additional search.
Args:
original_query: Original user query
action: Refinement action to execute
Returns:
Refined search query
"""
if action.action_type == "search":
return action.parameters.get("search_query", original_query)
elif action.action_type == "verify":
claim = action.parameters.get("claim", "")
return f"verify {original_query} {claim}"
elif action.action_type == "expand":
return f"{original_query} detailed explanation"
elif action.action_type == "clarify":
unclear = action.parameters.get("unclear_part", "")
return f"{original_query} {unclear} meaning definition"
return original_query
def merge_answers(
self,
original_answer: str,
new_information: str,
action: RefinementAction,
) -> str:
"""Merge new information into existing answer.
Args:
original_answer: Original answer text
new_information: New information to incorporate
action: The refinement action that produced this info
Returns:
Merged answer
"""
# Simple merging strategy - append with context
if action.action_type == "expand":
return f"{original_answer}\n\n**Additional Details:**\n{new_information}"
elif action.action_type == "verify":
return f"{original_answer}\n\n**Verification:**\n{new_information}"
elif action.action_type == "search":
return f"{original_answer}\n\n**Additional Information:**\n{new_information}"
elif action.action_type == "clarify":
return f"{original_answer}\n\n**Clarification:**\n{new_information}"
return f"{original_answer}\n\n{new_information}"
def prioritize_actions(
self,
actions: list[RefinementAction],
time_budget: float | None = None,
) -> list[RefinementAction]:
"""Prioritize refinement actions within constraints.
Args:
actions: List of actions to prioritize
time_budget: Optional time budget in seconds
Returns:
Prioritized list of actions
"""
# Estimate time per action type
time_estimates = {
"search": 2.0,
"verify": 3.0,
"expand": 1.5,
"clarify": 1.0,
"restructure": 0.5,
}
if time_budget is None:
return sorted(actions, key=lambda a: a.priority)
# Select actions that fit within budget
prioritized = []
remaining_time = time_budget
sorted_actions = sorted(actions, key=lambda a: a.priority)
for action in sorted_actions:
estimated_time = time_estimates.get(action.action_type, 1.0)
if estimated_time <= remaining_time:
prioritized.append(action)
remaining_time -= estimated_time
return prioritized