forked from Shubhamsaboo/awesome-llm-apps
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrag_reasoning_agent.py
More file actions
229 lines (199 loc) · 8.22 KB
/
rag_reasoning_agent.py
File metadata and controls
229 lines (199 loc) · 8.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
import streamlit as st
from agno.agent import Agent, RunEvent
from agno.embedder.openai import OpenAIEmbedder
from agno.knowledge.url import UrlKnowledge
from agno.models.anthropic import Claude
from agno.tools.reasoning import ReasoningTools
from agno.vectordb.lancedb import LanceDb, SearchType
from dotenv import load_dotenv
import os
# Load environment variables
load_dotenv()
# Page configuration
st.set_page_config(
page_title="Agentic RAG with Reasoning",
page_icon="🧐",
layout="wide"
)
# Main title and description
st.title("🧐 Agentic RAG with Reasoning")
st.markdown("""
This app demonstrates an AI agent that:
1. **Retrieves** relevant information from knowledge sources
2. **Reasons** through the information step-by-step
3. **Answers** your questions with citations
Enter your API keys below to get started!
""")
# API Keys Section
st.subheader("🔑 API Keys")
col1, col2 = st.columns(2)
with col1:
anthropic_key = st.text_input(
"Anthropic API Key",
type="password",
value=os.getenv("ANTHROPIC_API_KEY", ""),
help="Get your key from https://console.anthropic.com/"
)
with col2:
openai_key = st.text_input(
"OpenAI API Key",
type="password",
value=os.getenv("OPENAI_API_KEY", ""),
help="Get your key from https://platform.openai.com/"
)
# Check if API keys are provided
if anthropic_key and openai_key:
# Initialize knowledge base (cached to avoid reloading)
@st.cache_resource(show_spinner="📚 Loading knowledge base...")
def load_knowledge() -> UrlKnowledge:
"""Load and initialize the knowledge base with vector database"""
kb = UrlKnowledge(
urls=["https://docs.agno.com/introduction/agents.md"], # Default URL
vector_db=LanceDb(
uri="tmp/lancedb",
table_name="agno_docs",
search_type=SearchType.vector, # Use vector search
embedder=OpenAIEmbedder(
api_key=openai_key
),
),
)
kb.load(recreate=True) # Load documents into vector DB
return kb
# Initialize agent (cached to avoid reloading)
@st.cache_resource(show_spinner="🤖 Loading agent...")
def load_agent(_kb: UrlKnowledge) -> Agent:
"""Create an agent with reasoning capabilities"""
return Agent(
model=Claude(
id="claude-sonnet-4-20250514",
api_key=anthropic_key
),
knowledge=_kb,
search_knowledge=True, # Enable knowledge search
tools=[ReasoningTools(add_instructions=True)], # Add reasoning tools
instructions=[
"Include sources in your response.",
"Always search your knowledge before answering the question.",
],
markdown=True, # Enable markdown formatting
)
# Load knowledge and agent
knowledge = load_knowledge()
agent = load_agent(knowledge)
# Sidebar for knowledge management
with st.sidebar:
st.header("📚 Knowledge Sources")
st.markdown("Add URLs to expand the knowledge base:")
# Show current URLs
st.write("**Current sources:**")
for i, url in enumerate(knowledge.urls):
st.text(f"{i+1}. {url}")
# Add new URL
st.divider()
new_url = st.text_input(
"Add new URL",
placeholder="https://example.com/docs",
help="Enter a URL to add to the knowledge base"
)
if st.button("➕ Add URL", type="primary"):
if new_url:
with st.spinner("📥 Loading new documents..."):
knowledge.urls.append(new_url)
knowledge.load(
recreate=False, # Don't recreate DB
upsert=True, # Update existing docs
skip_existing=True # Skip already loaded docs
)
st.success(f"✅ Added: {new_url}")
st.rerun() # Refresh to show new URL
else:
st.error("Please enter a URL")
# Main query section
st.divider()
st.subheader("🤔 Ask a Question")
# Query input
query = st.text_area(
"Your question:",
value="What are Agents?",
height=100,
help="Ask anything about the loaded knowledge sources"
)
# Run button
if st.button("🚀 Get Answer with Reasoning", type="primary"):
if query:
# Create containers for streaming updates
col1, col2 = st.columns([1, 1])
with col1:
st.markdown("### 🧠 Reasoning Process")
reasoning_container = st.container()
reasoning_placeholder = reasoning_container.empty()
with col2:
st.markdown("### 💡 Answer")
answer_container = st.container()
answer_placeholder = answer_container.empty()
# Variables to accumulate content
citations = []
answer_text = ""
reasoning_text = ""
# Stream the agent's response
with st.spinner("🔍 Searching and reasoning..."):
for chunk in agent.run(
query,
stream=True, # Enable streaming
show_full_reasoning=True, # Show reasoning steps
stream_intermediate_steps=True, # Stream intermediate updates
):
# Update reasoning display
if chunk.reasoning_content:
reasoning_text = chunk.reasoning_content
reasoning_placeholder.markdown(
reasoning_text,
unsafe_allow_html=True
)
# Update answer display
if chunk.content and chunk.event in {RunEvent.run_response, RunEvent.run_completed}:
if isinstance(chunk.content, str):
answer_text += chunk.content
answer_placeholder.markdown(
answer_text,
unsafe_allow_html=True
)
# Collect citations
if chunk.citations and chunk.citations.urls:
citations = chunk.citations.urls
# Show citations if available
if citations:
st.divider()
st.subheader("📚 Sources")
for cite in citations:
title = cite.title or cite.url
st.markdown(f"- [{title}]({cite.url})")
else:
st.error("Please enter a question")
else:
# Show instructions if API keys are missing
st.info("""
👋 **Welcome! To use this app, you need:**
1. **Anthropic API Key** - For Claude AI model
- Sign up at [console.anthropic.com](https://console.anthropic.com/)
2. **OpenAI API Key** - For embeddings
- Sign up at [platform.openai.com](https://platform.openai.com/)
Once you have both keys, enter them above to start!
""")
# Footer with explanation
st.divider()
with st.expander("📖 How This Works"):
st.markdown("""
**This app uses the Agno framework to create an intelligent Q&A system:**
1. **Knowledge Loading**: URLs are processed and stored in a vector database (LanceDB)
2. **Vector Search**: Uses OpenAI's embeddings for semantic search to find relevant information
3. **Reasoning Tools**: The agent uses special tools to think through problems step-by-step
4. **Claude AI**: Anthropic's Claude model processes the information and generates answers
**Key Components:**
- `UrlKnowledge`: Manages document loading from URLs
- `LanceDb`: Vector database for efficient similarity search
- `OpenAIEmbedder`: Converts text to embeddings using OpenAI's embedding model
- `ReasoningTools`: Enables step-by-step reasoning
- `Agent`: Orchestrates everything to answer questions
""")