add main.py
This commit is contained in:
@@ -1,61 +1,72 @@
|
|||||||
|
"""
|
||||||
|
Simple CLI for the RAG‑agent.
|
||||||
|
|
||||||
|
The agent automatically chooses between a local ChromaDB search and a web search via Tavily.
|
||||||
|
It prints the answer together with the source label.
|
||||||
|
"""
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
from langchain_ollama import ChatOllama
|
from langchain_ollama import OllamaLLM
|
||||||
from langchain.agents import Tool, AgentExecutor, create_openai_tools_agent
|
from langchain_tavily import TavilySearchResults
|
||||||
from langchain.tools import tool
|
from langchain.tools import tool
|
||||||
from langchain.schema import HumanMessage
|
from langchain.agents import initialize_agent, AgentType
|
||||||
|
from langchain.chains import RetrievalQA
|
||||||
|
|
||||||
from vectorstore import create_vectorstore, load_documents
|
from vectorstore import create_vectorstore, load_documents
|
||||||
|
|
||||||
# Load env
|
# Load env for Tavily API key
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY")
|
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY")
|
||||||
if not TAVILY_API_KEY:
|
if not TAVILY_API_KEY:
|
||||||
raise RuntimeError("TAVILY_API_KEY not set in .env")
|
raise RuntimeError("TAVILY_API_KEY is missing in .env")
|
||||||
|
|
||||||
# Setup vector store
|
# 1. Vector store and retriever
|
||||||
vectorstore = create_vectorstore()
|
vectorstore = create_vectorstore()
|
||||||
# Load documents if not already loaded
|
|
||||||
if not Path("./chroma_db/chroma-collections.jsonl").exists():
|
|
||||||
load_documents("documents", vectorstore)
|
load_documents("documents", vectorstore)
|
||||||
|
|
||||||
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
|
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
|
||||||
|
|
||||||
@tool(name="search_local_kb", description="Search local knowledge base in ChromaDB")
|
# 2. Tools
|
||||||
|
@tool(name="search_local_kb", description="Search the local knowledge base using ChromaDB.")
|
||||||
def search_local_kb(query: str, top_k: int = 3) -> str:
|
def search_local_kb(query: str, top_k: int = 3) -> str:
|
||||||
docs = retriever.invoke({"query": query, "k": top_k})
|
docs = retriever.invoke({"query": query}) if hasattr(retriever, "invoke") else retriever.get_relevant_documents(query)
|
||||||
return "\n---\n".join([d.page_content for d in docs])
|
return "\n---\n".join([f"{d.metadata.get('source')}:\n{d.page_content[:200]}…" for d in docs])
|
||||||
|
|
||||||
@tool(name="web_search", description="Search the web via Tavily")
|
@tool(name="web_search", description="Search the web using Tavily.")
|
||||||
def web_search(query: str) -> str:
|
def web_search(query: str) -> str:
|
||||||
from tavily import TavilyClient
|
tavily = TavilySearchResults(api_key=TAVILY_API_KEY, max_results=3)
|
||||||
client = TavilyClient(api_key=TAVILY_API_KEY)
|
results = tavily.run(query)
|
||||||
results = client.search(query, max_results=3)
|
return "\n---\n".join([f"{r['title']} ({r['url']}):\n{r.get('content', '')[:200]}…" for r in results])
|
||||||
return "\n---\n".join([f"{r.title}\n{r.url}" for r in results])
|
|
||||||
|
|
||||||
tools = [search_local_kb, web_search]
|
# 3. Agent with simple routing logic
|
||||||
|
from langchain.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate
|
||||||
|
from langchain.chat_models import ChatOllama
|
||||||
|
|
||||||
system_prompt = (
|
chat = ChatOllama(model="llama3")
|
||||||
"You are an AI assistant that answers user questions.
|
|
||||||
If the answer can be found in local documents, use search_local_kb.\n"
|
system_prompt = "You are an assistant that can answer questions using either a local knowledge base or the web. If the question is about recent events or news, use web_search; otherwise use search_local_kb. Return the answer and specify the source as either chromadb or tavily."
|
||||||
"If the question is about recent events or requires up-to-date info, use web_search.\n"
|
prompt = ChatPromptTemplate.from_messages([
|
||||||
"Always indicate the source of your answer: chromadb or tavily."
|
SystemMessagePromptTemplate.from_template(system_prompt),
|
||||||
|
HumanMessagePromptTemplate.from_template("{input}")
|
||||||
|
])
|
||||||
|
|
||||||
|
agent_chain = initialize_agent(
|
||||||
|
tools=[search_local_kb, web_search],
|
||||||
|
llm=chat,
|
||||||
|
agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION,
|
||||||
|
verbose=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
agent = create_openai_tools_agent(
|
# 4. CLI loop
|
||||||
llm=ChatOllama(model="llama3", temperature=0),
|
if __name__ == "__main__":
|
||||||
tools=tools,
|
print("RAG Agent ready. Type 'exit' to quit.")
|
||||||
system_message=system_prompt,
|
|
||||||
)
|
|
||||||
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
|
|
||||||
|
|
||||||
print("RAG agent ready. Type 'exit' to quit.")
|
|
||||||
while True:
|
while True:
|
||||||
user_input = input("Query: ")
|
try:
|
||||||
if user_input.lower() in {"exit", "quit"}:
|
q = input("Query: ")
|
||||||
|
except EOFError:
|
||||||
break
|
break
|
||||||
response = executor.invoke({"input": user_input})
|
if q.strip().lower() in {"exit", "quit"}:
|
||||||
print(response["output"])
|
break
|
||||||
print("Goodbye!")
|
response = agent_chain.run(q)
|
||||||
|
print(f"\nAnswer:\n{response}\n")
|
||||||
|
|||||||
Reference in New Issue
Block a user