Schema Introspection
Mango samples your collections to infer field types, indexes, and cross-collection references. The result is injected into the system prompt so the LLM generates correct queries without guessing.
How it works
When you call agent.setup() with introspect=True, Mango runs introspect_schema() on your database:
- Sample documents — fetches up to 100 documents per collection (mix of sequential + random via
$sample) - Infer fields — walks every document, records field paths, types, and presence frequency
- Detect indexes — reads index definitions via
index_information() - Detect references — heuristic:
user_id→ looks foruserscollection,movieId→ looks formovies - Inject per turn — the schema is serialized into the dynamic part of the prompt on every question (see below)
MongoRunner caches the introspection result for introspect_ttl_s (default 300 s), and field_types() — used for literal coercion — keeps a per-collection 50-document sample cache.
Enable introspection
agent = MangoAgent(
...,
introspect=True, # run introspect_schema() on setup()
)
agent.setup()
Pass pre-computed schema
For production deployments you may want to introspect once and reuse:
schema = db.introspect_schema() # run once, save/cache the result
agent = MangoAgent(
...,
schema=schema, # pass directly, introspect=False (default)
)
agent.setup()
SchemaInfo
Each collection produces a SchemaInfo:
@dataclass
class SchemaInfo:
collection_name: str
document_count: int
fields: list[FieldInfo]
indexes: list[dict]
sample_documents: list[dict] # 5 representative docs
Each field produces a FieldInfo:
@dataclass
class FieldInfo:
name: str
path: str # dotted path e.g. "address.city"
types: list[str] # e.g. ["string", "null"]
frequency: float # 0.0–1.0, how often field appears
is_indexed: bool
is_unique: bool
is_reference: bool
reference_collection: str | None
sub_fields: list[FieldInfo] | None # for subdocuments
array_element_types: list[str] | None
sample_values: list[str] | None # distinct string values when the field looks categorical (≤ 25 distinct)
Large databases
The prompt never lists grouped collections. On every question, when the database has more than schema_always_all (default 4) collections, Mango lists all collection names and shows full field details only for the schema_top_k (default 3) collections best matching the question (keyword and stem matching against collection names and field names). With schema_always_all or fewer collections, every collection is detailed. The grouped-by-pattern view exists only in the list_collections tool output for databases with more than 50 collections.
For databases with more than 10 collections, Mango also enables schema linking enforcement: before the first run_mql call on any collection, the agent automatically runs describe_collection and prepends the result to the query response. The LLM always sees the correct field names and types at query time — without an extra round-trip and without relying on the LLM to remember to inspect the schema first.
For smaller databases (≤ 10 collections), the full schema is already in the system prompt, so enforcement is skipped.
agent = MangoAgent(..., schema_top_k=3, schema_always_all=4)
Manual schema inspection
schema = db.introspect_schema()
for collection_name, info in schema.items():
print(f"{collection_name}: {info.document_count} docs, {len(info.fields)} fields")
for field in info.fields:
print(f" {field.path} ({', '.join(field.types)}) freq={field.frequency:.0%}")