## Module 2: Build Your First Simple AI Application

Let's start with the simplest AI application. In this step, we will call OpenAI's `gpt-4o` model, which is a Large Language Model (LLM). It has already learned a lot of knowledge during its training. For information on how raw knowledge is converted into an LLM, please refer to the following materials. You can save them for your study later, let's go to Step 1.

- The foundational paper of Transformer: [Attention Is All You Need](https://arxiv.org/abs/1706.03762)
- YouTuber 3Blue1Brown's visualization of the Transformer: [Transformers (how LLMs work) explained visually](https://www.youtube.com/watch?v=wjZofJX0v4M)

### Step 1. Run the Simple AI Application's Streamlit Service

- In the VS Code terminal, use the `streamlit` command-line tool to run the following script to start the Streamlit service. You may have noticed that we added `poetry run` before `streamlit`. This allows us to use poetry to manage dependencies, rather than the default pip.

    ```bash
    poetry run streamlit run vanilla_ai_app.py --server.port 8501
    ```

    ```output
    Collecting usage statistics. To deactivate, set browser.gatherUsageStats to false.

    You can now view your Streamlit app in your browser.

    Local URL: http://localhost:8501
    Network URL: http://172.18.0.7:8501
    External URL: http://${LAB:HOST_MONITOR1_PUBLIC_IP}:8501
    ```

    ![90%](https://lab-static.pingcap.com/images/2025/7/24/4e420f46b9d43485f5dc87d8bd3c8584d5ed0981.png)

### Step 2. Use the Simple AI Application's Demo Web Page

- Click to visit your [RAG Demo Web Page](http://${LAB:HOST_MONITOR1_PUBLIC_IP}:8501/).

    ![90%](https://lab-static.pingcap.com/images/2025/7/24/9a4c1644a16628a8c63391ddad685953a6a6041f.png)

- Now, you can enter your question in the input box under `Enter your question:`, for example:

    ```txt
    What is TiDB?
    ```

- Then, click the `Send` button. After a short wait, you will get the answer!

    ![90%](https://lab-static.pingcap.com/quick-demo/demo-422/422-vanilla-ai-app-answer-0604.jpg)

- Congratulations🎉! You have completed your first AI application. You can continue to ask the AI some questions you are curious about. You can even try more difficult questions to see the limits of our initial AI application's capabilities.
- Next, let's see what's happening inside the code.

### Step 3. Simple AI Application Code Reading

Let's go back to [VS Code](${LAB:HTTPS_REVERSE_PROXY_URL}?next=${LAB:"/vscode/?folder=/root/tidb-lab-unify-storage-openai"|urlencode} "VS Code") and click on the code file `vanilla_ai_app.py`.

1. The script first imports the necessary libraries: `litellm` for interacting with the LLM, and `streamlit` for building the web interface. Additionally, it imports `LLM_RESPONSE_STYLE` from the `common` module, which is a predefined CSS style for beautifying the LLM's response output.

    ```python
    from litellm import completion
    import streamlit as st

    from common import LLM_RESPONSE_STYLE
    ```

2. The LLM to be used is defined. We set the model to `openai/gpt-4o`. The model name used by `litellm` has two-part: the part before the `/` is the provider, in this case, OpenAI, and the part after is the model name, defined internally by OpenAI.

    ```python
    llm_model = "openai/gpt-4o"
    ```

3. Set the title of the Streamlit page to "🔍 Vanilla AI Q&A Demo".

    ```python
    st.title("🔍 Vanilla AI Q&A Demo")
    ```

4. Display an instructional text on the page to inform the user of the application's function: the user enters a question, and the system will answer it based on its built-in knowledge.

    ```python
    st.write(
        "Enter your question, and the system will answer it based on the built-in knowledge"
    )
    ```

5. Use `st.text_input` to create a text input box that allows the user to enter their question. The entered question is stored in the `query` variable.

    ```python
    query = st.text_input("Enter your question:", "")
    ```

6. This code block handles the logic for when the user clicks the "Send" button and the `query` (the user's entered question) is not empty:
    - Use `with st.spinner("Processing...")` to display a loading animation, informing the user that the system is processing the request.
    - Construct a simple prompt, which is "Answer the question: " plus the user's question `query`.

    ```python
    if st.button("Send") and query:
        with st.spinner("Processing..."):
            prompt = f"Answer the question: {query}"
    ```

7. Call the `litellm.completion` function to interact with the LLM to generate an answer.
    - The `model` parameter specifies the LLM to use (i.e., `llm_model`).
    - The `messages` parameter is a list containing a dictionary that defines the message content (`prompt`) and role (`user`).

    ```python
    # Call LLM to generate answer
    response = completion(
        model=llm_model,
        messages=[{"content": prompt, "role": "user"}],
    )
    ```

8. Display the LLM's model name and a robot icon on the page.

    ```python
    st.markdown(f"### 🤖 {llm_model}")
    ```

9. Apply the predefined CSS style `LLM_RESPONSE_STYLE` to beautify the display of the LLM's response. The `unsafe_allow_html=True` parameter allows embedding HTML and CSS in Markdown.

    ```python
    st.markdown(LLM_RESPONSE_STYLE, unsafe_allow_html=True)
    ```

10. Display the answer generated by the LLM. The answer is extracted from `response.choices[0].message.content` and wrapped in an HTML `div` tag with the `llm-response` class to apply the style.

    ```python
    # show the response
    st.markdown(
        f'<div class="llm-response">{response.choices[0].message.content}</div>',
        unsafe_allow_html=True,
    )
    ```

### Step 4. Summary of the Simple AI Application

We can see that the simple AI application is very straightforward. In summary, it simply calls the OpenAI API to get an answer. All the knowledge is based on what the LLM was fed during its training. For example, the sample question above:

```text
What is TiDB?
```

The reason the LLM can answer this question is that OpenAI included relevant documents or introductions when training this model. This leads us to a question: what if the LLM didn't have this data during training? For example:

```text
Who is Cheese Wang at PingCAP?
```

![90%](https://lab-static.pingcap.com/images/2025/7/24/eff979e800235873edadc40167678a6ea8e51936.png)

As you can see, the LLM "fabricated" some information. This is because there was no similar information input when the LLM was trained. Therefore, it cannot correctly know the relationship between this employee and PingCAP. It can only "guess" that the person being asked about is the CTO, because a CTO's name is more closely associated with the company and more likely to be asked about.

And, the answer is wrong, because the lab author is ***Cheese Wang***, and he is not the CTO of PingCAP.

This behavior of LLMs is called **Hallucination**, which is a phenomenon we need to be particularly aware of when using LLMs. In the next module, we will improve our AI application to reduce the frequency of hallucinations and provide it with additional knowledge so that it can answer questions beyond its training data without changing the model itself.
