spatial-atlas / src /entropy /engine.py
Arun0808's picture
Spatial Atlas v1.0: spatial-aware research agent for AgentBeats Challenge
77a8cec
Raw
History Blame Contribute Delete
3.49 kB
"""
Spatial Atlas — Entropy-Guided Reasoning Engine
Estimates information gain to optimize reasoning trajectories.
Builds on the entropy-guided approach from Sprint 1.
Core idea: Before each reasoning step, estimate which action
would maximize information gain (reduce uncertainty the most).
This leads to more efficient trajectories and better cost-efficiency scores.
"""
import json
import logging
from typing import Any
logger = logging.getLogger("spatial-atlas.entropy")
class EntropyEngine:
"""Estimate information gain to guide reasoning decisions."""
def __init__(self, llm):
self.llm = llm
async def select_best_action(
self,
knowledge_state: dict[str, Any],
candidates: list[str],
query: str,
) -> tuple[str, str]:
"""
Given current knowledge and candidate actions, pick the highest info-gain action.
Returns:
Tuple of (selected_action, reasoning)
"""
if len(candidates) <= 1:
return candidates[0] if candidates else "", "Only one option available"
state_summary = json.dumps(knowledge_state, indent=2, default=str)
candidate_list = "\n".join(f"{i+1}. {c}" for i, c in enumerate(candidates))
prompt = f"""You are optimizing an information-gathering trajectory.
Goal: Answer this question: {query}
Current knowledge state:
{state_summary}
Candidate next actions:
{candidate_list}
For each action, estimate how much it would reduce uncertainty about answering the question.
Rate each from 1-10 (10 = most informative, reduces uncertainty the most).
Return JSON:
{{"rankings": [{{"action_index": 0, "info_gain": 8, "reason": "..."}}]}}"""
try:
result = await self.llm.generate(prompt, model_tier="fast", json_mode=True)
parsed = json.loads(result)
rankings = parsed.get("rankings", [])
if rankings:
best = max(rankings, key=lambda r: r.get("info_gain", 0))
idx = best.get("action_index", 0)
reason = best.get("reason", "Highest estimated information gain")
if 0 <= idx < len(candidates):
logger.info(f"Entropy: selected action {idx} (gain={best.get('info_gain')})")
return candidates[idx], reason
except Exception as e:
logger.warning(f"Entropy engine fallback (error: {e})")
# Fallback: first candidate
return candidates[0], "Fallback selection"
async def estimate_confidence(
self,
answer: str,
evidence: str,
query: str,
) -> float:
"""
Estimate confidence in an answer given the evidence.
Returns 0.0-1.0 confidence score.
Used to decide whether to reflect/refine.
"""
prompt = f"""Rate your confidence that this answer correctly addresses the question.
Question: {query}
Evidence summary (truncated):
{evidence[:2000]}
Proposed answer:
{answer}
Rate confidence from 0.0 (no confidence) to 1.0 (fully confident).
Consider: Does the evidence support the answer? Are there gaps?
Return JSON: {{"confidence": 0.85, "gaps": ["list of any gaps"]}}"""
try:
result = await self.llm.generate(prompt, model_tier="fast", json_mode=True)
parsed = json.loads(result)
return float(parsed.get("confidence", 0.5))
except Exception:
return 0.5 # Default moderate confidence