Annotation Interface Search


@Documented @Retention(RUNTIME) @Target({}) public @interface Search
How a Knowledge.Use.SEARCH source is ranked and rendered.

@Search is never placed on its own; it is the Knowledge.search() member of a knowledge declaration:


 @RoleSpec(knowledge = {
     @Knowledge(name = "product-docs", path = "knowledge/products",
                search = @Search(strategy = Strategy.HYBRID, topK = 8)),
     @Knowledge(name = "faq", path = "knowledge/faq")
 })
 public class SupportRole extends Role {

     @ActionSpec(type = ActionType.LLM, description = "Answer a question",
                 knowledge = {@Knowledge(name = "product-docs"), @Knowledge(name = "faq")})
     public String answer(String question) { ... }
 }
 

Every member is an array whose empty default means "not given"; write a single value as usual (topK = 8). More than one value fails at startup. A member left unset takes the value stated on it.

Several SEARCH sources in one scope (an action's named set, or the chat turn) run through one retrieval engine, so their @Search members merge field by field: a member set by one source applies to the scope, and two sources setting the same member to different values fail at startup. An action's own @Knowledge(name = ..., search = @Search(...)) replaces the declared @Search as a whole: a member the action's @Search leaves unset is not taken from the declaration, so it takes the value another source in the scope sets, or the value stated on it.

rerank = true requires a Reranker provider module on the classpath that serves the declared rerankerModel(); TnsAI bundles none. Without a matching provider the Role's retrieval configuration fails at the start of the retrieval, before result-cache lookup or index query/search work — onFailure cannot absorb a missing provider. Unexpected failures from the provider's local capability check, and failures raised while ranking, still follow onFailure().

Strategies

  • SEMANTIC - Vector similarity search only
  • KEYWORD - BM25/TF-IDF keyword search
  • HYBRID - Combined semantic + keyword
  • GRAPH - Knowledge graph traversal
  • MULTI_QUERY - Generate multiple queries for broader coverage
  • HIERARCHICAL - Child-hit selection with bounded parent expansion
  • TEMPORAL - Content relevance with bounded time decay
  • REASONING - Root-to-leaf tree descent with a model choosing the branch
Since:
0.18.0
Author:
TnsAI Team
See Also:
  • Element Details

    • strategy

      Search.Strategy[] strategy
      Retrieval strategy.

      Unset (empty) means Strategy.SEMANTIC.

      Returns:
      strategy
      Default:
      {}
    • queryParam

      String[] queryParam
      Name of the action parameter whose value is the retrieval query.

      Blank — the default — keeps the positional rule: the first String-typed parameter in declaration order that carries a non-blank value. That is right for a single-parameter action and wrong as soon as an identifier precedes the question:

      
       search = @Search(topK = 5)                         // retrieves on tenantId
       public String answer(String tenantId, String question) { ... }
      
       search = @Search(topK = 5, queryParam = "question") // retrieves on question
       public String answer(String tenantId, String question) { ... }
       

      Naming the parameter also pins the binding: without it, reordering the parameters or inserting a String in front of the question silently moves retrieval onto a different argument. Nothing fails — the corpus is searched for the wrong text, documents come back, and the model is handed confident grounding for a question nobody asked.

      Naming a parameter the action does not declare is a configuration error: the action fails at dispatch time and onFailure() does not apply, on the same terms as rerankerModel(). A declared parameter that is absent, null, blank, or not a String at call time is not an error — retrieval is skipped for that call, exactly as it is when the positional rule finds nothing.

      Parameter names come from the compiled bytecode, so the reactor's -parameters compiler flag is what makes this element work.

      Declared on a Role or Agent knowledge source this applies to every action that names the source, so each of them must declare a parameter of that name or fail. That is a strong requirement and deliberately so — the alternative, silently falling back to the positional rule on the actions that do not declare it, would reintroduce the very ambiguity naming the parameter was meant to remove. Set it on the action's own @Knowledge entry unless the actions genuinely share a signature.

      Unset (empty) means the positional rule.

      Returns:
      the query parameter's name, or blank for the positional rule
      Default:
      {}
    • rerank

      boolean[] rerank
      Whether to rerank results by relevance.

      When enabled, the intelligence module resolves a com.tnsai.intelligence.rag.Reranker provider for rerankerModel(). TnsAI does not bundle or silently emulate a cross-encoder; applications install the provider that owns model inference and transport.

      A blank rerankerModel() or identifier no installed provider serves is a configuration error. Role declarations fail while the Role is initialized, before any action dispatch; non-Role targets and programmatic overrides fail at dispatch before result-cache lookup or index query/search work. A non-positive topN() also fails at dispatch before cache or index work. onFailure() does not apply. Unexpected failures from the provider's local capability check, and failures raised while ranking, follow the failure policy.

      Unset (empty) means false.

      Returns:
      true to rerank
      Default:
      {}
    • rerankerModel

      String[] rerankerModel
      Exact, case-sensitive reranking model identifier.

      A non-blank value is required when rerank() is enabled. The selected reranker provider defines the identifier format.

      Unset (empty) means "".

      Returns:
      reranker model
      Default:
      {}
    • contextWindow

      int[] contextWindow
      Maximum context window size in tokens.

      Must be positive. The intelligence runtime measures the complete rendered context, including contextFormat() overhead, with the canonical content-aware TokenEstimator. Ranked document content is truncated only at Unicode code-point boundaries to fit.

      Unset (empty) means 4000.

      Returns:
      max tokens
      Default:
      {}
    • topK

      int[] topK
      Number of results to retrieve per source during ordinary ranked retrieval.

      Unset (empty) means 5.

      Returns:
      top K
      Default:
      {}
    • topN

      int[] topN
      Maximum number of results retained after ordinary retrieval reranking.

      Must be positive when rerank() is enabled. The runtime applies this limit after the provider returns for ordinary ranked retrieval. DIRECT does not apply result-count limits.

      With rerank() disabled the value is neither validated nor applied: there is no reranking stage to cap, and topK() alone bounds the ordinary retrieval result. The one place the limit outlives the reranker is Search.FallbackAction.RETRY_SIMPLE, which caps its un-reranked retry at this value when rerank() is enabled, so a degraded retrieval never injects more context than a healthy one.

      Unset (empty) means 3.

      Returns:
      top N after rerank
      Default:
      {}
    • minScore

      double[] minScore
      Minimum relevance score (0.0 - 1.0).

      The threshold is applied to the score emitted by the selected strategy, and increasing the value can only remove candidates. Semantic strategies use cosine similarity; keyword strategies use their native non-negative relevance score. Hybrid strategy RRF scores are normalized against the non-empty input streams, so 0.0 preserves every HYBRID candidate and the default 0.5 remains meaningful when either one or both streams return candidates.

      Unset (empty) means 0.5.

      Returns:
      min score
      Default:
      {}
    • deduplicate

      boolean[] deduplicate
      Whether to deduplicate similar results.

      Deduplication runs after query-result fusion and before optional reranking. The highest-ranked candidate remains the representative and retains its retrieval score.

      Unset (empty) means true.

      Returns:
      true to dedupe
      Default:
      {}
    • dedupeThreshold

      double[] dedupeThreshold
      Similarity threshold for deduplication.

      Must be finite and between 0.0 and 1.0, inclusive, when deduplicate() is enabled. Candidates at or above the threshold are grouped.

      Unset (empty) means 0.9.

      Returns:
      dedupe threshold
      Default:
      {}
    • queryExpansion

      Search.QueryExpansion[] queryExpansion
      Query expansion/transformation method.

      Unset (empty) means QueryExpansion.NONE.

      Returns:
      query expansion type
      Default:
      {}
    • queryExpansionModel

      String[] queryExpansionModel
      Exact, case-sensitive model identifier used by the query-expansion provider.

      A non-blank value is required when queryExpansion() is not Search.QueryExpansion.NONE, or when strategy() is Search.Strategy.MULTI_QUERY. TnsAI resolves a com.tnsai.intelligence.rag.QueryExpander provider for the configured expansion mode and model; the provider owns inference, credentials, transport, and lifecycle management. An identifier no installed provider serves fails while a Role is initialized, before any action dispatch. Non-Role targets and programmatic overrides fail at dispatch before result-cache lookup or index query/search work. onFailure() does not apply. Unexpected failures from the provider's local capability check, and failures raised while expanding, follow the failure policy.

      Unset (empty) means "".

      Returns:
      query-expansion model
      Default:
      {}
    • expandedQueries

      int[] expandedQueries
      Maximum number of generated query variations.

      The original query is always retained and does not count against this limit. Provider output is normalized, deduplicated, and truncated to this hard upper bound before retrieval.

      Unset (empty) means 3.

      Returns:
      query count
      Default:
      {}
    • includeSpec

      boolean[] includeSpec
      Whether to include source metadata in context.

      When false, ${source} and ${score} placeholders render no document values. Document content is treated as data and cannot introduce placeholders through template substitution.

      Unset (empty) means true.

      Returns:
      true to include metadata
      Default:
      {}
    • contextFormat

      String[] contextFormat
      Context format template.

      The only supported placeholders are ${content}, ${source}, and ${score}. Unsupported or unterminated placeholders fail configuration validation.

      Unset (empty) means "[Source: ${source}]\n${content}\n".

      Returns:
      format template
      Default:
      {}
    • cache

      boolean[] cache
      Whether to enable caching of retrieval results.

      When enabled, the intelligence module caches the fully retrieved and reranked document list in a bounded, per-Role in-memory cache. Cache keys isolate the normalized query, Role, selected sources, strategy, and every option that changes the document result. Raw query text and retrieved content are not retained in cache keys or telemetry.

      Unset (empty) means true.

      Returns:
      true to cache
      Default:
      {}
    • cacheTTL

      int[] cacheTTL
      Cache TTL in seconds.

      Must be positive when cache() is enabled. Binding eviction or corpus rebuild invalidates cached retrieval results regardless of the remaining TTL.

      Search.Strategy.TEMPORAL ranks by recency against the wall clock, which is not configuration and therefore cannot take part in the cache key. A cached temporal ranking is consequently pinned for the entry's TTL: within one TTL every hit is ordered as of the instant the entry was populated. Against the default 300 s and the built-in 30-day half-life the freshness multiplier moves by well under a hundredth of a percent, so it cannot reorder results; shorten this value if a deployment needs recency to turn over faster than that.

      Unset (empty) means 300.

      Returns:
      cache duration
      Default:
      {}
    • maxStaleness

      int[] maxStaleness
      How long past expiry a cached result may still serve Search.FallbackAction.USE_CACHE, in seconds.

      cacheTTL() bounds how long a result is fresh; this bounds how long an expired one may still stand in for a failed retrieval. The two are measured in sequence, not from the same instant: an entry is fresh for cacheTTL, then eligible as a stale fallback for a further maxStaleness, then gone. This mirrors HTTP stale-if-error (RFC 5861), whose max-age argument likewise counts from the end of the freshness lifetime.

      Without a ceiling, a provider that stays down keeps the model answering from ever-older grounding: retention would be bounded only by a successful refresh, an explicit cache clear, or eviction. A finite default makes the bound the norm — past it, the original failure is rethrown and Search.FallbackAction.USE_CACHE degrades to nothing rather than to something arbitrarily old.

      Use -1 to opt out and allow an unbounded fallback. Any other non-positive value is rejected when Search.FallbackAction.USE_CACHE is selected, on the same terms as cacheTTL().

      Unset (empty) means 3600.

      Returns:
      seconds past expiry a stale fallback stays eligible, or -1 for no ceiling
      Default:
      {}
    • onFailure

      Fallback behavior if retrieval fails at runtime.

      Applies to failures raised while serving a request — retrieval or reranker transport, provider exceptions, and incomplete FILE/URL source loading during binding construction. It does not apply to configuration this annotation cannot honour at all (an unknown knowledge name, blank rerankerModel() or non-positive topN() with rerank() enabled, no installed provider for the requested model, Search.FallbackAction.USE_CACHE with cache() disabled); those fail the action regardless of this setting, because Search.FallbackAction.CONTINUE would otherwise run the LLM with no retrieved context while still reporting success.

      Cancellation is not a retrieval failure: an interrupted or cancelled dispatch propagates regardless of this setting, so no policy swallows it or spends a retry on it.

      Unset (empty) means FallbackAction.CONTINUE.

      Returns:
      fallback action
      Default:
      {}