Skip to content

Commit 2687230

Browse files
author
Arena AI Agent
committed
feat(tools): 🌍 implement live web-search grounding (RAG via DuckDuckGo) to eradicate hallucinations and enforce empirical truth
1 parent ed088a4 commit 2687230

3 files changed

Lines changed: 41 additions & 9 deletions

File tree

epistemic_forge/experts/claim_expert.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,43 @@
1-
"""Claim Lattice Expert Implementation."""
1+
"""Claim Lattice Expert Implementation (Grounded with Real-World Search)."""
22
from typing import Dict, Any
33
from epistemic_forge.experts.base import EpistemicExpert
44
from epistemic_forge.models import ProjectSpec, ClaimLatticeOutput
55
from epistemic_forge.llm import generate_structured
6+
from epistemic_forge.tools.search import search_web
67
from loguru import logger
78

89
class ClaimLatticeExpert(EpistemicExpert):
910
"""Deconstructs the question into a structured, epistemically grounded claim lattice."""
1011

1112
@property
1213
def expert_name(self) -> str:
13-
return "Epistemic_Claim_Lattice_Generator"
14+
return "Grounded_Claim_Lattice_Generator"
1415

1516
def analyze(self, spec: ProjectSpec, context: Dict[str, Any]) -> ClaimLatticeOutput:
16-
"""Forces the LLM to generate claims ONLY if it can provide a warrant/explanation."""
17+
"""Uses Live Web Search to ground the LLM's claims in reality."""
18+
19+
# 1. Fetch real-world context before asking the LLM to build claims
20+
logger.debug("Gathering live empirical data to prevent hallucination...")
21+
search_query = f"{spec.question} scientific consensus"
22+
live_evidence = search_web(search_query, max_results=3)
1723

1824
messages = [
1925
{
2026
"role": "system",
2127
"content": (
22-
"You are a rigorous analytical philosopher and scientist. Your task is to break down the user's premise into a 'Claim Lattice'. "
23-
"CRITICAL RULE: You are strictly forbidden from making ANY claim without providing an 'epistemic_warrant' (a clear logical explanation or evidence) "
24-
"and a 'potential_falsifier' (what would prove it wrong). No confident mush allowed."
28+
"You are a rigorous analytical philosopher and empirical scientist. Your task is to break down the user's premise into a 'Claim Lattice'. "
29+
"CRITICAL RULE: You MUST ground your claims using the 'Live Evidence' provided. Do not hallucinate. "
30+
"You are strictly forbidden from making ANY claim without providing an 'epistemic_warrant' (a clear logical explanation) "
31+
"and a 'potential_falsifier'. No confident mush allowed."
2532
)
2633
},
2734
{
2835
"role": "user",
29-
"content": f"Core Premise: {spec.question}\nKeywords: {spec.keywords}\nDeconstruct this into rigorously grounded claims."
36+
"content": f"Core Premise: {spec.question}\nKeywords: {spec.keywords}\n\n=== LIVE EMPIRICAL EVIDENCE ===\n{live_evidence}\n=====================\n\nDeconstruct this into rigorously grounded claims, citing the evidence where applicable."
3037
}
3138
]
3239

33-
logger.debug("Dispatching to LLM for Claim Lattice Generation (Enforcing Truthfulness)...")
40+
logger.debug("Dispatching to LLM for Grounded Claim Lattice Generation...")
3441
return generate_structured(
3542
messages=messages,
3643
response_model=ClaimLatticeOutput,

epistemic_forge/tools/search.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""External Knowledge Retrieval Tool (Web Search).
2+
3+
Provides live grounding for Claim Lattices without requiring paid API keys
4+
(using DuckDuckGo Search).
5+
"""
6+
from duckduckgo_search import DDGS
7+
from loguru import logger
8+
from typing import List, Dict
9+
10+
def search_web(query: str, max_results: int = 3) -> str:
11+
"""Performs a web search and returns concatenated evidence."""
12+
logger.info(f"🔍 Executing Live Web Search for: '{query}'")
13+
try:
14+
results = DDGS().text(query, max_results=max_results)
15+
if not results:
16+
return "No external evidence found."
17+
18+
evidence = []
19+
for r in results:
20+
evidence.append(f"[Source: {r.get('title')}]\nSnippet: {r.get('body')}\nURL: {r.get('href')}")
21+
22+
return "\n\n".join(evidence)
23+
except Exception as e:
24+
logger.warning(f"Web search failed: {e}")
25+
return "Search tool temporarily unavailable."

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ classifiers = [
3131
"Topic :: Scientific/Engineering :: Artificial Intelligence",
3232
"Topic :: Text Processing :: Linguistic",
3333
]
34-
dependencies = ["litellm>=1.40.0", "pydantic>=2.0.0", "loguru>=0.7.0", "tenacity>=8.0.0", "instructor>=1.3.0", "rich>=13.0.0", "streamlit>=1.35.0"]
34+
dependencies = ["litellm>=1.40.0", "duckduckgo-search>=5.0.0", "pydantic>=2.0.0", "loguru>=0.7.0", "tenacity>=8.0.0", "instructor>=1.3.0", "rich>=13.0.0", "streamlit>=1.35.0"]
3535

3636
[project.optional-dependencies]
3737
dev = ["pytest>=7.0"]

0 commit comments

Comments
 (0)