Skip to content
Go back

Local LLM környezet kialakítása

Háttértörténet

Úgy alakult, hogy hozzám került egy HP EliteBook 840 G7 i5-10310U processzorral és 32 GB memóriával. Ez a gép kicsi és nem fogyaszt sokat, ezért arra gondoltam, megpróbálok valamilyen lokális LLM-futtatókörnyezetet összerakni rajta, hogy legyen egy kis játszóterem a különböző AI-os kísérletekhez.

A kezdetek

Mivel a jövőben még változhat, hogy pontosan mit szeretnék használni, egy Docker-alapú környezet mellett döntöttem.

Telepítettem a Docker Desktopot, majd összeállítottam az alábbi Docker Compose fájlt. Két konténert indítok: az egyikben az Ollama fut, elé pedig egy Caddy reverse proxy kerül, amely az API-kulcs ellenőrzését végzi. Ehhez a feladathoz a Caddy konfigurációja mindössze néhány sorból áll, de más reverse proxyval sem lenne bonyolultabb a megvalósítás.

name: local-llm
services:
  ollama:
    image: ollama/ollama:latest
    container_name: local-ollama
    restart: unless-stopped
    environment:
      OLLAMA_NO_CLOUD: "1"
      OLLAMA_CONTEXT_LENGTH: "8192"
      OLLAMA_MAX_LOADED_MODELS: "2"
      OLLAMA_KEEP_ALIVE: "30m"
    volumes:
      - type: bind
        source: C:/dev/local-llm/ollama
        target: /root/.ollama
    networks:
      - ollama_net

  caddy:
    image: caddy:latest
    container_name: ollama-proxy
    restart: unless-stopped
    ports:
      - "11434:8080"
    volumes:
      - type: bind
        source: C:/dev/local-llm/caddy/
        target: /etc/caddy/
    depends_on:
      - ollama
    networks:
      - ollama_net
    env_file: "caddy.env"

networks:
  ollama_net:
    driver: bridge
    internal: false

Az Ollama működését az alábbi környezeti változókat használva állítottam be (majd kiderül mennyire jó ez):

A Caddy számára az API-kulcsot egy külön caddy.env fájlban adom át:

OLLAMA_API_KEY=api-key

A C:/dev/local-llm/caddy/Caddyfile tartalma:

:8080 {
    @authorized header Authorization "Bearer {$OLLAMA_API_KEY}"

    handle @authorized {
        reverse_proxy ollama:11434
    }

    handle {
        respond "Unauthorized" 401
    }
}

Így az Ollama közvetlenül nincs publikálva a hoston, csak a Caddyn keresztül érhető el.

Fontos, hogy ez az API-kulcs csak egy egyszerű hitelesítési réteg. A fenti konfiguráció HTTP-t használ, szóval nem biztosít titkosított kommunikációt. Én ezt csak helyi hálózaton használom; internet felé nem engedem ki.

A Windows tűzfalon is engedélyezni kell a használt portot:

New-NetFirewallRule `                              
   -DisplayName "Ollama proxy - helyi hálózat" `
   -Direction Inbound `
   -Action Allow `
   -Protocol TCP `
   -LocalPort 11434 `
   -Profile Private `
   -RemoteAddress LocalSubnet

A WSL számára elérhető memóriát 24 GB-ra emeltem, mert alapértelmezetten a gép számára rendelkezésre álló memória felét állítja be.

Ezzel az alap környezet készen is van.

Modellválasztás

A RAG-kísérletekhez szükségem lesz egy embedding modellre is. Erre az EmbeddingGemmát választottam.

A szöveggeneráláshoz használt modell kiválasztása már nehezebb kérdés. A magyar nyelv és a laptop korlátozott erőforrásai miatt az alábbi modelleket próbáltam ki:

A modellek a vártnál valamivel lassabban reagáltak, de kezdésnek szerintem használhatók.

A kisebb tesztem során a qwen3.5:2b teljesített a leggyorsabban, nagyjából 10–14 token/s generálási sebességgel.

A nagyobb modellek jellemzően 3–7 token/s körüli sebességet értek el. A phi4-mini néha ennél valamivel gyorsabb volt, körülbelül 5–8 token/s értékkel.

A magyar szöveggenerálás minőségét és egy rövid chatpéldát nézve nálam eddig a Gemma 4 teljesített a legjobban. Később azért lehet, hogy megnézem majd a többit is, mire képesek egy-egy szituációban.

A modelleket a futó Ollama-konténerben egyszerűen le lehet tölteni az alábbi parancsokkal:

docker exec local-ollama ollama pull embeddinggemma
docker exec local-ollama ollama pull gemma4:e4b-it-qat

Local LLM próba

Nem maradt más hátra, mint tesztelni. C# kóddal fogom kipróbálni és a Microsoft Agent Framework és az OllamaSharp csomagot fogom használni. A teszt kedvéért limitálom a válasz maximális méretét, és kikapcsolom a thinking módot is.

Az alábbi NuGet csomagokat használtam:

<PackageReference Include="Microsoft.Agents.AI" Version="1.22.0" />
<PackageReference Include="OllamaSharp" Version="5.4.30" />

Mivel ezen a hardveren a válaszgenerálás lassabb lehet, az alapértelmezettnél hosszabb timeoutot állítok be a saját HttpClient példányon. A konfigurációhoz két környezeti változót használok:

using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OllamaSharp;
using OllamaSharp.Models;
using System.Net.Http.Headers;

var endpoint = Environment.GetEnvironmentVariable("LOCAL_OLLAMA_ENDPOINT") 
    ?? throw new InvalidOperationException("LOCAL_OLLAMA_ENDPOINT is missing.");

var apiKey = Environment.GetEnvironmentVariable("LOCAL_OLLAMA_API_KEY")
    ?? throw new InvalidOperationException("LOCAL_OLLAMA_API_KEY is missing.");

var modelName = "gemma4:e4b-it-qat";

var httpClient = new HttpClient
{
    BaseAddress = new Uri(endpoint),
    Timeout = TimeSpan.FromMinutes(5)
};
httpClient.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", apiKey);

AIAgent agent = new OllamaApiClient(httpClient, modelName).AsAIAgent(new ChatClientAgentOptions()
{
    ChatOptions = new ChatOptions
    {
        MaxOutputTokens = 500
    }
    .AddOllamaOption(OllamaOption.Think, false)
});

// Console.WriteLine(await agent.RunAsync("Mit lehet tudni a gemma4:e4b-it-qat modellről?"));

await foreach (var answerChunk in agent.RunStreamingAsync(
    "Könnyen érthetően definiáld, hogy mi a gemma4:e4b-it-qat modell. Röviden és tömören, 1-2 mondatban válaszolj!"))
{
    Console.Write(answerChunk.Text);
}

A RunAsync helyett szándékosan a RunStreamingAsync metódust használom. Lassabb generálásnál így nem kell megvárni a teljes választ, hanem folyamatosan ki tudom írni az érkező részleteket.

Erre meg is kaptam az alábbi választ: Ez egy az eredeti Gemma 4 alapú, utasítás-követéshez speciálisan trainált modellek hatékony verziója. A "QAT" technológia lehetővé teszi, hogy a modell kevés számú információs pontot (quantization) használva is maximalizálja sebességét és minimalizálja mérete, így gyorsan futtathető erőforrástípusokon.

A teszt szempontjából a válasz megérkezett, ugyanakkor maga a tartalma nem teljesen pontos. Ez rögtön egy jó példa arra is, hogy az LLM-ek által generált technikai állításokat érdemes ellenőrizni.

A technikai teszt ezzel sikeresen lezajlott, jöhet a használat. Ami miatt még aggódom, hogy a gyakorlatban mire lesz elég ez a 3-7 token/s körüli generálási sebesség. Ez majd később és akár egy másik bejegyzésben fog kiderülni.


Share this post on:

Next Post
ILogger scope és Serilog kapcsolata