Skip to content

Context Extraction

Each LLM step can declare step_context_queries. For every query, CARL searches your outer_context and injects the matching snippets into that step’s prompt — so each step sees only the context it needs. This is the RAG-like extraction at the heart of CARL.

LLMStepDescription(
number=1,
title="Financial analysis",
aim="Analyze financial performance.",
step_context_queries=["revenue growth", "profit margins", "cost efficiency"],
)

Configure search at the chain level with ContextSearchConfig:

FieldTypeDefaultPurpose
strategy"substring" | "vector""substring"The default search strategy.
substring_configdict | NoneNoneOptions for substring search.
vector_configdict | NoneNoneOptions for vector search.
embedding_modelstr | NoneNoneEmbedding model for vector search.
  • Substring (default) — fast, exact keyword matching, no extra dependencies.
  • Vector — semantic similarity via FAISS embeddings; see vector search.
from mmar_carl import ContextSearchConfig, ReasoningChain
search_config = ContextSearchConfig(
strategy="substring",
substring_config={
"case_sensitive": False, # default
"min_word_length": 2, # default
"max_matches_per_query": 3, # default
},
)
chain = ReasoningChain(steps=steps, search_config=search_config)

Or with the builder: ChainBuilder().with_search_config(search_config).

Mix plain string queries and ContextQuery objects in the same step to override the strategy for individual queries:

from mmar_carl import ContextQuery
step_context_queries=[
"EBITDA", # uses the chain default
ContextQuery(
query="revenue trends",
search_strategy="vector",
search_config={"similarity_threshold": 0.8, "max_results": 3},
),
ContextQuery(
query="NET_INCOME",
search_strategy="substring",
search_config={"case_sensitive": True},
),
]
ContextQuery fieldTypePurpose
querystrThe query text.
search_strategy"substring" | "vector" | NoneOverride for this query.
search_configdict | NoneExtra search options for this query.