Strona główna / Artykuły / Ręcznie stworzony loop narzędzia LangChain do porównywania aktualnych metryk zapasów

Ręcznie stworzony loop narzędzia LangChain do porównywania aktualnych metryk zapasów

Stwórz krok po kroku małego asystenta do porównywania akcji z LangChain i poznaj pętlę tworzenia, wiązania, wywoływania i wykonania, która umożliwia modelowi językowemu żądanie aktualnych danych zamiast domyślania się.

1667 słów

Model językowy zna tylko to, co znajduje się w jego danych treningowych, więc proszenie go o aktualną cenę akcji daje pewne przypuszczenia, a nie fakt. To poważny problem w przypadku wszelkich kwestii finansowych. Narzędzie do wywoływania funkcji rozwiązuje ten problem, pozwalając modelowi poprosić Twój kod o pobranie aktualnych danych, a następnie przeanalizować wynik. W tym przewodniku tworzymy kompaktowego asystenta, który porównuje dwie akcje pod względem ceny i stosunku ceny do zysku, przy czym na każdym etapie procesu pracy LangChain polegającego na wywoływaniu narzędzi pokazujemy, co dokładnie się dzieje: tworzenie, powiązanie, wywołanie i wykonanie.

Dlaczego model bez narzędzi tylko zgaduje

Wyobraź sobie pracownika sklepu, który zna na pamięć każdy produkt i zasadę, ale nie ma dostępu do systemu magazynowego. Jeśli zapytasz go, czy dana kurtka jest w magazynie w rozmiarze medium, otrzymasz pewną odpowiedź opartą na danych z zeszłego tygodnia. To właśnie jest model językowy sam w sobie: zdolny do formułowania odpowiedzi, ale ślepy na rzeczywistość obecną.

Podaj współpracownikowi skaner kodów kreskowych, a on będzie mógł sprawdzać informacje zamiast zgadywać. W LangChain skaner jest narzędziem: zwykłą funkcją, o której model może poprosić o uruchomienie, np. do wyszukiwania cen, zapytania do bazy danych lub wywołania API. Mechanizm wywoływania narzędzi pozwala modelowi zdecydować, kiedy użyć skanera, który element przeskanować oraz jak wykorzystać uzyskane dane.

Pętla czterostopniowa

Wywoływanie narzędzi (często nazywane wywoływaniem funkcji) zawsze odbywa się według tego samego cyklu:

  1. Stwórz narzędzie. Napisz funkcję w Pythonie z opisową nazwą, parametrami typowanymi oraz dokumentacją wyjaśniającą jej funkcjonowanie.
  2. Powiąż je z modelem. Wywołaj metodę .bind_tools() w modelu do rozmów, aby ten wiedział, jakie narzędzia istnieją i jakie argumenty przyjmują.
  • Wezwij model. Wyślij pytanie użytkownika. Jeśli potrzebuje on danych z zewnątrz, model zwraca ustrukturyzowaną prośbę, na przykład „wezwij get_stock_price z parametrem ticker='MSFT'”, zamiast ostatecznej odpowiedzi.
  • Egzekutuj i zwróć wyniki. Twój kod uruchamia żądaną funkcję i przekazuje wynik z powrotem do modelu, aby mógł on sformułować odpowiedź.
  • Kluczową cechą jest to, że to model, a nie twój kod, decyduje o tym, kiedy potrzebna jest jakaś narzędzie. Pytanie takie jak „Ile to 2+2?” otrzymuje bezpośrednią odpowiedź, natomiast „Porównaj MSFT i AAPL” może skutkować dwoma wywołaniami narzędzi w jednej odpowiedzi. Model jedynie żąda tych wywołań; ich uruchomienie pozostaje twoim zadaniem. Aby dowiedzieć się, w jaki sposób frameworki automatyzują ten proces, przeczytaj co dokładnie automatyzuje LangChain po stworzeniu pętli agenta.

    Krok 1: Zainstaluj zależności przy pierwszym uruchomieniu

    Skrypt zaczyna od sprawdzenia dostępnych pakietów i instalowania tych, które brakuje, aby ktoś mógł go uruchomić bez konieczności osobnego kroku pip install. Zamienia każdą nazwę pakietu na odpowiednią nazwę do importowania, zastępując myślniki podkreśleniami (langchain-groq staje się langchain_groq), a w razie problemów odwołuje się do pip poprzez bieżący interpreter:

    import sys
    import subprocess
    
    required_packages = ["langchain-groq", "langchain-core", "yfinance"]
    
    for package in required_packages:
        try:
            __import__(package.replace("-", "_"))
        except ImportError:
            print(f"📦 Package '{package}' not found. Installing now...")
            subprocess.check_call([sys.executable, "-m", "pip", "install", package])
    

    To nadaje się do demonstracji, ale w prawdziwych projektach zaleca się definiowanie zależności w pliku requirements.txt lub pyproject.toml; instalacje w czasie wykonywania sprawiają, że procesy budowania nie są powtarzalne.

    Krok 2: Podanie klucza API

    Model działa na Groq, więc klient Groq potrzebuje klucza API w środowisku. W demonstracji jest on przypisany bezpośrednio jako zmienna tymczasowa:

    import os
    os.environ["GROQ_API_KEY"] = "Your-API"
    

    Prawdziwe klucze powinny znajdować się w pliku .env wykluczonym z kontroli wersji lub w menedżerze sekretów, a nigdy w kodzie umieszczonym w repozytorium.

    Krok 3: Określenie narzędzia do danych giełdowych

    Narzędzie to wykorzystuje yfinance, aby znaleźć kod giełdowy, pobrać najnowszą cenę zamknięcia z danego dnia oraz odczytać kapitalizację rynkową i wskaźnik P/E z informacji o tym kodzie giełdowym:

    from langchain_core.tools import tool
    import yfinance as yf
    
    @tool
    def get_stock_price(ticker: str) -> str:
        """Fetches the current stock price and key statistics for a given ticker symbol."""
        try:
            stock = yf.Ticker(ticker)
            todays_data = stock.history(period='1d')
            if todays_data.empty:
                return f"Could not find data for ticker {ticker}."
    
            price = todays_data['Close'].iloc[-1]
            info = stock.info
            market_cap = info.get('marketCap', 'N/A')
            pe_ratio = info.get('trailingPE', 'N/A')
    
            return f"{ticker} Current Price: ${price:.2f}, Market Cap: {market_cap}, P/E Ratio: {pe_ratio}"
        except Exception as e:
            return f"Error fetching data for {ticker}: {str(e)}"
    

    Trzy elementy sprawiają, że ta funkcja jest dobrym narzędziem:

    • Dekorator @tool przekształca funkcję w narzędzie LangChain i wywodzi schemat wejścia na podstawie jej wskazówek typów.
    • Dokumentacja nie jest dekoratorem – model czyta ją wraz z nazwą, aby określić, kiedy narzędzie ma zostać użyte, dlatego powinna jasno opisywać, co narzędzie zwraca.
    • Błędy są zwracane jako opisowe łańcuchy znaków, a nie wywoływane. Nieznany kod giełdowy lub nieudana próba zwracają komunikat, który model może przeanalizować („nie udało się znaleźć danych”), zamiast wyjątku, który przerywa całe działanie.

    Należy pamiętać, że yfinance jest nieoficjalnym narzędziem otaczającym Yahoo Finance: dane mogą być opóźnione, a niektóre pola mogą brakować, stąd użycie wartości awaryjnych 'N/A'.

    Krok 4: Stworzenie modelu i powiązanie narzędzi

    Następnie tworzony jest model do rozmów, do którego dołączana jest lista narzędzi:

    from langchain_groq import ChatGroq
    
    llm = ChatGroq(
        model="openai/gpt-oss-120b",
        temperature=0
    )
    
    tools = [get_stock_price]
    llm_with_tools = llm.bind_tools(tools)
    

    bind_tools() z każdym żądaniem wysyła do modelu nazwy narzędzi, ich opisy oraz schematy argumentów, dzięki czemu model wie, o co może prosić. Należy zauważyć, że niewiązany llm również jest zachowywany; zostanie on później ponownie wykorzystany do stworzenia końcowego podsumowania. Nazwa modelu odzwierciedla to, co Groq oferował w momencie pisania tekstu, dlatego przed uruchomieniem należy sprawdzić aktualną listę modeli dostawcy.

    Ustawienie temperature=0 zapewnia bardziej spójny i konsekwentny wynik, choć zmniejsza losowość, a nie gwarantuje identycznych odpowiedzi.

    Krok 5: Budowa łańcucha promptów

    Śablon promptu zawiera instrukcję systemową oraz umieszcza pytanie użytkownika w wiadomości skierowanej do człowieka. Operator rury łączy następnie prompt z modelem świadomym narzędzi w jedną możliwą do uruchomienia całość, podobnie jak w pipeline’u Unixa:

    from langchain_core.prompts import ChatPromptTemplate
    from IPython.display import display, Markdown
    
    prompt = ChatPromptTemplate.from_messages([
        ("system", "You are an expert financial analyst. Use the tools provided to pull real-time data before comparing or concluding."),
        ("human", "{input}")
    ])
    
    chain = prompt | llm_with_tools
    

    Wiadomość systemowa pełni tu kluczową rolę: poleca modelowi pobrać dane za pomocą narzędzi przed przeprowadzeniem jakiejkolwiek porównania. Bez niej model może odpowiadać na podstawie przestarzałych danych treningowych.

    Krok 6: Uruchomienie pętli i obsługa wielu wywołań narzędzi

    Główny blok łączy wszystko ze sobą. Wywołuje łańcuch operacji, sprawdza, czy odpowiedź zawiera tool_calls, uruchamia każde z żądanych wyszukiwań, zbiera wyniki i na koniec prosi zwykły model o napisanie porównania na podstawie zebranych danych. Jeśli nie złożono żadnych żądań dotyczących narzędzi, wyświetla się bezpośrednia odpowiedź modelu:

    if __name__ == "__main__":
        query = "Compare the current stock price and P/E ratio of Microsoft (MSFT) AND Apple (AAPL). Which one looks cheaper based on P/E?"
        print(f"🚀 Invoking Financial Pipeline with query: '{query}'\n")
    
        # 1. Ask the model what tools it wants to use
        ai_message = chain.invoke({"input": query})
    
        # 2. Check if the model requested tool use
        if ai_message.tool_calls:
            print(f"🛠️ Model requesting {len(ai_message.tool_calls)} real-time tool lookups...\n")
            tool_outputs = []
    
            # 3. Execute ALL generated tool calls
            for tool_call in ai_message.tool_calls:
                if tool_call["name"] == "get_stock_price":
                    ticker_symbol = tool_call["args"]["ticker"]
                    print(f"   -> Executing tool lookup for: {ticker_symbol}")
    
                    result = get_stock_price.invoke(tool_call["args"])
                    print(f"      [Tool Output] {result}")
                    tool_outputs.append(result)
    
            # 4. Supply the full collective data back to the LLM
            summary_prompt = f"""
            User Query: {query}
            Real-time Data Harvested: {'; '.join(tool_outputs)}
    
            Synthesize a final response evaluating which asset looks cheaper.
            """
            final_answer = llm.invoke(summary_prompt)
    
            print("\n--- Final Analysis Output ---")
            display(Markdown(final_answer.content))
        else:
            print("\n--- Final Analysis Output ---")
            print(ai_message.content)
    

    W przypadku pytania dotyczącego zarówno Microsoft, jak i Apple model zazwyczaj zwraca dwa wywołania narzędzi w jednej odpowiedzi, po jednym na każdy ticker. Pętla wykonywa je wszystkie przed przejściem dalej, więc w ostatnim kroku dostępne są obie serie liczb jednocześnie. Model żąda wywołań równolegle, ale ten kod wykonuje je jeden po drugim; w przypadku wolnych API można by je wykonać jednocześnie.

    Dwa istotne aspekty warto znać, gdy to już będzie działać. Po pierwsze, sprawdzanie nazwy wewnątrz pętli służy do wyboru odpowiedniego narzędzia spośród kilku dostępnych; słownik łączący nazwy narzędzi z ich obiektami działa efektywniej niż seria instrukcji if. Po drugie, ta wersja przekazuje wyniki poprzez utworzenie nowego tekstu instrukcyjnego. Bardziej typowe dla LangChain podejście polega na dodawaniu każdego wyniku jako ToolMessage zawierającego odpowiadający mu tool_call_id do rozmowy, a następnie ponownym uruchomieniu modelu przypisanego do danego narzędzia, co pozwala zachować całą wymianę informacji i umożliwia modelowi żądanie dodatkowych wywołań, jeśli pierwsze wyniki są niewystarczające.

    Rozszerzanie asystenta odbywa się stopniowo: narzędzie takie jak get_financial_news lub calculate_valuation można dodać za pomocą tej samej funkcji bind_tools(), a model wybiera narzędzia na podstawie ich opisów.

    Główne wnioski

    • Narzędzie to funkcja z jasną nazwą, wskazówkami typu oraz dokumentacją; resztę załatwia dekorator @tool.
    • .bind_tools() łączy twoje funkcje z modelem, opisując je w każdej prośbie.
    • Model żąda jedynie wywołań narzędzi. Twój kod je wykonuje i zwraca wyniki, a ta kontrola jest przydatna, a nie ograniczeniem.
    • Zwracaj błędy z narzędzi jako czytelne łańcuchy znaków, aby jeden błędny zapytanie nie zakończyło całego procesu.
    • Zacznij od jednego narzędzia i jednego pętla, a następnie dodawaj narzędzia, przekazywanie wyników w formie wiadomości oraz konwergencję w zależności od potrzeb.

    To samo wzorce stosuje się tam, gdzie model potrzebuje aktualnych informacji – od danych pogodowych i stanu zapasów po rekordy CRM czy własną bazę danych – dzięki czemu asystenci mogą analizować żywe systemy, a nie zamarznięte kopie.