File size: 1,966 Bytes
7ff7119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
"""search_documents tool -- a rag_query_subgraph-ot hívja.

A chat search-intent-jénél az LLM ezt a tool-t választja. A tool egy belső
LangGraph subgraph-ot futtat, ami a hibrid keresést végzi (vektor + BM25 + RRF
+ rerank + format).

A LangSmith trace-ben a subgraph kibontva látszik a tool-call alatt -- szakmai
mélység jelzés a pitch demón.
"""

from __future__ import annotations

from langchain_core.tools import tool

from subgraphs.rag_query_subgraph import build_rag_query_subgraph
from tools.context import ChatToolContext


def build_search_documents_tool(ctx: ChatToolContext):
    # A subgraph-ot egyszer compile-oljuk a build-időben (closure-ben tartjuk)
    rag_subgraph = build_rag_query_subgraph(ctx.store)

    @tool
    def search_documents(query: str) -> str:
        """Szemantikus + kulcsszavas hibrid keresés a feltöltött dokumentumokban.

        Használd ha konkrét információt keresel a dokumentum-szövegekben:
        klauzulák, dátumok, határidők, tételek megnevezései.

        Args:
            query: keresési kifejezés magyarul (pl. 'szállítási határidő')
        """
        # Sync wrapper az async subgraph köré.
        #
        # Egységes minta a teljes alkalmazásban: az AsyncRuntime singleton
        # (long-lived background event loop) futtat minden async coroutine-t.
        # Ez biztosítja:
        #   * Stabil uvloop-mentes futás Streamlit alatt (nincs nest_asyncio)
        #   * Resource-megosztás: ChromaDB pool, sentence-transformers cache,
        #     AsyncSqliteSaver kapcsolat NEM épül újra hívásonként
        #   * Skálázódás: 100+ párhuzamos chat-kérés ugyanazt a loopot használja
        from app.async_runtime import AsyncRuntime

        result = AsyncRuntime.get().submit(
            rag_subgraph.ainvoke({"query": query, "top_k": 5})
        )
        return result.get("output", "Nem találtam releváns találatot.")

    return search_documents