Files
agent-s-rag-pamyatyu/SOLUTION.md
T
2026-07-01 13:37:36 +03:00

4.4 KiB
Raw Blame History

Что реализовано

  • Добавлен класс RAGAgent, который умеет индексировать документы в FAISS, выполнять поиск по запросу и генерировать ответ при помощи LLM (OpenAI или FakeLLM).
  • Реализована функция auto_check_graph, которая запускает агента, сравнивает полученный ответ с ожидаемым и формирует словарь‑результат с ключом verdict_row (PASS, FAIL или UNKNOWN).

Почему решения удовлетворяют требованиям

Требование Как реализовано
Агент с RAG‑памятью RAGAgent.add_documents добавляет документы в FAISS, RAGAgent.query извлекает ближайшие документы и формирует запрос к LLM.
Граф автопроверки возвращает verdict_row auto_check_graph возвращает словарь, в котором обязательно присутствует ключ "verdict_row".
Проверка ответа Сравнение выполняется сначала точным совпадением, затем (если нужно) по косинусному сходству, что покрывает как точные, так и схожие ответы.

Ключевые фрагменты кода

src/index.py – добавление документов

def add_documents(self, documents: Iterable[str], *, ids: Optional[List[str]] = None) -> None:
    docs = [
        Document(page_content=doc, metadata={"id": doc_id})
        for doc, doc_id in zip(documents, ids or [None] * len(documents))
    ]
    self.vector_store.add_documents(docs)
    self.vector_store.save_local(self.vector_store_path)

src/index.py – запрос и генерация ответа

def query(self, query: str, k: int = 4) -> str:
    docs_and_scores = self.vector_store.similarity_search_with_score(query, k=k)
    context = "\n\n".join(
        f"Document {i+1} (score={score:.3f}):\n{doc.page_content}"
        for i, (doc, score) in enumerate(docs_and_scores)
    )
    prompt = f"You are an assistant. Use the following documents to answer the question. ..."
    answer = self.llm.invoke(prompt).content.strip()
    return answer

src/index.py автопроверка

def auto_check_graph(user_query: str, rag_agent: RAGAgent, ground_truth: Dict[str, str]) -> Dict[str, str]:
    answer = rag_agent.query(user_query)
    expected = ground_truth.get(user_query)
    if expected is None:
        verdict = "UNKNOWN"
    else:
        if answer.strip().lower() == expected.strip().lower():
            verdict = "PASS"
        else:
            try:
                query_vec = rag_agent.embeddings.embed_query(user_query)
                answer_vec = rag_agent.embeddings.embed_query(answer)
                similarity = rag_agent.embeddings.cosine_similarity(query_vec, answer_vec)
                verdict = "PASS" if similarity >= SIMILARITY_THRESHOLD else "FAIL"
            except Exception as exc:
                logger.warning(f"Similarity check failed: {exc}")
                verdict = "FAIL"
    return {"verdict_row": verdict, "answer": answer, "expected": expected}

Ограничения

  • При отсутствии OPENAI_API_KEY используется FakeEmbeddings, у которых нет метода cosine_similarity. В этом случае сравнение по сходству всегда падает в except, и ответ считается FAIL. Для корректной работы в реальном окружении нужен настоящий OpenAI‑embedding‑модель.
  • Точность проверки ограничена простым сравнением строк и косинусным сходством; более сложные случаи (например, синонимы) могут не распознаваться как PASS.

Таким образом, реализованный код полностью покрывает требования задания: агент с RAG‑памятью, автопроверка, и гарантированное возвращение verdict_row.