LLM vs Agent AI

2026-03-12

W języku potocznym pojęcia AI, LLM, Agent AI nieźle się mieszają. Jeśli w danej chwili szukam przepisu na zapiekankę ziemniaczaną i zadaję to pytanie aplikacji na moim telefonie, to kto dla mnie pracuje?

Sprawa ma się dość prosto. LLM-y o których czasami myślimy, że to właśnie AI, to tylko dobrze wyszkolone „kalkulatory do słów”. W początkowych wersjach, nawet zadanie pytania ile to jest 3 razy 6 powodowało, że odpowiedź była udzielana w oparciu o prawdopodobieństwo (!). Na dodatek nie było to prawdopodobieństwo wyliczone w oparciu o czystą matematykę, tylko prawdopodobieństwo kolejnego słowa, które mogłoby się pojawić po 3 * 6 = … (!!!). LLM sam z siebie nie aktywował swojego aparatu rozumowania i stwierdzenia „hej – to jest proste działanie matematyczne – nie muszę zgadywać tylko po prostu policzę”. Żeby LLM zmusić do myślenia trzeba mu o tym było napisać w prompcie, albo ewentualnie przełączyć się na nowszy model. Mówiąc bardzo brutalnie i prawdopodobnie mocno przesadzając można stwierdzić, że LLM to bardzo ładnie wysławiający się głupiec. Nic tak na prawdę nie wie, nic nie umie, nic nie myśli, tylko pracuje na statystyce słów, żeby wyszły ładne kształtne zdania z zachowaniem odpowiedniego tonu i gramatyki. W dużym stopniu odpowiada to wizji „super komputerów” z filmów SF, gdzie komputer stwierdza, że „trzeba wyłączyć silnik, bo inaczej nastąpi eksplozja za 5, 4, 3….” – ale sam nic z tym nie robi. A nie robi z tym nic, bo nie może, bo jest tylko (i aż) kalkulatorem słów.

Z Agentami AI jest trochę inaczej. Jednym z komponentów Agenta AI jest LLM. Pozwala on zrozumieć o co pyta użytkownik, a potem wygenerować dla niego ładną odpowiedź. Jednak agent dodatkowo:

  • postrzega środowisko w jakim pracuje
  • podejmuje decyzje (np. o pobraniu świeżych informacji z interentu albo wykonania jakiś obliczeń)
  • planuje działania, układając sobie „w głowie” co po kolei należy zrobić
  • integruje się przy pomocy narzędzi z bazami danych lub innymi narzędziami
  • i wreszcie może przyjmować od użytkownika feedback i uwzględniać go przy przyszłych odpowiedziać, bo ma pamięć

Tak więc:

  • LLM jest częścią składową Agenta
  • Agent podejmuje decyzje, LLM nie podejmuje decyzji – jest tylko „kalkulatorem słów”
  • Agent działa w jakimś środowisku, zna narzędzia, dostępne bazy danych, wie gdzie i po co się połączyć, a LLM nie – LLM tylko odpowiada na prompt, jest absolutnym teoretykiem
  • Agent ma pamięć i dynamicznie uczy się z doświadczenia, a LLM wie tyle ile nauczył się na etapie trenowania, gdy był tworzony
  • Agent może sięgać do baz danych, łączyć się do Internetu, uruchamiać kod, który coś policzy, a LLM pracuje tylko w oparciu o tekst jaki otrzymuje na wejściu – jeśli prześlesz sensowny prompt, to otrzymasz sensowną odpowiedź, ale nie licz na to, że LLM jakoś te dane uzupełni, o ile nie było ich w prompcie ani w procesie uczenia jakiś czas temu
  • Agent może realizować określony cel – szukać w internecie, bazach danych, a nawet prowadzić transakcje, uruchamiać procesy, a LLM nie. On tylko generuje tekst
  • Agent ma możliwość adaptacji do zmieniającej się sytuacji, a LLM jest absolutnie statyczny.

Wracając wiec do początkowego pytania – co się dzieje i kto odpowiada na pytanie o to jak zrobić zapiekankę ziemniaczaną:

  • To jest agent. Najpierw uruchomił LLM, żeby zrozumieć czego chcesz
  • Zrozumiał po swojemu co chcesz zrobić i prawdopodobnie uznał, że nie wie jak się robi zapiekankę
  • Dlatego przejrzał swoje środowisko i dostępne narzędzia. Gdyby był agentem wyspecjalizowanym w gotowaniu to pewnie miałby dostęp do bazy danych z przepisami, ale… raczej bym na to nie liczył i pewnie podstawowym narzędziem jest wyszukiwarka internetowa
  • Agent ma możliwość planowania pracy, więc sobie planuje, np.: poszukam 10 przepisów, pobiorę strony, obejrzę albo nie obejrzę obrazki z tych stron, a potem zbuduję prompt i wyślę go do LLM, który zwróci mi ładny tekst i potem odeślę go do użytkownika
  • Teraz Agent wywołuje narzędzia, pobiera wyniki i generuje prompt i wysyła go do LLM żeby uzyskać odpowiedź.
  • Odpowiedź oddaje tobie

Myślę że obecnie (rok 2026) w większości pracujemy z Agentami. Czyste LLM obsługiwały nas może około 3 lata temu (2023).

By Rafał Kraik in AI

Linux: Raspberry Pi: Buzzer/TonalBuzzer

2026-02-01

Buzzer Piezoelektryczny to jedna z podstawowych metod na wydobycie dźwieku z Raspberry Pi. Po podłaczeniu buzzera można nim sterować korzystając z biblioteki gpiozero, która posiada fajną dokumentację dla Buzzera i TonalBuzzera::

15. API – Output Devices — gpiozero 2.0.1 Documentation

Do wygrywania „nutek” używa sie kodu, który może być

  • częstotliwością dźwięku, lub
  • wewnętrznym oznaczeniem kodu nuty w standardzie midi, lub
  • napisem reprezentującym nutę..

Dokładniejszy opis tonów możliwych do wydobycia jest tu:

22. API – Tones — gpiozero 2.0.1 Documentation

Co zrobić jeśli masz drewniane uszy i łatwiej przychodzi ci narysowanie & niż klucza wiolinowego?

Wtedy może się przydać mapka dźwięków, którą znalazłem tutaj:

Note names, MIDI numbers and frequencies

Żeby nie naruszyć praw autorskich przeklejam tylko kawałek tego obrazka:

By Rafał Kraik in Linuxy

Terraform: Zmiana nazwy zasobu

2026-01-13

Tworząc manifest terraforma, korzystasz z jakiś nazw dla zasobów. Nie tych, które zostaną użyte gdzieś tam w chmurze, tylko tych, które używamy wewnętrzenie w kodzie. Lubię myśleć o tych programistycznych nazwach zasobów, jak o zmiennych w języku programowania. Nie są to w pełni zmienne, bo zmienne definiujemy w bloku variable {}, a ja tu odnoszę się do nazw z bloku resource „” „NAME” {}

W każdym razie, wymyślając nazwy tych zmiennych pracujemy, jak programista i staramy się wymyślić coś sensownego. Po pewnym czasie może się jednak okazać, że ta nazwa zmiennej nie pasuje i trzeba by ją zmienić.

Problem w tym, że jeśli nasz manifest już był uruchomiony, to w chmurze istnieją zasoby. Uruchomienie terraform apply spowodowałoby, że rzeczywiste zasoby z chmury zostaną usunięte i utworzone na nowo, tylko dlatego, że zmieniliśmy nazwę resource w kodzie terraform.

Obejściem jest wykorzystanie polecenia terraform state mv. Może ono zmienić nazwę zasobu w state file. Dzięki temu uzyskamy zgodność między:

  • kodem manifestu terraform, który korzysta z nowej nazwy
  • stanem, który skojarzy rzeczywiste zasoby chmury z nowymi nazwami zasobów
  • samą chmurą, gdzie zasoby już są utworzone i nie trzeba ich usuwać i tworzyć na nowo

Ogólnie rzecz biorąc przed modyfikacją state należy sporządzić kopię state file. Można to zrobić dowolną metodą, ale da się też tak:

terraform state pull > my_copy.state.file

Potem uruchamiamy

terraform state list | grep '^OLD_NAME'

To pozwoli nam zrozumieć ile zasobów musi mieć dokonane zmiany. Może to być więcej niż jeden, zwłaszcza jeśli dany zasób składa się z innych zasobów, jak np. moduł

Potem można już uruchamiać polecenie

terraform state mv 'OLD_RESOURCE_NAME' 'NEW_RESOURCE_NAME'

State mv to sprytna komenda, która na czas modyfikacji pliku state blokuje go, uniemożliwiając jednoczesna edycję przez wiele procesów, jest to więc komenda bezpieczna.

Gdyby takich zasobów do zmiany było więcej to można użyć skryptu:

for addr in $(terraform state list | grep '^OLD_NAME'); do
new=$(echo "$addr" | sed 's/^OLD_NAME/NEW_NAME/')
echo "Moving: $addr -> $new"
terraform state mv "$addr" "$new"
done

Po wszystkim warto oczywiście uruchomić terraform plan. Dzięki temu przekonamy się, czy coś jeszcze zostało do zmiany

By Rafał Kraik in Azure

Terraform: ilustracja zależności (terraform graph)

2025-12-03

Czasami dobrze jest „zobaczyć” zależności w terraform na grafie. Można do tego wykorzystać polecenia

terraform graph > graph.dot

a potem wygenerować obraz przy pomocy dot.exe (element pakietu GraphViz)

dot.exe -Tpng graph.dot -o graph.png

Niestety to może się zakończyć błędem:

Error: graph.dot: syntax error in line 1 near ' ■d'

Problem jest w kodowaniu pliku. Można zmienić pierwsze polecenie na:

terraform graph | Out-File -Encoding ASCII graph.dot

Tutaj polecenie PowerShell Out-File zmienia kodowanie pliku na ASCII w locie i nie powinno być problemu przy uruchamianiu generowania obrazu za pomocą dot.exe

By Rafał Kraik in Azure

Python: Comprehension statement – co to jest?

2025-12-02

Można żyć z Pythonem w zgodnie nie znając comprehension statement, ale… może jednak warto, bo dzięki temu jest krócej, prościej, czytelniej, o ile tylko… rozumie się co to comprehension statement.

Cel jest prosty. Chcemy skrócić pętle – najlepiej do jednej linijki. No to popatrzmy na pętlę, której celem jest wygenerowanie kwadratów liczb parzystych z pewnej zadanej listy:

numbers = [1, 2, 3, 4, 5]
squares = []

for n in numbers:
    if n % 2 == 0:        # tylko liczby parzyste
        squares.append(n**2)

print(squares)  # Wynik: [4, 16]

Trzeba oczywiście zadeklarować listę numbers, potem pustą listę squares, a potem napisać for, badać parzystość przy użyciu if, podnosić do kwadratu i dodawać do listy no i na końcu wyświetlić wynik. Jest trochę długie, ale inaczej się nie da…. no właśnie stop! Comprehension skraca ten zapis do:

numbers = [1, 2, 3, 4, 5]
squares = [n**2 for n in numbers if n % 2 == 0]

print(squares)  # Wynik: [4, 16]

Ojej – ale co tu się dzieje? Oczywiście pomijamy pierwszą i ostatnią linijkę, bo one są oczywiste.

No to tak:

  • Wynikiem ma być lista, a listę oznacza się w pythonie nawiasami kwadratowymi, więc mamy squares = [ coś tam ]
  • Na liście mają się znaleźć kwadraty liczb, więc piszemy n**2, tylko co to jest to n?
  • No właśnie n to liczby, które pochodzą z listy numbers, dodajemy więc: for n in numbers
  • Ale ale! Przecież mieliśmy podnosić do kwadratu tylko liczby parzyste. No tak – dlatego dopisujemy if n % 2 == 0

W tym jednym zapisie jest cały ciąg operacji budujących pętlę for. Jest „for n in numbers”, jest „if n %2 == 0”, jest podnoszenie do kwadratu, czego ewentualnie nie ma to instrukcji append, ale ten append „dzieje się sam”, bo przecież tworząc zmienną squares napisaliśmy squares = [ …. ] czyli jest to jakiś rodzaj listy.

Comprehension można też użyć tworzyć zbiory danych, np tutaj do zbioru {} zostaną włożone wszystkie elementy z listy, a więc w efekcie nawet jeśli na liście były elementy się powtarzające, to w zbiorze będą już tylko unikalne

words = ["kot", "pies", "kot", "ryba"]
unique_lengths = {len(w) for w in words}
# Wynik: {3, 4}

To może na koniec, takie niebanalne zadanie:

Napisz pętlę, która wyświetli napis „Pan XX” lub „Pani XX” w oparciu o listę imiona. W liście imiona są zapisane imiona. Napis ma być Pan, jeśli imię kończy się spółgłoską lub Pani jeśli imię kończy się samogłoską. Skorzystaj z comprehension

imiona = ["Ala", "Ola", "Marek", "Jan", "Ewa"]

Rozwiązanie jest poniżej – scrolluj w dół:

i jeszcze

i jeszcze

i jeszcze

i jeszcze

i jeszcze

i jeszcze

i jeszcze

i jeszcze

tutaj:

wyniki = [
    ("Pani " + imie if imie[-1].lower() in "aeiouy" else "Pan " + imie)
    for imie in imiona
]

print(wyniki)
# Wynik: ['Pani Ala', 'Pani Ola', 'Pan Marek', 'Pan Jan', 'Pani Ewa']

By Rafał Kraik in Python

Azure: szukanie błędu w Logic App Standard w Log Analytics Workspace (KUSTO)

2025-10-02

Tzw. Logic App w Azure są dostępne w modelu „Consumption” oraz „Standard”. Zdarza się, że wydobycie informacji z logów zwłaszcza dla aplikacji „Standard” jest trudne. Oto przykład zapytania KUSTO uruchomionego w Log Analytics Workspace pozwalającego przeczytać w „wygodny” sposób, co takiego się stało. Owe „wygodny” jest w cudzysłowie, bo grzebanie w błędach absolutnie nie należy do przyjemności.

W drugiej linijce pojawia się RunId, które można znaleźć w interfejsie graficznym. Jeśli go nie znasz pomiń tą linijkę i zostaną wyświetlony wszystkie błędy ostatnio zgłoszone w aplikacji:

LogicAppWorkflowRuntime
| where RunId == "run-id"
| where Status == "Failed"
| order by TimeGenerated
| project TimeGenerated, OperationName, Code, tostring(parse_json(Error).message), ActionName

By Rafał Kraik in Azure

Windows: Sprawdzenie ważności hasła

2025-09-01

Aby zwiększyć bezpieczeństwo swojego konta, należy odpowiednio często zmieniać haslo. Zobaczmy jak to zrobić na systemie windows

Najpierw sugeruję sprawdzić swoją nazwę użytkownika:

whoami

Jeśli wynik to po prostu nazwa, to twój komputer nie jest w domenie i ważność hasła sprawdzisz poleceniem

net user twoja_nazwa

Jeśli jednak whoami zwraca wynik w postaci domena\twoja_nazwa, to korzystasz z konta domenowego i należy uruchomić

net user twoja_nazwa /domain

W obu przypadkach poszukaj pozycji „Password expires” obok której powinna być widoczna data

By Rafał Kraik in Helpdesk