Executable programs and extensions

Find slow steps in a local agent with Langfuse

Break one response's time into model, retrieval, and tool steps to decide where to investigate.

Langfuse displays trace events that an application explicitly sends. With a local instance and Python SDK v4, point the API1 base URL at that instance and instrument function calls with @observe. Installing Langfuse does not automatically trace arbitrary Ollama requests. Instrumented inputs and outputs can contain personal or document data, so choose recorded fields deliberately and mask sensitive values.

Use Langfuse to see which part of a local agent takes time: model calls, file reads, or tools. Python SDK trace events show the start, end, and duration of each step. The example traces a local Ollama request and a synthetic file read without storing prompt2 or response content.

Requirements and key details
  • A trace's total duration can include queueing, tools, model setup, and generation.
  • For new instrumentation, use @observe and get_client() from Python SDK v4 rather than older trace() examples.
  • Choose instrumentation boundaries so sensitive information is not recorded in Langfuse inputs or outputs.

Break end-to-end latency into processing steps

A slow agent does not always mean slow token3 generation. Retrieval, file reads, tool waits, retries, and response generation can all contribute. Recording each step in a Langfuse trace lets you compare which segment grew for the same test input.

Arrows lead from document, table, and mail icons to a robot beside a laptop
Recording each step's duration makes end-to-end latency easier to diagnose.

Start the local instance and prepare SDK instrumentation

In the repository root's docker-compose.yml, replace every value marked # CHANGEME. Restrict the web service's ports to 127.0.0.1:3000:3000 and set NEXTAUTH_URL to http://localhost:3000. Run docker compose up -d and docker compose ps, then confirm the port shows 127.0.0.1:3000->3000/tcp.

When Ready appears in docker compose logs -f langfuse-web, open http://localhost:3000 in a browser. Create the first user on the signup screen, then generate public and secret keys under the project's Settings → API Keys.

Prepare the Langfuse Compose repository
git clone https://github.com/langfuse/langfuse.git langfuse-local
cd langfuse-local
# 저장소 루트 docker-compose.yml에서 # CHANGEME 값을 바꾸고 NEXTAUTH_URL을 맞춰요.
Prepare the repository, then apply the following port mapping to the UI service.
Loopback-only port mapping for the UI service
ports:
  - "127.0.0.1:3000:3000"
Replace the existing ports entry on the Compose service exposing port 3000.
Start Langfuse and verify its port
docker compose up -d
docker compose ps
docker compose logs -f langfuse-web
Open http://localhost:3000 when the PORTS column shows 127.0.0.1:3000->3000/tcp.
A small robot device connected to browser, calendar, and message panels
Point the UI and tracing SDK at the same local instance.

Record model and tool steps with SDK v4

Install langfuse and requests, then set the project's public and secret API keys, LANGFUSE_BASE_URL=http://localhost:3000, and an already-installed Ollama model ID. @observe creates the parent request span; context managers from get_client() record Ollama generation and file-read tool observations beneath it. The sample omits input/output bodies and records only status and character count as metadata.

Install the SDK and set environment variables
python -m venv .venv
source .venv/bin/activate
python -m pip install -U langfuse requests
export LANGFUSE_PUBLIC_KEY='pk-lf-project-key'
export LANGFUSE_SECRET_KEY='sk-lf-project-secret'
export LANGFUSE_BASE_URL='http://localhost:3000'
export OLLAMA_MODEL='YOUR_INSTALLED_MODEL_ID'
Copy keys from project settings and use a model ID listed by ollama list.

After setting the environment variables, save the code below as run_trace.py. It calls Ollama once with a fixed prompt and reads a synthetic text file. The trace records duration and status for the two steps.

run_trace.py: trace Ollama and a synthetic file read
import os
from pathlib import Path
import requests
from langfuse import get_client, observe, propagate_attributes

MODEL = os.environ['OLLAMA_MODEL']
langfuse = get_client()

@observe(name='local-agent-request', as_type='span', capture_input=False, capture_output=False)
def run_trace():
    with propagate_attributes(trace_name='local-agent-toy', session_id='toy-session-1'):
        with langfuse.start_as_current_observation(as_type='generation', name='ollama-chat', model=MODEL) as generation:
            response = requests.post('http://127.0.0.1:11434/api/chat', json={'model': MODEL, 'stream': False, 'messages': [{'role': 'user', 'content': 'Reply with exactly: local trace test'}]}, timeout=120)
            response.raise_for_status()
            generation.update(metadata={'http_status': response.status_code})
        with langfuse.start_as_current_observation(as_type='tool', name='read-toy-file') as tool:
            text = Path('fixture.txt').read_text(encoding='utf-8')
            tool.update(metadata={'file': 'fixture.txt', 'characters': len(text)})
        print('Ollama status:', response.status_code, '| fixture characters:', len(text))

run_trace()
langfuse.flush()
Save this code block as run_trace.py. Put only synthetic text in fixture.txt; record model, HTTP status, and file character count, not prompt or response content.
Create the synthetic file and send a trace
printf '%s\n' 'Synthetic fixture for a local tracing example.' > fixture.txt && python run_trace.py
On success, the terminal prints HTTP 200 and a character count, and Langfuse shows a local-agent-toy trace.

Inspect a trace with a fixed, non-sensitive input

When local-agent-toy appears in Traces, open it and inspect the parent span, its ollama-chat generation and read-toy-file tool children, their durations, and recorded metadata.

For an initial 401/403, check that the public and secret keys came from the same project and that the API URL is http://localhost:3000. For a connection error, check service status and the PORTS value in docker compose ps; for Ollama, check curl http://127.0.0.1:11434/api/tags.

Only the synthetic prompt and fixture are used; document text and model output are not set as trace input/output.

An open cabinet of colored blocks, a wastebasket, and arranged blocks beside a checklist notebook
Compare one trace's step timings to separate model work from tool waits.

Terminology notes

  1. API — A defined interface that lets other code call a program’s functions.

    Back to the text
  2. Prompt — The input text sent to a model. For generative models it describes the desired result and strongly shapes the output.

    Back to the text
  3. Token — A unit into which a model divides input or output for processing.

    Back to the text

Frequently asked questions

What should you check first in this article?
Langfuse displays trace events that an application explicitly sends. With a local instance and Python SDK v4, point the API base URL at that instance and instrument function calls with `@observe`. Installing Langfuse does not automatically trace arbitrary Ollama requests. Instrumented inputs and outputs can contain personal or document data, so choose recorded fields deliberately and mask sensitive values.