Customer Service Discord Bot Using Local Models with Agentic RAG
You can also check this cookbook in colab hereTo run this, press “Runtime” and press “Run all” on a free Tesla T4 Google Colab instance!This notebook demonstrates how to build a customer service Discord bot powered by Retrieval Augmented Generation (RAG) using local models. It leverages the following technologies:
CAMEL: An open-source toolkit for building and deploying large language model (LLM) applications.
Firecrawl: A tool for web scraping and creating a local knowledge base.
Qdrant: A vector database for efficient knowledge retrieval.
Ollama: A local model deployment for running the LLM without external dependencies.
By following this notebook, you can build your own custom customer service bot that uses local models and a custom knowledge base.
Join our Discord if you need help + ⭐ Star us on Github ⭐
Next, prepare the knowledge base with Firecrawl. Firecrawl is a versatile web scraping and crawling tool designed to extract data efficiently from websites, which has been integrated with CAMEL. For more information, you can check out our Firecrawl cookbook: https://colab.research.google.com/drive/1lOmM3VmgR1hLwDKdeLGFve_75RFW0R9I?usp=sharing#scrollTo=1Nj0Oqnoy6oJLet’s set up your Firecrawl! You may skip this part if you already have your knowledge file.In order to run everything locally, we can use self-hosted firecrawl.For more details, please check out firecrawl documentation: https://docs.firecrawl.dev/contributing/guide
Copy
from getpass import getpassfirecrawl_api_url = getpass('Enter your API url: ')
Please make a copy of this notebook (important), or run this notebook locally.If you choose to make a copy of this notebook and stay in Google colab, connect the copied notebook to your local runtime by follow the following steps:
Install notebook locally by running the following command in your terminal:
After setting up Ollama, pull the Llama3 model by typing the following command into the terminal:
Copy
ollama pull qwq3. cd into a desired directory```bashcd <target_drectory_path>4. Create a `ModelFile` similar the one below in your project directory. (Optional)```bashFROM qwq# Set parametersPARAMETER temperature 0.8PARAMETER stop Result# Sets a custom system message to specify the behavior of the chat assistant# Leaving it blank for now.SYSTEM """ """
Create a script to get the base model (llama3) and create a custom model using the ModelFile above. Save this as a .sh file: (Optional)
Copy
#!/bin/zsh # variables model_name="qwq" custom_model_name="camel-qwq" #get the base model ollama pull $model_name #create the model file ollama create $custom_model_name -f ./ModelFile
from camel.agents import ChatAgentfrom camel.logger import disable_loggingdisable_logging()chat_agent = ChatAgent( system_message="You're a helpful assistant", message_window_size=10, model=ollama_model, token_limit=8192, #change base on your input size)
with open('local_data/camel.md', 'r') as file: knowledge = file.read()knowledge_message = BaseMessage.make_user_message( role_name="User", content=f"Based on the following knowledge: {knowledge}")chat_agent.update_memory(knowledge_message, "user")
print("Start chatting! Type 'exit' to end the conversation.")while True: user_input = input("User: ") if user_input.lower() == "exit": print("Ending conversation.") break assistant_response = chat_agent.step(user_input) print(f"Assistant: {assistant_response.msgs[0].content}")
Alternatively, if running on Colab, you could save your API keys and tokens as Colab Secrets, and use them across notebooks.To do so, comment out the above manual API key prompt code block(s), and uncomment the following codeblock.⚠️ Don’t forget granting access to the API key you would be using to the current notebook.
Copy
# import os# from google.colab import userdata# os.environ["DISCORD_BOT_TOKEN"] = userdata.get("DISCORD_BOT_TOKEN")
This code cell sets up a simple Discord bot using the DiscordApp class from the camel.bots library. The bot listens for messages in any channel it has access to and provides a response based on the input message.
Copy
from camel.bots import DiscordAppimport nest_asyncioimport discordnest_asyncio.apply()discord_bot = DiscordApp(token=discord_bot_token)@discord_bot.client.eventasync def on_message(message: discord.Message): if message.author == discord_bot.client.user: return if message.type != discord.MessageType.default: return if message.author.bot: return user_input = message.content chat_agent.reset() chat_agent.update_memory(knowledge_message, "user") assistant_response = chat_agent.step(user_input) response_content = assistant_response.msgs[0].content if len(response_content) > 2000: # discord message length limit for chunk in [response_content[i:i+2000] for i in range(0, len(response_content), 2000)]: await message.channel.send(chunk) else: await message.channel.send(response_content)discord_bot.run()
Integrating Qdrant for Large Files to build a more powerful Discord bot
Qdrant is a vector similarity search engine and vector database. It is designed to perform fast and efficient similarity searches on large datasets of vectors. This enables the chatbot to access and utilize external information to provide more comprehensive and accurate responses. By storing knowledge as vectors, Qdrant enables efficient semantic search, allowing the chatbot to find relevant information based on the meaning of the user’s query.Set up an embedding model and retriever for Qdrant: feel free switch to other embedding models supported by CAMEL.Set up an embedding model and retriever for Qdrant:
Copy
from camel.embeddings import SentenceTransformerEncoder # CAMEL also support other embeddingsentence_encoder = SentenceTransformerEncoder(model_name='intfloat/e5-large-v2')
Set up the AutoRetriever for automatically retrieving relevant information from a storage system.
Copy
from camel.retrievers import AutoRetrieverfrom camel.types import StorageTypeassistant_sys_msg = """You are a helpful assistant to answer question, I will give you the Original Query and Retrieved Context, answer the Original Query based on the Retrieved Context, if you can't answer the question just say I don't know. Just give the answer to me directly, no more other words needed. """auto_retriever = AutoRetriever( vector_storage_local_path="local_data2/", storage_type=StorageType.QDRANT, embedding_model=sentence_encoder )chat_agent_with_rag = ChatAgent( system_message=assistant_sys_msg, model=ollama_model, token_limit=8192, #change base on your input size)
Use Auto RAG to retrieve first and then answer the user’s query using CAMEL ChatAgent based on the retrieved info:If you are connecting this cookbook to a local runtime, adding files in your local path in contents might cause an error.
Copy
from camel.bots import DiscordAppimport nest_asyncioimport discordnest_asyncio.apply()discord_q_bot = DiscordApp(token=discord_bot_token)@discord_q_bot.client.event # triggers when a message is sent in the channelasync def on_message(message: discord.Message): if message.author == discord_q_bot.client.user: return if message.type != discord.MessageType.default: return if message.author.bot: return user_input = message.content query_and_retrieved_info = auto_retriever.run_vector_retriever( query=user_input, contents=[ # don't add a local path if you are connecting to a local runtime "https://docs.camel-ai.org/", #replace with your knowledge base ], top_k=3, return_detailed_info=False, similarity_threshold=0.5 ) user_msg = str(query_and_retrieved_info) assistant_response = chat_agent_with_rag.step(user_msg) response_content = assistant_response.msgs[0].content print(3) if len(response_content) > 2000: # discord message length limit for chunk in [response_content[i:i+2000] for i in range(0, len(response_content), 2000)]: await message.channel.send(chunk) else: await message.channel.send(response_content)discord_q_bot.run()
That’s everything: Got questions about 🐫 CAMEL-AI? Join us on Discord! Whether you want to share feedback, explore the latest in multi-agent systems, get support, or connect with others on exciting projects, we’d love to have you in the community! 🤝Check out some of our other work: