Vlastní lokální agent s pomocí Langraph a Ollama, bez nutnosti platit tokeny

Lokální LLM agent langgraph

Toto je návod, jak si postavit vlastního chytrého agenta na svém zařízení (bez potřeby platit za tokeny), který má přístup na internet a k nástroji kalkulačka. To vše s pomocí langgraph, Ollama a modelu Llama nebo Mistral.

LLM technologie, které jsem zvolil

  • Langgraph – Framework od Langchain pro tvorbu LLM agentů pomocí stavů a smyček
  • Langgraph Studio – vizualizace pomocí grafu toku
  • Ollama – open source engine pro lokální běh (tedy zdarma) opensource modelů
  • Llama 3.1 – velký jazykový open source model od Meta
  • DuckDuckGo – vyhledávací open source engine pro napojení LLM na aktuální informace

Celou aplikaci stavím na svém běžném tech stacku: Python, FastAPI, React, Tailwind – kde mám možnost jednoduše implementovat jakýkoliv nástroj, aniž bych musel od začátku vyvíjet komplet aplikaci.

Postup tvorby agenta

Nejprve si nainstalujeme do svého zařízení Ollama engine a spustíme.

brew install ollama
ollama serve

Následně stáhneme požadované modely. Já jsem zvolil starší model Llama 3.1 kvůli velikosti, protože některé modely zabírají hodně místa a stahování by trvalo delší dobu.

ollama pull llama3.1 # nebo jiný novější, třeba llama 3.3
ollama pull deepseek-r1:latest # nebo větší a výkonnější model

Stažení Llama 3.1 mi trvalo na mém macu zhruba 60 min.

Připravíme si requirements.txt a nainstalujeme potřebné knihovny:

langchain
langgraph  
langchain-community
duckduckgo-search

Připravíme si BE službu a vyzkoušíme rovnou dotaz:

from langchain_core.tools import tool
import ast
from langchain_community.tools import DuckDuckGoSearchRun
from langchain_ollama import ChatOllama
from typing import TypedDict, Annotated
from langgraph.graph.message import add_messages
from langgraph.graph import StateGraph, START
from langgraph.prebuilt import ToolNode, tools_condition
from langchain_core.messages import HumanMessage

# Create a calculator function
@tool
def calculator(query: str) -> str: 
  # Explain the aim of this function 
  """Use this tool to calculate the result of a mathematical expression."""
  # Use literal_eval to safely evaluate mathematical expressions provided in string format.
  return ast.literal_eval(query)

# Instantiate the object.
search = DuckDuckGoSearchRun()

# Define a variable to hold all the tools we'll use
tools = [search, calculator]

# Create a large model
model = ChatOllama(model="mistral", temperature=0.1).bind_tools(tools)

# Create a State object that acts as the system's memory
class State(TypedDict):
    messages: Annotated[list, add_messages]

# Build the model node
def model_node(state: State) -> State:
    res = model.invoke(state["messages"])
    return {"messages": res}

# Initialize the graph
builder = StateGraph(State) 

# Build the nodes
builder.add_node("model", model_node) 
builder.add_node("tools", ToolNode(tools))

# Add the edges
builder.add_edge(START, "model")
builder.add_conditional_edges("model", tools_condition)
builder.add_edge("tools", "model")

graph = builder.compile()

"""
with open("graph.png", "wb") as f:
  f.write(graph.get_graph().draw_mermaid_png())

"""
"""
# Create an input for the graph
input = {
    "messages": [
        HumanMessage(
            "Jak dopadla kauza bitcoin a Blažek?"
        )
    ]
}


result = graph.invoke(input)
print(result)
print("--------------The AI Agent's Answer------------------")
print(result["messages"][-1].content)

"""

V mém případě ještě připravím FE do své aplikace a dotazy mohu pokládat rovnou do vlastního UI rozhraní.

Zkusíme dotazy na aktuální informace. Agent použije nástroj vyhledávač DuckDuckGo.

Případně dotazy matematické. Zde se použije nástroj kalkulačka.

Nyní si ještě vytvoříme na backend části tvorbu grafu. Specifikum langgraph jsou stavy (states) a uzly (nodes), dále pak hrany (edges).

  • States (Stavy) – Uchovávají data, která procházejí grafem
  • Nodes (Uzly) – Funkce nebo komponenty, které zpracovávají a modifikují stav
  • Edges (Hrany) – Definují tok mezi uzly (mohou být podmíněné nebo přímé)
def create_agent_graph(model_name: str, temperature: float, tools_enabled: List[str]):
    tools = []
    
    TOOL_SUPPORTED_MODELS = [
        "llama3.1:latest",
        "mistral:latest"
    ]
    
    model_supports_tools = model_name in TOOL_SUPPORTED_MODELS
    
    # 1. PŘÍPRAVA NÁSTROJŮ
    if tools_enabled and model_supports_tools:
        if "search" in tools_enabled:
            search = DuckDuckGoSearchRun()
            tools.append(search)
        
        if "calculator" in tools_enabled:
            tools.append(calculator)
    
    # 2. VYTVOŘENÍ MODELU
    model = ChatOllama(model=model_name, temperature=temperature)
    
    if tools and model_supports_tools:
        model = model.bind_tools(tools)
    
    # 3. DEFINICE FUNKCE PRO MODEL NODE
    def model_node(state: State) -> State:
        try:
            res = model.invoke(state["messages"])
            return {"messages": res}
        except Exception as e:
            if "does not support tools" in str(e):
                model_without_tools = ChatOllama(model=model_name, temperature=temperature)
                res = model_without_tools.invoke(state["messages"])
                return {"messages": res}
            raise e
    
    # 4. VYTVOŘENÍ GRAFU
    builder = StateGraph(State)
    builder.add_node("model", model_node)
    
    # 5. PŘIDÁNÍ HRAN A NÁSTROJŮ
    if tools and model_supports_tools:
        builder.add_node("tools", ToolNode(tools))
        builder.add_edge(START, "model")
        builder.add_conditional_edges("model", tools_condition)
        builder.add_edge("tools", "model")
    else:
        # Bez nástrojů - jednoduchý flow
        builder.add_edge(START, "model")
    
    # 6. KOMPILACE GRAFU
    return builder.compile()

A následně si ještě uděláme vizualizaci grafu.

@router.post("/visualize")
async def visualize_graph(request: GraphVisualizationRequest):
    try:
        graph = create_agent_graph(
            request.model,
            request.temperature,
            request.tools_enabled
        )
        
        try:
            png_data = graph.get_graph().draw_mermaid_png()
            
            return Response(
                content=png_data,
                media_type="image/png",
                headers={
                    "Content-Disposition": "inline; filename=graph.png"
                }
            )
        except Exception as e:
            mermaid_code = graph.get_graph().draw_mermaid()
            
            return {
                "type": "mermaid",
                "content": mermaid_code,
                "error": f"PNG generation failed: {str(e)}"
            }

Následně si můžeme buď na frontendu vytvořit, nebo s pomocí langgraph studio zobrazit vizualizaci grafu.

Vidíme, že je zde start následně voláme daný model, který může nebo nemusí použít nástroj dle potřeby. Jakmile vykoná daný úkon, dojde ke konci.

Díky LangGraph vidíme LLM řízený tok práce (workflow), zatímco běžný agent by udělal jen „pošli prompt a počkej na odpověď“, agent langgraph může používat více smyčkové rozhodovací procesy a můžeme ovlivňovat každý specifický krok, který vede k nějakému řešení. Ideální pro složité produkční aplikace.

Pokud bychom chtěli, mohli bychom přidat i RAG na vlastní data, paměť pro ukládání informací z konverzací, nebo další potřebné nástroje. To vše ještě napojit na zabezpečená data a máme plně funkční produkční aplikaci pro velmi složité a komplexní dotazy.

Co se mi na řešení líbí

  • Lokální LLM spustitelný na vlastním zařízení
  • Langgraph pro řízený tok práce pomocí uzlů, hran a stavů
  • Vyhledávač DuckDuckGo jako free alternativa ke Google
  • Llama 3.1 – open source velký jazykový model

Celý kód, kterým jsem se inspiroval, najdete na github.

Příště si ukážeme, jak vytvořit v langgraph komplexní vyhledávač deep research, podobný jako má Google na Gemini.

Obsah článku

Líbí se Vám obsah?

Odebírejte Newsletter, ať vám nic neunikne.

Odebírejte novinky ze světa AI

Chcete-li se přihlásit k odběru tohoto blogu a dostávat upozornění na nové příspěvky e-mailem, zadejte svou e-mailovou adresu.

Sledujte mě na sítích.

Odběr novinek AI

Odebírejte novinky ze světa AI

Chcete-li se přihlásit k odběru tohoto blogu a dostávat upozornění na nové příspěvky e-mailem, zadejte svou e-mailovou adresu.

Podobné články

kurz chatgpt - školení AI

Praktické Školení chatGPT

Školení chatGPT pro firmy i jednotlivce. Díky tomuto kurzu se dozvíte, jak chat GPT používat při každodenní práci i na pomoc v osobním životě. Naučím

Číst více »