2026-03-15
Tworząc tools możemy je rejestrować korzystając z SQL lub Python. Oto przykład funkcji SQL
- Funkcja jest automatycznie rejestrowana w Unity Catalog
- Istotne jest, żeby funkcja miała zdefiniowane metadane, jak np komentarz o tym kiedy i do czego wykorzystywać funkcję. Można dodatkowo dodać opisy parameterów (PARAMETER DESCRIPTION) lub informacje o zwracanej wartości (RETURNS COMMENT). Generalnie – im więcej tym lepiej, bo dzięki tym informacjom agent będzie mógł sobie wybrać, z której funkcji chce skorzystać.
CREATE OR REPLACE FUNCTION total_revenue_by_customer(customer_id STRING)
RETURNS DOUBLE
COMMENT 'Zwraca całkowity obrót wygenerowany przez klienta na podstawie tabeli transactions’
LANGUAGE SQL
AS
$$
SELECT SUM(amount)
FROM sales.transactions
WHERE customer_id = total_revenue_by_customer.customer_id
$$;
Druga możliwość to utworzenie tool przez Python
- Dzięki użyciu DatabricksFunctionClient() ta funkcja będzie zarejestrowana w Unity Catalog
- Dekorator @client.register(…) umożliwia przekazanie metadanych, które opisują działanie funkcji.
- Dzięki dodatkowym wywołaniom funkcji modułu mlflow, ta funkcja uzyskuje automatycznie możliwość śledzenia jej wykonań a także np. przekazane parametery wejściowe i wyliczony wynik.
from databricks.sdk import DatabricksFunctionClient
import mlflow
# Rejestracja funkcji jako narzędzia
client = DatabricksFunctionClient()
@client.register(
name="total_revenue_by_customer",
description="Oblicza całkowity obrót wygenerowany przez klienta na podstawie danych sprzedażowych",
parameters=[{"name": "customer_id", "type": "string", "description": "Identyfikator klienta"}],
returns={"type": "double", "description": "Całkowity obrót klienta"}
)
def total_revenue_by_customer(customer_id: str) -> float:
# Śledzenie wykonania przez MLflow
with mlflow.start_run(run_name=f"revenue_calc_{customer_id}"):
mlflow.log_param("customer_id", customer_id)
# Przykładowe zapytanie do Lakehouse
query = f"SELECT SUM(amount) FROM sales.transactions WHERE customer_id = '{customer_id}'"
result = spark.sql(query).collect()[0][0]
mlflow.log_metric("total_revenue", result)
return result
Teraz, kiedy użytkownik zapyta o obrót generowany przez klienta, to Agent połączy się do Unity Catalog i przejrzy, czy są dostępne jakieś funkcje, które taką informację mogłyby udostępnić. To dlatego tak ważne są komentarze przekazywane podczas tworzenia funkcji. Gdy właściwa funkcja zostanie znaleziona, to Agent ja wywoła, a mlflow zaloguje wywołanie funkcji.
Zauważ, że funkcje SQL nie mają natywnego wsparcia dla mlflow, ale można je dodać wywołując je z notebooka:
- Ten kod automatycznie utworzy „wszystko co jest potrzebne” pod spodem, np. eksperyment z nazwą notebooka
- Jeśli chcesz nadać inną nazwę eksperymentu dodaj mlflow.set_experiment(„/Shared/CustomerRevenueAudit”)
import mlflow
with mlflow.start_run(run_name="sql_revenue_audit"):
mlflow.log_param("customer_id", 123)
result = spark.sql("SELECT total_revenue_by_customer(123)").collect()[0][0]
mlflow.log_metric("total_revenue", result)
W drugą stronę – usuwając z definicji funkcji pythonowej odwołania do mlflow, dostaniemy funkcję, która nadal będzie widoczna w Unity Catalog dla Agentów, ale której wykonania nie będą logowane.
Eksperymenty i historyczne informacje o uruchomieniach znajdziemy później w MLflow >> Experiments.
Można też odczytać wyniki eksperymentów programistycznie:
from mlflow import MlflowClient
client = MlflowClient()
experiment = client.get_experiment_by_name("/Shared/CustomerRevenueAudit")
runs = client.search_runs(experiment.experiment_id)
for run in runs:
print(run.info.run_name, run.data.params, run.data.metrics)
No tak… więc znowu mamy nowy problem:
- używać funkcji SQL czy Python?
- korzystać z mlflow czy nie?
SQL czy Python?
Wydaje się, że Python jest lepszy, bo nie tylko pozwoli na utworzenie czy zmodyfikowanie funkcji, ale dodatkowo fajnie integruje sie z istniejącymi API i metodami do zarządzania tymi funkcjami. Można z poziomu Pythona listować funkcje, nadawać do nich uprawnienia, zmieniać metadane itp. Z poziomu SQL tego nie zrobimy…
MlFlow czy bez?
W enterprise, zawsze warto mieć dobry governance, audyt, logi itp. Dlatego MlFlow to dobry wybór
2026-03-14
Agenci różnią się od AI tym, że mogą wywoływać narzędzia (tools). W Databricks istnieje określony sposób na definiowanie narzędzi, tak aby były one dobrze zarządzane (governance), żeby uzyskiwał do nich dostęp tylko ten kto powinien, oraz aby Agent mógł odnajdywać potrzebne dla niego narzędzia.
Zazwyczaj tool, to po prostu funkcja, tyle że z bardzo dobrymi metadanymi, opisującymi ludzkim językiem do czego ta funkcja służy, jakie parametery przyjmuje i co zwraca. Te funkcje są rejestrowane w Unity Catalog, który poniekąd z automatu załatwia sprawę governance.
Same funkcje, jak to funkcje mogą robić różne rzeczy: wykonywać skomplikowane obliczenia, wywoływać zapytania SQL, odpytywać zdalne API, konwertować dane z jednej postaci do drugiej, tworzyć podsumowania, analizować obrazy, tłumaczyć dokumenty i wiele innych.
Ponieważ istnieje wiele narzędzi, którymi „możemy robić AI”, może wyjaśnijmy czym są tools, a czym nie są.
- Tools nie są Machine Learning Modelem (MLM). MLM to model, który np. nauczył sie oceniać czy mail jest spamem czy nie. Tool może korzystać z MLM i może przesyłać do MLM wiadomości do oceny, ale tool sam w sobie nie jest MLM
- Tools nie są ChatBotami. ChatBot odpowiada za konwersację z użytkownikiem. Podczas takiej konwersacji ChatBot może potrzebować dodatkowej informacji, np. o ostatnich zdarzeniach politycznych, albo aktualnej pogodzie. Wtedy, jeśli tylko takie narzędzie jest dostępne, to wywoła to narzędzie, aby uzyskać niezbędne informacje. ChatBot sobie dalej z nich może skorzystać do udzielenia odpowiedzi
- Tools to nie API. API jest specyficzne dla serwisu, który owo API obsługuje, a co za tym idzie, funkcja, która korzysta z API musi komunikować się ze zdalną usługą zgodnie z regułami zdefiniowanymi w tym API. Tools to funkcja, która może łączyć sie do zadanego API. Tools na wejściu przyjmie pytanie, które ma być przesłane do API i w ten sposób ukryje szczegóły implementacyjne przed innymi programistami.
Tools mogą być wykorzystywane w Databricks w wielu miejscach. W szczególności:
- Tools mogą być zdefiniowane jako funkcje zarejestrowane w Unity Catalog i jest to dość często widziany scenariusz. Dzięki temu cały governance jest oddelegowany do Unity Catalog
- Tools mogą też być zaimplementowane bezpośrednio w kodzie agenta. Po prostu autor agenta wiedział, że będzie on często korzystać z pewnej funkcjonalności i wyposażył w nią agenta. Bardzo to wygodne, ale na pewno nie będzie tam całej wymaganej funkcjonalności, a ta która jest nie podlega zarządzaniu przez Databricks czy Unity Catalog
- Tools mogą wreszcie być dostępne przez serwery Model Context Protocol (MCP). Można sobie wyobrazić, że MCP to usługa w której można rejestrować różne tools i opisywać je w odpowiedni sposób pewnymi metadanymi. Kiedy agent ma do wykonania jakieś zadanie może zgłosić się do serwera MCP i w opariu o jego dane wybrac sobie te właściwe narzędzia do określonego zadania. Mając namiar na tools, można go następnie wywołać już w standardowy sposób. Istotne jest tylko, że zarówno agent jak i tool muszą być zaimplementowane zgodnie z protokołem MCP.
- Mamy serwery MCP managed – zarządzane przez Databricks, bez możliwości tworzenia private endpoints, ale gotowe do użycia w workspace
- Mamy serwery MCP external – czyli utworzone gdzieś całkiem na zewnątrz Databricks. Daje to największą elastyczność, bo usługa jest konfigurowana gdzieś indziej i Databricks nie nakłada dodatkowych warunków.
- Mamy wreszcie MCP custom – uruchamiane jako aplikacja w Databricks, co daje pełną kontrolę nad rozwiązaniem, podczas gdy wszystko zostaje w obrębie Databricks
Jeśli wydaje ci się, że serery MCP to coś dziwnego i jakby nadmiarowego to może i masz rację. Dawniej, gdy takich wynalazków nie mieliśmy, to każdą funkcję trzeba było napisać samodzielnie, a potem pisząc większy program wywoływać te funkcje. Problemem było to, że te funkcje trzeba było znać, rozumieć ich szczegóły implementacji itp. MCP ma być pewnym rozwiązaniem na tą bolączkę, bo… Ty piszesz tylko funkcje i je rejestrujesz podając mnóstwo metadanych. To Agent wybiera sobie sam, którą funkcję kiedy wykorzystać. Oczywiście praca wykonywana przez programistę ręcznie była zdecydowanie tańsza, bo przy MCP to Agent, a więc drogi AI, będzie każdorazowo wybierał właściwą funkcję do realizacji zadania, a przez niedeterministyczność AI może wybrać nie te dane co należy. Jest więc drożej, bardziej skomplikowanie, mamy większe ryzyko błędów, ale… tak jest modniej i być może takie podejście lepiej się skaluje, bo funkcji można sobie tworzyć tysiące, a potem można je sobie do woli modyfikować, a Agenci… no cóż, będą zużywać swoje cenne tokeny, żeby wybrać tę właściwą funkcję/tool i przesłać do niego poprawne argumenty. Tak to zostało wymyślone – i na pociechę, jeśli nie chesz to nie musisz z nich korzystać 😉
2026-03-13
Agent AI musi sie wykazać zrozumieniem sytuacji w jakiej się znajduje, bo inaczej może się wystawić na pośmiewisko… w celu usuniecia przyklejonej do sierści psa gumy do żucia może zaproponować wsadzenie psa do lodówki, w celu wysłania wiadomości do użytkownika, który nie istnieje utworzy mu konto itp. Jak to się dzieje, że Agent próbuje się odnaleźć w tych różnych sytuacjach? Jest kilka technik.
Percepcja – pozwala ustalić gdzie jesteśmy i jak wygląda z grubsza sytuacja. Kluczowym elementem jest to co wprowadził użytkownik: tekst, zdjęcia, audio. Jeśli agent ma jakieś czujniki, to w skład percepcji wchodzą też pomiary tych czujników. Innej odpowiedzi na pytanie jak się ubrać oczekujemy przecież latem a innej zimą. W skład percepcji wchodzi też historia do tej pory przeprowadzonej z tobą interkacji
Planowanie i decyzje – po zebraniu informacji agent przenalizuje wymagania i ewentualne zastrzeżenia co do tego co wolno robić, a co nie. Tę część definiujemy jako „system prompt”, czyli zestaw dyrektyw dotyczących zasad pracy agenta. To dlatego czasami agent odmawia współpracy, gdy pytamy o jakieś mniej legalne rzeczy. W planie zostną uwzględnione dostępne narzędzia i zbudowana zostanie sekwencja kroków do wykonania. Agent może mieć zresztą kilka pomysłów, wiec spróbuje wybrać ten najlepszy.
Akcja – dopiero na końcu dochodzi do wykonania akcji. To pasuje do reguły „najpierw pomyśl, potem rób”. Agent może stworzyć odpowiednie zapytania SQL lub API, odebrać odpowiedzi, a potem… no właśnie – albo zebrane informacje przesłać do LLM, żeby wygenerować ładną odpowiedź, albo nawet wykonać jakąś czynność, znowu korzystając z odpowiedniego API i narzędzia. Ta akcja to może być na przykład zarezerwowanie biletu, wygenerowanie pliku, czy zapalenie lampki.
Jak widać po drodze trzeba było użyć kilku komponentów:
- LLM do rozumienia pytania i sformułowania odpowiedzi, LLM może też być używany do podejmowania decyzji
- Pamięć do przechowywania historii konwersacji,
- Moduł planowania do podziału złożonych zadań na mniejsze części i określenia kolejności wykonania zadań
- Narzędzia do połączenia się z zewnętrzymi narzędziami
- Moduł wykonawczy do wykonania zaplanowanych czynności
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).
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:

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
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