Context Engineering with SQL: How Streaming Databases Power Smarter AI

Context Engineering with SQL: How Streaming Databases Power Smarter AI

·

13 min read

Introduction

Your AI agent just recommended a product that the customer returned last week. The support chatbot apologized for a shipping delay that was resolved two days ago. The fraud model flagged a transaction as suspicious based on an address the user updated yesterday. All three failures share the same root cause: stale context.

Context engineering is the discipline of assembling the right information, at the right time, into an LLM's prompt. A context engineering database, one that maintains fresh, structured data for AI prompts continuously, determines whether your system gives a helpful answer or a confidently wrong one. As production AI scales, the gap between "works in demo" and "works in production" almost always comes down to how fresh and well-structured the context is.

This article shows how a streaming database like RisingWave turns context engineering from a brittle, batch-driven pipeline into a set of SQL-defined materialized views that stay fresh automatically. You will see concrete SQL patterns for building unified customer profiles, live ML features, and always-current knowledge bases for retrieval-augmented generation (RAG). All SQL examples target RisingWave v2.3 and follow standard PostgreSQL-compatible syntax.

What Is Context Engineering and Why Does It Matter for AI?

Context engineering is the process of designing and optimizing the information that gets packed into an LLM's context window before each inference call. Unlike prompt engineering, which focuses on phrasing instructions, context engineering focuses on the data behind those instructions: which records to include, how fresh they need to be, and how to structure them so the model can reason over them effectively.

Why stale context degrades AI accuracy

LLMs have no memory of their own. Every piece of knowledge they use in a conversation comes from either their training data or the context window you provide. When that context window contains outdated information, the model cannot self-correct. It treats a week-old order status or a yesterday's support ticket with the same confidence as if it were current. The result is answers that sound authoritative but are factually wrong.

This matters more as AI moves from internal tools into customer-facing products. A wrong recommendation erodes trust. A chatbot that ignores a recent interaction feels broken. Stale context is the silent failure mode of production AI.

The token cost problem

Most context assembly pipelines today run on a batch schedule. Every few hours, a script pulls data from multiple databases, transforms it, and writes it to a vector store or context cache. Between runs, the context drifts further from reality.

The alternative, reprocessing everything on every request, is expensive. If you rebuild a customer profile from scratch for each API call, you pay for the full computation every time, plus the latency of querying multiple source systems. With LLM API pricing tied to token counts, stuffing oversized or redundant context into prompts drives up costs quickly.

What you need is incremental context maintenance: a system that processes only the changes in your source data and keeps a ready-to-query context representation up to date. This is exactly what streaming materialized views provide.

How Does a Streaming Database Enable Real-Time Context Engineering?

A streaming database like RisingWave continuously ingests data from sources like Kafka, PostgreSQL CDC, and MySQL CDC, then maintains SQL-defined materialized views that update incrementally as new events arrive. This architecture maps directly to the context engineering problem.

Materialized views as context building blocks

A materialized view in RisingWave is a precomputed query result that the database keeps in sync with its source data automatically. When a new order comes in, a support ticket gets resolved, or a user updates their preferences, the relevant materialized views update within seconds, not hours.

For context engineering, each materialized view represents a "context slice": a structured, always-fresh dataset ready to be pulled into an LLM prompt. You define the context shape with SQL, and the database handles the incremental maintenance.

CDC from operational databases into fresh context views

Change data capture (CDC) lets you stream changes from your operational databases (PostgreSQL, MySQL, MongoDB) into RisingWave without impacting production workloads. Instead of running expensive batch queries against your OLTP database, CDC streams only the rows that changed.

This means your context views reflect the latest state of your operational data. When a customer updates their shipping address in PostgreSQL, that change flows through CDC into RisingWave and updates every materialized view that references customer addresses, all without a manual refresh.

SQL-based: teams don't need new tools

One of the biggest barriers to better context engineering is tooling complexity. Many teams build context pipelines with a mix of Python scripts, Airflow DAGs, and custom ETL code. These pipelines are fragile, hard to test, and expensive to maintain.

With a streaming database, you define your context logic in SQL. Data engineers and ML engineers already know SQL. There is no new framework to learn, no new deployment model to manage. You write a CREATE MATERIALIZED VIEW statement, and the database handles the rest.

Example: customer context view

Here is a practical example that joins orders, support tickets, and user preferences into a single context view for a customer-facing AI agent:

-- Source: CDC from PostgreSQL operational database
CREATE SOURCE customers_cdc WITH (
    connector = 'postgres-cdc',
    hostname = 'prod-db.internal',
    port = '5432',
    username = 'rw_reader',
    password = 'secret',
    database.name = 'ecommerce',
    slot.name = 'risingwave_slot'
);

-- Tables created from CDC source
CREATE TABLE customers (
    customer_id INT PRIMARY KEY,
    name VARCHAR,
    email VARCHAR,
    tier VARCHAR,
    updated_at TIMESTAMP
) FROM customers_cdc TABLE 'public.customers';

CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    customer_id INT,
    product_name VARCHAR,
    amount DECIMAL,
    status VARCHAR,
    created_at TIMESTAMP
) FROM customers_cdc TABLE 'public.orders';

CREATE TABLE support_tickets (
    ticket_id INT PRIMARY KEY,
    customer_id INT,
    subject VARCHAR,
    status VARCHAR,
    priority VARCHAR,
    created_at TIMESTAMP,
    resolved_at TIMESTAMP
) FROM customers_cdc TABLE 'public.support_tickets';

CREATE TABLE preferences (
    customer_id INT PRIMARY KEY,
    preferred_channel VARCHAR,
    language VARCHAR,
    timezone VARCHAR,
    opt_in_marketing BOOLEAN
) FROM customers_cdc TABLE 'public.preferences';

-- Materialized view: unified customer context for AI agent
CREATE MATERIALIZED VIEW customer_context AS
SELECT
    c.customer_id,
    c.name,
    c.email,
    c.tier,
    -- Recent order summary
    COUNT(DISTINCT o.order_id) FILTER (
        WHERE o.created_at > NOW() - INTERVAL '90 days'
    ) AS orders_last_90d,
    SUM(o.amount) FILTER (
        WHERE o.created_at > NOW() - INTERVAL '90 days'
    ) AS spend_last_90d,
    MAX(o.created_at) AS last_order_date,
    -- Open support tickets
    COUNT(DISTINCT st.ticket_id) FILTER (
        WHERE st.status = 'open'
    ) AS open_tickets,
    MAX(st.subject) FILTER (
        WHERE st.status = 'open'
    ) AS latest_open_ticket_subject,
    -- Preferences
    p.preferred_channel,
    p.language,
    p.timezone
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
LEFT JOIN support_tickets st ON c.customer_id = st.customer_id
LEFT JOIN preferences p ON c.customer_id = p.customer_id
GROUP BY
    c.customer_id, c.name, c.email, c.tier,
    p.preferred_channel, p.language, p.timezone;

When your AI agent needs context for customer 42, it runs a single query:

SELECT * FROM customer_context WHERE customer_id = 42;

Expected output:

customer_idnameemailtierorders_last_90dspend_last_90dlast_order_dateopen_ticketslatest_open_ticket_subjectpreferred_channellanguagetimezone
42Jane Smithjane@example.comgold71249.952026-03-28 14:22:001Delayed shipment #8891emailenAmerica/Denver

This result is always fresh. When Jane's shipment arrives and the support ticket closes, open_tickets drops to 0 and latest_open_ticket_subject clears, with no batch job needed.

What Context Engineering Patterns Work Best with Streaming SQL?

Three patterns cover the majority of context engineering use cases in production AI systems. Each one maps naturally to streaming SQL.

Pattern 1: Unified customer profile (CDC from multiple sources)

The customer context view above is the simplest version of this pattern. In practice, customer data lives across multiple systems: a CRM, a billing platform, a product analytics tool, and a support desk. Each system has its own database.

With RisingWave, you create a CDC source for each operational database and join them in a single materialized view. The result is a 360-degree customer profile that updates continuously.

-- CDC sources from different operational systems
CREATE SOURCE crm_source WITH (
    connector = 'postgres-cdc',
    hostname = 'crm-db.internal',
    port = '5432',
    username = 'rw_reader',
    password = 'secret',
    database.name = 'crm',
    slot.name = 'risingwave_crm'
);

CREATE SOURCE billing_source WITH (
    connector = 'mysql-cdc',
    hostname = 'billing-db.internal',
    port = '3306',
    username = 'rw_reader',
    password = 'secret',
    database.name = 'billing'
);

CREATE TABLE crm_contacts (
    contact_id INT PRIMARY KEY,
    email VARCHAR,
    company VARCHAR,
    lifecycle_stage VARCHAR,
    last_activity TIMESTAMP
) FROM crm_source TABLE 'public.contacts';

CREATE TABLE billing_subscriptions (
    subscription_id INT PRIMARY KEY,
    email VARCHAR,
    plan VARCHAR,
    mrr DECIMAL,
    status VARCHAR,
    renewal_date DATE
) FROM billing_source TABLE 'billing.subscriptions';

-- Unified profile joining CRM and billing data
CREATE MATERIALIZED VIEW unified_customer_profile AS
SELECT
    cr.contact_id,
    cr.email,
    cr.company,
    cr.lifecycle_stage,
    cr.last_activity AS last_crm_activity,
    bs.plan AS current_plan,
    bs.mrr AS monthly_revenue,
    bs.status AS subscription_status,
    bs.renewal_date
FROM crm_contacts cr
LEFT JOIN billing_subscriptions bs ON cr.email = bs.email;

When your sales AI agent queries this view, it sees the latest CRM activity alongside current billing status. No stale joins. No overnight sync lag.

Pattern 2: Live feature computation for ML models

ML models in production need features that reflect current state, not yesterday's snapshot. Traditional feature stores rely on batch pipelines that compute features on a schedule. This means your fraud detection model might evaluate a transaction using features that are hours old.

Streaming SQL turns feature computation into a continuous process. Define your features as materialized views, and they update as the underlying events arrive.

-- Event stream from Kafka
CREATE SOURCE transactions WITH (
    connector = 'kafka',
    topic = 'payment.transactions',
    properties.bootstrap.server = 'kafka:9092'
) FORMAT PLAIN ENCODE JSON;

CREATE TABLE transaction_events (
    transaction_id VARCHAR,
    user_id INT,
    amount DECIMAL,
    merchant_category VARCHAR,
    country_code VARCHAR,
    event_time TIMESTAMP
) WITH (
    connector = 'kafka',
    topic = 'payment.transactions',
    properties.bootstrap.server = 'kafka:9092'
) FORMAT PLAIN ENCODE JSON;

-- Live feature vector for fraud detection
CREATE MATERIALIZED VIEW fraud_features AS
SELECT
    user_id,
    -- Spending velocity
    COUNT(*) FILTER (
        WHERE event_time > NOW() - INTERVAL '1 hour'
    ) AS txn_count_1h,
    COUNT(*) FILTER (
        WHERE event_time > NOW() - INTERVAL '24 hours'
    ) AS txn_count_24h,
    SUM(amount) FILTER (
        WHERE event_time > NOW() - INTERVAL '1 hour'
    ) AS spend_1h,
    SUM(amount) FILTER (
        WHERE event_time > NOW() - INTERVAL '24 hours'
    ) AS spend_24h,
    -- Geographic diversity
    COUNT(DISTINCT country_code) FILTER (
        WHERE event_time > NOW() - INTERVAL '24 hours'
    ) AS distinct_countries_24h,
    -- Merchant diversity
    COUNT(DISTINCT merchant_category) FILTER (
        WHERE event_time > NOW() - INTERVAL '1 hour'
    ) AS distinct_merchants_1h,
    -- Average transaction size
    AVG(amount) FILTER (
        WHERE event_time > NOW() - INTERVAL '7 days'
    ) AS avg_txn_7d
FROM transaction_events
GROUP BY user_id;

Expected output (queried for user 1001):

user_idtxn_count_1htxn_count_24hspend_1hspend_24hdistinct_countries_24hdistinct_merchants_1havg_txn_7d
1001312847.502340.0023195.42

These features update with every new transaction. When your fraud model evaluates a payment, it pulls features that reflect the user's activity up to this second, not the last batch run. RisingWave's architecture makes this possible without a separate feature store infrastructure, since the materialized view itself serves as the online feature layer.

Pattern 3: Fresh knowledge base for RAG

Retrieval-augmented generation (RAG) systems depend on having an up-to-date knowledge base. Most RAG pipelines index documents on a batch schedule: a nightly job crawls internal wikis, product docs, or knowledge articles and pushes them into a vector store. Between runs, any new or updated document is invisible to the AI.

A streaming database can maintain the "source of truth" layer that feeds your RAG pipeline. Instead of re-indexing everything, you maintain a materialized view that tracks which documents changed and need re-embedding.

-- CDC from the internal knowledge base (PostgreSQL)
CREATE SOURCE kb_source WITH (
    connector = 'postgres-cdc',
    hostname = 'kb-db.internal',
    port = '5432',
    username = 'rw_reader',
    password = 'secret',
    database.name = 'knowledge_base',
    slot.name = 'risingwave_kb'
);

CREATE TABLE articles (
    article_id INT PRIMARY KEY,
    title VARCHAR,
    body TEXT,
    category VARCHAR,
    author VARCHAR,
    published_at TIMESTAMP,
    updated_at TIMESTAMP
) FROM kb_source TABLE 'public.articles';

CREATE TABLE article_feedback (
    feedback_id INT PRIMARY KEY,
    article_id INT,
    helpful BOOLEAN,
    created_at TIMESTAMP
) FROM kb_source TABLE 'public.article_feedback';

-- Fresh knowledge base context with quality signals
CREATE MATERIALIZED VIEW rag_knowledge_base AS
SELECT
    a.article_id,
    a.title,
    a.body,
    a.category,
    a.updated_at,
    COUNT(af.feedback_id) FILTER (WHERE af.helpful = true) AS helpful_votes,
    COUNT(af.feedback_id) FILTER (WHERE af.helpful = false) AS unhelpful_votes,
    CASE
        WHEN COUNT(af.feedback_id) > 0
        THEN ROUND(
            COUNT(af.feedback_id) FILTER (WHERE af.helpful = true)::DECIMAL
            / COUNT(af.feedback_id) * 100, 1
        )
        ELSE NULL
    END AS helpfulness_score
FROM articles a
LEFT JOIN article_feedback af ON a.article_id = af.article_id
GROUP BY a.article_id, a.title, a.body, a.category, a.updated_at;

-- View to detect documents that need re-embedding
CREATE MATERIALIZED VIEW documents_needing_reindex AS
SELECT
    article_id,
    title,
    body,
    category,
    updated_at
FROM rag_knowledge_base
WHERE updated_at > NOW() - INTERVAL '1 hour';

Your embedding pipeline can poll documents_needing_reindex instead of scanning the entire knowledge base. This reduces embedding API costs dramatically because you only re-embed documents that actually changed. The rag_knowledge_base view also provides quality signals (helpfulness scores) so your retrieval layer can prioritize high-quality articles.

Comparing Batch vs. Streaming Context Engineering

DimensionBatch context pipelineStreaming SQL context (RisingWave)
Context freshnessMinutes to hours oldSeconds old
Compute costFull recomputation each runIncremental (proportional to changes)
ToolingPython + Airflow + custom ETLStandard SQL
Source integrationPeriodic queries against OLTPCDC (zero-impact on source databases)
Failure recoveryRe-run entire batchCheckpoint-based, automatic
Scaling complexityAdd more workers, tune DAGsAdd more compute nodes

The streaming approach wins on freshness and operational simplicity. The batch approach can still make sense for context that genuinely does not change often, like reference data or historical aggregations over months of data. In practice, most production AI systems benefit from a hybrid: streaming for operational context and batch for deep historical analysis.

FAQ

What is context engineering for AI?

Context engineering is the discipline of selecting, structuring, and delivering the right information into an LLM's context window for each inference call. It goes beyond prompt engineering by focusing on the data layer: ensuring the facts, user history, and domain knowledge the model receives are accurate, fresh, and relevant. Good context engineering reduces hallucinations, improves answer quality, and lowers token costs by avoiding unnecessary or stale data.

How does a streaming database differ from a vector database for context engineering?

A streaming database and a vector database serve complementary roles. A vector database stores embeddings and handles similarity search for unstructured content like documents and images. A streaming database like RisingWave maintains structured, always-fresh context (customer profiles, feature vectors, aggregated metrics) using SQL. In many production systems, the streaming database feeds the vector database by tracking which documents changed and need re-embedding, while also serving structured context directly to AI agents.

Can I use RisingWave materialized views as a feature store?

Yes. RisingWave's materialized views update incrementally as source data changes, which makes them a natural fit for online feature serving. You define features as SQL queries, and the database keeps them current. Applications query materialized views with standard SQL to retrieve feature vectors at inference time. This eliminates the need for a separate feature store system for real-time features.

How fresh is the context from a streaming materialized view?

Context freshness depends on the ingestion path. For data arriving through Kafka, materialized views typically reflect changes within one to five seconds of the event being produced. For CDC from PostgreSQL or MySQL, the latency depends on replication lag but is generally under ten seconds in a well-configured setup. This is orders of magnitude fresher than batch pipelines that run on hourly or daily schedules.

Conclusion

Context engineering determines whether your AI system gives accurate, helpful answers or confidently wrong ones. The core challenge is keeping the data behind your LLM prompts fresh, relevant, and structured, without building a fragile pipeline of batch scripts and manual orchestration.

Key takeaways:

  • Context engineering is a data problem. The quality of AI outputs depends on the freshness and relevance of the data you feed into the context window, not just how you phrase the prompt.
  • Streaming materialized views provide incremental context maintenance. Instead of recomputing everything on a schedule, a streaming database processes only the changes, keeping context fresh with sub-second latency.
  • CDC eliminates the batch bottleneck. Change data capture streams operational data into your context layer without impacting production databases or requiring expensive periodic queries.
  • SQL is the right interface for context logic. Defining context as materialized views means data engineers and ML engineers use tools they already know, with no new framework to learn.
  • Three patterns cover most use cases. Unified customer profiles, live feature vectors, and fresh RAG knowledge bases address the majority of production context engineering needs.

Ready to try this yourself? Try RisingWave Cloud free, no credit card required. Sign up here.

Join our Slack community to ask questions and connect with other stream processing developers.

Best-in-Class Event Streaming
for Agents, Apps, and Analytics
GitHubXLinkedInSlackYouTube
Sign up for our to stay updated.