Skip to content

Grounding Policy

The grounding policy system controls what context reaches the LLM during synthesis: RAG chunk text, full canonical document attachments, or both. It provides a single decideGrounding() function that evaluates a GroundingPolicy against available inputs and returns a GroundingDecision.

This is the final stage of the Knowledge Base pipeline, applied just before the LLM synthesis call.

Import

import { decideGrounding, type GroundingPolicy, type GroundingDecision } from "@modernpath/agent-framework";

decideGrounding()

Evaluate a grounding policy and decide what inputs to send to the model.

function decideGrounding(args: {
  retrievedText?: string;
  preparedDocuments?: PreparedDocument[];
  policy?: GroundingPolicy;
}): GroundingDecision
Parameter Type Description
args.retrievedText string RAG-retrieved text (chunk context from RetrievalService).
args.preparedDocuments PreparedDocument[] Canonical documents prepared by CanonicalGroundingService.
args.policy GroundingPolicy Policy configuration (defaults to { mode: "hybrid" }).

Returns: A GroundingDecision indicating exactly what should be sent to the model.

Basic usage

const decision = decideGrounding({
  retrievedText: ragAnswer.text,
  preparedDocuments: groundingResult.allDocumentsForAttachment,
  policy: { mode: "attachments_only" },
});

// Build the synthesis prompt:
const prompt = decision.retrievedTextForPrompt
  ? `Context:\n${decision.retrievedTextForPrompt}\n\nQuestion: ${userQuery}`
  : `Question: ${userQuery}`;

// Attach documents if decision says so:
const options = decision.includeAttachments
  ? DocumentAttachment.getGeminiOptions(groundingResult.allDocumentsForAttachment)
  : {};

const result = await client.generateContent(prompt, options);

GroundingPolicy

interface GroundingPolicy {
  mode?: GroundingMode;
  canonical?: {
    whenAvailable?: CanonicalWhenAvailable;
  };
  chunks?: {
    includeRetrievedText?: boolean;
    maxChars?: number;
  };
}

mode

Mode Description
"chunks_only" Only RAG chunk text is sent to the model. No document attachments.
"attachments_only" Only full canonical documents are attached. RAG text is excluded from the prompt.
"hybrid" (Default) Both RAG text and canonical documents are used. Behavior refined by sub-options.

canonical.whenAvailable

Controls hybrid mode behavior when canonical attachments are available.

Value Description
"prefer_attachments" When canonical documents are available, exclude RAG text from the prompt (use attachments only).
"augment_chunks" (Default) Send both RAG text and canonical attachments. More context, but higher token usage.

chunks.includeRetrievedText

Explicit override for whether RAG text is included in the prompt. When set, overrides the mode-based default.

chunks.maxChars

Truncate RAG text to this many characters. Helps reduce token usage and limits the surface for prompt injection from retrieved content. Default: no truncation.

GroundingDecision

The output of decideGrounding().

interface GroundingDecision {
  /** RAG text for the prompt (possibly truncated), or "" if excluded. */
  retrievedTextForPrompt: string;

  /** Whether canonical documents should be attached to the model call. */
  includeAttachments: boolean;

  /** Whether retrieved text is included (after policy + truncation). */
  includeRetrievedText: boolean;
}

Mode Behavior Matrix

The following table shows the default behavior for each mode, assuming both RAG text and canonical documents are available:

Mode retrievedTextForPrompt includeAttachments Notes
chunks_only RAG text false Simplest mode. No document fetching needed.
attachments_only "" true Full documents only.
attachments_only (no docs available) RAG text true Graceful fallback: if no documents were resolved, RAG text is included to avoid starving the model.
hybrid + augment_chunks RAG text true Both sources. Maximum context.
hybrid + prefer_attachments (docs available) "" true Attachments replace chunks when available.
hybrid + prefer_attachments (no docs) RAG text true Falls back to chunks when no attachments.

Examples

Chunks Only

The simplest mode. Use when you do not need full document attachments.

const decision = decideGrounding({
  retrievedText: "The supply temperature should be between 60-80C...",
  policy: { mode: "chunks_only" },
});

// decision.retrievedTextForPrompt = "The supply temperature should be between 60-80C..."
// decision.includeAttachments = false
// decision.includeRetrievedText = true

Attachments Only

Use when you want the model to work exclusively from canonical documents. RAG is used only for document selection, not for prompt context.

const decision = decideGrounding({
  retrievedText: "The supply temperature should be...",
  preparedDocuments: [sopDocument],
  policy: { mode: "attachments_only" },
});

// decision.retrievedTextForPrompt = ""
// decision.includeAttachments = true
// decision.includeRetrievedText = false

Graceful fallback

In attachments_only mode, if no canonical documents were resolved (e.g. metadata is missing or all fetches failed), the function falls back to including RAG text so the model is not left without any context.

Hybrid with Truncation

Send both, but limit RAG text to control token usage:

const decision = decideGrounding({
  retrievedText: longRetrievedText,
  preparedDocuments: [doc1, doc2],
  policy: {
    mode: "hybrid",
    canonical: { whenAvailable: "augment_chunks" },
    chunks: { maxChars: 2000 },
  },
});

// decision.retrievedTextForPrompt = first 2000 chars + "\n... [truncated]"
// decision.includeAttachments = true

Hybrid with Attachment Preference

In hybrid mode, when canonical documents are available, use them exclusively:

const decision = decideGrounding({
  retrievedText: "Some RAG context...",
  preparedDocuments: [sopDocument],
  policy: {
    mode: "hybrid",
    canonical: { whenAvailable: "prefer_attachments" },
  },
});

// decision.retrievedTextForPrompt = ""  (attachments take over)
// decision.includeAttachments = true

Integration Pattern

A typical agent synthesis step uses decideGrounding() as follows:

import {
  RetrievalService,
  CanonicalGroundingService,
  decideGrounding,
  DocumentAttachment,
  GeminiClient,
} from "@modernpath/agent-framework";

async function synthesize(
  query: string,
  retrieval: RetrievalService,
  grounding: CanonicalGroundingService,
  client: GeminiClient,
  ctx: { userId: number; auditingId: number },
  policy: GroundingPolicy,
) {
  // Step 1: Retrieve
  const answer = await retrieval.search(query, "hvac-kb");

  // Step 2: Resolve canonical documents
  const canonical = await grounding.prepareFromSources(answer.sources, ctx);

  // Step 3: Apply grounding policy
  const decision = decideGrounding({
    retrievedText: answer.text,
    preparedDocuments: canonical.allDocumentsForAttachment,
    policy,
  });

  // Step 4: Build prompt
  const prompt = decision.retrievedTextForPrompt
    ? `Context:\n${decision.retrievedTextForPrompt}\n\nQuestion: ${query}`
    : `Answer the following question: ${query}`;

  // Step 5: Attach documents if needed
  const geminiOpts = decision.includeAttachments
    ? DocumentAttachment.getGeminiOptions(canonical.allDocumentsForAttachment)
    : {};

  // Step 6: Generate
  return await client.generateContent(prompt, {
    systemPrompt: "You are an HVAC expert. Answer based on the provided documents.",
    ...geminiOpts,
  });
}

Types Reference

GroundingMode

type GroundingMode = "chunks_only" | "attachments_only" | "hybrid";

CanonicalWhenAvailable

type CanonicalWhenAvailable = "prefer_attachments" | "augment_chunks";