Dashboard Part 2 Optimize & Operationalize
🤖 Part 2 · Topic 3 of 3

Optimize & Operationalize GenAI Solutions

Making your GenAI solution production-ready. This topic covers generation parameters that control model behaviour, prompt engineering techniques for better responses, fine-tuning vs RAG tradeoffs, quota and throughput management, monitoring and tracing, and orchestrating multiple AI models together.

🐍 Python — every line explained ⏱️ ~45 min 🔥 High exam weight Requires Topics 1 & 2 (Part 2)
🔗
Building on Topics 1 & 2

Uses: token, LLM, deployment name, messages array, chat.completions.create(), RAG, Prompt Flow, evaluation metrics. New concepts introduced below before any code.

Optimisation and operationalisation terms

Temperature

A parameter (0.0 to 2.0) that controls how random or deterministic the model's output is. Low temperature (0.0–0.3) = more predictable, consistent responses. High temperature (0.8–2.0) = more creative, varied, sometimes unexpected responses. For factual tasks, use low temperature.

top_p (nucleus sampling)

An alternative to temperature. Controls output diversity by limiting the model to tokens that collectively represent the top P% of probability mass. 0.1 = very focused, 1.0 = all tokens considered. Use temperature OR top_p — not both simultaneously.

max_tokens

The maximum number of tokens the model can generate in its response. Does not affect input tokens. Setting this too low cuts off the response mid-sentence. Setting it too high wastes tokens (you pay for unused capacity).

frequency_penalty

A value from -2.0 to 2.0 that penalises the model for using words it has already used in the response. Positive values (0.5–1.0) reduce repetition — the model is less likely to repeat the same phrases. Useful for longer outputs.

presence_penalty

Similar to frequency_penalty but penalises any word that has appeared at all (not based on frequency). Encourages the model to introduce new topics and vocabulary. Useful for open-ended creative tasks.

stop (stop sequences)

A list of strings that, when generated, cause the model to stop. For example: stop=["###"] — if the model outputs "###" it stops immediately. Useful for structured outputs where you want the model to stop at a specific boundary marker.

TPM — Tokens Per Minute

The quota limit for Azure OpenAI — the maximum number of tokens your deployment can process per minute. Exceeding TPM returns HTTP 429 (Too Many Requests). You can set TPM per deployment and request quota increases from Microsoft.

PTU — Provisioned Throughput Units

A reserved capacity unit for Azure OpenAI. Instead of pay-per-token, you reserve a fixed number of PTUs that guarantee consistent throughput. More expensive upfront but no throttling. Best for predictable high-volume production workloads.

Fine-Tuning

Training a pre-existing model on your own dataset to make it better at a specific task or to adopt a specific writing style. Different from RAG — fine-tuning changes the model's weights permanently, while RAG provides context at query time. Fine-tuned models are also more expensive to run.

Zero-Shot Prompting

Asking the model to perform a task without providing any examples. Just a clear instruction: "Classify this email as spam or not spam." Works well for tasks the model already understands from training.

Few-Shot Prompting

Providing 2–5 examples of the task in the prompt before the actual question. The model learns the pattern from the examples and applies it. More reliable than zero-shot for specialised formats or unusual tasks.

Chain-of-Thought Prompting

Instructing the model to "think step by step" before giving its final answer. This dramatically improves accuracy on complex reasoning tasks like maths, logic, and multi-step problems. The model externalises its reasoning process.

Tracing

Recording the complete execution path of a Prompt Flow or multi-model pipeline — every step, every input, every output, every duration. Used for debugging, performance analysis, and cost attribution. Enabled in Foundry via Application Insights.

Model Reflection

A pattern where the model evaluates its own output and iteratively improves it. The model generates an answer, then critiques that answer, then revises it based on the critique. Can produce higher-quality outputs than a single generation pass.

Orchestration

Coordinating multiple AI models or services to work together in a pipeline. For example: GPT-4o summarises a document → Azure AI Language extracts key entities → another GPT model generates a report. Each model is specialised; orchestration combines them.

Controlling how the model generates text

Every call to the Chat Completions API can include optional parameters that change how the model generates its response. The exam tests whether you know which parameter to use for which problem.

🎚️
Analogy — A music mixing board

Think of the generation parameters as sliders on a mixing board. Temperature is the "creativity" dial — turn it up for jazz improvisation, turn it down for playing classical sheet music exactly. max_tokens is the track length limit. frequency_penalty is the "no repeating yourself" dial. stop sequences are the track markers where recording stops.

Temperature — the most important parameter

Temperature ValueBehaviourBest for
0.0Fully deterministic — same prompt always gives the same answerFactual Q&A, classification, extraction tasks where consistency is critical
0.1 – 0.3Very focused, slightly variedTechnical writing, code generation, structured summaries
0.7Balanced (Azure's default) — natural and somewhat variedGeneral conversation, customer service
1.0 – 1.5Creative and varied outputsMarketing copy, brainstorming, creative writing
2.0Very random — may become incoherentRarely used in production — experimental only

All parameters in a single Python call

import os
from openai import AzureOpenAI

client = AzureOpenAI(
    azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT"),
    api_key        = os.environ.get("AZURE_OPENAI_KEY"),
    api_version    = "2024-02-01"
)

response = client.chat.completions.create(
    model    = "my-gpt4o",
    messages = [
        {"role": "system", "content": "You are a product description writer."},
        {"role": "user",   "content": "Write a product description for wireless headphones."}
    ],

    # ── Generation control parameters ────────────────────────────────────

    temperature       = 0.8,
    # 0.8 = moderately creative (good for marketing copy)
    # Range: 0.0 (deterministic) to 2.0 (very random)
    # Use EITHER temperature OR top_p — not both

    max_tokens        = 300,
    # Maximum tokens in the response
    # Response is cut off if it reaches this limit
    # Does NOT include input tokens — just output

    frequency_penalty = 0.5,
    # Reduces repetition of words already used in the response
    # Range: -2.0 to 2.0  |  0 = no penalty  |  positive = less repetition

    presence_penalty  = 0.3,
    # Encourages new topics/vocabulary
    # Range: -2.0 to 2.0  |  0 = no penalty  |  positive = more novelty

    stop              = ["###", "END"],
    # Stop generating if the model outputs "###" or "END"
    # Useful for structured outputs with known end markers

    n                 = 1,
    # Number of response alternatives to generate
    # n=1 is standard. n=3 generates 3 different responses — you choose the best
    # Higher n costs proportionally more tokens
)

answer = response.choices[0].message.content
print(answer)
🎯
Exam Tip — Parameter Scenario Questions

"Outputs are inconsistent for the same question — sometimes accurate, sometimes not." → Lower temperature (towards 0.0) for more consistency.

"The model keeps repeating the same phrases." → Increase frequency_penalty

"Responses are getting cut off before completing." → Increase max_tokens

"Need the model to stop generating after producing a JSON object." → Use stop sequences — e.g. stop=["```"]

Getting better responses through better prompts

Prompt engineering is the practice of crafting prompts that reliably produce the outputs you want. These are the techniques the exam tests.

1. Zero-Shot Prompting
When: the task is straightforward and the model understands it from training

No examples provided — just a clear instruction. Works for well-understood tasks. Fast and simple but may not produce the exact format you need.

System: You are a sentiment classifier.
User: Classify this review as positive, negative, or neutral: "The product arrived on time but the packaging was damaged."
Assistant: Neutral
2. Few-Shot Prompting
When: you need a specific format, style, or behaviour the model might not infer from zero-shot

You include 2–5 example input/output pairs in the prompt. The model learns the pattern and applies it to the new input. More reliable for structured or unusual output formats.

System: You extract key information from customer complaints in JSON format.
User: Examples:
Input: "My order #12345 hasn't arrived after 3 weeks."
Output: {"order_id": "12345", "issue": "delayed delivery", "urgency": "high"}

Input: "The item in order #99001 was broken when I opened it."
Output: {"order_id": "99001", "issue": "damaged item", "urgency": "medium"}

Now process: "I never received my order #55555 from last month."
3. Chain-of-Thought (CoT) Prompting
When: the task involves complex reasoning, maths, logic, or multi-step analysis

Add "Think step by step" or "Let's reason through this" to the prompt. The model externalises its reasoning before giving a final answer. Dramatically improves accuracy on reasoning tasks.

User: A company has 3 servers. Each server processes 150 requests/minute. If traffic increases by 40%, how many servers will be needed? Think step by step before giving your answer.

Assistant: Let me work through this step by step.
Step 1: Current capacity = 3 × 150 = 450 req/min
Step 2: New traffic = 450 × 1.40 = 630 req/min
Step 3: Servers needed = 630 ÷ 150 = 4.2 → round up to 5
Answer: 5 servers
4. System Prompt Engineering
When: you need consistent persona, tone, constraints, or output format across all interactions

The system message is the most powerful control you have over the model. A well-crafted system message defines: persona, tone, knowledge scope, output format, what to refuse, and how to handle edge cases.

System message (well-engineered):
"You are a financial advisor assistant for Contoso Bank. Rules: (1) Only answer questions about Contoso Bank products. (2) Never speculate about stock prices or investment returns. (3) Always end with 'For personalised advice, speak with a Contoso advisor.' (4) If asked about competitor products, politely decline and focus on Contoso offerings. (5) Format responses as bullet points when listing features."
5. Meta-Prompting
When: you want the model to help you write a better prompt

Ask the model to help design the prompt itself: "Write a system prompt for an AI that helps CIBC customers track their spending." The model generates a prompt you then use in your application.

User: Write a detailed system prompt for an AI assistant that helps hospital nurses document patient observations efficiently and accurately, following medical documentation standards.

When to fine-tune a model and how it works

Fine-tuning customises a pre-trained model by training it further on your own dataset. The model's internal weights are updated to make it better at specific tasks or to adopt a specific writing style or domain knowledge.

Fine-tuning vs RAG — the most important decision

Decision factorUse RAGUse Fine-Tuning
GoalGround responses in specific, up-to-date documentsTeach the model a new style, format, or domain-specific behaviour
Data freshnessDocuments can be updated without retrainingModel must be retrained when data changes
Factual accuracyHigh — answers traced to source documentsLower — model may still hallucinate even after fine-tuning
CostLower upfront, per-query retrieval costTraining cost + higher inference cost (fine-tuned models cost more per token)
When to useEnterprise Q&A, document search, any use case where data changes regularlyTeaching specific tone/format, simplifying prompts, consistent output structure
🎯
Exam Tip — Fine-Tuning vs RAG Decision

"A company wants the AI to answer questions using their current product catalogue, which updates weekly."RAG — data changes frequently, fine-tuning every week is impractical.

"A company wants the AI to always respond in their brand's unique tone and use their specific terminology, without needing a long system prompt every time."Fine-Tuning — teaching style and format is what fine-tuning is for.

"A company needs their AI to avoid making factual errors about competitors."RAG — fine-tuning doesn't eliminate hallucination; grounding does.

Fine-tuning training data format

Azure OpenAI fine-tuning requires training data in JSONL format (one JSON object per line). Each object is a conversation with system, user, and assistant messages — showing the model the style of response you want.

# Fine-tuning training data format — JSONL (JSON Lines)
# Each line is one training example — a complete conversation
# The model learns to respond to "user" messages the way "assistant" does in your examples

# Line 1: training example 1
{"messages": [
    {"role": "system",    "content": "You are a concise technical support agent."},
    {"role": "user",      "content": "My printer won't connect to WiFi."},
    {"role": "assistant", "content": "Try: 1) Restart router. 2) Forget and rejoin network. 3) Update printer firmware."}
]}

# Line 2: training example 2
{"messages": [
    {"role": "system",    "content": "You are a concise technical support agent."},
    {"role": "user",      "content": "I can't login — password reset email not arriving."},
    {"role": "assistant", "content": "Check spam folder. Whitelist noreply@company.com. Try alternate email if registered."}
]}

# Minimum: 10 training examples (recommended: 50-100+)
# More examples = better fine-tuning results
# Upload this file to Foundry: your project → Fine-tuning → + New fine-tune job

Managing scale and avoiding throttling

💡
TPM vs PTU — Plain English

TPM (Tokens Per Minute) is like a tap with a flow rate limit. You can use as much water (tokens) as you want, but only up to the rate limit. If you try to use more, you get throttled (HTTP 429) until the next minute resets your allowance.

PTU (Provisioned Throughput Units) is like paying to have a dedicated pipe installed. Your pipe is always available — no sharing, no throttling. But you pay for the pipe whether you use it or not.

Standard (TPM-based)Provisioned Managed (PTU)
BillingPay per token usedFixed hourly cost regardless of usage
ThroughputVariable — may throttle at peakGuaranteed consistent throughput
ThrottlingYes — HTTP 429 if TPM exceededNo throttling — reserved capacity
Best forVariable/unpredictable traffic, dev/testProduction workloads with predictable high traffic
Minimum commitmentNoneMinimum 1 hour reservation

Handling HTTP 429 (throttling) in Python

New Python concept: try/except — a way to handle errors gracefully instead of crashing. Explained fully in comments.

import os, time
from openai import AzureOpenAI, RateLimitError

client = AzureOpenAI(
    azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT"),
    api_key        = os.environ.get("AZURE_OPENAI_KEY"),
    api_version    = "2024-02-01"
)

# New concept: try/except ────────────────────────────────────────────
# "try:" — attempt to run this code
# "except SomeError:" — if THIS specific error occurs, run this instead
# This prevents your program from crashing when an error happens
# It's like a safety net — "try this, but if it fails, do that"

MAX_RETRIES = 3   # How many times to retry before giving up

for attempt in range(MAX_RETRIES):   # range(3) = [0, 1, 2] — loops 3 times
    try:
        # Try to call the API
        response = client.chat.completions.create(
            model    = "my-gpt4o",
            messages = [{"role": "user", "content": "Explain quantum computing simply."}]
        )
        # If the call succeeded, print the result and break out of the loop
        print(response.choices[0].message.content)
        break    # "break" exits the loop immediately — success!

    except RateLimitError as e:
        # RateLimitError happens when we exceed our TPM quota (HTTP 429)
        # "as e" gives us access to the error details
        if attempt < MAX_RETRIES - 1:   # If this isn't our last attempt...
            wait_seconds = 2 ** attempt    # Exponential backoff: 1s, 2s, 4s
            print(f"Rate limited. Waiting {wait_seconds}s before retry {attempt+1}...")
            time.sleep(wait_seconds)      # time.sleep() pauses the program for N seconds
        else:
            # We've used all our retries — give up and report the error
            print(f"Failed after {MAX_RETRIES} attempts: {e}")

Keeping your GenAI solution healthy in production

From Part 1 Topic 4 you know Azure Monitor and Application Insights. GenAI solutions add additional monitoring needs specific to LLM behaviour.

Key metrics to monitor for GenAI

🔢
Token Usage

Prompt tokens + completion tokens = total cost. Monitor to detect runaway prompts (huge inputs) or verbose outputs driving up costs. Available in response.usage.

⏱️
Latency

Time from request sent to first token received (TTFT — Time to First Token) and total response time. GPT-4o is slower than GPT-3.5-turbo. Monitor to detect degradation.

Error Rate

429 (throttling), 400 (bad request), 500 (service error). Spikes in 429s indicate you need more TPM or should switch to PTU.

User Feedback

Thumbs up/down ratings from users on AI responses. Collect these to identify which query types perform poorly and guide further prompt or RAG improvements.

Enabling tracing in Foundry

Tracing records the complete execution of a Prompt Flow — every node, every input/output, every duration. This is invaluable for debugging.

1
Connect Application Insights to your Foundry project

ai.azure.com → your project → Settings → Tracing → Connect an Application Insights resource → Save.

2
Enable tracing on your flow

Open your Prompt Flow → Run settings → Enable Tracing. Every run now records complete node-by-node telemetry.

3
View traces in Application Insights

Azure portal → Application Insights → Investigate → Transaction search → Find your flow runs. See each node, its inputs, outputs, and duration in a waterfall view.

Self-improvement and multi-model pipelines

Model Reflection — the model critiques itself

Model Reflection is a pattern where you ask the model to generate a response, then ask it to critique that response, then generate an improved version. This iterative loop produces higher quality outputs than a single generation pass.

import os
from openai import AzureOpenAI

client = AzureOpenAI(
    azure_endpoint=os.environ.get("AZURE_OPENAI_ENDPOINT"),
    api_key=os.environ.get("AZURE_OPENAI_KEY"),
    api_version="2024-02-01"
)
MODEL = "my-gpt4o"

# ── Step 1: Generate initial response ─────────────────────────────────
user_task = "Write a 3-sentence summary of quantum computing for a non-technical audience."

initial = client.chat.completions.create(
    model    = MODEL,
    messages = [{"role": "user", "content": user_task}]
)
initial_response = initial.choices[0].message.content
print(f"INITIAL:\n{initial_response}\n")


# ── Step 2: Ask the model to critique its own response ────────────────
# We include the initial response in the conversation history
# so the model can see what it generated and evaluate it
critique = client.chat.completions.create(
    model    = MODEL,
    messages = [
        {"role": "user",      "content": user_task},
        {"role": "assistant", "content": initial_response},  # The initial response
        {"role": "user",      "content": "Critique this response. Is it accurate? "
                                          "Is it truly non-technical? What could be improved?"}
    ]
)
critique_text = critique.choices[0].message.content
print(f"CRITIQUE:\n{critique_text}\n")


# ── Step 3: Generate improved response based on the critique ──────────
improved = client.chat.completions.create(
    model    = MODEL,
    messages = [
        {"role": "user",      "content": user_task},
        {"role": "assistant", "content": initial_response},
        {"role": "user",      "content": "Critique: " + critique_text},
        {"role": "user",      "content": "Now write an improved version addressing the critique."}
    ]
)
improved_response = improved.choices[0].message.content
print(f"IMPROVED:\n{improved_response}")

Orchestration — multiple models working together

Real enterprise AI solutions often combine multiple models and services, each doing what it does best. The exam tests understanding of when to combine models and how.

💡
Example Multi-Model Pipeline — Customer Support

Step 1 — Whisper (Azure OpenAI): Transcribe the customer's voice call to text.

Step 2 — Azure AI Language: Extract intent (complaint/enquiry/cancellation) and key entities (account number, product name) from the transcript.

Step 3 — Azure AI Search (RAG): Retrieve relevant policy documents based on the intent.

Step 4 — GPT-4o: Generate a personalised, grounded response for the agent to read to the customer.

Step 5 — Azure AI Content Safety: Screen the generated response before delivery.

Each model is specialised. Prompt Flow orchestrates all 5 steps.

Optimisation — what the exam specifically tests

⚠️
Top 6 Tested Facts from This Topic

1. Temperature 0 = deterministic — Same prompt always gives same output. For factual tasks requiring consistency, use temperature 0.

2. Use temperature OR top_p — not both — They are alternatives. Microsoft recommends altering one but not both simultaneously.

3. Fine-tuning does NOT eliminate hallucination — Fine-tuning teaches style and format, not facts. For factual accuracy, use RAG.

4. Fine-tuning JSONL format — Training data must be in JSONL with messages arrays (system + user + assistant). Minimum 10 examples.

5. PTU for production, TPM for dev — If a scenario mentions "predictable high traffic" or "no throttling" → PTU (Provisioned). If it mentions "variable traffic" or "cost optimisation" → Standard TPM.

6. Chain-of-thought for complex reasoning — Add "think step by step" to any maths, logic, or multi-step analysis task. This dramatically improves accuracy and is directly tested.

Test your understanding

5 questions — select an answer to see the explanation immediately.

Topic 3 Quiz — Optimize & Operationalize 1 / 5
Scenario: A developer notices that their customer service chatbot gives slightly different answers every time the same question is asked. One response says "The return window is 30 days", the next says "You have up to 4 weeks to return items." Both are technically correct but inconsistent, which is confusing users.

Which parameter change will most effectively make responses consistent?

💡 Explanation

B is correct. Temperature controls randomness. High temperature = varied, creative outputs. Low temperature (near 0) = deterministic, consistent outputs. Setting temperature close to 0 will make the model give the same response to the same question every time — exactly what's needed for consistent factual customer service answers. Increasing temperature (option A) would make things worse. max_tokens (option C) controls response length, not consistency. frequency_penalty (option D) reduces word repetition within one response, not across separate responses.

Scenario: A financial services company wants to train an AI model to respond in their specific formal tone and always structure responses with "Situation:", "Options:", and "Recommendation:" headers. The format never changes regardless of the question type.

Which approach is most appropriate?

💡 Explanation

B is correct. Fine-tuning is ideal for teaching a specific output format, structure, or writing style that must be consistent across all responses. You provide training examples showing the format, the model learns it, and applies it without needing format instructions in every prompt. RAG (option A) retrieves data, not formatting examples. max_tokens (option C) controls length, not structure. Zero-shot prompting (option D) works but requires repeating the format instructions in every system or user message — fine-tuning eliminates this overhead and is more reliable.

Scenario: A maths tutoring app uses GPT-4o to help students with algebra problems. When asked "If 3x + 7 = 22, what is x?", the model sometimes gives wrong answers directly. The developer wants to improve accuracy significantly without changing the model.

Which prompt engineering technique should they apply?

💡 Explanation

B is correct. Chain-of-thought (CoT) prompting is the most effective technique for mathematical and logical reasoning tasks. Adding "Solve this step by step" or "Show your working" forces the model to reason through each step before committing to an answer, which dramatically improves accuracy. The model is less likely to make errors when it explicitly writes out each algebraic step. While few-shot (option C) can help, CoT is specifically the technique for reasoning/maths. Temperature 2.0 (option A) increases errors. Reducing max_tokens (option D) would prevent showing working, making things worse.

Scenario: A company's Azure OpenAI deployment processes customer service queries. Traffic is exactly 50,000 requests per day consistently, 7 days a week. The team is tired of occasional HTTP 429 throttling during peak hours that disrupts service.

Which deployment type should they switch to?

💡 Explanation

B is correct. The scenario describes predictable, consistent high traffic and a requirement for no throttling — this is exactly the use case for Provisioned Managed (PTU). PTU reserves a fixed capacity that is always available and never throttled. Standard (option A) can have its TPM increased but is still subject to throttling. F0 (option C) is a free tier — it has stricter limits, not fewer. Multi-region distribution (option D) can spread load but doesn't eliminate throttling and adds complexity without guaranteeing throughput.

A developer needs to generate structured customer feedback analysis. They want the model to output ONLY a JSON object and stop immediately after the closing brace. Which parameter achieves this?

💡 Explanation

C is correct. Stop sequences are specifically designed for this scenario — they tell the model to stop generating the moment a specific string appears. If you instruct the model to wrap the JSON in code fences (```json ... ```), you can use stop=["```"] to stop after the closing fence. Temperature 0 (option A) makes it consistent but doesn't stop it from adding commentary after the JSON. max_tokens (option B) might cut off the JSON before it's complete. presence_penalty (option D) encourages new topics — the opposite of what you want, and it doesn't control stopping behaviour.

Mark this topic as complete
🎉
Part 2 Complete!

You've finished all 3 topics in Implement Generative AI Solutions (15–20% of the exam). Before moving on, test your knowledge with flashcards and the full quiz.

🃏 Part 2 Flashcards 📝 Part 2 Full Quiz Start Part 3 — Agentic →