What We Are Building
A Personal Research Assistant that:
- Searches the web for information
- Reads and summarizes articles
- Saves research notes
- Generates reports
- Has a beautiful web interface
Project Structure
Architecture Diagram
research-agent/
app.py # Main Streamlit app
agent.py # Agent logic
tools.py # Custom tools
database.py # SQLite for notes
requirements.txt # Dependencies
.env # API keys
Step 1: Install Dependencies
pip install streamlit langchain langchain-openai duckduckgo-search python-dotenv
Step 2: Create Database
python
# database.py
import sqlite3
from datetime import datetime
def init_db():
conn = sqlite3.connect("research.db")
conn.execute("""
CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
topic TEXT NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
conn.commit()
conn.close()
def save_note(topic, content):
conn = sqlite3.connect("research.db")
conn.execute("INSERT INTO notes (topic, content) VALUES (?, ?)", (topic, content))
conn.commit()
conn.close()
def get_notes(limit=10):
conn = sqlite3.connect("research.db")
notes = conn.execute(
"SELECT topic, content, created_at FROM notes ORDER BY created_at DESC LIMIT ?",
(limit,)
).fetchall()
conn.close()
return notes
Step 3: Create Tools
python
# tools.py
from langchain_core.tools import tool
from duckduckgo_search import DDGS
@tool
def web_search(query: str) -> str:
"""Search the web for current information on any topic"""
with DDGS() as ddgs:
results = list(ddgs.text(query, max_results=5))
return "\n".join([f"**{r['title']}**\n{r['body'][:200]}..." for r in results])
@tool
def summarize_text(text: str) -> str:
"""Create a concise summary of the given text"""
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o")
response = llm.invoke(f"Summarize this in 3-5 key points:\n\n{text}")
return response.content
@tool
def save_research(topic: str, findings: str) -> str:
"""Save research findings to the database"""
from database import save_note
save_note(topic, findings)
return f"Research on '{topic}' saved successfully!"
@tool
def get_saved_notes() -> str:
"""Retrieve previously saved research notes"""
from database import get_notes
notes = get_notes(5)
if not notes:
return "No saved notes yet."
return "\n\n".join([f"**{n[0]}** ({n[2]}):\n{n[1]}" for n in notes])
Step 4: Create Agent
python
# agent.py
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
from tools import web_search, summarize_text, save_research, get_saved_notes
def create_agent():
llm = ChatOpenAI(model="gpt-4o", temperature=0)
agent = create_react_agent(
model=llm,
tools=[web_search, summarize_text, save_research, get_saved_notes],
)
return agent
Step 5: Create Web Interface
python
# app.py
import streamlit as st
from agent import create_agent
from database import init_db, get_notes
# Initialize
st.set_page_config(page_title="Research Assistant", page_icon="đŦ")
init_db()
st.title("đŦ AI Research Assistant")
st.caption("Search, summarize, and save research findings")
# Initialize agent
if "agent" not in st.session_state:
st.session_state.agent = create_agent()
if "messages" not in st.session_state:
st.session_state.messages = []
# Sidebar - Saved Notes
with st.sidebar:
st.header("đ Saved Notes")
notes = get_notes(10)
if notes:
for note in notes:
with st.expander(note[0]):
st.write(note[1])
st.caption(note[2])
else:
st.info("No notes saved yet. Start researching!")
# Chat interface
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
if prompt := st.chat_input("What would you like to research?"):
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
with st.chat_message("assistant"):
with st.spinner("Researching..."):
result = st.session_state.agent.invoke({
"messages": [{"role": "user", "content": prompt}]
})
response = result["messages"][-1].content
st.markdown(response)
st.session_state.messages.append({"role": "assistant", "content": response})
Step 6: Run It
streamlit run app.py
How to Extend This Project
Add More Tools
python
@tool
def read_url(url: str) -> str:
"""Read and extract text from a URL"""
import requests
from bs4 import BeautifulSoup
response = requests.get(url)
soup = BeautifulSoup(response.text, "html.parser")
return soup.get_text()[:2000]
Add User Authentication
python
import streamlit as st
if "authenticated" not in st.session_state:
st.session_state.authenticated = False
if not st.session_state.authenticated:
password = st.text_input("Password", type="password")
if password == "secret":
st.session_state.authenticated = True
else:
st.stop()
What You Learned
| Skill | What You Can Do |
|---|---|
| LangChain | Build AI agents with tools |
| LangGraph | Create complex workflows |
| RAG | Give agents knowledge |
| Streamlit | Build web interfaces |
| SQLite | Save and retrieve data |
| Deployment | Put apps online |