4.4 KiB
4.4 KiB
Что реализовано
- Добавлен класс
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.