From 3316f4a814c0edd98d32588fb9c528220ee162b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D0=B5=D0=BC=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D0=BC=D0=B8=D1=80=D0=BE=D0=B2=D0=B8=D1=87=20=D0=91=D0=B0?= =?UTF-8?q?=D0=B1=D0=B0=D0=B9=D0=BA=D0=B8=D0=BD?= Date: Thu, 28 May 2026 16:40:41 +0000 Subject: [PATCH] feat: solution for 6a1864f78a94f887e50d46da --- .../6a1864f78a94f887e50d46da/solution.py | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 solutions/6a1864f78a94f887e50d46da/solution.py diff --git a/solutions/6a1864f78a94f887e50d46da/solution.py b/solutions/6a1864f78a94f887e50d46da/solution.py new file mode 100644 index 0000000..710af4e --- /dev/null +++ b/solutions/6a1864f78a94f887e50d46da/solution.py @@ -0,0 +1,87 @@ +# -------------------- vectorstore.py -------------------- +from pathlib import Path +from langchain_chroma import Chroma +from langchain_ollama import OllamaEmbeddings +from langchain_text_splitters import RecursiveCharacterTextSplitter + +def create_vectorstore(persist_directory: str = "./chroma_db"): + embeddings = OllamaEmbeddings(model="nomic-embed-text") + vector_store = Chroma( + collection_name="rag_collection", + embedding_function=embeddings, + persist_directory=persist_directory, + ) + return vector_store + +def load_documents(directory: str, vectorstore): + splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50) + docs = [] + for file_path in Path(directory).glob("*.txt"): + text = file_path.read_text(encoding="utf-8") + docs.extend(splitter.create_documents([text])) + for file_path in Path(directory).glob("*.md"): + text = file_path.read_text(encoding="utf-8") + docs.extend(splitter.create_documents([text])) + vectorstore.add_documents(docs) + +# -------------------- tools.py -------------------- +from langchain.tools import tool +from langchain_ollama import ChatOllama + +@tool +def search_local_kb(query: str, top_k: int = 3) -> str: + """Semantic search in the local ChromaDB knowledge base.""" + retriever = vectorstore.as_retriever(search_kwargs={"k": top_k}) + docs = retriever.invoke({"query": query})["documents"] + return "\n".join(doc.page_content for doc in docs) + +@tool +def web_search(query: str) -> str: + """Web search using Tavily.""" + from langchain_tavily import TavilySearchResults + tavily = TavilySearchResults(api_key=__import__("os").environ["TAVILY_API_KEY"]) + results = tavily.invoke({"query": query}) + return "\n".join(f"{r['title']}: {r['url']}" for r in results) + +# -------------------- agent.py -------------------- +from langchain.agents import create_agent +from langchain_ollama import ChatOllama + +llm = ChatOllama(model="llama3", temperature=0.2) + +system_prompt = """ +You are an assistant that answers user questions. +If the answer can be found in the local knowledge base, use `search_local_kb`. +Otherwise, use `web_search`. +Always indicate the source of your answer: either "chromadb" or "tavily". +""" + +agent = create_agent( + model=llm, + tools=[search_local_kb, web_search], + system_prompt=system_prompt, +) + +# -------------------- main.py -------------------- +import os +from dotenv import load_dotenv + +load_dotenv() + +if __name__ == "__main__": + # Initialize vectorstore and load documents if not already loaded + vectorstore = create_vectorstore() + if not vectorstore.get_collection().count(): + load_documents("documents", vectorstore) + vectorstore.persist() + + print("Chat started. Type 'exit' to quit.") + while True: + user_input = input("\nЗапрос: ").strip() + if user_input.lower() in ("exit", "quit", "выход"): + break + result = agent.invoke({"messages": [{"role": "human", "content": user_input}]}) + ai_msg = result["messages"][-1] + print(f"[{ai_msg.tool_calls[0]['name'].capitalize()}] {ai_msg.content}") + source = "chromadb" if ai_msg.tool_calls[0]["name"] == "search_local_kb" else "tavily" + print(f"Источник: {source}") \ No newline at end of file