{"id":15055267,"url":"https://github.com/alfonsokan/eskwelabs_chatbot","last_synced_at":"2026-02-10T16:31:50.136Z","repository":{"id":255897655,"uuid":"853840901","full_name":"alfonsokan/eskwelabs_chatbot","owner":"alfonsokan","description":"A RAG chatbot that answers both Eskwelabs bootcamp-specific queries and general bootcamp-related questions.","archived":false,"fork":false,"pushed_at":"2024-09-08T16:50:33.000Z","size":3501,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-14T05:03:09.964Z","etag":null,"topics":["embeddings","genai","genai-chatbot","ollama","prompt-engineering","retrieval-augmented-generation","streamlit","vector-database"],"latest_commit_sha":null,"homepage":"https://askwelabscapstoneproject.streamlit.app/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alfonsokan.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-07T17:23:11.000Z","updated_at":"2024-09-08T16:51:18.000Z","dependencies_parsed_at":"2024-09-07T18:44:13.089Z","dependency_job_id":"f504cc8a-ba3d-4edc-8522-d92a093b587a","html_url":"https://github.com/alfonsokan/eskwelabs_chatbot","commit_stats":null,"previous_names":["alfonsokan/eskwelabs_chatbot"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/alfonsokan/eskwelabs_chatbot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alfonsokan%2Feskwelabs_chatbot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alfonsokan%2Feskwelabs_chatbot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alfonsokan%2Feskwelabs_chatbot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alfonsokan%2Feskwelabs_chatbot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alfonsokan","download_url":"https://codeload.github.com/alfonsokan/eskwelabs_chatbot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alfonsokan%2Feskwelabs_chatbot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29307904,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-10T16:09:25.305Z","status":"ssl_error","status_checked_at":"2026-02-10T16:08:52.170Z","response_time":65,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["embeddings","genai","genai-chatbot","ollama","prompt-engineering","retrieval-augmented-generation","streamlit","vector-database"],"created_at":"2024-09-24T21:39:39.971Z","updated_at":"2026-02-10T16:31:50.115Z","avatar_url":"https://github.com/alfonsokan.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Eskwelabs Chatbot\nThis project focuses on the end-to-end development of a Q\u0026A Chatbot tailored to answer bootcamp-related queries, specifically for Eskwelabs. The methodology covers the key steps, including knowledge base embedding,  Retrieval-Augmented Generation (RAG) chatbot development using LangChain, and deployment via Streamlit. \n\n![image](https://github.com/user-attachments/assets/3dd5ed7f-c6aa-4778-ac5e-8fd789fcda6c)\n\n**Disclaimer**: This guide demonstrates how to create your own chatbot using `Llama3.1`. However, `Llama3.1` struggles with making multiple tool calls simultaneously. In contrast, `GPT-Turbo-3.5` handles this task more efficiently. For improved results, `GPT-Turbo-3.5` is recommended over `Llama3.1`. You can try out the chatbot powered by GPT-Turbo-3.5 [here.](https://askwelabscapstoneproject.streamlit.app/)\n\n\u003cbr/\u003e\n\n## Tech Stack\n- ChromaDB: Vector Store\n- LangChain: Chatbot Framework\n- Llama3.1: Large Language Model\n- text-embedding-ada-002: Embedding Model\n- SemanticChunker: Chunking Strategy\n\n\u003cbr/\u003e\n\n## Installation\n1. Clone the repository\n```bash\ngit clone https://github.com/alfonsokan/eskwelabs_chatbot.git\n```\n2. Install libraries\n```bash\npip install -r requirements.txt\n```\n3. Install an open-source LLM using Ollama. Refer to the [Ollama documentation](https://github.com/ollama/ollama) and select an LLM.\n\n\u003cbr/\u003e\n\nThen, run the following command in the command line (CMD):\n\n```bash\nollama run llama3.1\n```\n\n4. For the code repository, open terminal and run the following command:\n```python\nstreamlit run app.py\n```\n\n\u003cbr/\u003e\n\n## Methodology\nThe flow chart below displays the 4-step approach to developing the chatbot.\n\n![Askwelabs_Capstone-Project_Group-3](https://github.com/user-attachments/assets/72319f8f-0e94-4b05-8aa8-9fdadb78e640)\n\n**1. Data Preparation**\n\n\n\nFor this step, the documents are embeddings and stored in the vector database called `embeddings_deployment_sentencetransformer` located in this repository. \n\nIf interested, the code for embedding the documents can be viewed [here](https://colab.research.google.com/drive/1iyz_SkHv7TVDgKJBuRYb1iTtVfxDyGU0?usp=sharing).\n\n\u003cbr/\u003e\n\n**2. Retriever Generation**\n- There are two retriever tools, Eskwelabs Info Retriever and General Bootcamp Info Retriever, created from the embedded knowledge base.\n\n![image](https://github.com/user-attachments/assets/f2926ccf-800a-4d8e-8f18-9e8b62697335)\n\n- Another retriever is optionally used when a user submits their resume to the chatbot.\n    \n![image](https://github.com/user-attachments/assets/dc6b0a63-9e09-49dc-bc5b-1df98b1e3343)\n\n\u003cbr/\u003e\n\n**3. Tool-calling Agent Creation**\n\nThree parameters to instantiate a tool-calling agent:\n\n- List of retriever tools\n```python\n    resume = st.file_uploader(\"Upload File\", type=['txt', 'docx', 'pdf'])\n\n    # if a resume is passed, include resume retriever as tool\n    if resume is not None:\n        with open(resume.name, \"wb\") as f:\n            f.write(resume.getbuffer())\n        resume_tool = resume_retriever_tool(resume.name)\n        eskwelabs_bootcamp_info_search_tool, bootcamp_vs_alternatives_search_tool = create_db_retriever_tools(vectordb)\n        tools = [resume_tool, eskwelabs_bootcamp_info_search_tool, bootcamp_vs_alternatives_search_tool]\n\n    # if no resume is passed, do not include resume retriever as tool\n    else:\n        eskwelabs_bootcamp_info_search_tool, bootcamp_vs_alternatives_search_tool = create_db_retriever_tools(vectordb)\n        tools = [eskwelabs_bootcamp_info_search_tool, bootcamp_vs_alternatives_search_tool]\n```\n\n- LLM (Llama 3.1)\n```python\nfrom langchain_ollama import ChatOllama\n\nllm = ChatOllama(\n    model = \"llama3.1\",\n    temperature = 0.1,\n    num_predict = 350,\n    verbose=True.\n)\n```\n- Prompt passed to the chatbot\n```python\nfrom langchain_core.prompts import ChatPromptTemplate\nfrom langchain_core.prompts import MessagesPlaceholder\n\nprompt = ChatPromptTemplate(\n    messages=[\n        MessagesPlaceholder(variable_name='chat_history'),\n        ('system', \"You're a helpful assistant who provides concise, complete answers without getting cut off mid-statement. Stick strictly to the user's questions, avoiding any unnecessary details.\"),\n        ('human', '{input}'),\n        MessagesPlaceholder(variable_name=\"agent_scratchpad\")       \n                                                                    \n    ]\n)\n```\n\nAfterwards, the tool-calling agent can now be instantiated:\n```python\nfrom langchain.agents import create_tool_calling_agent, AgentExecutor\n\nagent=create_tool_calling_agent(llm,tools,prompt)\nagent_executor=AgentExecutor(agent=agent,tools=tools,verbose=True, handle_parsing_errors=True)\n```\n\u003cbr/\u003e\n\n**4. Response Generation**\n- Pass the tool-calling agent, user input, as well as chat history to generate a response.\n```python\ndef process_chat(agent_executor, user_input, chat_history):\n    response = agent_executor.invoke(\n        {'input': user_input,\n         'chat_history': chat_history\n         },\n    )\n    return response['output']\n```\n\u003cbr/\u003e\n\n## Recommendations\n- Using a ReAct agent instead of a tool-calling agent\n    -   Explore output quality using a ReAct agent instead of a tool-calling agent. Develop a ReAct prompt that enables the LLM to generate reasoning traces before taking action on a task.\n- Explore different chunking strategies and embedding model\n- Connect the chatbot to a third-party database (Redis-Upstash) to allow long-term storage of chat history\n\n\u003cbr/\u003e\n\n## Appendix\n### Chatbot's Selective History Retrieval Mechanism\n\n![image](https://github.com/user-attachments/assets/230b3557-7740-42b5-b261-8dd25345c9da)\n\n- Past conversations’ user query and chatbot response are stored in a temporary vector store\n- For each new user query, only the most relevant parts of the vector store are retrieved and passed as chat history to the chatbot.\n- Importance: This feature reduces token consumption by efficiently retrieving only the relevant parts of the chat history, preventing unnecessary length and minimizing what is passed to the LLM.\n- Code snippet of app with chat history implemented:\n```python\nif \"messages\" not in st.session_state:\n    st.session_state.messages = []\n\n\nif \"chat_history\" not in st.session_state:\n    st.session_state.chat_history = []\n\nif \"unique_id\" not in st.session_state:\n    st.session_state.unique_id = 0\n\n\nif \"chat_history_vector_store\" not in st.session_state:\n    st.session_state.chat_history_vector_store = None\n\nif \"fed_chat_history\" not in st.session_state:\n    st.session_state.fed_chat_history = []\n\n\n# Display chat messages from history on app rerun\nfor message in st.session_state.messages:\n    with st.chat_message(message[\"role\"]):\n        st.markdown(message[\"content\"])\n\n# React to user input\nif user_input := st.chat_input(\"Say something\"):\n    # Display user message in chat message container\n    with st.chat_message(\"human\"):\n        st.markdown(user_input)\n    # Add user message to chat history\n    st.session_state.messages.append({\"role\": \"user\", \"content\": user_input})\n\n    if st.session_state.chat_history_vector_store:\n        results = st.session_state.chat_history_vector_store.similarity_search(query=user_input,\n                                                                k=4,\n                                                                filter={'use_case':'chat_history'})\n\n        sequenced_chat_history = [(parse_message(results.metadata['msg_element']), results.metadata['msg_placement']) for results in results]\n        sequenced_chat_history.sort(key=lambda pair: pair[1])\n        st.session_state.fed_chat_history = [message[0] for message in sequenced_chat_history]\n\n\n    # chatbot response\n    response = process_chat(agent_executor, user_input, st.session_state.fed_chat_history)\n\n    st.session_state.chat_history.append(HumanMessage(content=user_input))\n    st.session_state.chat_history.append(AIMessage(content=response))\n\n    formatted_human_message = format_message(HumanMessage(content=user_input))\n    formatted_ai_message = format_message(AIMessage(content=response))\n\n\n    # Display assistant response in chat message container\n    with st.chat_message(\"assistant\"):\n        st.markdown(response)\n    # Add assistant response to chat history\n    st.session_state.messages.append({\"role\": \"assistant\", \"content\": response})\n\n\n    # Add the last two messages (HumanMessage and AIMessage) to the vector store\n    if st.session_state.chat_history_vector_store:\n        st.session_state.chat_history_vector_store.add_texts(\n            texts=[st.session_state.chat_history[-2].content, st.session_state.chat_history[-1].content], \n            ids=[str(st.session_state.unique_id), str(st.session_state.unique_id + 1)],\n            metadatas=[\n                {'msg_element': formatted_human_message, 'msg_placement': str(st.session_state.unique_id), 'use_case':'chat_history'},\n                {'msg_element': formatted_ai_message, 'msg_placement': str(st.session_state.unique_id+1), 'use_case':'chat_history'}\n            ],\n            embedding=embedding_function\n        )\n        st.session_state.unique_id += 2\n    else:\n        # Initialize the vector store with the last two messages\n        st.session_state.chat_history_vector_store = Chroma.from_texts(\n            texts=[st.session_state.chat_history[-2].content, st.session_state.chat_history[-1].content], \n            ids=[str(st.session_state.unique_id), str(st.session_state.unique_id + 1)],\n            metadatas=[\n                {'msg_element': formatted_human_message, 'msg_placement': str(st.session_state.unique_id), 'use_case':'chat_history'},\n                {'msg_element': formatted_ai_message, 'msg_placement': str(st.session_state.unique_id+1), 'use_case':'chat_history'}\n            ],\n            embedding=embedding_function\n        )\n        st.session_state.unique_id += 2\n    \n    st.session_state.chat_history = [] # after embedding convos to vector store, clear chat history before the end of the loop\n```\n\n\u003cbr/\u003e\n\n### Knowledge Base Embedding\nThe code for the embedding of the knowledge base can be found [here.](https://colab.research.google.com/drive/1iyz_SkHv7TVDgKJBuRYb1iTtVfxDyGU0?usp=sharing)\n\n\u003cbr/\u003e\n\n### LangSmith Tracing\nLangSmith can be a useful tool for debugging the chatbot application. To trace its runs, do the following:\n- Create a LangSmith account\n- Retrieve API key\n- Create `.env` file\n```python\nLANGCHAIN_TRACING_V2=true\nLANGCHAIN_API_KEY='ENTER_API_KEY_HERE'\nLANGCHAIN_PROJECT='PROJECT_NAME'\n```\n- In the `app.py` file, make sure environment variables are loaded properly.\n```python\nfrom dotenv import load_dotenv\nload_dotenv()\n```\n- LangSmith can be used to check if the LLM calls the appropriate tool/s for the prompt.\n![image](https://github.com/user-attachments/assets/b848364f-512d-436f-9455-40d709112d7e)\n![image](https://github.com/user-attachments/assets/2a8084b6-28a2-41e9-8ad9-f4b5d706e199)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falfonsokan%2Feskwelabs_chatbot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falfonsokan%2Feskwelabs_chatbot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falfonsokan%2Feskwelabs_chatbot/lists"}