|
| 1 | +import { Callout } from 'nextra/components' |
| 2 | + |
| 3 | +# PremAI RAG Agent |
| 4 | + |
| 5 | +This example demonstrates the use of uAgents with Prem.ai to build a Retrieval-Augmented Generation (RAG) system, The agent handles health and wellness queries, providing informative responses. It integrates intelligent query handling with dynamic knowledge retrieval capabilities, making it a robust solution. |
| 6 | + |
| 7 | +### Supporting documentation |
| 8 | + |
| 9 | +- [Creating an agent↗️](/guides/agents/create-a-uagent) |
| 10 | +- [Creating an interval task ↗️](/guides/agents/interval-task) |
| 11 | +- [Communicating with other agents ↗️](/guides/agents/communicating-with-other-agents) |
| 12 | +- [Register in Almanac ↗️](/guides/agents/register-in-almanac) |
| 13 | +- [Almanac Contract ↗️](/references/contracts/uagents-almanac/almanac-overview) |
| 14 | + |
| 15 | +## Prerequisites |
| 16 | + |
| 17 | +Before proceeding, ensure you have the following: |
| 18 | + |
| 19 | + 1. **Python Development Environment**: |
| 20 | + |
| 21 | + - **Python:** Download and install from [Python official website ↗️](https://www.python.org/downloads/). |
| 22 | + - **Poetry:** Install by following the instructions on [Poetry's official website ↗️](https://python-poetry.org/docs/#installation). |
| 23 | + - Dependencies installed via `poetry add uagents` and other required libraries. |
| 24 | + |
| 25 | + 2. **PremAI Account**: |
| 26 | + |
| 27 | + - Sign up at [PremAI ↗️](https://app.premai.io/accounts/signup/) |
| 28 | + - Access the PremAI dashboard. |
| 29 | + |
| 30 | + |
| 31 | +## Steps to Obtain API Keys |
| 32 | + |
| 33 | +To get the required API key and other details, you need to follow these steps: |
| 34 | + |
| 35 | + 1. **Sign In and Generate an API Key**: |
| 36 | + |
| 37 | + - Log in to your Prem account. |
| 38 | + - Navigate to the API Keys section in your account settings. |
| 39 | + - Generate a new `API key` and securely store it for future use. |
| 40 | + |
| 41 | + 2. **Create a New Project**: |
| 42 | + |
| 43 | + - In the Prem dashboard, go to the Projects section. |
| 44 | + - Click on `Create New Project`. |
| 45 | + - Provide a name and description for your project. |
| 46 | + - After creation, note the `Project ID` associated with your new project. |
| 47 | + |
| 48 | + 3. **Set Up a Repository**: |
| 49 | + |
| 50 | + - Within your project, navigate to the Repositories section. |
| 51 | + - Click on Create New Repository. |
| 52 | + - Provide a name and description for your repository. |
| 53 | + - Add the required document for your use case by clicking on the `Add document` button. |
| 54 | + - After creation, note the `Repository ID` associated with your new repository. |
| 55 | + |
| 56 | +<Callout type="info" emoji="ℹ️"> |
| 57 | + You can obtain the `API_KEY`, `REPO_KEY` and `PROJECT_ID` from the [PremAI dashboard ↗️](https://app.premai.io/projects/). |
| 58 | +</Callout> |
| 59 | + |
| 60 | +## Project Structure |
| 61 | + |
| 62 | +``` |
| 63 | +premai-rag-agent/ |
| 64 | +. |
| 65 | +├── poetry.lock |
| 66 | +├── premai-rag-agent.py |
| 67 | +├── pyproject.toml |
| 68 | +└── README.md |
| 69 | +``` |
| 70 | +## Setting Up Environment Variables |
| 71 | + |
| 72 | +To load the environment variables, use the following command: |
| 73 | + |
| 74 | +- Navigate to the root directory and source the `.env` file by run `source .env` |
| 75 | + |
| 76 | +### Example `.env` File |
| 77 | + |
| 78 | +Here is an example of what your `.env` file might look like: |
| 79 | + |
| 80 | +```bash |
| 81 | +export API_KEY="YOUR_API_KEY" |
| 82 | +export PROJECT_ID="YOUR_PROJECT_ID" |
| 83 | +export REPO_ID="YOUR_REPO_ID" |
| 84 | +``` |
| 85 | + |
| 86 | +## PremAI RAG Agent Setup |
| 87 | + |
| 88 | +### Overview of `query_prem_ai` function. |
| 89 | + |
| 90 | +The `query_prem_ai` function is responsible for querying the Prem.ai API with a user's health-related question. It formats the user's input as a message, then sends the query to the API, which searches a specific repository for relevant responses. The function then processes the API's response, extracting and cleaning the content by removing unnecessary references (like citation numbers). In case of an error, it raises a runtime exception with a descriptive error message. This function enables the system to retrieve tailored health advice based on the user's input. |
| 91 | + |
| 92 | + |
| 93 | +```py copy |
| 94 | +prem_client = Prem(api_key=API_KEY) |
| 95 | + |
| 96 | +def query_prem_ai(user_query): |
| 97 | + """ |
| 98 | + Handles both initial and follow-up queries by calling Prem.ai API. |
| 99 | + """ |
| 100 | + try: |
| 101 | + messages = [{"role": "user", "content": user_query}] |
| 102 | + repositories = dict(ids=[REPO_ID], similarity_threshold=0.25, limit=5) |
| 103 | + response = prem_client.chat.completions.create( |
| 104 | + project_id=PROJECT_ID, |
| 105 | + messages=messages, |
| 106 | + repositories=repositories, |
| 107 | + stream=False, |
| 108 | + model="gpt-4o", |
| 109 | + ) |
| 110 | + final_response = response.choices[0].message.content |
| 111 | + cleaned_response = re.sub(r'\[\d+\]', '', final_response) |
| 112 | + return cleaned_response |
| 113 | + except Exception as e: |
| 114 | + raise RuntimeError(f"Error querying Prem.ai: {e}") |
| 115 | + |
| 116 | +``` |
| 117 | + |
| 118 | +### PremAI agent mechanism |
| 119 | + |
| 120 | +#### 1. User Agent (`user_agent`) |
| 121 | + |
| 122 | +The `user_agent` is responsible for initiating the conversation and receiving the user's queries. It sends the query to the `prem_agent` for processing and displays the response back to the user. It also handles follow-up queries and the exit condition. |
| 123 | + |
| 124 | +```py copy |
| 125 | +user_agent = Agent(name="health_user_agent", seed="health_user_recovery") |
| 126 | + |
| 127 | +@user_agent.on_event("startup") |
| 128 | +async def send_health_query(ctx: Context): |
| 129 | + ctx.logger.info("[health_user_agent]: Sending initial query.") |
| 130 | + await ctx.send(prem_agent.address, HealthQuery(user_query=initial_query)) |
| 131 | + |
| 132 | +@user_agent.on_message(model=HealthResponse, replies={HealthQuery, ExitMessage}) |
| 133 | +async def handle_health_response(ctx: Context, sender: str, msg: HealthResponse): |
| 134 | + ctx.logger.info(f"[health_user_agent]: Received response: {msg.response}") |
| 135 | + follow_up_query = input("Ask your next question (or type 'exit' to quit): ").strip() |
| 136 | + if follow_up_query.lower() in {"exit", "quit"}: |
| 137 | + await ctx.send(sender, ExitMessage(message="Exiting chat. Goodbye!")) |
| 138 | + else: |
| 139 | + await ctx.send(sender, HealthQuery(user_query=follow_up_query)) |
| 140 | +``` |
| 141 | + |
| 142 | +#### Explanation of `user_agent` |
| 143 | + |
| 144 | +- The agent listens for a startup event, where it sends the first health query to the `prem_agent`. |
| 145 | +- When it receives a response from `prem_agent`, it presents the answer to the user and asks if they have a follow-up question. |
| 146 | +- If the user chooses to exit, it sends an exit message to end the conversation. |
| 147 | + |
| 148 | +#### 2. Prem Agent (`prem_agent`) |
| 149 | + |
| 150 | +The `prem_agent` processes the queries by interacting with the Prem.ai API. It retrieves the response from the API and sends it back to the `user_agent`. It also handles errors and exit messages. |
| 151 | + |
| 152 | +```py copy |
| 153 | +prem_agent = Agent(name="health_prem_agent", seed="health_prem_recovery") |
| 154 | + |
| 155 | +@prem_agent.on_message(model=HealthQuery, replies={HealthResponse, ExitMessage}) |
| 156 | +async def process_health_query(ctx: Context, sender: str, msg: HealthQuery): |
| 157 | + ctx.logger.info(f"[health_prem_agent]: Processing query: {msg.user_query}") |
| 158 | + try: |
| 159 | + response = query_prem_ai(msg.user_query) |
| 160 | + await ctx.send(sender, HealthResponse(response=response)) |
| 161 | + except RuntimeError as e: |
| 162 | + await ctx.send(sender, ExitMessage(message="Failed to process query.")) |
| 163 | + |
| 164 | +@prem_agent.on_message(model=ExitMessage) |
| 165 | +async def handle_exit_message(ctx: Context, sender: str, msg: ExitMessage): |
| 166 | + ctx.logger.info(f"[health_prem_agent]: {msg.message}") |
| 167 | + |
| 168 | +``` |
| 169 | + |
| 170 | +#### Explanation of `prem_agent` |
| 171 | + |
| 172 | +- The `prem_agent` listens for `HealthQuery` messages from the `user_agent`. Upon receiving a query, it sends the query to the Prem.ai API for processing. |
| 173 | +- After getting the response, the `prem_agent` sends the answer back to the `user_agent`. |
| 174 | +- If an error occurs, the agent sends an exit message with the error notification. |
| 175 | + |
| 176 | +### Whole Script |
| 177 | + |
| 178 | +This section presents the entire script, allowing users to easily copy and paste it for testing or deployment. |
| 179 | + |
| 180 | +```py copy |
| 181 | +import re |
| 182 | +import os |
| 183 | +from uagents import Field, Model, Context, Agent, Bureau |
| 184 | +from premai import Prem |
| 185 | + |
| 186 | +REPO_ID = os.getenv("REPO_ID") |
| 187 | +PROJECT_ID = os.getenv("PROJECT_ID") |
| 188 | +API_KEY = os.getenv("API_KEY") |
| 189 | + |
| 190 | +prem_client = Prem(api_key=API_KEY) |
| 191 | + |
| 192 | +def query_prem_ai(user_query): |
| 193 | + """ |
| 194 | + Handles both initial and follow-up queries by calling Prem.ai API. |
| 195 | + """ |
| 196 | + try: |
| 197 | + messages = [{"role": "user", "content": user_query}] |
| 198 | + repositories = dict(ids=[REPO_ID], similarity_threshold=0.25, limit=5) |
| 199 | + response = prem_client.chat.completions.create( |
| 200 | + project_id=PROJECT_ID, |
| 201 | + messages=messages, |
| 202 | + repositories=repositories, |
| 203 | + stream=False, |
| 204 | + model="gpt-4o", |
| 205 | + ) |
| 206 | + final_response = response.choices[0].message.content |
| 207 | + cleaned_response = re.sub(r'\[\d+\]', '', final_response) |
| 208 | + return cleaned_response |
| 209 | + except Exception as e: |
| 210 | + raise RuntimeError(f"Error querying Prem.ai: {e}") |
| 211 | + |
| 212 | + |
| 213 | +class HealthQuery(Model): |
| 214 | + user_query: str = Field(description="The user's initial or follow-up query about health and wellness.") |
| 215 | + |
| 216 | +class HealthResponse(Model): |
| 217 | + response: str = Field(description="The response text returned by the Prem.ai API.") |
| 218 | + |
| 219 | +class ExitMessage(Model): |
| 220 | + message: str = Field(description="The exit message sent to the user when the chat session ends.") |
| 221 | + |
| 222 | +user_agent = Agent(name="health_user_agent", seed="health_user_recovery") |
| 223 | +prem_agent = Agent(name="health_prem_agent", seed="health_prem_recovery") |
| 224 | + |
| 225 | +initial_query = input("Ask your health and wellness question: ").strip() |
| 226 | + |
| 227 | +@user_agent.on_event("startup") |
| 228 | +async def send_health_query(ctx: Context): |
| 229 | + ctx.logger.info("[health_user_agent]: Sending initial query.") |
| 230 | + await ctx.send(prem_agent.address, HealthQuery(user_query=initial_query)) |
| 231 | + |
| 232 | +@user_agent.on_message(model=HealthResponse, replies={HealthQuery, ExitMessage}) |
| 233 | +async def handle_health_response(ctx: Context, sender: str, msg: HealthResponse): |
| 234 | + ctx.logger.info(f"[health_user_agent]: Received response: {msg.response}") |
| 235 | + follow_up_query = input("Ask your next question (or type 'exit' to quit): ").strip() |
| 236 | + if follow_up_query.lower() in {"exit", "quit"}: |
| 237 | + await ctx.send(sender, ExitMessage(message="Exiting chat. Goodbye!")) |
| 238 | + else: |
| 239 | + await ctx.send(sender, HealthQuery(user_query=follow_up_query)) |
| 240 | + |
| 241 | + |
| 242 | +@prem_agent.on_message(model=HealthQuery, replies={HealthResponse, ExitMessage}) |
| 243 | +async def process_health_query(ctx: Context, sender: str, msg: HealthQuery): |
| 244 | + ctx.logger.info(f"[health_prem_agent]: Processing query: {msg.user_query}") |
| 245 | + try: |
| 246 | + response = query_prem_ai(msg.user_query) |
| 247 | + await ctx.send(sender, HealthResponse(response=response)) |
| 248 | + except RuntimeError as e: |
| 249 | + await ctx.send(sender, ExitMessage(message="Failed to process query.")) |
| 250 | + |
| 251 | +@prem_agent.on_message(model=ExitMessage) |
| 252 | +async def handle_exit_message(ctx: Context, sender: str, msg: ExitMessage): |
| 253 | + ctx.logger.info(f"[health_prem_agent]: {msg.message}") |
| 254 | + |
| 255 | +bureau = Bureau(port=8000, endpoint="http://localhost:8000/submit") |
| 256 | +bureau.add(user_agent) |
| 257 | +bureau.add(prem_agent) |
| 258 | + |
| 259 | +if __name__ == "__main__": |
| 260 | + bureau.run() |
| 261 | + |
| 262 | +``` |
| 263 | + |
| 264 | +### Poetry Dependencies: |
| 265 | + |
| 266 | +```py |
| 267 | +[tool.poetry.dependencies] |
| 268 | +python = ">=3.9,<3.13" |
| 269 | +uagents = "^0.18.1" |
| 270 | +python-dotenv = "^1.0.1" |
| 271 | +premai = "^0.3.79" |
| 272 | +``` |
| 273 | + |
| 274 | +### Instructions to execute the example. |
| 275 | + |
| 276 | +- Navigate to the root folder of the example. |
| 277 | +- Update the `.env` file with require variables. |
| 278 | +- Install dependencies by running `poetry install`. |
| 279 | +- Execute the script with `python premai-rag-agent.py`. |
| 280 | + |
| 281 | + |
| 282 | +## Expected Output |
| 283 | + |
| 284 | +``` |
| 285 | +Ask your health and wellness question: How does sleep affect overall wellness? |
| 286 | +INFO: [health_user_agent]: Starting agent with address: agent1q02chts3w84vfa83t2egvt8tfg33h84na6mmut8rvmq5v5n9fyppjkx89yd |
| 287 | +INFO: [health_user_agent]: [health_user_agent]: Sending initial query. |
| 288 | +INFO: [health_prem_agent]: Starting agent with address: agent1qtpx9u4phc5vnt9mpt26x6p397wx89ymadkq2w9hrmtxse609g8py3k4e3y |
| 289 | +INFO: [health_user_agent]: Registering on almanac contract... |
| 290 | +INFO: [health_prem_agent]: Registering on almanac contract... |
| 291 | +INFO: [health_prem_agent]: [health_prem_agent]: Processing query: How does sleep affect overall wellness? |
| 292 | +INFO:httpx:HTTP Request: POST https://app.premai.io/v1/chat/completions "HTTP/1.1 200 OK" |
| 293 | +INFO: [bureau]: Starting server on http://0.0.0.0:8000 (Press CTRL+C to quit) |
| 294 | +INFO: [health_user_agent]: [health_user_agent]: Received response: Sleep plays a crucial role in overall wellness, influencing various aspects of physical and mental health. Here are some key ways in which sleep affects wellness: |
| 295 | +
|
| 296 | +1. **Physical Health**: Sleep is vital for maintaining physical health. It supports bodily functions such as tissue repair, muscle growth, and immune function. Lack of sleep has been linked to a higher risk of chronic conditions such as obesity, heart disease, and diabetes. |
| 297 | +
|
| 298 | +2. **Cognitive Function**: Adequate sleep is essential for optimal brain function. It affects concentration, productivity, and performance. Sleep is also crucial for memory consolidation, allowing the brain to process and retain information. |
| 299 | +
|
| 300 | +Overall, prioritizing good sleep hygiene and establishing a consistent sleep routine are foundational to maintaining overall wellness and enhancing quality of life. |
| 301 | +Ask your next question (or type 'exit' to quit): How can hydration improve overall health? |
| 302 | +INFO: [health_prem_agent]: [health_prem_agent]: Processing query: How can hydration improve overall health? |
| 303 | +INFO:httpx:HTTP Request: POST https://app.premai.io/v1/chat/completions "HTTP/1.1 200 OK" |
| 304 | +INFO: [health_user_agent]: Registering on almanac contract...complete |
| 305 | +INFO: [health_prem_agent]: Registering on almanac contract...complete |
| 306 | +INFO: [health_user_agent]: [health_user_agent]: Received response: Hydration significantly impacts overall health and well-being in various ways. Here are some key benefits: |
| 307 | +
|
| 308 | +1. **Physical Performance**: Proper hydration is crucial for maintaining physical performance. It helps regulate body temperature, lubricates joints, and delivers nutrients to cells, which is essential for physical activities, both in everyday life and during exercise. |
| 309 | +
|
| 310 | +2. **Cognitive Function**: Dehydration can affect cognitive functions such as attention, memory, and mood. Staying hydrated helps maintain cognitive performance and may reduce feelings of fatigue and confusion. |
| 311 | +
|
| 312 | +Overall, maintaining proper hydration is a simple yet powerful way to promote health and prevent various physical and cognitive issues. It is generally recommended to drink an adequate amount of water daily, which can vary based on factors like age, climate, activity level, and individual health needs. |
| 313 | +Ask your next question (or type 'exit' to quit): |
| 314 | +``` |
0 commit comments