3.6 KiB
3.6 KiB
What was implemented
- A FastAPI service exposing a single
/askendpoint that accepts a user question and returns an answer together with the sources used. - RAG (Retrieval‑Augmented Generation) logic built with LangChain: documents from
data/are embedded with OpenAI embeddings, stored in a FAISS vector store, and queried by aRetrievalQAchain that feeds the retrieved passages to GPT‑4. - Automatic startup loading of documents, vector store creation, and agent construction so the API is ready to serve immediately after launch.
Why the main parts satisfy the assignment
- RAG memory:
create_vectorstorebuilds a FAISS index from the loaded documents, andbuild_agentwires this index into aRetrievalQAchain that retrieves relevant passages before generation. - Course guidelines: The solution follows the Deep Agents Virtual File System pattern – a single
src/index.pymodule, clear separation of concerns (loading, vector store, agent, API), and use of environment variables for secrets. - Python implementation: All code is pure Python 3.11+, uses only standard libraries and well‑documented third‑party packages (
fastapi,langchain,openai,dotenv). - Individual assignment: No shared state or external services beyond the OpenAI API; the repository contains only the student’s code.
Key code excerpts
Loading documents (src/index.py)
def load_documents(path: Path) -> List:
if not path.exists() or not path.is_dir():
print(f"Warning: Data directory '{path}' not found. No documents loaded.")
return []
loader = DirectoryLoader(str(path), glob="**/*.txt")
documents = loader.load()
print(f"Loaded {len(documents)} documents from '{path}'.")
return documents
Creating the vector store (src/index.py)
def create_vectorstore(documents: List) -> FAISS:
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(documents, embeddings)
print("FAISS vector store created.")
return vectorstore
Building the RetrievalQA agent (src/index.py)
def build_agent(vectorstore: FAISS) -> RetrievalQA:
llm = OpenAI(model_name="gpt-4", temperature=0, openai_api_key=OPENAI_API_KEY)
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
return_source_documents=True,
)
print("RetrievalQA agent constructed.")
return qa_chain
FastAPI endpoint (src/index.py)
@app.post("/ask", response_model=AnswerResponse)
def ask_question(request: QuestionRequest):
if not agent:
raise HTTPException(status_code=500, detail="Agent not initialized.")
try:
result = agent({"question": request.question})
answer = result.get("answer", "")
sources = [doc.metadata.get("source", "") for doc in result.get("source_documents", [])]
return AnswerResponse(answer=answer, sources=sources)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
Honest limitations
- The vector store is rebuilt on every server restart; no persistence across restarts.
- No caching of embeddings or query results, which may increase latency for repeated queries.
- Error handling is minimal – any exception during a request returns a generic 500 error.
- The solution assumes all documents are plain
.txt; other formats would need additional loaders.
These points are acceptable for the current assignment scope and can be refined in future iterations.