OpenViking uses two-stage retrieval: intent analysis + hierarchical retrieval + rerank.
Query → Intent Analysis → Hierarchical Retrieval → Rerank → Results
↓ ↓ ↓
TypedQuery Directory Recursion Refined Scoring
Feature
find()
search()
Session context
Not needed
Required
Intent analysis
Not used
LLM analysis
Query count
Single query
0-5 TypedQueries
Latency
Low
Higher
Use case
Simple queries
Complex tasks
# find(): Simple query
results = await client .find (
"OAuth authentication" ,
target_uri = "viking://resources/"
)
# search(): Complex task (needs session context)
results = await client .search (
"Help me create an RFC document" ,
session_info = session
)
IntentAnalyzer uses LLM to analyze query intent and generate 0-5 TypedQueries.
Session compression summary
Last 5 messages
Current query
@dataclass
class TypedQuery :
query : str # Rewritten query
context_type : ContextType # MEMORY/RESOURCE/SKILL
intent : str # Query purpose
priority : int # 1-5 priority
Type
Style
Example
skill
Verb-first
"Create RFC document", "Extract PDF tables"
resource
Noun phrase
"RFC document template", "API usage guide"
memory
"User's XX"
"User's code style preferences"
0 queries : Chitchat, greetings that don't need retrieval
Multiple queries : Complex tasks may need skill + resource + memory
HierarchicalRetriever uses priority queue to recursively search directory structure.
Step 1: Determine root directories by context_type
↓
Step 2: Global vector search to locate starting directories
↓
Step 3: Merge starting points + Rerank scoring
↓
Step 4: Recursive search (priority queue)
↓
Step 5: Convert to MatchedContext
context_type
Root Directories
MEMORY
viking://user/memories, viking://agent/memories
RESOURCE
viking://resources
SKILL
viking://agent/skills
Recursive Search Algorithm
while dir_queue :
current_uri , parent_score = heapq .heappop (dir_queue )
# Search children
results = await search (parent_uri = current_uri )
for r in results :
# Score propagation
final_score = 0.5 * embedding_score + 0.5 * parent_score
if final_score > threshold :
collected .append (r )
if not r .is_leaf : # Directory continues recursion
heapq .heappush (dir_queue , (r .uri , final_score ))
# Convergence detection
if topk_unchanged_for_3_rounds :
break
Parameter
Value
Description
SCORE_PROPAGATION_ALPHA
0.5
50% embedding + 50% parent
MAX_CONVERGENCE_ROUNDS
3
Convergence detection rounds
GLOBAL_SEARCH_TOPK
3
Global search candidates
MAX_RELATIONS
5
Max relations per resource
Rerank refines candidate results in THINKING mode.
Rerank AK/SK configured
Using THINKING mode (default for search())
If rerank returns an invalid result or the API call fails, retrieval falls back to vector scores
if rerank_client and mode == THINKING :
scores = rerank_client .rerank_batch (query , documents )
else :
scores = [r ["_score" ] for r in results ] # Vector scores
Starting point evaluation : Evaluate global search candidate directories
Recursive search : Evaluate children at each level
Backend
Model
Volcengine
doubao-seed-rerank
@dataclass
class MatchedContext :
uri : str # Resource URI
context_type : ContextType
is_leaf : bool # Whether file
abstract : str # L0 abstract
score : float # Final score
relations : List [RelatedContext ] # Related contexts
@dataclass
class FindResult :
memories : List [MatchedContext ]
resources : List [MatchedContext ]
skills : List [MatchedContext ]
query_plan : Optional [QueryPlan ] # Present for search()
query_results : Optional [List [QueryResult ]]
total : int