feat: solution for 'Экзамен: RAG-агент с ChromaDB и веб-поиском'
This commit is contained in:
+64
-27
@@ -1,43 +1,80 @@
|
||||
**What was implemented**
|
||||
- Replaced the previous Qdrant‑based vector store with a lightweight wrapper around **ChromaDB** (`src/vector_store.py`).
|
||||
- Updated the `RAGAgent` to work exclusively with the new `ChromaVectorStore`.
|
||||
- Kept the FastAPI endpoints (`/ingest`, `/query`, `/websearch`) unchanged, so the public API and web‑search logic remain intact.
|
||||
- Removed every import and reference to Qdrant, ensuring the stack now matches the assignment.
|
||||
**SOLUTION.md**
|
||||
|
||||
**Why the main parts satisfy the requirements**
|
||||
- `ChromaVectorStore` creates a Chroma client and a collection, then exposes `add_documents` and `similarity_search` that match the original Qdrant interface.
|
||||
- `RAGAgent` uses this store for ingestion and querying, and still relies on OpenAI embeddings, so the RAG workflow is preserved.
|
||||
- The FastAPI app simply forwards requests to the agent; no Qdrant code is touched, so the vector database is now exclusively ChromaDB.
|
||||
- Web‑search utilities (`src/web_search.py`) are untouched, so the search‑to‑ingest pipeline continues to work.
|
||||
### Что реализовано
|
||||
- **ChromaDB** вместо Qdrant: подключаем клиент, создаём коллекцию и сохраняем векторные представления документов.
|
||||
- **Разбиение текста** на чанки, чтобы не превышать лимит токенов при эмбеддинге.
|
||||
- **Веб‑поиск** через DuckDuckGo (HTML‑парсинг) для получения дополнительных контекстов.
|
||||
- **RAG‑pipeline**: поиск в ChromaDB → добавление веб‑сниппетов → генерация ответа GPT‑3.5‑turbo.
|
||||
- **CLI**: `add <file>` для загрузки документов, `ask <question>` для запросов.
|
||||
|
||||
**Key code excerpts**
|
||||
### Почему это соответствует требованиям
|
||||
- **ChromaDB** – указанная в условии векторная база. В коде используется `chromadb.Client` и `Settings(persist_directory=…)`.
|
||||
- **Веб‑поиск** реализован через `requests` + `BeautifulSoup`, возвращает несколько сниппетов.
|
||||
- **RAG**: `ChromaVectorStore.query` возвращает ближайшие документы, а `generate_answer` формирует финальный ответ, учитывая как локальный контекст, так и веб‑сниппеты.
|
||||
- **CLI** упрощает взаимодействие и демонстрирует полный цикл от загрузки до ответа.
|
||||
|
||||
`src/vector_store.py` – Chroma client and collection creation
|
||||
### Ключевые фрагменты кода
|
||||
|
||||
**src/index.py – embed_text**
|
||||
```python
|
||||
self.client = chromadb.Client()
|
||||
self.collection = self.client.get_or_create_collection(name=collection_name)
|
||||
def embed_text(text: str) -> List[float]:
|
||||
response = openai.Embedding.create(
|
||||
input=text,
|
||||
model=EMBEDDING_MODEL,
|
||||
)
|
||||
return response["data"][0]["embedding"]
|
||||
```
|
||||
|
||||
`src/rag_agent.py` – ingestion uses the new store
|
||||
**src/index.py – chunk_text**
|
||||
```python
|
||||
self.vector_store.add_documents(docs_with_embeddings)
|
||||
def chunk_text(text: str, max_tokens: int = 500) -> List[str]:
|
||||
max_chars = max_tokens * 4
|
||||
paragraphs = [p.strip() for p in text.split("\n") if p.strip()]
|
||||
...
|
||||
return chunks
|
||||
```
|
||||
|
||||
`src/main.py` – FastAPI endpoint that calls the agent
|
||||
**src/index.py – ChromaVectorStore**
|
||||
```python
|
||||
@app.post("/ingest")
|
||||
def ingest(request: IngestRequest):
|
||||
docs = [doc.dict() for doc in request.documents]
|
||||
rag_agent.ingest(docs)
|
||||
class ChromaVectorStore:
|
||||
def __init__(self, collection_name: str = CHROMA_COLLECTION_NAME):
|
||||
self.client: Client = chromadb.Client(
|
||||
Settings(persist_directory=CHROMA_PERSIST_DIR,
|
||||
anonymized_telemetry=False)
|
||||
)
|
||||
self.collection = self.client.get_or_create_collection(name=collection_name)
|
||||
```
|
||||
|
||||
`src/web_search.py` – still feeds results into the agent
|
||||
**src/index.py – add_documents_from_file**
|
||||
```python
|
||||
agent.ingest(docs_to_ingest)
|
||||
def add_documents_from_file(file_path: str) -> None:
|
||||
...
|
||||
documents = [{"text": chunk, "metadata": {"source": file_path}} for chunk in chunks]
|
||||
store = ChromaVectorStore()
|
||||
store.add_documents(documents)
|
||||
```
|
||||
|
||||
**Honest limitations**
|
||||
- ChromaDB is used in its default in‑memory mode; data will not persist across server restarts unless a persistent storage path is configured.
|
||||
- No additional error handling for Chroma connection failures has been added beyond the basic try/except in the API routes.
|
||||
**src/index.py – ask_query**
|
||||
```python
|
||||
def ask_query(query: str) -> None:
|
||||
store = ChromaVectorStore()
|
||||
chroma_results = store.query(query, k=5)
|
||||
chroma_context = "\n\n".join([doc["document"] for doc in chroma_results])
|
||||
|
||||
Overall, the project now uses only ChromaDB for vector storage, keeps all existing functionality, and respects the assignment constraints.
|
||||
web_snippets = web_search(query, num_results=3)
|
||||
web_context = "\n\n".join(web_snippets)
|
||||
|
||||
combined_context = "\n\n---\n\n".join(filter(None, [chroma_context, web_context]))
|
||||
answer = generate_answer(combined_context, query)
|
||||
print("\nAnswer:\n")
|
||||
print(answer)
|
||||
```
|
||||
|
||||
### Ограничения и возможные улучшения
|
||||
- **Идентификаторы** генерируются простым префиксом; при больших коллекциях возможны коллизии.
|
||||
- **Отсутствует** кэширование веб‑результатов и ограничение частоты запросов к DuckDuckGo.
|
||||
- **Нет** обработки ошибок при чтении файлов и при работе с ChromaDB (например, при отсутствии коллекции).
|
||||
- **Тесты** не покрыты – стоит добавить unit‑тесты для `embed_text`, `chunk_text`, `web_search` и `ChromaVectorStore`.
|
||||
- **Параметры** (количество результатов, токен‑лимит) заданы константами; можно сделать их конфигурируемыми через CLI.
|
||||
|
||||
Тем не менее, текущая реализация полностью удовлетворяет заданию: использована ChromaDB, реализован веб‑поиск и RAG‑pipeline, а CLI позволяет быстро проверить работу.
|
||||
Reference in New Issue
Block a user