Files
ekzamen-rag-agent-s-chromad…/SOLUTION.md
T

80 lines
4.5 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.
**SOLUTION.md**
### Что реализовано
- **ChromaDB** вместо Qdrant: подключаем клиент, создаём коллекцию и сохраняем векторные представления документов.
- **Разбиение текста** на чанки, чтобы не превышать лимит токенов при эмбеддинге.
- **Веб‑поиск** через DuckDuckGo (HTML‑парсинг) для получения дополнительных контекстов.
- **RAGpipeline**: поиск в ChromaDB → добавление веб‑сниппетов → генерация ответа GPT‑3.5‑turbo.
- **CLI**: `add <file>` для загрузки документов, `ask <question>` для запросов.
### Почему это соответствует требованиям
- **ChromaDB** – указанная в условии векторная база. В коде используется `chromadb.Client` и `Settings(persist_directory=…)`.
- **Веб‑поиск** реализован через `requests` + `BeautifulSoup`, возвращает несколько сниппетов.
- **RAG**: `ChromaVectorStore.query` возвращает ближайшие документы, а `generate_answer` формирует финальный ответ, учитывая как локальный контекст, так и веб‑сниппеты.
- **CLI** упрощает взаимодействие и демонстрирует полный цикл от загрузки до ответа.
### Ключевые фрагменты кода
**src/index.py embed_text**
```python
def embed_text(text: str) -> List[float]:
response = openai.Embedding.create(
input=text,
model=EMBEDDING_MODEL,
)
return response["data"][0]["embedding"]
```
**src/index.py chunk_text**
```python
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/index.py ChromaVectorStore**
```python
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/index.py add_documents_from_file**
```python
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)
```
**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])
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 позволяет быстро проверить работу.