Files
ragflow/rag/advanced_rag/harness/config.py
Yingfeng f1641228e2 Refine agentic search & orchestration loop (#18057)
## Summary

This PR improves the RAGFlow agentic-search path in three areas: it
stops the outer agent from re-looping over the same rag call, lets the
medium thinking mode discover and follow new sub-claims mid-loop, and
strengthens retrieval by having the LLM emit synonym-rich queries with
time/date/number terms boosted.

1. Avoid the outer re-loop — keep all multi-hop cycles inside agentic
RAG

2. Dynamic claims in medium mode — keep querying newly discovered
sub-questions
medium now enables allows_dynamic_claims. During orchestration, when
claim analysis discovers a new required sub-question
(discovered_claims), the loop spawns it as a new ClaimTarget and
continues searching it in subsequent cycles (bounded by the
dynamic-claim budget) instead of stopping. Also added:

3. Stronger query strategy — synonym-rich queries + time/date/number
weighting

LLM-generated synonyms: the claim-analysis prompt now instructs the
model to write each next_queries entry as a retrieval-boosted query that
actively folds in entity aliases, DATE/TIME synonyms (e.g. 1994 → 1994,
66th Academy Awards), and number/unit variants (e.g. 1.95 m → 6 ft 5
in).

Time/date/number boosting: query.py boosts numeric/date tokens to a high
weight (_NUM_DATE_TOKEN_RE).
2026-08-11 13:40:11 +08:00

113 lines
3.4 KiB
Python

"""Thinking mode configurations."""
from rag.advanced_rag.harness.types import ExecutionStrategy
THINKING_MODES: dict[str, ExecutionStrategy] = {
"low": ExecutionStrategy(
label="low",
execution_strategy="direct_search",
requires_decomposition=False,
requires_agent_loop=False,
requires_sufficiency_judge=False,
requires_selective_gen=False,
allows_dynamic_claims=False,
allows_replan=False,
max_orchestrator_cycles=1,
max_agent_cycles=0,
max_parallel_agents=1,
available_tools=["hybrid_search", "web_search", "bm25_search"],
sufficiency_threshold=0.85,
fallback_to_direct_llm=False,
),
"medium": ExecutionStrategy(
label="medium",
execution_strategy="decompose_and_search",
requires_decomposition=True,
requires_agent_loop=False,
requires_sufficiency_judge=True,
requires_selective_gen=True,
allows_dynamic_claims=True,
allows_replan=False,
max_orchestrator_cycles=3,
max_agent_cycles=0,
max_parallel_agents=1,
available_tools=["hybrid_search", "web_search", "bm25_search"],
sufficiency_threshold=0.75,
fallback_to_direct_llm=False,
c_high=0.75,
c_low=0.45,
llm_floor=0.55,
allows_reconcile=False,
),
"high": ExecutionStrategy(
label="high",
execution_strategy="agentic_research",
requires_decomposition=True,
requires_agent_loop=False,
requires_sufficiency_judge=True,
requires_selective_gen=True,
allows_dynamic_claims=False,
allows_replan=False,
max_orchestrator_cycles=3,
max_agent_cycles=2,
max_parallel_agents=2,
available_tools=[
"hybrid_search",
"web_search",
"bm25_search",
"ontology_navigate",
"dataset_navigation_by_tree",
"graph_explore",
"inspector_open_context",
"inspector_compare",
],
sufficiency_threshold=0.65,
fallback_to_direct_llm=False,
c_high=0.70,
c_low=0.40,
llm_floor=0.50,
allows_reconcile=True,
),
"ultra": ExecutionStrategy(
label="ultra",
execution_strategy="deep_research",
requires_decomposition=True,
requires_agent_loop=True,
requires_sufficiency_judge=True,
requires_selective_gen=True,
allows_dynamic_claims=True,
allows_replan=True,
max_orchestrator_cycles=4,
max_agent_cycles=2,
max_parallel_agents=3,
available_tools=[
"hybrid_search",
"bm25_search",
"web_search",
"structured_query",
"ontology_navigate",
"dataset_navigation_by_tree",
"mindmap_navigate",
"graph_explore",
"wiki_query",
"inspector_open_context",
"inspector_compare",
"inspector_grep_within",
"inspector_request_adjacent",
],
sufficiency_threshold=0.55,
fallback_to_direct_llm=True,
c_high=0.65,
c_low=0.35,
llm_floor=0.45,
allows_reconcile=True,
),
}
def get_mode(label: str) -> ExecutionStrategy:
mode = THINKING_MODES.get(label)
if not mode:
raise ValueError(f"Unknown thinking mode: {label}. Available: {list(THINKING_MODES.keys())}")
return mode