Files
agent-s-rag-pamyatyu/SOLUTION.md
T
2026-07-01 10:57:34 +03:00

72 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
**What was implemented**
- A FastAPI service exposing a single `/ask` endpoint that accepts a user question and returns an answer together with the sources used.
- RAG (RetrievalAugmented Generation) logic built with LangChain: documents from `data/` are embedded with OpenAI embeddings, stored in a FAISS vector store, and queried by a `RetrievalQA` chain that feeds the retrieved passages to GPT4.
- 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_vectorstore` builds a FAISS index from the loaded documents, and `build_agent` wires this index into a `RetrievalQA` chain that retrieves relevant passages before generation.
- **Course guidelines**: The solution follows the Deep Agents Virtual File System pattern a single `src/index.py` module, 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 welldocumented thirdparty packages (`fastapi`, `langchain`, `openai`, `dotenv`).
- **Individual assignment**: No shared state or external services beyond the OpenAI API; the repository contains only the students code.
**Key code excerpts**
*Loading documents* (`src/index.py`)
```python
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`)
```python
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`)
```python
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`)
```python
@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.