,

Azure Prompt Flow, Authoring to Evaluation to Deploy (Azure Gen AI Series, Part 15)

Prompt Flow now carries a retirement date. Here is how it works, when it still earns a place in your Azure pipeline, and where to build new instead.

Azure Gen AI Series · Part 15 of 30

Prompt Flow has a retirement date. Microsoft set it at April 20, 2027, and flagged the tool as no longer recommended for new development, with a migration path to the Microsoft Agent Framework. I still open it most weeks, because the flows I shipped last year run in production and are not going anywhere before that date. So this part is two things at once: how the tool works, and an honest read on where it still belongs now that the clock is running.

Status, July 2026: Prompt Flow now appears as Prompt Flow (classic) in Microsoft Foundry and Azure Machine Learning. Microsoft has published an end of support date of April 20, 2027 and advises moving existing flows to the Microsoft Agent Framework before then. The tool is fully usable today. Treat it as maintain-and-migrate, not build-new. Pin your promptflow package version and watch the migration guide.
Key takeaways: A flow is a directed graph of nodes described in a single flow.dag.yaml file. Nodes are tools: LLM and Prompt nodes use Jinja2 templates, Python nodes run your code, and secrets live in named connections, not in the graph. Variants let you A or B test a prompt inside one node. Evaluation flows score a batch run and give you numbers instead of vibes. A deployed flow becomes an HTTP endpoint. All of that still works, and none of it is where I would start a new project in mid 2026.

What Prompt Flow is

Prompt Flow is a development tool for building applications on top of large language models. It gives you a way to chain a prompt, a model call, and your own code into one pipeline, run that pipeline on a single input or a whole test set, and score the results. It shows up in three surfaces: an open-source Python package called promptflow with a command line named pf, a Visual Studio Code extension with a visual graph editor, and a hosted authoring experience inside Microsoft Foundry and Azure Machine Learning. Same flow definition underneath all three.

The unit you work with is a flow. A flow is a directed acyclic graph, which means nodes connected by arrows that never loop back. Each node does one job and passes its output to the next. The whole graph, its inputs, its outputs, its nodes, and the connections they use, lives in one YAML file named flow.dag.yaml. That file is the source of truth. The visual editor and the portal both read and write it, so you can hand-edit the YAML or drag boxes and get the same result. If you called an Azure model from code back in Part 11, a flow is that same call wrapped in a graph that you can test and score without writing the harness yourself.

A flow is a graph of nodesEach node is a tool; output flows left to right into the next nodeInputsquestionPrompt nodeJinja2 templateLLM nodemodel callPython nodepost-processOutputsanswer
The whole graph lives in flow.dag.yaml. The editor and the portal both read and write that one file.
Who this is for: You have deployed an Azure OpenAI or Foundry model and called it from code. You have not built a flow before and you do not need any MLOps background. By the end you will know how a flow is structured, how to author and score one, and whether to put new work here at all. If you have not deployed a model yet, start with Part 3. If you are weighing Prompt Flow against the newer agent runtime, read it next to Part 13.

How a flow is put together

Four ideas carry the whole tool: tools, connections, inputs and outputs, and variants. A tool is the kind of work a node does. The three you use constantly are the LLM tool, which calls a chat or completion model with a templated prompt; the Prompt tool, which builds prompt text to hand to another node; and the Python tool, which runs a function you wrote for anything the model cannot do, such as parsing JSON, calling an internal API, or shaping the final answer. LLM and Prompt nodes are written as Jinja2 templates, so the prompt text sits in its own file with placeholders. Python nodes are plain Python files with a decorated entry function.

A connection is where secrets go. Rather than pasting an endpoint and key into the graph, you create a named connection once, an Azure OpenAI connection for example, and each LLM node references it by name and names the model in a deployment_name field. This is the part I appreciate most, because it keeps keys out of the YAML and out of source control. The same pattern wires a Content Safety node to the service I covered in Part 14, so a moderation check becomes one more node in the graph instead of a separate service call you bolt on by hand.

Inputs and outputs define the contract. Flow inputs are the fields you feed in, a question string say, and flow outputs are the fields you read back, referenced from a node output with the dollar-brace syntax. Variants are the last idea and the reason people stick with the tool longer than they planned. A variant is an alternate version of a Prompt or LLM node, a different prompt or a different temperature, stored side by side in the same flow. You run all variants over the same data and compare. That turns prompt tuning from guesswork into a table you can read.

ToolWhat the node doesWritten in
LLM toolCalls a chat or completion model with a templated promptJinja2
Prompt toolBuilds prompt text to pass to another nodeJinja2
Python toolRuns your own logic for parsing, routing, or post-processingPython
Content SafetyScreens text through Azure AI Content Safetyconnection
EmbeddingTurns text into vectors for a lookupconnection
Index LookupRetrieves passages from a vector index for RAGconnection

Should you still build on Prompt Flow?

My answer is no for anything green-field, and a firm yes for maintenance. If you already run flows, keep running them. They will work until April 2027 and the migration guidance is not a same-week emergency. But for a project starting today, building on a tool with a published sunset means you inherit a rewrite. The place Microsoft points new agent work is the Foundry Agent Service and the Microsoft Agent Framework, which is exactly the runtime I walked through in Part 13.

There is one real exception. The evaluation half of Prompt Flow, batch runs and scored metrics, is genuinely useful and has a longer life outside the graph editor through the Azure AI Evaluation SDK, which I cover properly in a later part. So the honest split is this: skip Prompt Flow as an orchestration layer for new builds, but do not skip the discipline it teaches, which is scoring a change on a fixed test set before you ship it. That habit outlives the tool.

My take

AWS never had a Prompt Flow equivalent that tried to be both a visual orchestrator and an eval harness in one. Bedrock split those jobs, Prompt Management and Flows on one side, model evaluation on the other, which I wrote up in the AWS series. Watching Microsoft now peel evaluation out of Prompt Flow and fold orchestration into the Agent Framework, the two clouds are converging on the same shape. The visual all-in-one flow tool was a phase, not a destination.

Author a two-node flow

Here is the smallest flow worth running: one LLM node that answers a support question, with the prompt in a Jinja2 file. First the graph. This is the full flow.dag.yaml.

inputs:
  question:
    type: string
outputs:
  answer:
    type: string
    reference: ${answer_node.output}
nodes:
- name: answer_node
  type: llm
  source:
    type: code
    path: answer.jinja2
  inputs:
    deployment_name: gpt-4o
    temperature: 0.2
    question: ${inputs.question}
  connection: aoai_connection
  api: chat

The prompt itself sits in answer.jinja2, with system and user roles marked as plain text sections:

system:
You answer product support questions in one short paragraph.
If you are unsure, say so plainly.

user:
{{question}}

Create the connection once, then test the flow on a single input from the command line:

pip install promptflow promptflow-tools

pf connection create --file aoai.yaml --name aoai_connection

pf flow test --flow . --inputs question='How do I reset my password?'

Expected output is a small JSON object keyed by your flow output name:

{
    'answer': 'Open Settings, choose Security, then select Reset password and follow the emailed link.'
}

Failure mode: if the connection name in the YAML does not match a connection you created, pf raises a connection not found error before any token is spent. Create the connection first, confirm it with pf connection list, then rerun. A second common trip is a deployment_name that does not exist in the linked Azure OpenAI resource, which surfaces as a 404 from the model call, not a flow error. The pf sub-commands have shifted slightly across promptflow releases, so pin the version. [VERIFY: pf command names against your installed promptflow version]

Variants and how I test prompts

The reason I reach for a flow rather than a raw script is the variant loop. On that single answer_node I can define variant_0 as the terse prompt at temperature 0.7, variant_1 as the same prompt with a formatting rule added at temperature 0.2, and variant_2 with two worked examples baked into the system message. All three live in the same flow. I run each over the same test set and read the scores side by side instead of eyeballing a handful of replies and guessing which prompt is better.

The sample below is one run of exactly that, three variants scored on a groundedness metric from 1 to 5. The lift from variant_0 to variant_2 is the kind of gap you cannot see by reading ten answers, but it jumps out once you plot it. This is illustrative, not a benchmark of the models themselves. [AUTHOR: add anecdote about a variant that scored well but felt worse in production]

Groundedness by variantSample evaluation run, score 1 to 5, higher is better12345variant_03.4variant_14.2variant_24.6
Same node, three prompts, one metric. Variant_2 wins on groundedness in this sample run.

Evaluation flows and metrics

An evaluation flow is a second flow whose job is to score the first one. It takes the outputs of a batch run and, row by row, produces a metric: groundedness against a context, relevance to the question, similarity to a reference answer, or a pass or fail from a rule you write in a Python node. You run your main flow over a data file to get answers, then run the evaluation flow over those answers to get numbers. The batch run and the eval run are separate commands, which feels like one step too many at first and turns out to be the right seam once you have more than one metric.

Run the batch and evaluation from the command line against a JSONL data file with a column mapping that tells the flow which column feeds which input:

pf run create --flow . --data ./questions.jsonl 
  --column-mapping question='${data.question}' 
  --name base_run --stream

pf run create --flow ./eval_groundedness --data ./questions.jsonl 
  --run base_run 
  --column-mapping answer='${run.outputs.answer}' context='${data.context}' 
  --name eval_run --stream

The eval run prints an aggregate metric per variant, which is what feeds the comparison table below. The number that matters is not the top score, it is the gap between variants on the same data. A prompt that reads better to you is worth nothing if it does not move the metric on your own examples.

Worked example

Take a 200-row test set of real support questions, each with a reference context. Run all three variants, then score with a pass rule: an answer passes if groundedness is 4 or higher. Variant_0 passes 142 of 200, which is 71 percent. Variant_1 passes 172, which is 86 percent. Variant_2 passes 182, which is 91 percent. Those three pass rates are the second chart below. The jump from 71 to 86 percent came purely from a formatting rule and a lower temperature, no model change and no extra tokens at inference. That is the cheapest 15 points you will find.

Pass rate on the 200-row setPercent of answers scoring groundedness 4 or higher0255075100variant_071variant_186variant_291
The 71, 86, and 91 percent pass rates from the worked example, plotted against a 0 to 100 axis.
VariantPrompt changeTempGroundednessPass rate
variant_0terse instruction, no format rule0.73.471%
variant_1added a one-paragraph format rule0.24.286%
variant_2added two worked examples0.24.691%

Tracing a flow run

When a flow returns a wrong answer, the useful question is which node went wrong, not which prompt looks off. Prompt Flow records a trace for every run. Each node shows its inputs, its output, the tokens it spent, and how long it took. Local pf runs open that trace in a browser view, and each batch run in the portal keeps the same per-node detail. I lean on this more than any other feature, because it turns a vague bad output into one specific node I can fix.

Two habits pay off. Read the LLM node output before you read the Python node that parses it, because most failures I chase are a model that returned prose where the next node expected JSON, not a bug in the parser. And watch the token count per node across a batch, since one wordy variant can double your spend without moving the score at all. The trace puts cost and quality on the same screen, so tuning one stops hiding what it does to the other.

In practice: Before you compare two variants on quality, sort the trace by tokens per row. I have watched a variant win on groundedness by 0.3 while costing 40 percent more tokens per answer. On a low-volume tool that trade is fine. On a hot path it is the wrong pick, and the metric alone would have hidden it.

From local flow to an endpoint

Once a flow behaves and scores well, you deploy it and it becomes an HTTP endpoint. In Azure that is a managed online endpoint: the flow, its connections, and a scoring script get packaged and hosted behind a URL your app calls with the flow inputs as JSON. You pick the compute size, the endpoint scales within the limits you set, and you pay for the compute while it runs plus the model tokens each call spends. The connections you used locally must exist in the workspace you deploy to, which is the single most common reason a flow that ran clean on a laptop returns a 500 in the cloud.

Gotcha: a managed online endpoint holds compute whether or not anyone calls it. Unlike the serverless model calls from earlier parts, a deployed flow on a dedicated instance bills for the instance around the clock. For a low-traffic internal tool this can cost more than the model usage it serves. Check whether a scheduled batch run or a scale-to-zero option fits before you stand up an always-on endpoint.

Before you deploy to production: deploy first to a test endpoint, send the same 200-row set through the live URL, and confirm the scores match your local run before you point real traffic at it. Verify every connection exists in the target workspace, and keep the previous deployment live until the new one passes, so a rollback is one traffic switch rather than a redeploy.

Maintain what you have, build new on Agent Framework

Here is where I land after a year of running flows in production. Keep the ones you have; they are stable and the April 2027 date is far enough out that a rushed migration would cost you more than it saves. Use the variant-and-evaluate loop on every prompt change you make, in Prompt Flow or out of it, because scoring on a fixed set is the habit that actually moves quality. But do not start a new orchestration project here. Put new agent work on the Foundry Agent Service from Part 13, and carry the evaluation discipline over with you.

If you have an existing flow, do one thing this week: run it over a 200-row set and record the score. That single number is your baseline for the migration, and you will want it the day you rebuild the flow on the newer runtime. Next in the series is Part 16, fine-tuning Azure OpenAI, where the question shifts from shaping the prompt to changing the model itself.

Azure Gen AI Series · Part 15 of 30
« Previous: Part 14  |  Guide  |  Next: Part 16 »

References

About The Author


Discover more from Journal of Intelligent Infrastructure – By Dr Pranay Jha

Subscribe to get the latest posts sent to your email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Architect’s Toolkit

About the Author

Dr. Pranay Jha is a Cloud and AI Consultant with 18+ years of experience in hybrid cloud, virtualization, and enterprise infrastructure transformation. He specializes in VMware technologies, multi-cloud strategy, and Generative AI solutions. He holds a PhD in Computer Applications with research focused on Cloud and AI, has published multiple research papers, and has been a VMware vExpert since 2016 and a VMUG Community Leader.

Discover more from Journal of Intelligent Infrastructure - By Dr Pranay Jha

Subscribe now to keep reading and get access to the full archive.

Continue reading