Activity 1.5: Prompting Techniques
Work in progress
This section is under construction. This information hasn’t been reviewed or edited yet!
Practical Activity Overview
Building on our previous chat application, we can expand it to create a prompt engineering lab that allows students to experiment with different prompting techniques and parameters.
Prerequisites
- Python 3.8 or higher installed on your system
- Basic familiarity with command line/terminal
- A text editor or IDE of your choice
Activities
Step 1: Set Up Your Development Environment
1.1 Make sure you are using the virtual environment we created in the previous activity:
- On Windows:
.\venv\Scripts\activate- On macOS/Linux:
source venv/bin/activateStep 2: Add Parameter Controls
2.1 Add temperature and top-P controls:
# Add parameter controls to sidebar
st.sidebar.subheader("Generation Parameters")
temperature = st.sidebar.slider("Temperature", 0.0, 1.0, 0.7, 0.1,
help="Higher values make output more random, lower more deterministic")
top_p = st.sidebar.slider("Top-P", 0.0, 1.0, 0.9, 0.1,
help="Controls diversity via nucleus sampling")2.2 Add prompt technique selection:
# Add prompt technique selector
prompt_technique = st.sidebar.selectbox(
"Prompt Technique",
["Basic", "Few-Shot Learning", "Chain-of-Thought", "Self-Consistency"]
)
# Function to apply prompt techniques
def apply_prompt_technique(user_input, technique):
if technique == "Basic":
return user_input
elif technique == "Few-Shot Learning":
return f"""Here are some examples of how to respond:
Question: What is the capital of France?
Answer: The capital of France is Paris.
Question: What is the boiling point of water?
Answer: Water boils at 100 degrees Celsius at standard pressure.
Now answer this question: {user_input}"""
elif technique == "Chain-of-Thought":
return f"""Think through this step-by-step to solve the problem:
{user_input}
Let's break this down into steps:
1. """
elif technique == "Self-Consistency":
return f"""Generate three different approaches to answer this question, then select the best one:
{user_input}
Approach 1:"""
return user_inputStep 3: Add Comparative View
3.1 Add a comparative view for different techniques:
# Add a compare button
if st.sidebar.button("Compare All Techniques"):
if "user_input" in st.session_state and st.session_state.user_input:
st.subheader("Technique Comparison")
techniques = ["Basic", "Few-Shot Learning", "Chain-of-Thought", "Self-Consistency"]
# Create columns for comparison
cols = st.columns(len(techniques))
for i, technique in enumerate(techniques):
with cols[i]:
st.markdown(f"**{technique}**")
modified_prompt = apply_prompt_technique(st.session_state.user_input, technique)
with st.spinner(f"Generating {technique} response..."):
if model_type == "Ollama":
response = generate_ollama_response([{"role": "user", "content": modified_prompt}],
temperature=temperature, top_p=top_p)
else:
response = generate_gemini_response([{"role": "user", "content": modified_prompt}],
temperature=temperature, top_p=top_p)
st.text_area("Response", response, height=300)Step 4: Update Model Response Functions
4.1 Update the model response functions to include parameters:
def generate_ollama_response(messages, temperature=0.7, top_p=0.9):
# Convert our message format to Ollama's expected format
ollama_messages = [{"role": m["role"], "content": m["content"]} for m in messages]
response = requests.post("http://localhost:11434/api/chat",
json={
"model": "llama3.2:1b",
"messages": ollama_messages,
"stream": False,
"options": {
"temperature": temperature,
"top_p": top_p
}
}
)
if response.status_code == 200:
return response.json()["message"]["content"]
else:
raise Exception(f"Ollama error: {response.text}")
def generate_gemini_response(messages, temperature=0.7, top_p=0.9):
# Convert our messages to Gemini format
gemini_messages = []
for message in messages:
role = "user" if message["role"] == "user" else "model"
gemini_messages.append(types.Content(role=role, parts=[types.Part.from_text(text=message["content"])]))
response = client.models.generate_content(
model="gemini-2.0-flash",
contents=gemini_messages,
generation_config={
"temperature": temperature,
"top_p": top_p
}
)
return response.textStep 5: Add Prompt Template Library
5.1 Add a prompt template library:
# Add prompt template library
with st.sidebar.expander("Prompt Template Library"):
templates = {
"Summarize Text": "Summarize the following text in 3-5 bullet points: {{input}}",
"Explain Concept": "Explain {{input}} in simple terms a high school student would understand.",
"Compare and Contrast": "Compare and contrast {{input}}. Highlight key similarities and differences.",
"Generate Ideas": "Generate 5 creative ideas related to {{input}}.",
"Analyze Argument": "Analyze the following argument and identify any logical fallacies: {{input}}"
}
selected_template = st.selectbox("Select Template", list(templates.keys()))
if st.button("Apply Template"):
template = templates[selected_template]
if "user_input" in st.session_state and st.session_state.user_input:
new_prompt = template.replace("{{input}}", st.session_state.user_input)
st.session_state.user_input = new_prompt
st.experimental_rerun()Step 6: Experiment and Observe
6.1 Now that you’ve implemented the prompt engineering lab, experiment with:
- Different prompting techniques (Basic, Few-Shot, Chain-of-Thought, Self-Consistency)
- Adjusting temperature and top-P parameters to see how they affect outputs
- Comparing responses across different techniques side-by-side
- Using pre-built prompt templates for common tasks
- Maintaining conversation context while experimenting
Key Learning Points
- Experiment with different prompting techniques (Basic, Few-Shot, Chain-of-Thought, Self-Consistency)
- Adjust temperature and top-P parameters to see how they affect outputs
- Compare responses across different techniques side-by-side
- Use pre-built prompt templates for common tasks
- Maintain conversation context while experimenting
Security Note
Never commit your .env file to version control. Add it to your .gitignore file if you’re using Git.
Complete Script
Here’s the full app.py script with all the prompt engineering lab additions:
import os
import streamlit as st
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_community.llms import Ollama
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import SystemMessage, HumanMessage
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Check for API key
if not os.getenv('GOOGLE_API_KEY'):
st.error("Please set your Google API Key in the .env file!")
st.stop()
st.title("Prompt Engineering Lab")
model_type = st.sidebar.selectbox("Model", ["Gemini", "Ollama"])
# Initialize session state
if "messages" not in st.session_state:
st.session_state.messages = []
if "user_input" not in st.session_state:
st.session_state.user_input = ""
# Add parameter controls to sidebar
st.sidebar.subheader("Generation Parameters")
temperature = st.sidebar.slider("Temperature", 0.0, 1.0, 0.7, 0.1)
top_p = st.sidebar.slider("Top-P", 0.0, 1.0, 0.9, 0.1)
context_window = st.sidebar.slider("Context Window Size", 1, 10, 5)
# Prompt technique library
PROMPT_TECHNIQUES = {
"Basic": lambda query: query,
"Few-Shot Learning": lambda query: f"""Here are some examples of how to respond:
Question: What is the capital of France?
Answer: The capital of France is Paris.
Question: What is the boiling point of water?
Answer: Water boils at 100 degrees Celsius at standard pressure.
Now answer this question: {query}""",
"Chain-of-Thought": lambda query: f"""Think through this step-by-step to solve the problem:
{query}
Let's break this down into steps:
1. """,
"Self-Consistency": lambda query: f"""Generate three different approaches to answer this question, then select the best one:
{query}
Approach 1:"""
}
# Prompt template library
PROMPT_TEMPLATES = {
"Summarize Text": "Summarize the following text in 3-5 bullet points: {input}",
"Explain Concept": "Explain {input} in simple terms a high school student would understand.",
"Compare and Contrast": "Compare and contrast {input}. Highlight key similarities and differences.",
"Generate Ideas": "Generate 5 creative ideas related to {input}.",
"Analyze Argument": "Analyze the following argument and identify any logical fallacies: {input}"
}
# Add prompt technique selector
prompt_technique = st.sidebar.selectbox("Prompt Technique", list(PROMPT_TECHNIQUES.keys()))
# Add prompt template library
with st.sidebar.expander("Prompt Template Library"):
selected_template = st.selectbox("Select Template", list(PROMPT_TEMPLATES.keys()))
if st.button("Apply Template"):
if st.session_state.user_input:
new_prompt = PROMPT_TEMPLATES[selected_template].replace("{input}", st.session_state.user_input)
st.session_state.user_input = new_prompt
st.experimental_rerun()
# Display chat history
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.write(message["content"])
# Create a function to get the appropriate model with parameters
@st.cache_resource
def get_conversation_chain():
if model_type == "Gemini":
llm = ChatGoogleGenerativeAI(
model="gemini-2.0-flash",
temperature=temperature,
top_p=top_p
)
else:
llm = Ollama(
model="llama3.2:1b",
base_url="http://localhost:11434",
temperature=temperature,
top_p=top_p
)
# Create a system message template
system_template = "You are a helpful AI assistant."
# Create a chat prompt template with memory
prompt = ChatPromptTemplate.from_messages([
SystemMessage(content=system_template),
MessagesPlaceholder(variable_name="history"),
HumanMessage(content="{input}")
])
# Initialize memory
memory = ConversationBufferMemory(k=context_window, return_messages=True, memory_key="history")
# Load existing conversation into memory
for msg in st.session_state.messages[-context_window:]:
if msg["role"] == "user":
memory.chat_memory.add_user_message(msg["content"])
else:
memory.chat_memory.add_ai_message(msg["content"])
# Create the conversation chain
chain = ConversationChain(llm=llm, prompt=prompt, memory=memory, verbose=False)
return chain, max_tokens
# Add token counting display
if st.session_state.messages:
chain, max_tokens = get_conversation_chain()
total_tokens = sum(len(msg["content"].split()) * 1.3 for msg in st.session_state.messages)
st.sidebar.metric("Estimated Tokens Used", int(total_tokens))
st.sidebar.progress(min(1.0, total_tokens / max_tokens))
st.sidebar.text(f"{model_type} context: ~{max_tokens} tokens")
# Add a compare button
if st.sidebar.button("Compare All Techniques"):
if st.session_state.user_input:
st.subheader("Technique Comparison")
cols = st.columns(len(PROMPT_TECHNIQUES))
for i, (technique_name, technique_func) in enumerate(PROMPT_TECHNIQUES.items()):
with cols[i]:
st.markdown(f"**{technique_name}**")
modified_prompt = technique_func(st.session_state.user_input)
with st.spinner(f"Generating {technique_name} response..."):
chain, _ = get_conversation_chain()
response = chain.invoke({"input": modified_prompt})
st.text_area("Response", response["response"], height=300)
user_input = st.chat_input("Type your message here...")
if user_input:
# Store the user input for template application
st.session_state.user_input = user_input
# Apply selected prompt technique
modified_input = PROMPT_TECHNIQUES[prompt_technique](user_input)
# Add user message to history
st.session_state.messages.append({"role": "user", "content": modified_input})
# Display user message
with st.chat_message("user"):
st.write(modified_input)
try:
# Get the conversation chain
chain, _ = get_conversation_chain()
# Generate response
response = chain.invoke({"input": modified_input})
assistant_response = response["response"]
# Add assistant response to history
st.session_state.messages.append({"role": "assistant", "content": assistant_response})
# Display assistant response
with st.chat_message("assistant"):
st.write(assistant_response)
except Exception as e:
st.error(str(e))
# Add button to clear conversation history
if st.sidebar.button("Clear Conversation"):
st.session_state.messages = []
st.session_state.user_input = ""
st.experimental_rerun()