# Create an AI math tutoring app using Streamlit, LangChain, and ChatGPT in just 30 lines of code

Create your AI math tutoring app with Streamlit, LangChain, and ChatGPT in just 30 lines of code.

The advancements in large language models (LLMs) have attracted a lot of attention. While some believe it’s just hype, many see it as an opportunity to develop new products or improve existing ones.

New products and plugins based on LLM are quickly being released, driven by three main factors that boost productivity:

1. LLMs have become incredibly powerful.

We have already learned how to use them better (such as engineering tips).

3. There are tools available that can speed up and simplify the development process (such as Streamlit, LangChain).

In this article, we will create a 30-line code for a math tutoring application.

**Outline**

The article includes the following sections:

Project Breakdown

Project Reminder

LangChain

Streamlit

Integration.

Improvement areas and conclusions

Project Breakdown

This project primarily consists of three parts:

1. Prompt Engineering: Although LLMs are highly capable tools, your interaction with them plays a critical role in obtaining useful and accurate responses. Therefore, how you write your prompts is very important. We will learn best practices for prompt engineering, such as chaining ideas and minimal learning.

2. LangChain: This is an open source development framework used for creating applications based on LLM.

3. Streamlit: This is a development framework for quickly and easily converting your data scripts into web applications. It doesn’t require any front-end experience, all you need is Python and we will provide detailed explanations for each part.

Project Reminder

With the rise of LLMs, prompting engineering has entered our lives. At a high level, it focuses on optimizing prompts (i.e. input to LLMs) to effectively query LLMs and obtain accurate and expected responses.

As the field of technical communication is becoming a new discipline, there are many things to consider when creating documentation.

For the prompts used in our math tutoring application, we will be utilizing two types of prompt techniques:

Chain thinking prompt: A prompt technique with a structure of {input, chain thinking, output}, where chain thinking is a series of natural language inference steps in between. We will be using it to create a continuous flow of steps to achieve solutions.

Small learning: It simply means adding input-output examples in the prompts so that the model knows what we expect.

This is the prompt we will use in our application:

```
prompt= """Act as a counselor to help students solve math and arithmetic reasoning problems. Students will ask you questions. Think step by step to get the answer. Write down each reasoning step.
You will be asked to show answers or give clues that will help the students come up with answers on their own. Here are some sample questions, with expected answers and clues:
Question: John has two houses. Each house has 3 bedrooms and each bedroom has 2 Windows.
Each house has a kitchen with two Windows. In addition, each house has five Windows that are not in the bedroom or kitchen.
How many Windows are there in John's house?
Answer: Each house has 3 bedrooms and each bedroom has 2 Windows, so each house has 3 x 2 = 6 Windows.
Each house also has a kitchen with 2 Windows, so each house has 2 x 1 = 2 Windows.
Each house also has 5 Windows that are not in the bedroom or kitchen, so each house has 5 x 1 = 5 Windows.
In total, each house has 6 + 2 + 5 = 13 Windows.
Since John has 2 houses, he has a total of 2 x 13 = 26 Windows. The answer is 26.
Clue: 1. Find the number of bedroom Windows, kitchen Windows, and other Windows separately
2. Add them together to find the total number of Windows in each house
3. Find the total number of Windows in all houses.
Question: There are 15 trees in the woodland. The woodworkers will plant trees in the woodlands today. When they're done, there will be 21 trees. How many trees have the woodworkers planted today?
Answer: Originally there were 15 trees. After the workers planted the trees, there were 21 trees. So the workers planted 21-15 = 6 trees. The answer is six." ,
Clue: 1. Start with the total number of trees after planting and subtract the original number of trees to find out how many trees were planted.
2. Use subtraction to find the difference between two numbers.
Question: Leah has 32 bars of chocolate and her sister has 42. If they eat 35 pieces, how many pieces will they have left?
Answer: Initially, Leah had 32 bars of chocolate. Her sister has $42. So they have a total of 32 + 42 = 74. After eating 35 pieces, they're left with 74-35 = 39 pieces. The answer is $39.
Tip: 1. Start with the total amount of chocolate they own. 2. Subtract the amount of chocolate they eat.
problem：{question}
"""
```

The final question pertains to an input variable, which we will discuss in the LangChain section.

When we use this prompt to ask a question, the model generates both an answer and clues at the same time. As it formats the response in the way shown in the example, it will be a standard string from which we will be able to extract the answer and clues.

By the way, I didn’t include the prompt in the line numbers of the script because it’s a string that can be customized as needed (more or fewer lines).

LangChain is an open-source development framework for applications that use large language models (LLMs). It provides abstractions in the form of components to enable more efficient or programmatic use of LLMs.

We will be using LangChain’s template prompts, with the questions serving as input variables for the template.

```
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
def generate_response(question):
chat = ChatOpenAI(temperature=0.0, openai_api_key=openai_api_key)
prompt_template = ChatPromptTemplate.from_template(template=prompt)
messages = prompt_template.format_messages(
question=question
)
response = chat(messages)
return response.content
```

ChatOpenAI is an abstraction of the ChatGPT API endpoint by LangChain. In the generate_response function, we first create a ChatGPT model with a temperature value of 0. The temperature parameter adjusts the randomness of the output. Higher values make the output more random, while lower values make it more focused and certain.

The openai_api_key parameter stores the API key, which can be obtained from the API Keys menu on the OpenAI website. When creating the application, we will add an input box for the user to enter their API key.

Next, we create a prompt template from the previously created prompt string. The prompt is defined as an input variable in the template. The next step is to create the message, which is the final input to the model. Finally, the response variable is the output generated by the model.

**Streamlit**

Our prompts and models are ready. The final step is to transform them into a web application. Thanks to the straightforward syntax of Streamlit, this step is quite easy.

The following code adds a title to the application and creates an input box as a password so that users can enter their API key.

```
import streamlit as st
# add title
st.set_page_config(page_title="Your Friendly Math Tutor")
st.title("Your Friendly Math Tutor")
# add input box
openai_api_key = st.sidebar.text_input('OpenAI API Key', type='password')
```

The API key is saved as the openai_api_key variable and then used in the generate_response function (explained in the LangChain section).

Other user interactions are handled in the code snippet below:

```
with st.form('myform'):
question = st.text_input('Enter question:', '')
clues = st.form_submit_button('Give me clues')
answer = st.form_submit_button('Show me the answer')
if not openai_api_key.startswith('sk-'):
st.warning('Please enter your OpenAI API key!', icon='⚠')
if clues and openai_api_key.startswith('sk-'):
st.info(generate_response(question).split("Clues")[1][2:])
if answer and openai_api_key.startswith('sk-'):
st.info(generate_response(question).split("Clues")[0])
```

“Question” is a text input box where users will input questions to be answered by an AI mentor.

“Clues” is a submission button. Once clicked, the generated clues from the model will be displayed.

“Answer” is a submission button. Once clicked, the answer generated by the model will be displayed.

The conditional statement checks whether the user has entered the correct API key and which button has been clicked.

The generate_response function returns the response in the following format as a string:

Answer: Michael has 58 golf balls. He lost 23 on Tuesday, so he had 58 – 23 = 35 golf balls left. On Wednesday, he lost another 2, so he had 35 – 2 = 33 golf balls at the end of Wednesday. The answer is 33. Clues: 1. Start with the total number of golf balls Michael has. 2. Subtract the number of golf balls he lost on Tuesday. 3. Subtract the number of golf balls he lost on Wednesday.

We use the split function to extract the answers and clues separately from this response. It’s important to note that this is not the optimal way to parse the output. A better option is to have the model return the response in JSON format or use LangChain’s output parser. I have identified this as an area for improvement in the application.

Summary

Let’s put these parts together. Below is the script for creating our AI math tutor application:

```
import streamlit as st
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
st.set_page_config(page_title="Your Friendly Math Tutor")
st.title("Your Friendly Math Tutor")
openai_api_key = st.sidebar.text_input('OpenAI API Key', type='password')
prompt = """
Act as a counselor to help students solve math and arithmetic reasoning problems. Students will ask you questions. Think step by step to get the answer. Write down each reasoning step.
You will be asked to show answers or give clues that will help the students come up with answers on their own. Here are some sample questions, with expected answers and clues:
Question: John has two houses. Each house has 3 bedrooms and each bedroom has 2 Windows.
Each house has a kitchen with two Windows. In addition, each house has five Windows that are not in the bedroom or kitchen.
How many Windows are there in John's house?
Answer: Each house has 3 bedrooms and each bedroom has 2 Windows, so each house has 3 x 2 = 6 Windows.
Each house also has a kitchen with 2 Windows, so each house has 2 x 1 = 2 Windows.
Each house also has 5 Windows that are not in the bedroom or kitchen, so each house has 5 x 1 = 5 Windows.
In total, each house has 6 + 2 + 5 = 13 Windows.
Since John has 2 houses, he has a total of 2 x 13 = 26 Windows. The answer is 26.
Clue: 1. Find the number of bedroom Windows, kitchen Windows, and other Windows separately
2. Add them together to find the total number of Windows in each house
3. Find the total number of Windows in all houses.
Question: There are 15 trees in the woodland. The woodworkers will plant trees in the woodlands today. When they're done, there will be 21 trees. How many trees have the woodworkers planted today?
Answer: Originally there were 15 trees. After the workers planted the trees, there were 21 trees. So the workers planted 21-15 = 6 trees. The answer is six." ,
Clue: 1. Start with the total number of trees after planting and subtract the original number of trees to find out how many trees were planted.
2. Use subtraction to find the difference between two numbers.
Question: Leah has 32 bars of chocolate and her sister has 42. If they eat 35 pieces, how many pieces will they have left?
Answer: Initially, Leah had 32 bars of chocolate. Her sister has $42. So they have a total of 32 + 42 = 74. After eating 35 pieces, they're left with 74-35 = 39 pieces. The answer is $39.
Tip: 1. Start with the total amount of chocolate they own. 2. Subtract the amount of chocolate they eat.
problem：{question}
"""
def generate_response(question):
chat = ChatOpenAI(temperature=0.0, openai_api_key=openai_api_key)
prompt_template = ChatPromptTemplate.from_template(template=prompt)
messages = prompt_template.format_messages(
question=question
)
response = chat(messages)
return response.content
with st.form('myform'):
question = st.text_input('Enter question:', '')
clues = st.form_submit_button('Give me clues')
answer = st.form_submit_button('Show me the answer')
if not openai_api_key.startswith('sk-'):
st.warning('Please enter your OpenAI API key!', icon='⚠')
if clues and openai_api_key.startswith('sk-'):
st.info(generate_response(question).split("Clues")[1][2:])
if answer and openai_api_key.startswith('sk-'):
st.info(generate_response(question).split("Clues")[0])
```

Excluding comments, this is 30 lines of code (including blank lines).

Save this script as streamlit_app.py (or any name you prefer), and then run the command “streamlit run streamlit_app.py” in the terminal.

Then, the application will open in your default browser. You will see the following content:

Then the application will open in your default browser. You will see the following: enter your question and click the “Give Me Clues” button. The model will generate clues that will help you progressively find the answer. If you click the “Give Me the Answer” button, it will provide a step-by-step solution.

Here are some answers to questions and models:

Question: I have 10 pencils. My friend gave me two more. Then, I lost four pencils. How many pencils do I have left?

Clue: 1. Start with the number of pencils you have. 2. Add the number of pencils your friend gave you. 3. Subtract the number of pencils you have lost.

Translation: I have 10 pencils. My friend gave me 2 more, so now I have 10 + 2 = 12 pencils. However, I lost 4 pencils, so now I only have 12 – 4 = 8 pencils left. The answer is 8.

Question: I had 30 dollars. Then, I bought three candies. Now, I have 15 dollars left. How much does one candy cost?

Clues: 1. Find the total amount spent on candy by subtracting the remaining money from the initial amount. 2. Divide the total cost by the number of candies bought to determine the cost of one piece of candy.

Answer: I started with $30 and bought three candies, so I spent 3x dollars on candy. After buying candy, I had $15 left, so I had 30 – 3x = $15. Solving for x, I got x = 5. So each candy cost $5. The answer is 5.

Improvement and Conclusion: Firstly, this is an AI math tutor that can assist you in solving simple math and arithmetic reasoning problems. It is not designed for college students, but I believe it can be helpful for second or third graders.

However, by using more complex cues and external tools, its abilities can be extended. For example, LangChain allows the implementation of Wolfram Alpha as a component within the chain. This enables our applications to solve highly complex problems.

Another area for improvement could be displaying clues one by one. I will work on improving the application to implement this change.

Finally, we ran the application locally. To make it shareable and serviceable for others, we can host our data application on an AWS EC2 (or any other cloud) instance so that others can access it. A good alternative solution can be Streamlit Community Cloud, which makes hosting and sharing your application very simple. I will write another article to explain how to implement these improvements.