Skip to content

Proposal: Data-aware, versioned prompts in Feast #7110

Open

Description

@patelchaitany

Summary

LLM applications put user data into their prompts: a customer's balance, their recent orders, their location. Feast already stores and serves that data, but it knows nothing about the prompt around it.

We'd like Feast to also hold the prompt: defined next to the features it uses, versioned like other Feast definitions, and filled with live features when an application asks for it. Feast would only build the prompt. Calling the model and running agents stay in the application, in any framework.

Problem

Today every team writes its own glue between features and prompts:

row = store.get_online_features(features=[...], entity_rows=[{"customer_id": 42}]).to_dict()
prompt = f"You are a loan advisor for {row['name'][0]}. Balance: {row['balance'][0]} ..."
  • No versions. Nobody can say which prompt produced last week's answer.
  • Drift. Training and evaluation code rebuilds the prompt differently from the live service.
  • No size control. A customer with a long history overflows the model's context window.

Who hits this: an ML engineer who already uses Feast for classic models and now builds an LLM feature on the same data, often in a regulated company such as a bank or an insurer.

Why not just application code? The hard part is the part Feast already owns: rebuilding exactly what the model saw at a past time. A fine-tuning or evaluation dataset needs each example's prompt as it would have been at that moment, which takes point-in-time features and the prompt version used then. Application code can't reproduce that reliably; Feast's registry and offline store can.

Other tools solve only half of this. LangChain, LlamaIndex and CrewAI have prompt templates, but each is tied to its framework and doesn't know the data. The MLflow Prompt Registry versions the wording, but the application still fetches and fills in every value. Feast has the data but no prompt.

The idea

A prompt is a function over feature views, stored in the Feast registry:

@prompt(sources=[customer_profile, active_loans, question], max_tokens=1500)
def loan_advisor(profile, loans, question):
    return (
        f"You are a loan advisor for {profile['first_name']}. "
        f"Credit score: {profile['credit_score']}, active loans: {loans['count']}.\n"
        f"Customer asks: {question['text']}"
    )
prompt = store.render_prompt("loan_advisor", [{"customer_id": 42, "text": "Should I take another loan?"}])
  • Versioned: feast apply saves each change as a new version, and loan_advisor@v2 pins one.
  • Filled on request: Feast reads the features and returns the text, tagged with its version. Nothing about the prompt is stored in the online store.
  • Same prompt for training: the same function runs on point-in-time features from get_historical_features.
  • Fits a token budget: when there is too much data, the least important parts are cut first, and important ones like the instructions are never cut.
  • Works with MLflow: the wording can live in the MLflow Prompt Registry (template="prompts:/loan_advisor@production"), with Feast supplying the data.
  • Any framework, any language: the result is plain text, from the Python SDK or the feature server over HTTP.

Example: bank loan assistant

A bank's assistant explains a customer's loan history and whether to take another loan. Its prompt needs current loans and credit score, the last 20 payments, and preferences from earlier conversations. With this idea:

  • the bank can answer "what did the assistant know when it gave this advice?" from the prompt version and point-in-time features;
  • the assistant only ever sees this customer's features, through Feast's access control, and never touches core banking systems;
  • prompt size stays bounded and predictable.

Questions for the community

  1. Should a prompt be written as a Python function, a template, or both?
  2. Should Feast have its own version aliases (loan_advisor@production), or leave rollout to MLflow?
  3. Should a prompt render chat messages (system, user) as well as plain text?
  4. Should prompts be their own permission resource, separate from the features they read?

References

  • #6824 — Token budgets for prompts (in review)

Activity

  1. Joystyxx commented on Nov 7, 2026

    @Joystyxx
    Contributor

    Hi @patelchaitany , this is a very important proposal. The gap between feature stores and LLM prompts is exactly where data drift and lineage problems occur.

    I have been building real-time ML pipelines using Feast for feature serving, and I have recently been working with LLM data infrastructure. Based on that experience, here are my thoughts on your questions:

    1. Python function vs. template?
      A Python function is better for the execution engine because it can handle conditional logic and token budgeting. However, the interface should allow users to define the prompt as a template inside the function, so it remains readable.

    2. Feast versioning aliases vs. MLflow?
      Feast should own the version aliases (e.g., loan_advisor@production). The core value of this proposal is that the prompt version is linked to the feature data version. If the data lineage lives in Feast, the prompt lineage must also live in Feast. MLflow can be an optional external registry, but Feast should be the source of truth for execution.

    3. Render chat messages vs. plain text?
      Render chat messages (JSON with role and content). Modern LLM APIs expect this format, and it allows Feast to handle system instructions differently from user input, which is essential for token budgeting and safety.

    4. Separate permission resource?
      Yes. A prompt should be its own permission resource. It should inherit the access controls of the features it reads, but also allow platform teams to restrict who can execute a specific prompt against sensitive feature views.

    I would be happy to help build a Proof of Concept (PoC) for the SDK implementation if the community moves forward with this design.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions