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

4.5 KiB
Raw Blame History

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

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

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

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

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

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 позволяет быстро проверить работу.