Klienci Go dla Ollama: porównanie SDK i przykłady z Qwen3/GPT-OSS

Integracja Ollama z Go: przewodnik po SDK, przykłady i najlepsze praktyki produkcyjne.

Page content

Ten przewodnik oferuje wszechstronny przegląd dostępnych Go SDK dla Ollama oraz porównuje ich zestaw funkcji.

Zajmiemy się praktycznymi przykładami w Go dotyczącymi wywoływania modeli Qwen3 i GPT-OSS hostowanych na Ollama — zarówno za pomocą surowych wywołań REST API, jak i oficjalnego klienta Go — w tym szczegółowym omówieniem obsługi trybów myślenia (thinking) i niemyślenia (non-thinking) w Qwen3.

go and ollama

Dlaczego Ollama + Go?

Ollama udostępnia małe, pragmatyczne API HTTP (zwykle uruchamiane na http://localhost:11434) zaprojektowane dla obciążeń generate i chat, z wbudowanym wsparciem dla strumieniowania (streamingu) i zarządzania modelami. Oficjalna dokumentacja wyczerpująco opisuje struktury żądań i odpowiedzi dla /api/generate oraz /api/chat oraz semantykę strumieniowania.

Go to doskonały wybór do budowania klientów Ollama, dzięki jego silnemu wsparciu biblioteki standardowej dla HTTP, doskonałej obsłudze JSON, natywnym mechanizmom współbieżności (concurrency) oraz interfejsom ze statycznym typowaniem, które wychwytują błędy w czasie kompilacji. Aby zobaczyć, jak Ollama porównuje się z vLLM, Docker Model Runner, LocalAI i dostawcami chmury — w tym kiedy wybrać każdą z tych opcji — zobacz LLM Hosting: Porównanie infrastruktury lokalnej, self-hosted i chmurowej.

Stan na październik 2025 roku to opcje Go SDK, które najprawdopodobniej rozważysz.


Go SDK dla Ollama — co jest dostępne?

SDK / Pakiet Status i „właściciel” Zakres (Generate/Chat/Streaming) Zarządzanie modelami (pull/list/itp.) Dodatkowe funkcje / Uwagi
github.com/ollama/ollama/api Oficjalny pakiet wewnątrz repozytorium Ollama; używany przez samą aplikację CLI ollama Pełne pokrycie odpowiadające REST; wsparcie strumieniowania Tak Uważany za kanonicznego klienta Go; API blisko odzwierciedla dokumentację.
LangChainGo (github.com/tmc/langchaingo/llms/ollama) Społecznościowy framework (LangChainGo) z modułem LLM Ollama Chat/Completion + streaming za pośrednictwem abstrakcji frameworka Ograniczone (zarządzanie modelami nie jest głównym celem) Świetne, jeśli chcesz łańcuchy, narzędzia i bazy wektorowe w Go; mniej surowe SDK.
github.com/swdunlop/ollama-client Społecznościowy klient Skupienie na czacie; dobre eksperymenty z wywoływaniem narzędzi (tool-calling) Częściowe Stworzony do eksperymentów z wywoływaniem narzędzi; nie jest pełną, 1:1 powierzchnią API.
Inne społecznościowe SDK (np. ollamaclient, trzeciostronne „go-ollama-sdk”) Społecznościowe Różne Różne Jakość i zakres pokrycia się różnią; oceń w oparciu o konkretne repozytorium.

Rekomendacja: W środowisku produkcyjnym preferuj github.com/ollama/ollama/api — jest utrzymywany wraz z głównym projektem i odzwierciedla API REST.


Qwen3 i GPT-OSS na Ollama: thinking vs non-thinking (co warto wiedzieć)

  • Tryb myślenia (Thinking mode) w Ollama oddziela „rozumowanie” modelu od końcowego outputu, gdy jest włączony. Nasza ściągawka Ollama dokumentuje flagi włączenia/wyłączenia myślenia (--think, --hidethinking) dla wspieranych modeli.
  • (https://www.glukhov.org/pl/llm-performance/benchmarks/qwen3-30b-vs-gpt-oss-20b/ “Qwen3:30b vs GPT-OSS:20b: Szczegóły techniczne, wydajność i porównanie szybkości”) wspiera dynamiczne przełączanie: dodaj /think lub /no_think w wiadomościach systemowych/użytkownika, aby przełączać tryby w każdym kole rundy; obowiązuje najnowsza instrukcja.
  • GPT-OSS: użytkownicy raportują, że wyłączanie myślenia (np. /set nothink lub --think=false) może być niedostatecznie stabilne na gpt-oss:20b; planuj filtrowanie/ukrywanie wszelkiego rozumowania, które Twoja UI nie powinna wyświetlać.

Część 1 — Wywoływanie Ollama za pomocą surowego REST (Go, net/http)

Wspólne typy

Najpierw zdefiniujmy wspólne typy i funkcje pomocnicze, których użyjemy w naszych przykładach:

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"
)

// ---- Chat API Types ----

type ChatMessage struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

type ChatRequest struct {
	Model    string        `json:"model"`
	Messages []ChatMessage `json:"messages"`
	// Some servers expose thinking control as a boolean flag.
	// Even if omitted, you can still control Qwen3 via /think or /no_think tags.
	Think   *bool          `json:"think,omitempty"`
	Stream  *bool          `json:"stream,omitempty"`
	Options map[string]any `json:"options,omitempty"`
}

type ChatResponse struct {
	Model     string `json:"model"`
	CreatedAt string `json:"created_at"`
	Message   struct {
		Role     string `json:"role"`
		Content  string `json:"content"`
		Thinking string `json:"thinking,omitempty"` // present when thinking is on
	} `json:"message"`
	Done bool `json:"done"`
}

// ---- Generate API Types ----

type GenerateRequest struct {
	Model   string         `json:"model"`
	Prompt  string         `json:"prompt"`
	Think   *bool          `json:"think,omitempty"`
	Stream  *bool          `json:"stream,omitempty"`
	Options map[string]any `json:"options,omitempty"`
}

type GenerateResponse struct {
	Model     string `json:"model"`
	CreatedAt string `json:"created_at"`
	Response  string `json:"response"`           // final text for non-stream
	Thinking  string `json:"thinking,omitempty"` // present when thinking is on
	Done      bool   `json:"done"`
}

// ---- Helper Functions ----

func httpPostJSON(url string, payload any) ([]byte, error) {
	body, err := json.Marshal(payload)
	if err != nil {
		return nil, err
	}
	c := &http.Client{Timeout: 60 * time.Second}
	resp, err := c.Post(url, "application/json", bytes.NewReader(body))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return io.ReadAll(resp.Body)
}

// bptr returns a pointer to a boolean value
func bptr(b bool) *bool { return &b }

Chat — Qwen3 z włączonym thinkingiem (i jak go wyłączyć)

func chatQwen3Thinking() error {
	endpoint := "http://localhost:11434/api/chat"

	req := ChatRequest{
		Model:   "qwen3:8b-thinking", // any :*-thinking tag you have pulled
		Think:   bptr(true),
		Stream:  bptr(false),
		Messages: []ChatMessage{
			{Role: "system", Content: "You are a precise assistant."},
			{Role: "user",   Content: "Explain recursion with a short Go example."},
		},
	}

	raw, err := httpPostJSON(endpoint, req)
	if err != nil {
		return err
	}
	var out ChatResponse
	if err := json.Unmarshal(raw, &out); err != nil {
		return err
	}
	fmt.Println("🧠 thinking:\n", out.Message.Thinking)
	fmt.Println("\n💬 answer:\n", out.Message.Content)
	return nil
}

// Turn thinking OFF for the next turn by:
// (a) setting Think=false, and/or
// (b) adding "/no_think" to the most-recent system/user message (Qwen3 soft switch).
// Qwen3 honors the latest /think or /no_think instruction in multi-turn chats.
func chatQwen3NoThinking() error {
	endpoint := "http://localhost:11434/api/chat"

	req := ChatRequest{
		Model:  "qwen3:8b-thinking",
		Think:  bptr(false),
		Stream: bptr(false),
		Messages: []ChatMessage{
			{Role: "system", Content: "You are brief. /no_think"},
			{Role: "user",   Content: "Explain recursion in one sentence."},
		},
	}

	raw, err := httpPostJSON(endpoint, req)
	if err != nil {
		return err
	}
	var out ChatResponse
	if err := json.Unmarshal(raw, &out); err != nil {
		return err
	}
	// Expect thinking to be empty; still handle defensively.
	if out.Message.Thinking != "" {
		fmt.Println("🧠 thinking (unexpected):\n", out.Message.Thinking)
	}
	fmt.Println("\n💬 answer:\n", out.Message.Content)
	return nil
}

(Miękki przełącznik /think i /no_think Qwen3 jest udokumentowany przez zespół Qwen; w czatach wielokolejowych obowiązuje ostatnia instrukcja.)

Chat — GPT-OSS z thinkingiem (i zastrzeżenie)

func chatGptOss() error {
	endpoint := "http://localhost:11434/api/chat"

	req := ChatRequest{
		Model:  "gpt-oss:20b",
		Think:  bptr(true),   // request separated reasoning if supported
		Stream: bptr(false),
		Messages: []ChatMessage{
			{Role: "user", Content: "What is dynamic programming? Explain the core idea."},
		},
	}

	raw, err := httpPostJSON(endpoint, req)
	if err != nil {
		return err
	}
	var out ChatResponse
	if err := json.Unmarshal(raw, &out); err != nil {
		return err
	}
	// Known quirk: disabling thinking may not fully suppress reasoning on gpt-oss:20b.
	// Always filter/hide thinking in UI if you don't want to surface it.
	fmt.Println("🧠 thinking:\n", out.Message.Thinking)
	fmt.Println("\n💬 answer:\n", out.Message.Content)
	return nil
}

Użytkownicy raportują, że wyłączanie myślenia na gpt-oss:20b (np. /set nothink lub --think=false) może być ignorowane — zaplanuj filtrowanie po stronie klienta, jeśli jest to potrzebne.

Generate — Qwen3 i GPT-OSS

func generateQwen3() error {
	endpoint := "http://localhost:11434/api/generate"
	req := GenerateRequest{
		Model:  "qwen3:4b-thinking",
		Prompt: "In 2–3 sentences, what are B-Trees used for in databases?",
		Think:  bptr(true),
	}
	raw, err := httpPostJSON(endpoint, req)
	if err != nil {
		return err
	}
	var out GenerateResponse
	if err := json.Unmarshal(raw, &out); err != nil {
		return err
	}
	if out.Thinking != "" {
		fmt.Println("🧠 thinking:\n", out.Thinking)
	}
	fmt.Println("\n💬 answer:\n", out.Response)
	return nil
}

func generateGptOss() error {
	endpoint := "http://localhost:11434/api/generate"
	req := GenerateRequest{
		Model:  "gpt-oss:20b",
		Prompt: "Briefly explain backpropagation in neural networks.",
		Think:  bptr(true),
	}
	raw, err := httpPostJSON(endpoint, req)
	if err != nil {
		return err
	}
	var out GenerateResponse
	if err := json.Unmarshal(raw, &out); err != nil {
		return err
	}
	if out.Thinking != "" {
		fmt.Println("🧠 thinking:\n", out.Thinking)
	}
	fmt.Println("\n💬 answer:\n", out.Response)
	return nil
}

Struktury REST i zachowanie strumieniowania pochodzą bezpośrednio z odniesienia API Ollama.


Część 2 — Wywoływanie Ollama za pomocą oficjalnego Go SDK (github.com/ollama/ollama/api)

Oficjalny pakiet udostępnia Client z metodami odpowiadającymi API REST. Sam CLI Ollama używa tego pakietu do komunikacji z usługą, co czyni go najbezpieczniejszym wyborem pod kątem kompatybilności.

Instalacja

go get github.com/ollama/ollama/api

Chat — Qwen3 (thinking WŁ/CZ)

package main

import (
	"context"
	"fmt"
	"log"

	"github.com/ollama/ollama/api"
)

func chatWithQwen3Thinking(ctx context.Context, thinking bool) error {
	client, err := api.ClientFromEnvironment() // honors OLLAMA_HOST if set
	if err != nil {
		return err
	}

	req := &api.ChatRequest{
		Model: "qwen3:8b-thinking",
		// Many server builds expose thinking as a top-level flag;
		// additionally, you can control Qwen3 via /think or /no_think in messages.
		Think: api.Ptr(thinking),
		Messages: []api.Message{
			{Role: "system", Content: "You are a precise assistant."},
			{Role: "user",   Content: "Explain merge sort with a short Go snippet."},
		},
	}

	var resp api.ChatResponse
	if err := client.Chat(ctx, req, &resp); err != nil {
		return err
	}

	if resp.Message.Thinking != "" {
		fmt.Println("🧠 thinking:\n", resp.Message.Thinking)
	}
	fmt.Println("\n💬 answer:\n", resp.Message.Content)
	return nil
}

func main() {
	ctx := context.Background()
	if err := chatWithQwen3Thinking(ctx, true); err != nil {
		log.Fatal(err)
	}
	// Example: non-thinking
	if err := chatWithQwen3Thinking(ctx, false); err != nil {
		log.Fatal(err)
	}
}

Chat — GPT-OSS (obchodź rozumowanie ostrożnie)

func chatWithGptOss(ctx context.Context) error {
	client, err := api.ClientFromEnvironment()
	if err != nil {
		return err
	}
	req := &api.ChatRequest{
		Model: "gpt-oss:20b",
		Think: api.Ptr(true),
		Messages: []api.Message{
			{Role: "user", Content: "What is memoization and when is it useful?"},
		},
	}
	var resp api.ChatResponse
	if err := client.Chat(ctx, req, &resp); err != nil {
		return err
	}
	// If you intend to hide reasoning, do it here regardless of flags.
	if resp.Message.Thinking != "" {
		fmt.Println("🧠 thinking:\n", resp.Message.Thinking)
	}
	fmt.Println("\n💬 answer:\n", resp.Message.Content)
	return nil
}

Generate — Qwen3 i GPT-OSS

func generateWithQwen3(ctx context.Context) error {
	client, err := api.ClientFromEnvironment()
	if err != nil {
		return err
	}
	req := &api.GenerateRequest{
		Model:  "qwen3:4b-thinking",
		Prompt: "Summarize the role of a B-Tree in indexing.",
		Think:  api.Ptr(true),
	}
	var resp api.GenerateResponse
	if err := client.Generate(ctx, req, &resp); err != nil {
		return err
	}
	if resp.Thinking != "" {
		fmt.Println("🧠 thinking:\n", resp.Thinking)
	}
	fmt.Println("\n💬 answer:\n", resp.Response)
	return nil
}

func generateWithGptOss(ctx context.Context) error {
	client, err := api.ClientFromEnvironment()
	if err != nil {
		return err
	}
	req := &api.GenerateRequest{
		Model:  "gpt-oss:20b",
		Prompt: "Explain gradient descent in simple terms.",
		Think:  api.Ptr(true),
	}
	var resp api.GenerateResponse
	if err := client.Generate(ctx, req, &resp); err != nil {
		return err
	}
	if resp.Thinking != "" {
		fmt.Println("🧠 thinking:\n", resp.Thinking)
	}
	fmt.Println("\n💬 answer:\n", resp.Response)
	return nil
}

Powierzchnia oficjalnego pakietu odzwierciedla dokumentację REST i jest aktualizowana równolegle z głównym projektem.


Strumieniowanie odpowiedzi (Streaming responses)

Dla strumieniowania w czasie rzeczywistym ustaw Stream: bptr(true) w swoim żądaniu. Odpowiedź zostanie dostarczona jako bloki JSON oddzielone znacznikami nowej linii:

func streamChatExample() error {
	endpoint := "http://localhost:11434/api/chat"
	req := ChatRequest{
		Model:  "qwen3:8b-thinking",
		Think:  bptr(true),
		Stream: bptr(true), // Enable streaming
		Messages: []ChatMessage{
			{Role: "user", Content: "Explain quicksort algorithm step by step."},
		},
	}

	body, _ := json.Marshal(req)
	resp, err := http.Post(endpoint, "application/json", bytes.NewReader(body))
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	decoder := json.NewDecoder(resp.Body)
	for {
		var chunk ChatResponse
		if err := decoder.Decode(&chunk); err == io.EOF {
			break
		} else if err != nil {
			return err
		}
		
		// Process thinking and content as they arrive
		if chunk.Message.Thinking != "" {
			fmt.Print(chunk.Message.Thinking)
		}
		fmt.Print(chunk.Message.Content)
		
		if chunk.Done {
			break
		}
	}
	return nil
}

Z oficjalnym SDK użyj funkcji wywołania zwrotnego (callback) do obsługi bloków strumienia:

func streamWithOfficialSDK(ctx context.Context) error {
	client, _ := api.ClientFromEnvironment()
	
	req := &api.ChatRequest{
		Model: "qwen3:8b-thinking",
		Think: api.Ptr(true),
		Messages: []api.Message{
			{Role: "user", Content: "Explain binary search trees."},
		},
	}
	
	err := client.Chat(ctx, req, func(resp api.ChatResponse) error {
		if resp.Message.Thinking != "" {
			fmt.Print(resp.Message.Thinking)
		}
		fmt.Print(resp.Message.Content)
		return nil
	})
	
	return err
}

Praca z Qwen3 thinking vs non-thinking (praktyczne wytyczne)

  • Dwa mechanizmy sterowania:

    1. Boolean flaga thinking wspierana przez funkcję myślenia w Ollama; oraz
    2. Miękkie przełączniki Qwen3 komendy /think i /no_think w najnowszej wiadomości systemowej/użytkownika. Najnowsza instrukcja rządzi następnymi rundami.
  • Domyślna postawa: non-thinking dla szybkich odpowiedzi; eskaluj do thinking dla zadań wymagających rozumowania krok po kroku (matematyka, planowanie, debugowanie, złożona analiza kodu).

  • Interfejsy użytkownika strumieniowe: gdy myślenie jest włączone, możesz zobaczyć przeplatające się ramki rozumowania/ zawartości w strumieniu — buforuj lub renderuj je osobno i daj użytkownikom przełącznik „pokaż rozumowanie”. (Zobacz dokumentację API dla formatu strumieniowania.)

  • Rozmowy wielokolejowe: Qwen3 zapamiętuje tryb myślenia z poprzednich rund. Jeśli chcesz przełączyć go w trakcie rozmowy, użyj zarówno flagi, jak i komendy miękkiego przełącznika dla niezawodności.

Uwagi dotyczące GPT-OSS

  • Traktuj rozumowanie jako obecne, nawet jeśli próbujesz je wyłączyć; filtruj po stronie klienta, jeśli Twój UX nie powinien go wyświetlać.
  • Dla aplikacji produkcyjnych używających GPT-OSS, implementuj logikę filtrowania po stronie klienta, która może wykrywać i usuwać wzorce rozumowania, jeśli jest to potrzebne.
  • Dokładnie testuj swój konkretny wariant modelu GPT-OSS, ponieważ zachowanie może się różnić między różnymi kwantyzacjami i wersjami.

Najlepsze praktyki i wskazówki produkcyjne

Obsługa błędów i terminy wygaśnięcia (timeouts)

Zawsze implementuj właściwą obsługę timeoutów i odzyskiwanie z błędów:

func robustChatRequest(ctx context.Context, model string, messages []api.Message) (*api.ChatResponse, error) {
	// Set a reasonable timeout
	ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
	defer cancel()
	
	client, err := api.ClientFromEnvironment()
	if err != nil {
		return nil, fmt.Errorf("creating client: %w", err)
	}
	
	req := &api.ChatRequest{
		Model:    model,
		Messages: messages,
		Options: map[string]interface{}{
			"temperature": 0.7,
			"num_ctx":     4096, // context window size
		},
	}
	
	var resp api.ChatResponse
	if err := client.Chat(ctx, req, &resp); err != nil {
		return nil, fmt.Errorf("chat request failed: %w", err)
	}
	
	return &resp, nil
}

Pooling i ponowne używanie połączeń

Ponownie używaj klienta Ollama między żądaniami, zamiast tworzyć nowego za każdym razem:

type OllamaService struct {
	client *api.Client
}

func NewOllamaService() (*OllamaService, error) {
	client, err := api.ClientFromEnvironment()
	if err != nil {
		return nil, err
	}
	return &OllamaService{client: client}, nil
}

func (s *OllamaService) Chat(ctx context.Context, req *api.ChatRequest) (*api.ChatResponse, error) {
	var resp api.ChatResponse
	if err := s.client.Chat(ctx, req, &resp); err != nil {
		return nil, err
	}
	return &resp, nil
}

Konfiguracja środowiska

Używaj zmiennych środowiskowych dla elastycznego wdrażania:

export OLLAMA_HOST=http://localhost:11434
export OLLAMA_NUM_PARALLEL=2
export OLLAMA_MAX_LOADED_MODELS=2

Oficjalne SDK automatycznie respektuje OLLAMA_HOST za pośrednictwem api.ClientFromEnvironment().

Monitorowanie i logowanie

Implementuj strukturalizowane logowanie dla systemów produkcyjnych:

func loggedChat(ctx context.Context, logger *log.Logger, req *api.ChatRequest) error {
	start := time.Now()
	client, _ := api.ClientFromEnvironment()
	
	var resp api.ChatResponse
	err := client.Chat(ctx, req, &resp)
	
	duration := time.Since(start)
	logger.Printf("model=%s duration=%v error=%v tokens=%d", 
		req.Model, duration, err, len(resp.Message.Content))
	
	return err
}

Podsumowanie

  • Dla projektów Go, github.com/ollama/ollama/api jest najbardziej kompletnym i gotowym do produkcji wyborem. Jest utrzymywany równolegle z głównym projektem Ollama, używany przez oficjalny CLI i zapewnia kompleksowe pokrycie API ze gwarancją kompatybilności.

  • Dla wyższych abstrakcji, rozważ LangChainGo, gdy potrzebujesz łańcuchów, narzędzi, baz wektorowych i pipeline’ów RAG, choć wymienisz pewną kontrolę niskiego poziomu na wygodę.

  • Qwen3 daje Ci czystą i niezawodną kontrolę nad trybem myślenia za pomocą zarówno flag, jak i przełączników na poziomie wiadomości (/think, /no_think), czyniąc go idealnym dla aplikacji, które potrzebują zarówno szybkich odpowiedzi, jak i głębokiego rozumowania.

  • Dla GPT-OSS, zawsze planuj sanitizację outputu rozumowania po stronie klienta, gdy jest to konieczne, ponieważ flaga wyłączająca myślenie może nie być konsekwentnie respektowana.

  • W środowisku produkcyjnym, implementuj odpowiednią obsługę błędów, pooling połączeń, timeouty i monitorowanie, aby budować solidne aplikacje zasilane przez Ollama.

Kombinacja silnego typowania Go, doskonałego wsparcia współbieżności i prostego API Ollama czyni ten stack idealnym do budowania aplikacji zasilanych AI — od prostych czatbotów po złożone systemy RAG.

Kluczowe wnioski

Oto szybkie odniesienie do wyboru Twojego podejścia:

Przypadek użycia Zalecane podejście Dlaczego
Aplikacja produkcyjna github.com/ollama/ollama/api Oficjalne wsparcie, pełne pokrycie API, utrzymywane z głównym projektem
Pipeline RAG/łańcuchy/narzędzia LangChainGo Abstrakcje wysokiego poziomu, integracje z bazami wektorowymi
Nauka/eksperymentowanie Surowy REST z net/http Pełna transparentność, brak zależności, edukacyjny
Szybki prototyp Oficjalne SDK Równowaga prostoty i mocy
Strumieniowy interfejs czatu Oficjalne SDK z callbackami Wbudowane wsparcie dla streamingu, czyste API

Wytyczne doboru modelu:

  • Qwen3: Najlepszy dla aplikacji wymagających kontrolowalnego trybu myślenia, niezawodnych rozmów wielokolejowych
  • GPT-OSS: Silna wydajność, ale wymaga defensywnego obchodzenia outputu myślenia/rozumowania
  • Inne modele: Testuj starannie; zachowanie myślenia różni się w zależności od rodziny modeli

Odniesienia i dalsze czytanie

Oficjalna dokumentacja

Alternatywy Go SDK

Zasoby specyficzne dla modeli

Powiązane tematy

Inne przydatne linki

Dla szerszego porównania Ollama z innymi lokalnymi i chmurowymi infrastrukturami LLM, sprawdź nasze LLM Hosting: Porównanie infrastruktury lokalnej, self-hosted i chmurowej.

Subskrybuj

Otrzymuj nowe wpisy o systemach, infrastrukturze i inżynierii AI.