Once you’ve configured your vector database and ingested content, you can control which AI Consumers access specific knowledge base articles and refine query results using metadata filters.
A collection is a logical grouping of knowledge base articles with independent access control rules. When you ingest content via the Konnect API, assign it to a collection using the collection field in the metadata.
Example metadata structure:
{
"content": "Quarterly revenue increased 15%...",
"metadata": {
"collection": "finance-reports",
"date": "2023-10-14",
"tags": ["finance", "quarterly"],
"source": "internal"
}
}
Two independent mechanisms control which results consumers receive:
-
ACL filtering: Server restricts collections based on AI Consumer Groups
-
Metadata filtering: Clients specify criteria (tags, dates, sources) to narrow results within authorized collections
This example assumes you have already created AI Consumer Groups (finance, admin, contractor) and configured the Key Authentication Strategy for your AI Consumers.
Set the following environment variables before deploying:
-
OPENAI_API_KEY: Your OpenAI API key
-
DB_PASSWORD: Your PostgreSQL database password
Never hardcode credentials in your policy configuration. Always use environment variables or secrets.
curl -X POST https://{region}.api.konghq.com/v1/ai-gateways/{AIGatewayId}/policies \
--header "accept: application/json" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer $KONNECT_TOKEN" \
--data '
{
"type": "ai-rag-injector",
"name": "finance-db",
"display_name": "Finance DB",
"config": {
"consumer_identifier": "consumer_group",
"global_acl_config": {
"allow": [],
"deny": []
},
"collection_acl_config": {
"finance-reports": {
"allow": [
"finance",
"admin"
],
"deny": [
"contractor"
]
},
"public-docs": {
"allow": [],
"deny": []
}
},
"embeddings": {
"model": {
"name": "text-embedding-3-small",
"provider": "openai"
},
"auth": {
"header_name": "Authorization",
"header_value": "Bearer ${OPENAI_API_KEY}"
}
},
"vectordb": {
"strategy": "pgvector",
"dimensions": 1536,
"distance_metric": "cosine",
"pgvector": {
"host": "localhost",
"port": 5432,
"user": "postgres",
"password": "${DB_PASSWORD}",
"database": "kong-pgvector"
}
}
}
}
'
This configuration creates the following access rules:
-
finance-reports: Accessible only to AI Consumers in the finance or admin groups. Contractors are explicitly denied.
-
public-docs: Accessible to all AI Consumers (empty allow and deny lists).
- Other collections: No access (empty global ACL means deny by default).
The AI Policy checks access in this order:
-
Deny list: If subject matches, deny access
-
Allow list: If list exists and subject doesn’t match, deny access
-
Empty ACL: If both lists are empty, allow access
Collections with their own ACL in collection_acl_config ignore global_acl_config entirely. They must explicitly list all allowed subjects.
LLM clients can refine search results by specifying filter criteria in the query request. Filters apply within the collections. The AI RAG Injector Policy uses a Bedrock-compatible filter grammar with the following operators:
-
equals: Exact match
-
greaterThan: Greater than (>)
-
greaterThanOrEquals: Greater than or equal to (>=)
-
lessThan: Less than (<)
-
lessThanOrEquals: Less than or equal to (<=)
-
in: Match any value in array
-
andAll: Combine multiple filter clauses
You can combine multiple conditions with andAll:
{
"andAll": [
{"equals": {"key": "source", "value": "internal"}},
{"in": {"key": "tags", "value": ["finance", "quarterly"]}},
{"greaterThanOrEquals": {"key": "date", "value": "2023-01-01"}}
]
}
Filter parameters:
|
Parameter
|
Description
|
filters
|
JSON object with filter clauses using the grammar above
|
filter_mode
|
Controls how chunks with no metadata are handled:
• "compatible": Includes chunks matching filter OR chunks with no metadata
• "strict": Includes only chunks matching filter
|
stop_on_filter_error
|
Fail query on filter parse error (default: false)
|
You can include filters in the ai-rag-injector parameter of your request:
curl "http://localhost:8000/" \
-H "Content-Type: application/json" \
--json '{
"messages": [
{
"role": "user",
"content": "What were Q4 results?"
}
],
"ai-rag-injector": {
"filters": {
"andAll": [
{
"equals": {
"key": "source",
"value": "internal"
}
},
{
"in": {
"key": "tags",
"value": [
"q4",
"quarterly"
]
}
}
]
},
"filter_mode": "strict",
"stop_on_filter_error": false
}
}'
The following diagram shows how ACL and metadata filtering work together during query processing:
flowchart TB
Start([Query Request]) --> Auth[Authenticate AI Consumer]
Auth --> CheckACL{Authorized
Collections?}
CheckACL -->|No| Deny[❌ Access Denied]
CheckACL -->|Yes| HasFilter{Metadata
Filters
Specified?}
HasFilter -->|No| SearchAll[Search all chunks
in authorized collections]
HasFilter -->|Yes| FilterMode{filter_mode
setting?}
FilterMode -->|compatible| SearchCompat[Return chunks matching filter
OR chunks with no metadata]
FilterMode -->|strict| SearchStrict[Return only chunks
matching filter]
SearchAll --> Return[✓ Return Results]
SearchCompat --> Return
SearchStrict --> Return