mgonzs13/llama_ros

llama.cpp (GGUF LLMs) and llava.cpp (GGUF VLMs) for ROS 2

C++

264

1,010 commits

updated Sep 24, 2026

See the code

README

llama_ros

This repository provides a set of ROS 2 packages to integrate llama.cpp into ROS 2. Using the llama_ros packages, you can easily incorporate the powerful optimization capabilities of llama.cpp into your ROS 2 projects by running GGUF-based LLMs and VLMs. You can also use features from llama.cpp such as GBNF grammars and modify LoRAs in real-time.

License: MIT GitHub release Code Size Last Commit GitHub issues GitHub pull requests Contributors Python Formatter Check C++ Formatter Check Doxygen Deployment

ROS 2 DistroBranchBuild statusDocker Image
HumblemainHumble BuildDocker Image
IronmainIron BuildDocker Image
JazzymainJazzy BuildDocker Image
KiltedmainKilted BuildDocker Image
LyricalmainLyrical BuildDocker Image

Table of Contents

  1. Related Projects
  2. Installation
  3. Docker
  4. Usage
  5. Demos
  • chatbot_ros → This chatbot, integrated into ROS 2, uses whisper_ros, to listen to people speech; and llama_ros, to generate responses. The chatbot is controlled by a state machine created with YASMIN.
  • explainable_ros → A ROS 2 tool to explain the behavior of a robot. Using the integration of LangChain, logs are stored in a vector database. Then, RAG is applied to retrieve relevant logs for user questions answered with llama_ros.

Installation

To run llama_ros with CUDA, first, you must install the CUDA Toolkit. Then, you can compile llama_ros with --cmake-args -DGGML_CUDA=ON to enable CUDA support.

Then clone the repository and install the Python dependencies:

cd ~/ros2_ws/src
git clone https://github.com/mgonzs13/llama_ros.git
cd llama_ros
pip3 install --break-system-packages -r requirements.txt
cd ~/ros2_ws
rosdep install --from-paths src --ignore-src -r -y
colcon build --cmake-args -DGGML_CUDA=ON # add this for CUDA

To run the tests:

colcon test --executor sequential --packages-select llama_ros llama_bt
colcon test-result --verbose

Docker

Build the llama_ros docker or download an image from DockerHub. You can choose to build llama_ros with CUDA (USE_CUDA) and choose the CUDA version (CUDA_VERSION). Remember that you have to use DOCKER_BUILDKIT=0 to compile llama_ros with CUDA when building the image.

DOCKER_BUILDKIT=0 docker build -t llama_ros --build-arg USE_CUDA=1 --build-arg CUDA_VERSION=12-6 .

Run the docker container. If you want to use CUDA, you have to install the NVIDIA Container Toolkit and add --gpus all.

docker run -it --rm --gpus all llama_ros

Usage

llama_cli

Commands are included in llama_ros to speed up the test of GGUF-based LLMs within the ROS 2 ecosystem. This way, the following commands are integrating into the ROS 2 commands:

launch

Using this command launch a LLM from a YAML file. The configuration of the YAML is used to launch the LLM in the same way as using a regular launch file. Here is an example of how to use it:

ros2 llama launch ~/ros2_ws/src/llama_ros/llama_bringup/models/StableLM-Zephyr.yaml

prompt

Using this command send a prompt to a launched LLM. The command uses a string, which is the prompt and has the following arguments:

  • (-r, --reset): Whether to reset the LLM before prompting
  • (-t, --temp): The temperature value
  • (--image-url): Image url to sent to a VLM

Here is an example of how to use it:

ros2 llama prompt "Do you know ROS 2?" -t 0.0

Launch Files

First of all, you need to create a launch file to use llama_ros or llava_ros. This launch file will contain the main parameters to download the model from HuggingFace and configure it. Take a look at the following examples and the predefined launch files.

llama_ros (Python Launch)

Click to expand
from launch import LaunchDescription
from launch_ros.actions import Node


def generate_launch_description():

    return LaunchDescription([
        Node(
            package="llama_ros",
            executable="llama_node",
            name="llama_node",
            namespace="llama",
            parameters=[{
                "context.n_ctx": 2048,
                "context.n_batch": 8,
                "context.n_predict": 2048,
                "gpu.n_gpu_layers": 0,
                "cpu.n_threads": 1,
                "model.repo": "TheBloke/Marcoroni-7B-v3-GGUF",
                "model.filename": "marcoroni-7b-v3.Q4_K_M.gguf",
                "prompt.system_prompt_type": "Alpaca",
            }],
        )
    ])
ros2 launch llama_bringup marcoroni.launch.py

llama_ros (YAML Config)

Click to expand
/**:
  ros__parameters:
    model:
      repo: "cstr/Spaetzle-v60-7b-GGUF"
      filename: "Spaetzle-v60-7b-q4-k-m.gguf"
    context:
      n_ctx: 2048
      n_batch: 8
      n_predict: 2048
    gpu:
      n_gpu_layers: 0
    cpu:
      n_threads: 1
    prompt:
      system_prompt_type: "Alpaca"
import os
from launch import LaunchDescription
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory


def generate_launch_description():
    return LaunchDescription([
        Node(
            package="llama_ros",
            executable="llama_node",
            name="llama_node",
            namespace="llama",
            parameters=[os.path.join(
                get_package_share_directory("llama_bringup"),
                "models", "Spaetzle.yaml")],
        )
    ])
ros2 launch llama_bringup spaetzle.launch.py

llama_ros (YAML Config + model shards)

Click to expand
model:
  repo: "Qwen/Qwen2.5-Coder-7B-Instruct-GGUF" # Hugging Face repo
  filename: "qwen2.5-coder-7b-instruct-q4_k_m-00001-of-00002.gguf" # model shard file in repo

context:
  n_ctx: 2048 # context of the LLM in tokens
  n_batch: 8 # batch size in tokens
  n_predict: 2048 # max tokens, -1 == inf

gpu:
  n_gpu_layers: 0 # layers to load in GPU

cpu:
  n_threads: 1 # threads

prompt:
  system_prompt_type: "ChatML" # system prompt type
ros2 llama launch Qwen2.yaml

llama_ros (Speculative Decoding)

Click to expand

Speculative decoding accelerates text generation by drafting candidate tokens and verifying them in parallel with the main model. llama_ros supports draft-model-based methods (draft-simple, draft-eagle3, draft-mtp) and self-speculative ngram-based methods (ngram-simple, ngram-map-k, ngram-map-k4v, ngram-mod, ngram-cache) that require no separate model. Note that speculative decoding requires context.n_parallel: 1.

/**:
  ros__parameters:
    model:
      repo: lmstudio-community/Meta-Llama-3.1-8B-Instruct-GGUF
      filename: Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 2048
      n_predict: 2048
      n_parallel: 1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      system_prompt_type: Llama-3
    speculative:
      type: draft-simple
      draft:
        n_max: 16
        n_min: 0
        p_min: 0.75
        n_gpu_layers: -1
        model:
          repo: lmstudio-community/Llama-3.2-1B-Instruct-GGUF
          filename: Llama-3.2-1B-Instruct-Q4_K_M.gguf
ros2 launch llama_bringup llama-3-speculative.launch.py

llava_ros (Python Launch)

Click to expand
from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():

    return LaunchDescription([
        Node(
            package="llama_ros",
            executable="llava_node",
            name="llava_node",
            namespace="llama",
            parameters=[{
                "context.n_ctx": 8192,
                "context.n_batch": 512,
                "gpu.n_gpu_layers": 33,
                "cpu.n_threads": 1,
                "context.n_predict": 8192,
                "model.repo": "cjpais/llava-1.6-mistral-7b-gguf",
                "model.filename": "llava-v1.6-mistral-7b.Q4_K_M.gguf",
                "mmproj.repo": "cjpais/llava-1.6-mistral-7b-gguf",
                "mmproj.filename": "mmproj-model-f16.gguf",
                "prompt.system_prompt_type": "Mistral",
            }],
        )
    ])
ros2 launch llama_bringup llava.launch.py

llava_ros (YAML Config)

Click to expand
/**:
  ros__parameters:
    model:
      repo: "cjpais/llava-1.6-mistral-7b-gguf"
      filename: "llava-v1.6-mistral-7b.Q4_K_M.gguf"
    mmproj:
      repo: "cjpais/llava-1.6-mistral-7b-gguf"
      filename: "mmproj-model-f16.gguf"
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: 33
    cpu:
      n_threads: 1
    prompt:
      system_prompt_type: "Mistral"
import os
from launch import LaunchDescription
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory


def generate_launch_description():
    return LaunchDescription([
        Node(
            package="llama_ros",
            executable="llava_node",
            name="llava_node",
            namespace="llama",
            parameters=[os.path.join(
                get_package_share_directory("llama_bringup"),
                "models", "llava-mistral.yaml")],
        )
    ])
ros2 launch llama_bringup llava.launch.py

llava_ros (Audio)

Click to expand
/**:
  ros__parameters:
    model:
      repo: "mradermacher/Qwen2-Audio-7B-Instruct-GGUF"
      filename: "Qwen2-Audio-7B-Instruct.Q4_K_M.gguf"
    mmproj:
      repo: "mradermacher/Qwen2-Audio-7B-Instruct-GGUF"
      filename: "Qwen2-Audio-7B-Instruct.mmproj-f16.gguf"
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: 29
    cpu:
      n_threads: -1
    prompt:
      system_prompt_type: "ChatML"
import os
from launch import LaunchDescription
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory


def generate_launch_description():
    return LaunchDescription([
        Node(
            package="llama_ros",
            executable="llava_node",
            name="llava_node",
            namespace="llama",
            parameters=[os.path.join(
                get_package_share_directory("llama_bringup"),
                "models", "Qwen2-Audio.yaml")],
        )
    ])
ros2 launch llama_bringup llava.launch.py

ROS 2 Parameters

The following tables list all the ROS 2 parameters available when launching llama_node or llava_node. Parameters are organized by namespace.

General

ParamTypeDefaultDescription
verbosityint323Log verbosity level
no_allocboolfalseDisable memory allocation for output tokens

Model (model.*)

ParamTypeDefaultDescription
model.pathstring""Local file path to the GGUF model
model.repostring""HuggingFace repository ID to download the model from
model.filenamestring""Filename of the model in the HuggingFace repository
model.warmupbooltrueRun a warmup inference on load
model.check_tensorsboolfalseValidate model tensor data on load

Multimodal Projector (mmproj.*)

ParamTypeDefaultDescription
mmproj.pathstring""Local file path to the multimodal projector
mmproj.repostring""HuggingFace repository ID to download the projector from
mmproj.filenamestring""Filename of the projector in the HuggingFace repository
mmproj.use_gpubooltrueUse GPU for the multimodal projector
mmproj.devicestring""Device for the projector (none disables GPU, "" follows gpu.devices)
mmproj.disabledboolfalseDisable loading the multimodal projector

Context / Inference (context.*)

ParamTypeDefaultDescription
context.seedint32-1RNG seed for sampling (-1 for default)
context.n_ctxint320Context size in tokens (0 for model default)
context.n_batchint322048Logical batch size for prompt processing
context.n_ubatchint32512Physical batch size
context.n_keepint320Number of tokens to keep from the initial prompt on context shift
context.n_chunksint32-1Max number of chunks to process (-1 for unlimited)
context.n_predictint32-1Max tokens to predict (-1 for unlimited when using ctx_shift)
context.n_parallelint321Number of parallel sequences to decode
context.n_outputs_maxint320Maximum number of outputs per slot (0 for unlimited)
context.numastring"none"NUMA strategy: none, distribute, isolate, numactl, mirror, or count
context.pooling_typestring""Pooling type: none, mean, cls, last, or rerank
context.attention_typestring""Attention type: causal or non_causal
context.embeddingboolfalseEnable embedding mode
context.rerankingboolfalseEnable reranking mode (sets pooling to rerank and enables embedding)
context.ctx_shiftboolfalseEnable context shifting
context.swa_fullboolfalseEnable full sliding window attention
context.cont_batchingbooltrueEnable continuous batching
context.use_jinjabooltrueUse Jinja2 templating engine for chat templates (required for tool calls and reasoning)
context.prefill_assistantbooltruePrefill any trailing assistant message into the response
context.force_pure_content_parserboolfalseBypass Jinja template tool-call/reasoning parsing and force raw content output for all requests. Useful as a fallback when the template parser produces incorrect results
context.enable_reasoningint32-1Server-level reasoning control: -1 = auto (follow template), 0 = disable thinking, 1 = enable thinking
context.reasoning_formatstring"deepseek"How reasoning content is returned in API responses: none, auto, deepseek_legacy, or deepseek

GPU / Backend (gpu.*)

ParamTypeDefaultDescription
gpu.n_gpu_layersint32-1Number of layers to offload to GPU (-1 for all)
gpu.main_gpuint320Main GPU index
gpu.split_modestring"layer"GPU split mode: none, layer, or row
gpu.flash_attn_typestring"auto"Flash attention type: auto, enabled, or disabled
gpu.tensor_splitdouble[][0.0]Tensor split proportions across GPUs
gpu.devicesstring[][]GPU device names to use
gpu.fit_params_targetint64[][1073741824]Per-device memory target in bytes for automatic VRAM fitting (one per device)
gpu.no_kv_offloadboolfalseDisable KV cache offloading to GPU
gpu.no_op_offloadboolfalseDisable operation offloading
gpu.no_hostboolfalseDisable host buffer usage
gpu.no_extra_buftsboolfalseDisable extra buffer types

Model Overrides

ParamTypeDefaultDescription
kv_overridesstring[][]Override GGUF model metadata key-value pairs. Format: "key=int:123", "key=float:3.14", "key=bool:true", or "key=str:value"
tensor_buft_overridesstring[][]Override tensor buffer types by regex pattern. Format: "pattern=CPU" (buft name from available backends)

Control Vector (control_vector.*)

ParamTypeDefaultDescription
control_vector.layer_startint32-1Start layer for control vector application
control_vector.layer_endint32-1End layer for control vector application
control_vectorsstring[][]Control vector files with optional strength. Format: "path/to/cvector.gguf" or "path@0.5"

Multimodal (multimodal.*)

ParamTypeDefaultDescription
multimodal.image_min_tokensint32-1Minimum number of tokens per image (-1 for auto)
multimodal.image_max_tokensint32-1Maximum number of tokens per image (-1 for auto)
multimodal.mtmd_batch_max_tokensint321024Maximum batch tokens for multimodal data

Memory (memory.*)

ParamTypeDefaultDescription
memory.load_modestring"auto"Mode to load the model (auto, none, mmap, mlock, direct_io)
memory.lazy_modestring"auto"On-demand tensor reading (off, auto, on) (requires mmap)
memory.kv_unifiedboolfalseUse unified KV cache
memory.cache_idle_slotsbooltrueSave and clear idle KV cache slots when a new task starts

CPU (cpu.*)

ParamTypeDefaultDescription
cpu.n_threadsint32-1Number of threads for generation (-1 for auto-detect)
cpu.pollint3250Thread pool polling interval
cpu.maskstring""CPU affinity mask for generation threads
cpu.rangestring""CPU range for generation threads
cpu.prioritystring"normal"Thread scheduling priority: low, normal, medium, high, or realtime
cpu.strictboolfalseStrict CPU affinity for generation threads

CPU Batch (cpu_batch.*)

ParamTypeDefaultDescription
cpu_batch.n_threadsint32-1Number of threads for batch processing (-1 for auto-detect)
cpu_batch.pollint3250Thread pool polling interval for batch processing
cpu_batch.maskstring""CPU affinity mask for batch processing threads
cpu_batch.rangestring""CPU range for batch processing threads
cpu_batch.prioritystring"normal"Thread scheduling priority for batch processing
cpu_batch.strictboolfalseStrict CPU affinity for batch processing threads

RoPE (rope.*)

ParamTypeDefaultDescription
rope.freq_basefloat0.0RoPE base frequency (0.0 for model default)
rope.freq_scalefloat0.0RoPE frequency scale factor (0.0 for model default)
rope.scaling_typestring""RoPE scaling type: none, linear, yarn, or longrope

YaRN (yarn.*)

ParamTypeDefaultDescription
yarn.ext_factorfloat-1.0YaRN extrapolation mix factor (-1.0 for model default)
yarn.attn_factorfloat-1.0YaRN attention magnitude scaling factor
yarn.beta_fastfloat-1.0YaRN low correction dimension
yarn.beta_slowfloat-1.0YaRN high correction dimension
yarn.orig_ctxint320YaRN original context size

Group Attention (grp_attn.*)

ParamTypeDefaultDescription
grp_attn.nint321Self-extend group attention factor (1 for disabled)
grp_attn.wint32512Self-extend group attention width

KV Cache (cache.*)

ParamTypeDefaultDescription
cache.type_kstring"f16"Data type for K cache: f32, f16, bf16, q8_0, q4_0, q4_1, iq4_nl, q5_0, or q5_1
cache.type_vstring"f16"Data type for V cache (same options as cache.type_k)
cache.cache_promptbooltrueEnable prompt caching (reuse previously evaluated KV state)
cache.cache_ram_mibint328192RAM limit for the prompt cache in MiB (-1 = no limit, 0 = disable cache)
cache.n_cache_reuseint320Minimum chunk size in tokens to reuse from the KV cache via shifting (0 = disabled)
cache.n_ctx_checkpointsint3232Maximum number of context checkpoints per slot (0 = disabled)
cache.checkpoint_min_stepint32256Minimum spacing between context checkpoints

Fit Parameters (fit.*)

ParamTypeDefaultDescription
fit.enabledbooltrueAutomatically fit model parameters to available memory
fit.min_ctxint324096Minimum context size when fitting parameters

Speculative Decoding (speculative.*)

Speculative decoding uses draft tokens to accelerate generation, then verifies them in parallel with the main model. llama_ros supports both draft-model-based and self-speculative (ngram-based) approaches.

Note: Speculative decoding requires context.n_parallel: 1 (single slot) and is not supported with embedding/reranking models.

ParamTypeDefaultDescription
speculative.typestring"none"Speculative decoding type: none, draft-simple, draft-eagle3, draft-mtp, ngram-simple, ngram-map-k, ngram-map-k4v, ngram-mod, or ngram-cache
Draft Model (speculative.draft.*)

Used with draft-model-based types (draft-simple, draft-eagle3, draft-mtp).

ParamTypeDefaultDescription
speculative.draft.n_maxint3216Maximum number of tokens to draft per speculative step
speculative.draft.n_minint320Minimum number of draft tokens required to attempt verification. If the draft model produces fewer tokens than this, the draft is discarded and a single token is generated instead. 0 is recommended
speculative.draft.p_mindouble0.75Minimum probability threshold for draft tokens (greedy)
speculative.draft.p_splitdouble0.1Split probability threshold for speculative sampling
speculative.draft.n_gpu_layersint32-1Number of layers to offload to GPU for the draft model (-1 for all)
speculative.draft.cache_type_kstring"f16"KV cache type for K in the draft model (e.g. f16, q8_0, q4_0)
speculative.draft.cache_type_vstring"f16"KV cache type for V in the draft model (e.g. f16, q8_0, q4_0)
speculative.draft.model.pathstring""Local file path to the draft model GGUF file
speculative.draft.model.repostring""HuggingFace repository ID for the draft model
speculative.draft.model.filenamestring""Filename of the draft model in the HuggingFace repository
speculative.draft.backend_samplingbooltrueWhether to offload draft sampling to the backend
Ngram-mod (speculative.ngram_mod.*)

Used with speculative.type: ngram-mod. A hash-based self-speculative method that learns n-gram patterns from the prompt without a separate model.

ParamTypeDefaultDescription
speculative.ngram_mod.n_matchint3224N-gram size for lookup (minimum 16 recommended)
speculative.ngram_mod.n_maxint3264Maximum number of tokens to draft per step
speculative.ngram_mod.n_minint3248Minimum draft length required to attempt verification
Ngram-simple (speculative.ngram_simple.*)

Used with speculative.type: ngram-simple. A lightweight self-speculative method based on n-gram lookup with no draft model required.

ParamTypeDefaultDescription
speculative.ngram_simple.size_nint3212N-gram size for lookup
speculative.ngram_simple.size_mint3248M-gram size for speculative tokens
speculative.ngram_simple.min_hitsint321Minimum hits at n-gram lookup for m-gram to be proposed
Ngram-map-k (speculative.ngram_map_k.*)

Used with speculative.type: ngram-map-k. Self-speculative decoding with n-gram keys only.

ParamTypeDefaultDescription
speculative.ngram_map_k.size_nint3212N-gram size for lookup
speculative.ngram_map_k.size_mint3248M-gram size for speculative tokens
speculative.ngram_map_k.min_hitsint321Minimum hits at n-gram lookup for m-gram to be proposed
Ngram-map-k4v (speculative.ngram_map_k4v.*)

Used with speculative.type: ngram-map-k4v. Self-speculative decoding with n-gram keys and 4 m-gram values; higher acceptance rate than ngram-map-k at higher cost.

ParamTypeDefaultDescription
speculative.ngram_map_k4v.size_nint3212N-gram size for lookup
speculative.ngram_map_k4v.size_mint3248M-gram size for speculative tokens
speculative.ngram_map_k4v.min_hitsint321Minimum hits at n-gram lookup for m-gram to be proposed
Ngram-cache (speculative.ngram_cache.*)

Used with speculative.type: ngram-cache. Self-speculative decoding with a 3-level n-gram cache; optionally load pre-built static and dynamic caches from disk.

ParamTypeDefaultDescription
speculative.ngram_cache.lookup_cache_staticstring""Path to a pre-built static n-gram lookup cache
speculative.ngram_cache.lookup_cache_dynamicstring""Path to a dynamic n-gram lookup cache file

Prompt & Chat (prompt.*)

ParamTypeDefaultDescription
prompt.prefixstring""Text prepended to every user prompt
prompt.suffixstring""Text appended to every user prompt
prompt.system_promptstring""Initial system prompt
prompt.system_prompt_filestring""Path to a file containing the system prompt
prompt.system_prompt_typestring""System prompt type (loads from a predefined YAML in llama_ros/prompts/)
prompt.chat_template_filestring""Path to a Jinja chat template file
prompt.stopping_wordsstring[][]List of words/tokens that stop generation

LoRA Adapters (lora.*)

ParamTypeDefaultDescription
lora.adaptersstring[][]List of LoRA adapter names to load
lora.init_without_applyboolfalseLoad LoRA adapters without applying them
lora.<lora_name>.repostring""HuggingFace repository for the LoRA adapter
lora.<lora_name>.filenamestring""Filename of the LoRA adapter in the repository
lora.<lora_name>.file_pathstring""Local file path to the LoRA adapter
lora.<lora_name>.scaledouble1.0LoRA adapter scale factor (clamped to [0.0, 1.0])

Messages

SamplingConfig (llama_msgs/msg/SamplingConfig)

The SamplingConfig message is used in GenerateResponse and GenerateChatCompletions goals to configure sampling behaviour per request.

FieldTypeDefaultDescription
seeduint324294967295 (LLAMA_DEFAULT_SEED)RNG seed (4294967295 = random)
n_prevint3264Number of previous tokens to consider for repetition penalties
n_probsint320Return top-N token probabilities (0 = disabled)
min_keepint320Minimum number of tokens to keep after sampling (0 = disabled)
ignore_eosboolfalseIgnore end-of-stream tokens and continue generating
no_perfboolfalseDisable performance metrics collection
timing_per_tokenboolfalseCollect per-token timing data
logit_biasLogitBiasArray[]Logit biases for specific tokens
logit_bias_eogLogitBiasArray[]Pre-calculated logit biases for end-of-generation tokens
tempfloat320.80Sampling temperature
dynatemp_rangefloat320.0Dynamic temperature range (0.0 = disabled)
dynatemp_exponentfloat321.0Dynamic temperature exponent
top_kint3240Top-K sampling (0 = disabled)
top_pfloat320.95Top-P (nucleus) sampling (1.0 = disabled)
min_pfloat320.05Min-P sampling (0.0 = disabled)
top_n_sigmafloat32-1.0Top-N-sigma sampling (-1.0 = disabled)
xtc_probabilityfloat320.0XTC sampling probability (0.0 = disabled)
xtc_thresholdfloat320.1XTC sampling threshold (values > 0.5 disable XTC)
typical_pfloat321.0Locally typical sampling (1.0 = disabled)
penalty_last_nint3264Number of last tokens to consider for penalties (0 = disable, -1 = context size)
penalty_repeatfloat321.0Repetition penalty (1.0 = disabled)
penalty_freqfloat320.0Frequency penalty (0.0 = disabled)
penalty_presentfloat320.0Presence penalty (0.0 = disabled)
dry_multiplierfloat320.0DRY repetition penalty multiplier (0.0 = disabled)
dry_basefloat321.75DRY repetition penalty base
dry_allowed_lengthint322Tokens extending repetitions beyond this length receive DRY penalty
dry_penalty_last_nint3264Tokens to scan for DRY repetitions (0 = disable, -1 = context size)
dry_sequence_breakersstring[]["\n", ":", "\"", "*"]Sequence breakers for DRY
adaptive_targetfloat32-1.0Adaptive-P target probability (negative = disabled)
adaptive_decayfloat320.90Adaptive-P EMA decay
mirostatint320Mirostat mode (0 = disabled, 1 = Mirostat v1, 2 = Mirostat v2)
mirostat_etafloat320.10Mirostat learning rate
mirostat_taufloat325.0Mirostat target entropy
samplers_sequencestring"edskypmxt"Sampler pipeline order (chars map to: e=penalties, d=DRY, s=top-N-sigma, k=top-K, y=typical-P, p=top-P, m=min-P, x=XTC, t=temp)
grammarstring""GBNF grammar string to constrain sampling
grammar_schemastring""JSON schema converted to a GBNF grammar
grammar_lazyboolfalseUse lazy grammar evaluation (grammar only activates after a trigger)
grammar_triggersGrammarTrigger[][]Trigger conditions for lazy grammar activation
preserved_tokensint32[][]Token IDs that should never be penalised or modified
backend_samplingboolfalseUse hardware-accelerated (backend) sampling if available
reasoning_budgetint32-1Token budget for reasoning (-1 = disabled, ≥ 0 = max thinking tokens)
reasoning_budget_startint32[][]Token IDs for the thinking start tag. Auto-populated from the chat template if empty
reasoning_budget_endint32[][]Token IDs for the thinking end tag. Auto-populated from the chat template if empty
reasoning_budget_forcedint32[][]Token sequence forcibly injected when the budget is exhausted (message + end tag). Auto-populated if empty. Distinct from force_pure_content_parser: this controls when to stop thinking, not how the template is parsed
reasoning_budget_messagestring""Text inserted before the thinking end tag when the reasoning budget is exhausted (e.g. "Wait, I need to conclude.")
reasoning_controlboolfalseCreate the budget sampler on demand so reasoning can be ended at runtime

GenerateChatCompletions Goal (llama_msgs/action/GenerateChatCompletions)

FieldTypeDefaultDescription
messagesChatMessage[][]Conversation history as a list of chat messages
add_generation_promptboolfalseAppend the generation prompt token sequence after the last message
use_jinjaboolfalseUse Jinja2 chat template (required for tool calls and reasoning)
toolsChatReqTool[][]List of tools the model may call
tool_choiceint320Tool selection mode: 0 = auto, 1 = required (must call a tool), 2 = none
extract_reasoningboolfalseExtract <think> reasoning content from the response into reasoning_content
sampling_configSamplingConfig—Per-request sampling configuration (see SamplingConfig table above)
reasoning_formatChatReasoningFormat3How reasoning content is returned: 0=none, 1=auto, 2=deepseek_legacy, 3=deepseek
imagessensor_msgs/Image[][]Images for VLM inference
audiosstd_msgs/UInt8MultiArray[][]Audio buffers for multimodal inference
parallel_tool_callsboolfalseAllow the model to return multiple tool calls in a single message
streamboolfalseStream partial results as feedback messages
force_pure_content_parserboolfalsePer-request override of context.force_pure_content_parser — bypasses template tool-call/reasoning parsing

LoRA Adapters

You can use LoRA adapters when launching LLMs. Using llama.cpp features, you can load multiple adapters choosing the scale to apply for each adapter. Here you have an example of using LoRA adapters with Phi-3. You can list the LoRAs using the /llama/list_loras service and modify their scales values by using the /llama/update_loras service. A scale value of 0.0 means not using that LoRA.

Click to expand
/**:
  ros__parameters:
    model:
      repo: bartowski/Phi-3.5-mini-instruct-GGUF
      filename: Phi-3.5-mini-instruct-Q4_K_M.gguf
    context:
      n_ctx: 2048
      n_batch: 8
      n_predict: 2048
    gpu:
      n_gpu_layers: 0
    cpu:
      n_threads: 1
    prompt:
      system_prompt_type: Phi-3
    lora:
      adapters:
        - code_writer
        - summarization
      code_writer:
        repo: zhhan/adapter-Phi-3-mini-4k-instruct_code_writing
        filename: Phi-3-mini-4k-instruct-adaptor-f16-code_writer.gguf
        scale: 0.5
      summarization:
        repo: zhhan/adapter-Phi-3-mini-4k-instruct_summarization
        filename: Phi-3-mini-4k-instruct-adaptor-f16-summarization.gguf
        scale: 0.5

ROS 2 Clients

Both llama_ros and llava_ros provide ROS 2 interfaces to access the main functionalities of the models. Here you have some examples of how to use them inside ROS 2 nodes. Moreover, take a look to the llama_demo_node.py and llava_demo_node.py demos.

Tokenize

Click to expand
from rclpy.node import Node
from llama_msgs.srv import Tokenize


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create the client
        self.srv_client = self.create_client(Tokenize, "/llama/tokenize")

        # create the request
        req = Tokenize.Request()
        req.text = "Example text"

        # call the tokenize service
        self.srv_client.wait_for_service()
        tokens = self.srv_client.call(req).tokens

Detokenize

Click to expand
from rclpy.node import Node
from llama_msgs.srv import Detokenize


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create the client
        self.srv_client = self.create_client(Detokenize, "/llama/detokenize")

        # create the request
        req = Detokenize.Request()
        req.tokens = [123, 123]

        # call the tokenize service
        self.srv_client.wait_for_service()
        text = self.srv_client.call(req).text

Embeddings

Click to expand

Remember to launch llama_ros with embedding set to true to be able of generating embeddings with your LLM.

from rclpy.node import Node
from llama_msgs.srv import GenerateEmbeddings


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create the client
        self.srv_client = self.create_client(GenerateEmbeddings, "/llama/generate_embeddings")

        # create the request
        req = GenerateEmbeddings.Request()
        req.prompt = "Example text"
        req.normalization = 2  # -1=none, 0=max abs int16, 1=taxicab, 2=euclidean, >2=p-norm

        # call the embedding service
        self.srv_client.wait_for_service()
        embeddings = self.srv_client.call(req).embeddings

Generate Response

Click to expand
import rclpy
from rclpy.node import Node
from rclpy.action import ActionClient
from llama_msgs.action import GenerateResponse


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create the client
        self.action_client = ActionClient(
            self, GenerateResponse, "/llama/generate_response")

        # create the goal and set the sampling config
        goal = GenerateResponse.Goal()
        goal.prompt = self.prompt
        goal.sampling_config.temp = 0.2

        # wait for the server and send the goal
        self.action_client.wait_for_server()
        send_goal_future = self.action_client.send_goal_async(
            goal)

        # wait for the server
        rclpy.spin_until_future_complete(self, send_goal_future)
        get_result_future = send_goal_future.result().get_result_async()

        # wait again and take the result
        rclpy.spin_until_future_complete(self, get_result_future)
        result: GenerateResponse.Result = get_result_future.result().result

Generate Response (llava)

Click to expand
import cv2
from cv_bridge import CvBridge

import rclpy
from rclpy.node import Node
from rclpy.action import ActionClient
from llama_msgs.action import GenerateResponse


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create a cv bridge for the image
        self.cv_bridge = CvBridge()

        # create the client
        self.action_client = ActionClient(
            self, GenerateResponse, "/llama/generate_response")

        # create the goal and set the sampling config
        goal = GenerateResponse.Goal()
        goal.prompt = self.prompt
        goal.sampling_config.temp = 0.2

        # add your image to the goal
        image = cv2.imread("/path/to/your/image", cv2.IMREAD_COLOR)
        goal.images.append(self.cv_bridge.cv2_to_imgmsg(image))

        # wait for the server and send the goal
        self.action_client.wait_for_server()
        send_goal_future = self.action_client.send_goal_async(
            goal)

        # wait for the server
        rclpy.spin_until_future_complete(self, send_goal_future)
        get_result_future = send_goal_future.result().get_result_async()

        # wait again and take the result
        rclpy.spin_until_future_complete(self, get_result_future)
        result: GenerateResponse.Result = get_result_future.result().result

Generate Chat Completions

Click to expand

The GenerateChatCompletions action provides an OpenAI-compatible chat completions interface with support for tool calling, reasoning, and streaming.

import rclpy
from rclpy.node import Node
from rclpy.action import ActionClient
from llama_msgs.action import GenerateChatCompletions
from llama_msgs.msg import ChatMessage


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create the client
        self.action_client = ActionClient(
            self, GenerateChatCompletions, "/llama/generate_chat_completions")

        # create the goal
        goal = GenerateChatCompletions.Goal()
        goal.messages = [
            ChatMessage(role="system", content="You are a helpful assistant."),
            ChatMessage(role="user", content="What is ROS 2?")
        ]
        goal.sampling_config.temp = 0.2
        goal.stream = True

        # wait for the server and send the goal
        self.action_client.wait_for_server()
        send_goal_future = self.action_client.send_goal_async(goal)

        # wait for the server
        rclpy.spin_until_future_complete(self, send_goal_future)
        get_result_future = send_goal_future.result().get_result_async()

        # wait again and take the result
        rclpy.spin_until_future_complete(self, get_result_future)
        result = get_result_future.result().result

Get Metadata

Click to expand
from rclpy.node import Node
from llama_msgs.srv import GetMetadata


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create the client
        self.srv_client = self.create_client(GetMetadata, "/llama/get_metadata")

        # call the metadata service
        req = GetMetadata.Request()
        self.srv_client.wait_for_service()
        metadata = self.srv_client.call(req).metadata

Rerank Documents

Click to expand

Remember to launch llama_ros with reranking set to true.

from rclpy.node import Node
from llama_msgs.srv import RerankDocuments


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create the client
        self.srv_client = self.create_client(RerankDocuments, "/llama/rerank_documents")

        # create the request
        req = RerankDocuments.Request()
        req.query = "What is robotics?"
        req.documents = ["Robotics is a field of engineering.", "The weather is sunny."]

        # call the reranking service
        self.srv_client.wait_for_service()
        scores = self.srv_client.call(req).scores

LangChain

There is a llama_ros_langchain package, a llama_ros integration for LangChain. Thus, prompt engineering techniques could be applied. Here you have an example to use it.

llama_ros (Chain)

Click to expand
import rclpy
from llama_ros_langchain import LlamaROS
from langchain.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser


rclpy.init()

# create the llama_ros llm for langchain
llm = LlamaROS()

# create a prompt template
prompt_template = "tell me a joke about {topic}"
prompt = PromptTemplate(
    input_variables=["topic"],
    template=prompt_template
)

# create a chain with the llm and the prompt template
chain = prompt | llm | StrOutputParser()

# run the chain
text = chain.invoke({"topic": "bears"})
print(text)

rclpy.shutdown()

llama_ros (Stream)

Click to expand
import rclpy
from llama_ros_langchain import LlamaROS
from langchain.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser


rclpy.init()

# create the llama_ros llm for langchain
llm = LlamaROS()

# create a prompt template
prompt_template = "tell me a joke about {topic}"
prompt = PromptTemplate(
    input_variables=["topic"],
    template=prompt_template
)

# create a chain with the llm and the prompt template
chain = prompt | llm | StrOutputParser()

# run the chain
for c in chain.stream({"topic": "bears"}):
    print(c, flush=True, end="")

rclpy.shutdown()

llava_ros

Click to expand
import rclpy
from llama_ros_langchain import LlamaROS

rclpy.init()

# create the llama_ros llm for langchain
llm = LlamaROS()

# bind the url_image
image_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
llm = llm.bind(image_url=image_url).stream("Describe the image")

# run the llm
for c in llm:
    print(c, flush=True, end="")

rclpy.shutdown()

llama_ros_embeddings (RAG)

Click to expand
import rclpy
from langchain_chroma import Chroma
from llama_ros_langchain import LlamaROSEmbeddings


rclpy.init()

# create the llama_ros embeddings for langchain
embeddings = LlamaROSEmbeddings()

# create a vector database and assign it
db = Chroma(embedding_function=embeddings)

# create the retriever
retriever = db.as_retriever(search_kwargs={"k": 5})

# add your texts
db.add_texts(texts=["your_texts"])

# retrieve documents
documents = retriever.invoke("your_query")
print(documents)

rclpy.shutdown()

llama_ros (Reranker)

Click to expand
import rclpy
from llama_ros_langchain import LlamaROSReranker
from llama_ros_langchain import LlamaROSEmbeddings

from langchain_community.vectorstores import FAISS
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.retrievers import ContextualCompressionRetriever


rclpy.init()

# load the documents
documents = TextLoader("../state_of_the_union.txt",).load()
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500, chunk_overlap=100)
texts = text_splitter.split_documents(documents)

# create the llama_ros embeddings
embeddings = LlamaROSEmbeddings()

# create the VD and the retriever
retriever = FAISS.from_documents(
    texts, embeddings).as_retriever(search_kwargs={"k": 20})

# create the compressor using the llama_ros reranker
compressor = LlamaROSReranker()
compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor, base_retriever=retriever
)

# retrieve the documents
compressed_docs = compression_retriever.invoke(
    "What did the president say about Ketanji Jackson Brown"
)

for doc in compressed_docs:
    print("-" * 50)
    print(doc.page_content)
    print("\n")

rclpy.shutdown()

llama_ros (LLM + RAG + Reranker)

Click to expand
import bs4
import rclpy

from langchain_chroma import Chroma
from langchain_community.document_loaders import WebBaseLoader
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_core.messages import SystemMessage
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.retrievers import ContextualCompressionRetriever

from llama_ros_langchain import ChatLlamaROS, LlamaROSEmbeddings, LlamaROSReranker


rclpy.init()

# load, chunk and index the contents of the blog
loader = WebBaseLoader(
    web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",),
    bs_kwargs=dict(
        parse_only=bs4.SoupStrainer(class_=("post-content", "post-title", "post-header"))
    ),
)
docs = loader.load()

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(documents=splits, embedding=LlamaROSEmbeddings())

# retrieve and generate using the relevant snippets of the blog
retriever = vectorstore.as_retriever(search_kwargs={"k": 20})

# create prompt
prompt = ChatPromptTemplate.from_messages(
    [
        SystemMessage("You are an AI assistant that answer questions briefly."),
        HumanMessagePromptTemplate.from_template(
            "Taking into account the followin information:{context}\n\n{question}"
        ),
    ]
)

# create rerank compression retriever
compressor = LlamaROSReranker(top_n=3)
compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor, base_retriever=retriever
)


def format_docs(docs):
    formated_docs = ""

    for d in docs:
        formated_docs += f"\n\n\t- {d.page_content}"

    return formated_docs


# create and use the chain
rag_chain = (
    {"context": compression_retriever | format_docs, "question": RunnablePassthrough()}
    | prompt
    | ChatLlamaROS(temp=0.0)
    | StrOutputParser()
)

for c in rag_chain.stream("What is Task Decomposition?"):
    print(c, flush=True, end="")

rclpy.shutdown()

chat_llama_ros (Chat + VLM)

Click to expand
import rclpy
from llama_ros_langchain import ChatLlamaROS
from langchain_core.messages import SystemMessage
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from langchain_core.output_parsers import StrOutputParser


rclpy.init()

# create chat
chat = ChatLlamaROS(
    temp=0.2,
    penalty_last_n=8
)

# create prompt template with messages
prompt = ChatPromptTemplate.from_messages([
    SystemMessage("You are a IA that just answer with a single word."),
    HumanMessagePromptTemplate.from_template(template=[
        {"type": "text", "text": "<__media__>Who is the character in the middle of the image?"},
        {"type": "image_url", "image_url": "{image_url}"}
    ])
])

# create the chain
chain = prompt | chat | StrOutputParser()

# stream and print the LLM output
for text in chain.stream({"image_url": "https://pics.filmaffinity.com/Dragon_Ball_Bola_de_Dragaon_Serie_de_TV-973171538-large.jpg"}):
    print(text, end="", flush=True)

print("", end="\n", flush=True)

rclpy.shutdown()

chat_llama_ros (Chat + Audio)

Click to expand
import sys
import time
import rclpy
from langchain_core.messages import SystemMessage
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from langchain_core.output_parsers import StrOutputParser
from llama_ros_langchain import ChatLlamaROS


def main():
    if len(sys.argv) < 2:
        prompt = "What's that sound?"
    else:
        prompt = " ".join(sys.argv[1:])

    tokens = 0
    initial_time = -1
    eval_time = -1

    rclpy.init()
    chat = ChatLlamaROS(temp=0.0)

    prompt = ChatPromptTemplate.from_messages(
        [
            SystemMessage("You are an IA that answer questions."),
            HumanMessagePromptTemplate.from_template(
                template=[
                    {"type": "text", "text": f"<__media__>{prompt}"},
                    {"type": "image_url", "image_url": "{audio_url}"},
                ]
            ),
        ]
    )

    chain = prompt | chat | StrOutputParser()

    initial_time = time.time()
    for text in chain.stream(
        {
            "audio_url": "https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen2-Audio/audio/glass-breaking-151256.mp3"
        }
    ):
        tokens += 1
        print(text, end="", flush=True)
        if eval_time < 0:
            eval_time = time.time()

    print("", end="\n", flush=True)

    end_time = time.time()
    print(f"Time to eval: {eval_time - initial_time} s")
    print(f"Prediction speed: {tokens / (end_time - eval_time)} t/s")

    rclpy.shutdown()


if __name__ == "__main__":
    main()

chat_llama_ros (Structured output)

Click to expand
import rclpy
from typing import Optional

from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from llama_ros_langchain import ChatLlamaROS
from pydantic import BaseModel, Field

rclpy.init()

class Joke(BaseModel):
    """Joke to tell user."""

    setup: str = Field(description="The setup of the joke")
    punchline: str = Field(description="The punchline to the joke")
    rating: Optional[int] = Field(
        default=None, description="How funny the joke is, from 1 to 10"
    )

chat = ChatLlamaROS(temp=0.6, penalty_last_n=8)

structured_chat = chat.with_structured_output(
    Joke, method="function_calling"
)

prompt = ChatPromptTemplate.from_messages(
    [
        HumanMessagePromptTemplate.from_template(
            template=[
                {"type": "text", "text": "{prompt}"},
            ]
        ),
    ]
)

chain = prompt | structured_chat

res = chain.invoke({"prompt": "Tell me a joke about cats"})

print(f"Response: {res}")

rclpy.shutdown()

chat_llama_ros (Tools)

Click to expand

The current implementation of Tools allows executing tools without requiring a model trained for that task.

from random import randint

import rclpy

from langchain_core.tools import tool
from langchain_core.messages import HumanMessage
from llama_ros_langchain import ChatLlamaROS

rclpy.init()

@tool
def get_inhabitants(city: str) -> int:
    """Get the current temperature of a city"""
    return randint(4_000_000, 8_000_000)


@tool
def get_curr_temperature(city: str) -> int:
    """Get the current temperature of a city"""
    return randint(20, 30)

chat = ChatLlamaROS(temp=0.6, penalty_last_n=8)

messages = [
    HumanMessage(
        "What is the current temperature in Madrid? And its inhabitants?"
    )
]

llm_tools = chat.bind_tools(
    [get_inhabitants, get_curr_temperature], tool_choice='any'
)

all_tools_res = llm_tools.invoke(messages)
messages.append(all_tools_res)

for tool in all_tools_res.tool_calls:
    selected_tool = {
        "get_inhabitants": get_inhabitants, "get_curr_temperature": get_curr_temperature
    }[tool['name']]

    tool_msg = selected_tool.invoke(tool)

    formatted_output = f"{tool['name']}({''.join(tool['args'].values())}) = {tool_msg.content}"

    tool_msg.additional_kwargs = {'args': tool['args']}
    messages.append(tool_msg)

res = llm_tools.invoke(messages)

print(f"Response: {res.content}")

rclpy.shutdown()

chat_llama_ros (Reasoning)

Click to expand

A reasoning model is required, such as Deepseek R1

import time
from random import randint

import rclpy

from langchain_core.messages import HumanMessage
from llama_ros_langchain import ChatLlamaROS

rclpy.init()

chat = ChatLlamaROS(temp=0.6, penalty_last_n=8)

messages = [
    HumanMessage(
        "Here we have a book, a laptop, 9 eggs and a nail. Please tell me how to stack them onto each other in a stable manner."
    )
]

res = chat.invoke(messages)

print(f"Response: {res.content.strip()}")
print(f"Reasoning: {res.additional_kwargs["reasoning_content"]}")

rclpy.shutdown()

chat_llama_ros (Agent)

Click to expand
import time
from random import randint

import rclpy

from langchain_core.tools import tool
from langchain_core.messages import HumanMessage
from langchain.agents import create_agent
from llama_ros_langchain import ChatLlamaROS

rclpy.init()

@tool
def get_inhabitants(city: str) -> int:
    """Get the current temperature of a city"""
    return randint(4_000_000, 8_000_000)


@tool
def get_curr_temperature(city: str) -> int:
    """Get the current temperature of a city"""
    return randint(20, 30)

chat = ChatLlamaROS(temp=0.0)

agent_executor = create_agent(
    chat, [get_inhabitants, get_curr_temperature]
)

response = agent_executor.invoke(
    {
        "messages": [
            HumanMessage(
                content="What is the current temperature in Madrid? And its inhabitants?"
            )
        ]
    }
)

print(f"Response: {response['messages'][-1].content}")

rclpy.shutdown()

Demos

LLM Demo

ros2 launch llama_bringup spaetzle.launch.py
ros2 run llama_demos llama_demo_node

https://github.com/mgonzs13/llama_ros/assets/25979134/9311761b-d900-4e58-b9f8-11c8efefdac4

Speculative Decoding Demo

ros2 launch llama_bringup llama-3-speculative.launch.py
ros2 run llama_demos llama_demo_node

MTP Speculative Decoding Demo

ros2 launch llama_bringup Qwen3.5-MTP.launch.py
ros2 run llama_demos chatllama_demo_node

Embeddings Generation Demo

ros2 llama launch ~/ros2_ws/src/llama_ros/llama_bringup/models/bge-base-en-v1.5.yaml
ros2 run llama_demos llama_embeddings_demo_node

https://github.com/user-attachments/assets/7d722017-27dc-417c-ace7-bf6b747e4ced

Reranking Demo

ros2 llama launch ~/ros2_ws/src/llama_ros/llama_bringup/models/jina-reranker.yaml
ros2 run llama_demos llama_rerank_demo_node

https://github.com/user-attachments/assets/4b4adb4d-7c70-43ea-a2c1-9be57d211484

RAG Demo (LLM + chat template + RAG + Reranking + Stream)

ros2 llama launch ~/ros2_ws/src/llama_ros/llama_bringup/models/bge-base-en-v1.5.yaml
ros2 llama launch ~/ros2_ws/src/llama_ros/llama_bringup/models/jina-reranker.yaml
ros2 llama launch Qwen3.yaml
Click to expand Qwen3.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/Qwen_Qwen3-8B-GGUF
      filename: Qwen_Qwen3-8B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      stopping_words: ["<|im_end|>"]
ros2 run llama_demos llama_rag_demo_node

https://github.com/user-attachments/assets/b4e3957d-1f92-427b-a1a8-cfc76737c0d6

Chat Template Demo

ros2 llama launch MiniCPM-2.6.yaml
Click to expand MiniCPM-2.6.yaml
/**:
  ros__parameters:
    model:
      repo: "openbmb/MiniCPM-V-2_6-gguf"
      filename: "ggml-model-Q4_K_M.gguf"
    mmproj:
      repo: "openbmb/MiniCPM-V-2_6-gguf"
      filename: "mmproj-model-f16.gguf"
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: 20
    cpu:
      n_threads: -1
ros2 run llama_demos chatllama_image_demo_node

ChatLlamaROS demo

VLM Demo

ros2 launch llama_bringup minicpm-2.6.launch.py
ros2 run llama_demos llava_demo_node

https://github.com/mgonzs13/llama_ros/assets/25979134/4a9ef92f-9099-41b4-8350-765336e3503c

Chat Multi-Image Demo

ros2 llama launch MiniCPM-2.6.yaml
Click to expand MiniCPM-2.6.yaml
/**:
  ros__parameters:
    model:
      repo: "openbmb/MiniCPM-V-2_6-gguf"
      filename: "ggml-model-Q4_K_M.gguf"
    mmproj:
      repo: "openbmb/MiniCPM-V-2_6-gguf"
      filename: "mmproj-model-f16.gguf"
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: 20
    cpu:
      n_threads: -1
ros2 run llama_demos chatllama_multi_image_demo_node

Chat Multi-Image (User Input) Demo

ros2 llama launch MiniCPM-2.6.yaml
Click to expand MiniCPM-2.6.yaml
/**:
  ros__parameters:
    model:
      repo: "openbmb/MiniCPM-V-2_6-gguf"
      filename: "ggml-model-Q4_K_M.gguf"
    mmproj:
      repo: "openbmb/MiniCPM-V-2_6-gguf"
      filename: "mmproj-model-f16.gguf"
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: 20
    cpu:
      n_threads: -1
ros2 run llama_demos chatllama_multi_image_user_demo_node

MTMD Audio Demo

ros2 llama launch Qwen2-Audio.yaml
Click to expand Qwen2-Audio.yaml
/**:
  ros__parameters:
    model:
      repo: mradermacher/Qwen2-Audio-7B-Instruct-GGUF
      filename: Qwen2-Audio-7B-Instruct.Q4_K_M.gguf
    mmproj:
      repo: mradermacher/Qwen2-Audio-7B-Instruct-GGUF
      filename: Qwen2-Audio-7B-Instruct.mmproj-f16.gguf
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      system_prompt_type: ChatML
ros2 run llama_demos mtmd_audio_demo_node

Chat Audio Demo

ros2 llama launch Qwen2-Audio.yaml
Click to expand Qwen2-Audio.yaml
/**:
  ros__parameters:
    model:
      repo: mradermacher/Qwen2-Audio-7B-Instruct-GGUF
      filename: Qwen2-Audio-7B-Instruct.Q4_K_M.gguf
    mmproj:
      repo: mradermacher/Qwen2-Audio-7B-Instruct-GGUF
      filename: Qwen2-Audio-7B-Instruct.mmproj-f16.gguf
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
ros2 run llama_demos chatllama_audio_demo_node

Chat Multi-Audio Demo

ros2 llama launch Qwen2-Audio.yaml
Click to expand Qwen2-Audio.yaml
/**:
  ros__parameters:
    model:
      repo: mradermacher/Qwen2-Audio-7B-Instruct-GGUF
      filename: Qwen2-Audio-7B-Instruct.Q4_K_M.gguf
    mmproj:
      repo: mradermacher/Qwen2-Audio-7B-Instruct-GGUF
      filename: Qwen2-Audio-7B-Instruct.mmproj-f16.gguf
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
ros2 run llama_demos chatllama_multi_audio_demo_node

Chat Structured Output Demo

ros2 llama launch Qwen3.yaml
Click to expand Qwen3.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/Qwen_Qwen3-8B-GGUF
      filename: Qwen_Qwen3-8B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      stopping_words: ["<|im_end|>"]
ros2 run llama_demos chatllama_structured_demo_node

Structured Output ChatLlama

Chat Tools Demo

ros2 llama launch Qwen3.yaml
Click to expand Qwen3.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/Qwen_Qwen3-8B-GGUF
      filename: Qwen_Qwen3-8B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      stopping_words: ["<|im_end|>"]
ros2 run llama_demos chatllama_tools_demo_node

Tools ChatLlama

Streaming Tools Demo

ros2 llama launch Qwen3.yaml
Click to expand Qwen3.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/Qwen_Qwen3-8B-GGUF
      filename: Qwen_Qwen3-8B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      stopping_words: ["<|im_end|>"]
ros2 run llama_demos chatllama_streaming_tools_demo_node

Chat Reasoning Demo (DeepSeek-R1)

ros2 llama launch DeepSeek-R1.yaml
Click to expand DeepSeek-R1.yaml
/**:
  ros__parameters:
    model:
      repo: unsloth/DeepSeek-R1-Distill-Qwen-7B-GGUF
      filename: DeepSeek-R1-Distill-Qwen-7B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: 1
    prompt:
      chat_template_file: llama-cpp-deepseek-r1.jinja
ros2 run llama_demos chatllama_reasoning_demo_node

DeepSeekR1 ChatLlama

Reasoning + Tools Demo

ros2 llama launch Qwen3.yaml
Click to expand Qwen3.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/Qwen_Qwen3-8B-GGUF
      filename: Qwen_Qwen3-8B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      stopping_words: ["<|im_end|>"]
ros2 run llama_demos chatllama_reasoning_tools_demo_node

PDDL Demo

ros2 llama launch Qwen3.yaml
Click to expand Qwen3.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/Qwen_Qwen3-8B-GGUF
      filename: Qwen_Qwen3-8B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      stopping_words: ["<|im_end|>"]
ros2 run llama_demos chatllama_pddl_demo_node

Agent Demo

ros2 llama launch Qwen3.yaml
Click to expand Qwen3.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/Qwen_Qwen3-8B-GGUF
      filename: Qwen_Qwen3-8B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      stopping_words: ["<|im_end|>"]
ros2 run llama_demos chatllama_agent_demo_node

Agent ChatLlama

Parallel Slots Demo

This demo shows how to use multiple parallel slots (context.n_parallel) to process several requests concurrently via continuous batching. Launch the model with n_parallel: 4:

ros2 llama launch SmolLM2-slots.yaml
Click to expand SmolLM2-slots.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/SmolLM2-1.7B-Instruct-GGUF
      filename: SmolLM2-1.7B-Instruct-Q4_K_L.gguf
    context:
      n_ctx: 2048
      n_batch: 8
      n_predict: 2048
      n_parallel: 4
    gpu:
      n_gpu_layers: 0
    cpu:
      n_threads: -1
    prompt:
      system_prompt_type: ChatML
ros2 run llama_demos llama_slots_demo_node
audio
cpp
embeddings
ggml
gguf
gpt
langchain
llama
llamacpp
llava
llavacpp
llm
multimodal
rerank
reranking
ros2
vlm

Contributors

mgonzs13

990 commits

agonzc34

14 commits

Alvvalencia

1 commits

b0rh

1 commits

mgonzs13/llama_ros

llama.cpp (GGUF LLMs) and llava.cpp (GGUF VLMs) for ROS 2

C++

264

1,010 commits

updated Sep 24, 2026

See the code

README

llama_ros

This repository provides a set of ROS 2 packages to integrate llama.cpp into ROS 2. Using the llama_ros packages, you can easily incorporate the powerful optimization capabilities of llama.cpp into your ROS 2 projects by running GGUF-based LLMs and VLMs. You can also use features from llama.cpp such as GBNF grammars and modify LoRAs in real-time.

License: MIT GitHub release Code Size Last Commit GitHub issues GitHub pull requests Contributors Python Formatter Check C++ Formatter Check Doxygen Deployment

ROS 2 DistroBranchBuild statusDocker Image
HumblemainHumble BuildDocker Image
IronmainIron BuildDocker Image
JazzymainJazzy BuildDocker Image
KiltedmainKilted BuildDocker Image
LyricalmainLyrical BuildDocker Image

Table of Contents

  1. Related Projects
  2. Installation
  3. Docker
  4. Usage
  5. Demos
  • chatbot_ros → This chatbot, integrated into ROS 2, uses whisper_ros, to listen to people speech; and llama_ros, to generate responses. The chatbot is controlled by a state machine created with YASMIN.
  • explainable_ros → A ROS 2 tool to explain the behavior of a robot. Using the integration of LangChain, logs are stored in a vector database. Then, RAG is applied to retrieve relevant logs for user questions answered with llama_ros.

Installation

To run llama_ros with CUDA, first, you must install the CUDA Toolkit. Then, you can compile llama_ros with --cmake-args -DGGML_CUDA=ON to enable CUDA support.

Then clone the repository and install the Python dependencies:

cd ~/ros2_ws/src
git clone https://github.com/mgonzs13/llama_ros.git
cd llama_ros
pip3 install --break-system-packages -r requirements.txt
cd ~/ros2_ws
rosdep install --from-paths src --ignore-src -r -y
colcon build --cmake-args -DGGML_CUDA=ON # add this for CUDA

To run the tests:

colcon test --executor sequential --packages-select llama_ros llama_bt
colcon test-result --verbose

Docker

Build the llama_ros docker or download an image from DockerHub. You can choose to build llama_ros with CUDA (USE_CUDA) and choose the CUDA version (CUDA_VERSION). Remember that you have to use DOCKER_BUILDKIT=0 to compile llama_ros with CUDA when building the image.

DOCKER_BUILDKIT=0 docker build -t llama_ros --build-arg USE_CUDA=1 --build-arg CUDA_VERSION=12-6 .

Run the docker container. If you want to use CUDA, you have to install the NVIDIA Container Toolkit and add --gpus all.

docker run -it --rm --gpus all llama_ros

Usage

llama_cli

Commands are included in llama_ros to speed up the test of GGUF-based LLMs within the ROS 2 ecosystem. This way, the following commands are integrating into the ROS 2 commands:

launch

Using this command launch a LLM from a YAML file. The configuration of the YAML is used to launch the LLM in the same way as using a regular launch file. Here is an example of how to use it:

ros2 llama launch ~/ros2_ws/src/llama_ros/llama_bringup/models/StableLM-Zephyr.yaml

prompt

Using this command send a prompt to a launched LLM. The command uses a string, which is the prompt and has the following arguments:

  • (-r, --reset): Whether to reset the LLM before prompting
  • (-t, --temp): The temperature value
  • (--image-url): Image url to sent to a VLM

Here is an example of how to use it:

ros2 llama prompt "Do you know ROS 2?" -t 0.0

Launch Files

First of all, you need to create a launch file to use llama_ros or llava_ros. This launch file will contain the main parameters to download the model from HuggingFace and configure it. Take a look at the following examples and the predefined launch files.

llama_ros (Python Launch)

Click to expand
from launch import LaunchDescription
from launch_ros.actions import Node


def generate_launch_description():

    return LaunchDescription([
        Node(
            package="llama_ros",
            executable="llama_node",
            name="llama_node",
            namespace="llama",
            parameters=[{
                "context.n_ctx": 2048,
                "context.n_batch": 8,
                "context.n_predict": 2048,
                "gpu.n_gpu_layers": 0,
                "cpu.n_threads": 1,
                "model.repo": "TheBloke/Marcoroni-7B-v3-GGUF",
                "model.filename": "marcoroni-7b-v3.Q4_K_M.gguf",
                "prompt.system_prompt_type": "Alpaca",
            }],
        )
    ])
ros2 launch llama_bringup marcoroni.launch.py

llama_ros (YAML Config)

Click to expand
/**:
  ros__parameters:
    model:
      repo: "cstr/Spaetzle-v60-7b-GGUF"
      filename: "Spaetzle-v60-7b-q4-k-m.gguf"
    context:
      n_ctx: 2048
      n_batch: 8
      n_predict: 2048
    gpu:
      n_gpu_layers: 0
    cpu:
      n_threads: 1
    prompt:
      system_prompt_type: "Alpaca"
import os
from launch import LaunchDescription
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory


def generate_launch_description():
    return LaunchDescription([
        Node(
            package="llama_ros",
            executable="llama_node",
            name="llama_node",
            namespace="llama",
            parameters=[os.path.join(
                get_package_share_directory("llama_bringup"),
                "models", "Spaetzle.yaml")],
        )
    ])
ros2 launch llama_bringup spaetzle.launch.py

llama_ros (YAML Config + model shards)

Click to expand
model:
  repo: "Qwen/Qwen2.5-Coder-7B-Instruct-GGUF" # Hugging Face repo
  filename: "qwen2.5-coder-7b-instruct-q4_k_m-00001-of-00002.gguf" # model shard file in repo

context:
  n_ctx: 2048 # context of the LLM in tokens
  n_batch: 8 # batch size in tokens
  n_predict: 2048 # max tokens, -1 == inf

gpu:
  n_gpu_layers: 0 # layers to load in GPU

cpu:
  n_threads: 1 # threads

prompt:
  system_prompt_type: "ChatML" # system prompt type
ros2 llama launch Qwen2.yaml

llama_ros (Speculative Decoding)

Click to expand

Speculative decoding accelerates text generation by drafting candidate tokens and verifying them in parallel with the main model. llama_ros supports draft-model-based methods (draft-simple, draft-eagle3, draft-mtp) and self-speculative ngram-based methods (ngram-simple, ngram-map-k, ngram-map-k4v, ngram-mod, ngram-cache) that require no separate model. Note that speculative decoding requires context.n_parallel: 1.

/**:
  ros__parameters:
    model:
      repo: lmstudio-community/Meta-Llama-3.1-8B-Instruct-GGUF
      filename: Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 2048
      n_predict: 2048
      n_parallel: 1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      system_prompt_type: Llama-3
    speculative:
      type: draft-simple
      draft:
        n_max: 16
        n_min: 0
        p_min: 0.75
        n_gpu_layers: -1
        model:
          repo: lmstudio-community/Llama-3.2-1B-Instruct-GGUF
          filename: Llama-3.2-1B-Instruct-Q4_K_M.gguf
ros2 launch llama_bringup llama-3-speculative.launch.py

llava_ros (Python Launch)

Click to expand
from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():

    return LaunchDescription([
        Node(
            package="llama_ros",
            executable="llava_node",
            name="llava_node",
            namespace="llama",
            parameters=[{
                "context.n_ctx": 8192,
                "context.n_batch": 512,
                "gpu.n_gpu_layers": 33,
                "cpu.n_threads": 1,
                "context.n_predict": 8192,
                "model.repo": "cjpais/llava-1.6-mistral-7b-gguf",
                "model.filename": "llava-v1.6-mistral-7b.Q4_K_M.gguf",
                "mmproj.repo": "cjpais/llava-1.6-mistral-7b-gguf",
                "mmproj.filename": "mmproj-model-f16.gguf",
                "prompt.system_prompt_type": "Mistral",
            }],
        )
    ])
ros2 launch llama_bringup llava.launch.py

llava_ros (YAML Config)

Click to expand
/**:
  ros__parameters:
    model:
      repo: "cjpais/llava-1.6-mistral-7b-gguf"
      filename: "llava-v1.6-mistral-7b.Q4_K_M.gguf"
    mmproj:
      repo: "cjpais/llava-1.6-mistral-7b-gguf"
      filename: "mmproj-model-f16.gguf"
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: 33
    cpu:
      n_threads: 1
    prompt:
      system_prompt_type: "Mistral"
import os
from launch import LaunchDescription
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory


def generate_launch_description():
    return LaunchDescription([
        Node(
            package="llama_ros",
            executable="llava_node",
            name="llava_node",
            namespace="llama",
            parameters=[os.path.join(
                get_package_share_directory("llama_bringup"),
                "models", "llava-mistral.yaml")],
        )
    ])
ros2 launch llama_bringup llava.launch.py

llava_ros (Audio)

Click to expand
/**:
  ros__parameters:
    model:
      repo: "mradermacher/Qwen2-Audio-7B-Instruct-GGUF"
      filename: "Qwen2-Audio-7B-Instruct.Q4_K_M.gguf"
    mmproj:
      repo: "mradermacher/Qwen2-Audio-7B-Instruct-GGUF"
      filename: "Qwen2-Audio-7B-Instruct.mmproj-f16.gguf"
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: 29
    cpu:
      n_threads: -1
    prompt:
      system_prompt_type: "ChatML"
import os
from launch import LaunchDescription
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory


def generate_launch_description():
    return LaunchDescription([
        Node(
            package="llama_ros",
            executable="llava_node",
            name="llava_node",
            namespace="llama",
            parameters=[os.path.join(
                get_package_share_directory("llama_bringup"),
                "models", "Qwen2-Audio.yaml")],
        )
    ])
ros2 launch llama_bringup llava.launch.py

ROS 2 Parameters

The following tables list all the ROS 2 parameters available when launching llama_node or llava_node. Parameters are organized by namespace.

General

ParamTypeDefaultDescription
verbosityint323Log verbosity level
no_allocboolfalseDisable memory allocation for output tokens

Model (model.*)

ParamTypeDefaultDescription
model.pathstring""Local file path to the GGUF model
model.repostring""HuggingFace repository ID to download the model from
model.filenamestring""Filename of the model in the HuggingFace repository
model.warmupbooltrueRun a warmup inference on load
model.check_tensorsboolfalseValidate model tensor data on load

Multimodal Projector (mmproj.*)

ParamTypeDefaultDescription
mmproj.pathstring""Local file path to the multimodal projector
mmproj.repostring""HuggingFace repository ID to download the projector from
mmproj.filenamestring""Filename of the projector in the HuggingFace repository
mmproj.use_gpubooltrueUse GPU for the multimodal projector
mmproj.devicestring""Device for the projector (none disables GPU, "" follows gpu.devices)
mmproj.disabledboolfalseDisable loading the multimodal projector

Context / Inference (context.*)

ParamTypeDefaultDescription
context.seedint32-1RNG seed for sampling (-1 for default)
context.n_ctxint320Context size in tokens (0 for model default)
context.n_batchint322048Logical batch size for prompt processing
context.n_ubatchint32512Physical batch size
context.n_keepint320Number of tokens to keep from the initial prompt on context shift
context.n_chunksint32-1Max number of chunks to process (-1 for unlimited)
context.n_predictint32-1Max tokens to predict (-1 for unlimited when using ctx_shift)
context.n_parallelint321Number of parallel sequences to decode
context.n_outputs_maxint320Maximum number of outputs per slot (0 for unlimited)
context.numastring"none"NUMA strategy: none, distribute, isolate, numactl, mirror, or count
context.pooling_typestring""Pooling type: none, mean, cls, last, or rerank
context.attention_typestring""Attention type: causal or non_causal
context.embeddingboolfalseEnable embedding mode
context.rerankingboolfalseEnable reranking mode (sets pooling to rerank and enables embedding)
context.ctx_shiftboolfalseEnable context shifting
context.swa_fullboolfalseEnable full sliding window attention
context.cont_batchingbooltrueEnable continuous batching
context.use_jinjabooltrueUse Jinja2 templating engine for chat templates (required for tool calls and reasoning)
context.prefill_assistantbooltruePrefill any trailing assistant message into the response
context.force_pure_content_parserboolfalseBypass Jinja template tool-call/reasoning parsing and force raw content output for all requests. Useful as a fallback when the template parser produces incorrect results
context.enable_reasoningint32-1Server-level reasoning control: -1 = auto (follow template), 0 = disable thinking, 1 = enable thinking
context.reasoning_formatstring"deepseek"How reasoning content is returned in API responses: none, auto, deepseek_legacy, or deepseek

GPU / Backend (gpu.*)

ParamTypeDefaultDescription
gpu.n_gpu_layersint32-1Number of layers to offload to GPU (-1 for all)
gpu.main_gpuint320Main GPU index
gpu.split_modestring"layer"GPU split mode: none, layer, or row
gpu.flash_attn_typestring"auto"Flash attention type: auto, enabled, or disabled
gpu.tensor_splitdouble[][0.0]Tensor split proportions across GPUs
gpu.devicesstring[][]GPU device names to use
gpu.fit_params_targetint64[][1073741824]Per-device memory target in bytes for automatic VRAM fitting (one per device)
gpu.no_kv_offloadboolfalseDisable KV cache offloading to GPU
gpu.no_op_offloadboolfalseDisable operation offloading
gpu.no_hostboolfalseDisable host buffer usage
gpu.no_extra_buftsboolfalseDisable extra buffer types

Model Overrides

ParamTypeDefaultDescription
kv_overridesstring[][]Override GGUF model metadata key-value pairs. Format: "key=int:123", "key=float:3.14", "key=bool:true", or "key=str:value"
tensor_buft_overridesstring[][]Override tensor buffer types by regex pattern. Format: "pattern=CPU" (buft name from available backends)

Control Vector (control_vector.*)

ParamTypeDefaultDescription
control_vector.layer_startint32-1Start layer for control vector application
control_vector.layer_endint32-1End layer for control vector application
control_vectorsstring[][]Control vector files with optional strength. Format: "path/to/cvector.gguf" or "path@0.5"

Multimodal (multimodal.*)

ParamTypeDefaultDescription
multimodal.image_min_tokensint32-1Minimum number of tokens per image (-1 for auto)
multimodal.image_max_tokensint32-1Maximum number of tokens per image (-1 for auto)
multimodal.mtmd_batch_max_tokensint321024Maximum batch tokens for multimodal data

Memory (memory.*)

ParamTypeDefaultDescription
memory.load_modestring"auto"Mode to load the model (auto, none, mmap, mlock, direct_io)
memory.lazy_modestring"auto"On-demand tensor reading (off, auto, on) (requires mmap)
memory.kv_unifiedboolfalseUse unified KV cache
memory.cache_idle_slotsbooltrueSave and clear idle KV cache slots when a new task starts

CPU (cpu.*)

ParamTypeDefaultDescription
cpu.n_threadsint32-1Number of threads for generation (-1 for auto-detect)
cpu.pollint3250Thread pool polling interval
cpu.maskstring""CPU affinity mask for generation threads
cpu.rangestring""CPU range for generation threads
cpu.prioritystring"normal"Thread scheduling priority: low, normal, medium, high, or realtime
cpu.strictboolfalseStrict CPU affinity for generation threads

CPU Batch (cpu_batch.*)

ParamTypeDefaultDescription
cpu_batch.n_threadsint32-1Number of threads for batch processing (-1 for auto-detect)
cpu_batch.pollint3250Thread pool polling interval for batch processing
cpu_batch.maskstring""CPU affinity mask for batch processing threads
cpu_batch.rangestring""CPU range for batch processing threads
cpu_batch.prioritystring"normal"Thread scheduling priority for batch processing
cpu_batch.strictboolfalseStrict CPU affinity for batch processing threads

RoPE (rope.*)

ParamTypeDefaultDescription
rope.freq_basefloat0.0RoPE base frequency (0.0 for model default)
rope.freq_scalefloat0.0RoPE frequency scale factor (0.0 for model default)
rope.scaling_typestring""RoPE scaling type: none, linear, yarn, or longrope

YaRN (yarn.*)

ParamTypeDefaultDescription
yarn.ext_factorfloat-1.0YaRN extrapolation mix factor (-1.0 for model default)
yarn.attn_factorfloat-1.0YaRN attention magnitude scaling factor
yarn.beta_fastfloat-1.0YaRN low correction dimension
yarn.beta_slowfloat-1.0YaRN high correction dimension
yarn.orig_ctxint320YaRN original context size

Group Attention (grp_attn.*)

ParamTypeDefaultDescription
grp_attn.nint321Self-extend group attention factor (1 for disabled)
grp_attn.wint32512Self-extend group attention width

KV Cache (cache.*)

ParamTypeDefaultDescription
cache.type_kstring"f16"Data type for K cache: f32, f16, bf16, q8_0, q4_0, q4_1, iq4_nl, q5_0, or q5_1
cache.type_vstring"f16"Data type for V cache (same options as cache.type_k)
cache.cache_promptbooltrueEnable prompt caching (reuse previously evaluated KV state)
cache.cache_ram_mibint328192RAM limit for the prompt cache in MiB (-1 = no limit, 0 = disable cache)
cache.n_cache_reuseint320Minimum chunk size in tokens to reuse from the KV cache via shifting (0 = disabled)
cache.n_ctx_checkpointsint3232Maximum number of context checkpoints per slot (0 = disabled)
cache.checkpoint_min_stepint32256Minimum spacing between context checkpoints

Fit Parameters (fit.*)

ParamTypeDefaultDescription
fit.enabledbooltrueAutomatically fit model parameters to available memory
fit.min_ctxint324096Minimum context size when fitting parameters

Speculative Decoding (speculative.*)

Speculative decoding uses draft tokens to accelerate generation, then verifies them in parallel with the main model. llama_ros supports both draft-model-based and self-speculative (ngram-based) approaches.

Note: Speculative decoding requires context.n_parallel: 1 (single slot) and is not supported with embedding/reranking models.

ParamTypeDefaultDescription
speculative.typestring"none"Speculative decoding type: none, draft-simple, draft-eagle3, draft-mtp, ngram-simple, ngram-map-k, ngram-map-k4v, ngram-mod, or ngram-cache
Draft Model (speculative.draft.*)

Used with draft-model-based types (draft-simple, draft-eagle3, draft-mtp).

ParamTypeDefaultDescription
speculative.draft.n_maxint3216Maximum number of tokens to draft per speculative step
speculative.draft.n_minint320Minimum number of draft tokens required to attempt verification. If the draft model produces fewer tokens than this, the draft is discarded and a single token is generated instead. 0 is recommended
speculative.draft.p_mindouble0.75Minimum probability threshold for draft tokens (greedy)
speculative.draft.p_splitdouble0.1Split probability threshold for speculative sampling
speculative.draft.n_gpu_layersint32-1Number of layers to offload to GPU for the draft model (-1 for all)
speculative.draft.cache_type_kstring"f16"KV cache type for K in the draft model (e.g. f16, q8_0, q4_0)
speculative.draft.cache_type_vstring"f16"KV cache type for V in the draft model (e.g. f16, q8_0, q4_0)
speculative.draft.model.pathstring""Local file path to the draft model GGUF file
speculative.draft.model.repostring""HuggingFace repository ID for the draft model
speculative.draft.model.filenamestring""Filename of the draft model in the HuggingFace repository
speculative.draft.backend_samplingbooltrueWhether to offload draft sampling to the backend
Ngram-mod (speculative.ngram_mod.*)

Used with speculative.type: ngram-mod. A hash-based self-speculative method that learns n-gram patterns from the prompt without a separate model.

ParamTypeDefaultDescription
speculative.ngram_mod.n_matchint3224N-gram size for lookup (minimum 16 recommended)
speculative.ngram_mod.n_maxint3264Maximum number of tokens to draft per step
speculative.ngram_mod.n_minint3248Minimum draft length required to attempt verification
Ngram-simple (speculative.ngram_simple.*)

Used with speculative.type: ngram-simple. A lightweight self-speculative method based on n-gram lookup with no draft model required.

ParamTypeDefaultDescription
speculative.ngram_simple.size_nint3212N-gram size for lookup
speculative.ngram_simple.size_mint3248M-gram size for speculative tokens
speculative.ngram_simple.min_hitsint321Minimum hits at n-gram lookup for m-gram to be proposed
Ngram-map-k (speculative.ngram_map_k.*)

Used with speculative.type: ngram-map-k. Self-speculative decoding with n-gram keys only.

ParamTypeDefaultDescription
speculative.ngram_map_k.size_nint3212N-gram size for lookup
speculative.ngram_map_k.size_mint3248M-gram size for speculative tokens
speculative.ngram_map_k.min_hitsint321Minimum hits at n-gram lookup for m-gram to be proposed
Ngram-map-k4v (speculative.ngram_map_k4v.*)

Used with speculative.type: ngram-map-k4v. Self-speculative decoding with n-gram keys and 4 m-gram values; higher acceptance rate than ngram-map-k at higher cost.

ParamTypeDefaultDescription
speculative.ngram_map_k4v.size_nint3212N-gram size for lookup
speculative.ngram_map_k4v.size_mint3248M-gram size for speculative tokens
speculative.ngram_map_k4v.min_hitsint321Minimum hits at n-gram lookup for m-gram to be proposed
Ngram-cache (speculative.ngram_cache.*)

Used with speculative.type: ngram-cache. Self-speculative decoding with a 3-level n-gram cache; optionally load pre-built static and dynamic caches from disk.

ParamTypeDefaultDescription
speculative.ngram_cache.lookup_cache_staticstring""Path to a pre-built static n-gram lookup cache
speculative.ngram_cache.lookup_cache_dynamicstring""Path to a dynamic n-gram lookup cache file

Prompt & Chat (prompt.*)

ParamTypeDefaultDescription
prompt.prefixstring""Text prepended to every user prompt
prompt.suffixstring""Text appended to every user prompt
prompt.system_promptstring""Initial system prompt
prompt.system_prompt_filestring""Path to a file containing the system prompt
prompt.system_prompt_typestring""System prompt type (loads from a predefined YAML in llama_ros/prompts/)
prompt.chat_template_filestring""Path to a Jinja chat template file
prompt.stopping_wordsstring[][]List of words/tokens that stop generation

LoRA Adapters (lora.*)

ParamTypeDefaultDescription
lora.adaptersstring[][]List of LoRA adapter names to load
lora.init_without_applyboolfalseLoad LoRA adapters without applying them
lora.<lora_name>.repostring""HuggingFace repository for the LoRA adapter
lora.<lora_name>.filenamestring""Filename of the LoRA adapter in the repository
lora.<lora_name>.file_pathstring""Local file path to the LoRA adapter
lora.<lora_name>.scaledouble1.0LoRA adapter scale factor (clamped to [0.0, 1.0])

Messages

SamplingConfig (llama_msgs/msg/SamplingConfig)

The SamplingConfig message is used in GenerateResponse and GenerateChatCompletions goals to configure sampling behaviour per request.

FieldTypeDefaultDescription
seeduint324294967295 (LLAMA_DEFAULT_SEED)RNG seed (4294967295 = random)
n_prevint3264Number of previous tokens to consider for repetition penalties
n_probsint320Return top-N token probabilities (0 = disabled)
min_keepint320Minimum number of tokens to keep after sampling (0 = disabled)
ignore_eosboolfalseIgnore end-of-stream tokens and continue generating
no_perfboolfalseDisable performance metrics collection
timing_per_tokenboolfalseCollect per-token timing data
logit_biasLogitBiasArray[]Logit biases for specific tokens
logit_bias_eogLogitBiasArray[]Pre-calculated logit biases for end-of-generation tokens
tempfloat320.80Sampling temperature
dynatemp_rangefloat320.0Dynamic temperature range (0.0 = disabled)
dynatemp_exponentfloat321.0Dynamic temperature exponent
top_kint3240Top-K sampling (0 = disabled)
top_pfloat320.95Top-P (nucleus) sampling (1.0 = disabled)
min_pfloat320.05Min-P sampling (0.0 = disabled)
top_n_sigmafloat32-1.0Top-N-sigma sampling (-1.0 = disabled)
xtc_probabilityfloat320.0XTC sampling probability (0.0 = disabled)
xtc_thresholdfloat320.1XTC sampling threshold (values > 0.5 disable XTC)
typical_pfloat321.0Locally typical sampling (1.0 = disabled)
penalty_last_nint3264Number of last tokens to consider for penalties (0 = disable, -1 = context size)
penalty_repeatfloat321.0Repetition penalty (1.0 = disabled)
penalty_freqfloat320.0Frequency penalty (0.0 = disabled)
penalty_presentfloat320.0Presence penalty (0.0 = disabled)
dry_multiplierfloat320.0DRY repetition penalty multiplier (0.0 = disabled)
dry_basefloat321.75DRY repetition penalty base
dry_allowed_lengthint322Tokens extending repetitions beyond this length receive DRY penalty
dry_penalty_last_nint3264Tokens to scan for DRY repetitions (0 = disable, -1 = context size)
dry_sequence_breakersstring[]["\n", ":", "\"", "*"]Sequence breakers for DRY
adaptive_targetfloat32-1.0Adaptive-P target probability (negative = disabled)
adaptive_decayfloat320.90Adaptive-P EMA decay
mirostatint320Mirostat mode (0 = disabled, 1 = Mirostat v1, 2 = Mirostat v2)
mirostat_etafloat320.10Mirostat learning rate
mirostat_taufloat325.0Mirostat target entropy
samplers_sequencestring"edskypmxt"Sampler pipeline order (chars map to: e=penalties, d=DRY, s=top-N-sigma, k=top-K, y=typical-P, p=top-P, m=min-P, x=XTC, t=temp)
grammarstring""GBNF grammar string to constrain sampling
grammar_schemastring""JSON schema converted to a GBNF grammar
grammar_lazyboolfalseUse lazy grammar evaluation (grammar only activates after a trigger)
grammar_triggersGrammarTrigger[][]Trigger conditions for lazy grammar activation
preserved_tokensint32[][]Token IDs that should never be penalised or modified
backend_samplingboolfalseUse hardware-accelerated (backend) sampling if available
reasoning_budgetint32-1Token budget for reasoning (-1 = disabled, ≥ 0 = max thinking tokens)
reasoning_budget_startint32[][]Token IDs for the thinking start tag. Auto-populated from the chat template if empty
reasoning_budget_endint32[][]Token IDs for the thinking end tag. Auto-populated from the chat template if empty
reasoning_budget_forcedint32[][]Token sequence forcibly injected when the budget is exhausted (message + end tag). Auto-populated if empty. Distinct from force_pure_content_parser: this controls when to stop thinking, not how the template is parsed
reasoning_budget_messagestring""Text inserted before the thinking end tag when the reasoning budget is exhausted (e.g. "Wait, I need to conclude.")
reasoning_controlboolfalseCreate the budget sampler on demand so reasoning can be ended at runtime

GenerateChatCompletions Goal (llama_msgs/action/GenerateChatCompletions)

FieldTypeDefaultDescription
messagesChatMessage[][]Conversation history as a list of chat messages
add_generation_promptboolfalseAppend the generation prompt token sequence after the last message
use_jinjaboolfalseUse Jinja2 chat template (required for tool calls and reasoning)
toolsChatReqTool[][]List of tools the model may call
tool_choiceint320Tool selection mode: 0 = auto, 1 = required (must call a tool), 2 = none
extract_reasoningboolfalseExtract <think> reasoning content from the response into reasoning_content
sampling_configSamplingConfig—Per-request sampling configuration (see SamplingConfig table above)
reasoning_formatChatReasoningFormat3How reasoning content is returned: 0=none, 1=auto, 2=deepseek_legacy, 3=deepseek
imagessensor_msgs/Image[][]Images for VLM inference
audiosstd_msgs/UInt8MultiArray[][]Audio buffers for multimodal inference
parallel_tool_callsboolfalseAllow the model to return multiple tool calls in a single message
streamboolfalseStream partial results as feedback messages
force_pure_content_parserboolfalsePer-request override of context.force_pure_content_parser — bypasses template tool-call/reasoning parsing

LoRA Adapters

You can use LoRA adapters when launching LLMs. Using llama.cpp features, you can load multiple adapters choosing the scale to apply for each adapter. Here you have an example of using LoRA adapters with Phi-3. You can list the LoRAs using the /llama/list_loras service and modify their scales values by using the /llama/update_loras service. A scale value of 0.0 means not using that LoRA.

Click to expand
/**:
  ros__parameters:
    model:
      repo: bartowski/Phi-3.5-mini-instruct-GGUF
      filename: Phi-3.5-mini-instruct-Q4_K_M.gguf
    context:
      n_ctx: 2048
      n_batch: 8
      n_predict: 2048
    gpu:
      n_gpu_layers: 0
    cpu:
      n_threads: 1
    prompt:
      system_prompt_type: Phi-3
    lora:
      adapters:
        - code_writer
        - summarization
      code_writer:
        repo: zhhan/adapter-Phi-3-mini-4k-instruct_code_writing
        filename: Phi-3-mini-4k-instruct-adaptor-f16-code_writer.gguf
        scale: 0.5
      summarization:
        repo: zhhan/adapter-Phi-3-mini-4k-instruct_summarization
        filename: Phi-3-mini-4k-instruct-adaptor-f16-summarization.gguf
        scale: 0.5

ROS 2 Clients

Both llama_ros and llava_ros provide ROS 2 interfaces to access the main functionalities of the models. Here you have some examples of how to use them inside ROS 2 nodes. Moreover, take a look to the llama_demo_node.py and llava_demo_node.py demos.

Tokenize

Click to expand
from rclpy.node import Node
from llama_msgs.srv import Tokenize


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create the client
        self.srv_client = self.create_client(Tokenize, "/llama/tokenize")

        # create the request
        req = Tokenize.Request()
        req.text = "Example text"

        # call the tokenize service
        self.srv_client.wait_for_service()
        tokens = self.srv_client.call(req).tokens

Detokenize

Click to expand
from rclpy.node import Node
from llama_msgs.srv import Detokenize


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create the client
        self.srv_client = self.create_client(Detokenize, "/llama/detokenize")

        # create the request
        req = Detokenize.Request()
        req.tokens = [123, 123]

        # call the tokenize service
        self.srv_client.wait_for_service()
        text = self.srv_client.call(req).text

Embeddings

Click to expand

Remember to launch llama_ros with embedding set to true to be able of generating embeddings with your LLM.

from rclpy.node import Node
from llama_msgs.srv import GenerateEmbeddings


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create the client
        self.srv_client = self.create_client(GenerateEmbeddings, "/llama/generate_embeddings")

        # create the request
        req = GenerateEmbeddings.Request()
        req.prompt = "Example text"
        req.normalization = 2  # -1=none, 0=max abs int16, 1=taxicab, 2=euclidean, >2=p-norm

        # call the embedding service
        self.srv_client.wait_for_service()
        embeddings = self.srv_client.call(req).embeddings

Generate Response

Click to expand
import rclpy
from rclpy.node import Node
from rclpy.action import ActionClient
from llama_msgs.action import GenerateResponse


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create the client
        self.action_client = ActionClient(
            self, GenerateResponse, "/llama/generate_response")

        # create the goal and set the sampling config
        goal = GenerateResponse.Goal()
        goal.prompt = self.prompt
        goal.sampling_config.temp = 0.2

        # wait for the server and send the goal
        self.action_client.wait_for_server()
        send_goal_future = self.action_client.send_goal_async(
            goal)

        # wait for the server
        rclpy.spin_until_future_complete(self, send_goal_future)
        get_result_future = send_goal_future.result().get_result_async()

        # wait again and take the result
        rclpy.spin_until_future_complete(self, get_result_future)
        result: GenerateResponse.Result = get_result_future.result().result

Generate Response (llava)

Click to expand
import cv2
from cv_bridge import CvBridge

import rclpy
from rclpy.node import Node
from rclpy.action import ActionClient
from llama_msgs.action import GenerateResponse


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create a cv bridge for the image
        self.cv_bridge = CvBridge()

        # create the client
        self.action_client = ActionClient(
            self, GenerateResponse, "/llama/generate_response")

        # create the goal and set the sampling config
        goal = GenerateResponse.Goal()
        goal.prompt = self.prompt
        goal.sampling_config.temp = 0.2

        # add your image to the goal
        image = cv2.imread("/path/to/your/image", cv2.IMREAD_COLOR)
        goal.images.append(self.cv_bridge.cv2_to_imgmsg(image))

        # wait for the server and send the goal
        self.action_client.wait_for_server()
        send_goal_future = self.action_client.send_goal_async(
            goal)

        # wait for the server
        rclpy.spin_until_future_complete(self, send_goal_future)
        get_result_future = send_goal_future.result().get_result_async()

        # wait again and take the result
        rclpy.spin_until_future_complete(self, get_result_future)
        result: GenerateResponse.Result = get_result_future.result().result

Generate Chat Completions

Click to expand

The GenerateChatCompletions action provides an OpenAI-compatible chat completions interface with support for tool calling, reasoning, and streaming.

import rclpy
from rclpy.node import Node
from rclpy.action import ActionClient
from llama_msgs.action import GenerateChatCompletions
from llama_msgs.msg import ChatMessage


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create the client
        self.action_client = ActionClient(
            self, GenerateChatCompletions, "/llama/generate_chat_completions")

        # create the goal
        goal = GenerateChatCompletions.Goal()
        goal.messages = [
            ChatMessage(role="system", content="You are a helpful assistant."),
            ChatMessage(role="user", content="What is ROS 2?")
        ]
        goal.sampling_config.temp = 0.2
        goal.stream = True

        # wait for the server and send the goal
        self.action_client.wait_for_server()
        send_goal_future = self.action_client.send_goal_async(goal)

        # wait for the server
        rclpy.spin_until_future_complete(self, send_goal_future)
        get_result_future = send_goal_future.result().get_result_async()

        # wait again and take the result
        rclpy.spin_until_future_complete(self, get_result_future)
        result = get_result_future.result().result

Get Metadata

Click to expand
from rclpy.node import Node
from llama_msgs.srv import GetMetadata


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create the client
        self.srv_client = self.create_client(GetMetadata, "/llama/get_metadata")

        # call the metadata service
        req = GetMetadata.Request()
        self.srv_client.wait_for_service()
        metadata = self.srv_client.call(req).metadata

Rerank Documents

Click to expand

Remember to launch llama_ros with reranking set to true.

from rclpy.node import Node
from llama_msgs.srv import RerankDocuments


class ExampleNode(Node):
    def __init__(self) -> None:
        super().__init__("example_node")

        # create the client
        self.srv_client = self.create_client(RerankDocuments, "/llama/rerank_documents")

        # create the request
        req = RerankDocuments.Request()
        req.query = "What is robotics?"
        req.documents = ["Robotics is a field of engineering.", "The weather is sunny."]

        # call the reranking service
        self.srv_client.wait_for_service()
        scores = self.srv_client.call(req).scores

LangChain

There is a llama_ros_langchain package, a llama_ros integration for LangChain. Thus, prompt engineering techniques could be applied. Here you have an example to use it.

llama_ros (Chain)

Click to expand
import rclpy
from llama_ros_langchain import LlamaROS
from langchain.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser


rclpy.init()

# create the llama_ros llm for langchain
llm = LlamaROS()

# create a prompt template
prompt_template = "tell me a joke about {topic}"
prompt = PromptTemplate(
    input_variables=["topic"],
    template=prompt_template
)

# create a chain with the llm and the prompt template
chain = prompt | llm | StrOutputParser()

# run the chain
text = chain.invoke({"topic": "bears"})
print(text)

rclpy.shutdown()

llama_ros (Stream)

Click to expand
import rclpy
from llama_ros_langchain import LlamaROS
from langchain.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser


rclpy.init()

# create the llama_ros llm for langchain
llm = LlamaROS()

# create a prompt template
prompt_template = "tell me a joke about {topic}"
prompt = PromptTemplate(
    input_variables=["topic"],
    template=prompt_template
)

# create a chain with the llm and the prompt template
chain = prompt | llm | StrOutputParser()

# run the chain
for c in chain.stream({"topic": "bears"}):
    print(c, flush=True, end="")

rclpy.shutdown()

llava_ros

Click to expand
import rclpy
from llama_ros_langchain import LlamaROS

rclpy.init()

# create the llama_ros llm for langchain
llm = LlamaROS()

# bind the url_image
image_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
llm = llm.bind(image_url=image_url).stream("Describe the image")

# run the llm
for c in llm:
    print(c, flush=True, end="")

rclpy.shutdown()

llama_ros_embeddings (RAG)

Click to expand
import rclpy
from langchain_chroma import Chroma
from llama_ros_langchain import LlamaROSEmbeddings


rclpy.init()

# create the llama_ros embeddings for langchain
embeddings = LlamaROSEmbeddings()

# create a vector database and assign it
db = Chroma(embedding_function=embeddings)

# create the retriever
retriever = db.as_retriever(search_kwargs={"k": 5})

# add your texts
db.add_texts(texts=["your_texts"])

# retrieve documents
documents = retriever.invoke("your_query")
print(documents)

rclpy.shutdown()

llama_ros (Reranker)

Click to expand
import rclpy
from llama_ros_langchain import LlamaROSReranker
from llama_ros_langchain import LlamaROSEmbeddings

from langchain_community.vectorstores import FAISS
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.retrievers import ContextualCompressionRetriever


rclpy.init()

# load the documents
documents = TextLoader("../state_of_the_union.txt",).load()
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500, chunk_overlap=100)
texts = text_splitter.split_documents(documents)

# create the llama_ros embeddings
embeddings = LlamaROSEmbeddings()

# create the VD and the retriever
retriever = FAISS.from_documents(
    texts, embeddings).as_retriever(search_kwargs={"k": 20})

# create the compressor using the llama_ros reranker
compressor = LlamaROSReranker()
compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor, base_retriever=retriever
)

# retrieve the documents
compressed_docs = compression_retriever.invoke(
    "What did the president say about Ketanji Jackson Brown"
)

for doc in compressed_docs:
    print("-" * 50)
    print(doc.page_content)
    print("\n")

rclpy.shutdown()

llama_ros (LLM + RAG + Reranker)

Click to expand
import bs4
import rclpy

from langchain_chroma import Chroma
from langchain_community.document_loaders import WebBaseLoader
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_core.messages import SystemMessage
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.retrievers import ContextualCompressionRetriever

from llama_ros_langchain import ChatLlamaROS, LlamaROSEmbeddings, LlamaROSReranker


rclpy.init()

# load, chunk and index the contents of the blog
loader = WebBaseLoader(
    web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",),
    bs_kwargs=dict(
        parse_only=bs4.SoupStrainer(class_=("post-content", "post-title", "post-header"))
    ),
)
docs = loader.load()

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(documents=splits, embedding=LlamaROSEmbeddings())

# retrieve and generate using the relevant snippets of the blog
retriever = vectorstore.as_retriever(search_kwargs={"k": 20})

# create prompt
prompt = ChatPromptTemplate.from_messages(
    [
        SystemMessage("You are an AI assistant that answer questions briefly."),
        HumanMessagePromptTemplate.from_template(
            "Taking into account the followin information:{context}\n\n{question}"
        ),
    ]
)

# create rerank compression retriever
compressor = LlamaROSReranker(top_n=3)
compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor, base_retriever=retriever
)


def format_docs(docs):
    formated_docs = ""

    for d in docs:
        formated_docs += f"\n\n\t- {d.page_content}"

    return formated_docs


# create and use the chain
rag_chain = (
    {"context": compression_retriever | format_docs, "question": RunnablePassthrough()}
    | prompt
    | ChatLlamaROS(temp=0.0)
    | StrOutputParser()
)

for c in rag_chain.stream("What is Task Decomposition?"):
    print(c, flush=True, end="")

rclpy.shutdown()

chat_llama_ros (Chat + VLM)

Click to expand
import rclpy
from llama_ros_langchain import ChatLlamaROS
from langchain_core.messages import SystemMessage
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from langchain_core.output_parsers import StrOutputParser


rclpy.init()

# create chat
chat = ChatLlamaROS(
    temp=0.2,
    penalty_last_n=8
)

# create prompt template with messages
prompt = ChatPromptTemplate.from_messages([
    SystemMessage("You are a IA that just answer with a single word."),
    HumanMessagePromptTemplate.from_template(template=[
        {"type": "text", "text": "<__media__>Who is the character in the middle of the image?"},
        {"type": "image_url", "image_url": "{image_url}"}
    ])
])

# create the chain
chain = prompt | chat | StrOutputParser()

# stream and print the LLM output
for text in chain.stream({"image_url": "https://pics.filmaffinity.com/Dragon_Ball_Bola_de_Dragaon_Serie_de_TV-973171538-large.jpg"}):
    print(text, end="", flush=True)

print("", end="\n", flush=True)

rclpy.shutdown()

chat_llama_ros (Chat + Audio)

Click to expand
import sys
import time
import rclpy
from langchain_core.messages import SystemMessage
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from langchain_core.output_parsers import StrOutputParser
from llama_ros_langchain import ChatLlamaROS


def main():
    if len(sys.argv) < 2:
        prompt = "What's that sound?"
    else:
        prompt = " ".join(sys.argv[1:])

    tokens = 0
    initial_time = -1
    eval_time = -1

    rclpy.init()
    chat = ChatLlamaROS(temp=0.0)

    prompt = ChatPromptTemplate.from_messages(
        [
            SystemMessage("You are an IA that answer questions."),
            HumanMessagePromptTemplate.from_template(
                template=[
                    {"type": "text", "text": f"<__media__>{prompt}"},
                    {"type": "image_url", "image_url": "{audio_url}"},
                ]
            ),
        ]
    )

    chain = prompt | chat | StrOutputParser()

    initial_time = time.time()
    for text in chain.stream(
        {
            "audio_url": "https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen2-Audio/audio/glass-breaking-151256.mp3"
        }
    ):
        tokens += 1
        print(text, end="", flush=True)
        if eval_time < 0:
            eval_time = time.time()

    print("", end="\n", flush=True)

    end_time = time.time()
    print(f"Time to eval: {eval_time - initial_time} s")
    print(f"Prediction speed: {tokens / (end_time - eval_time)} t/s")

    rclpy.shutdown()


if __name__ == "__main__":
    main()

chat_llama_ros (Structured output)

Click to expand
import rclpy
from typing import Optional

from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
from llama_ros_langchain import ChatLlamaROS
from pydantic import BaseModel, Field

rclpy.init()

class Joke(BaseModel):
    """Joke to tell user."""

    setup: str = Field(description="The setup of the joke")
    punchline: str = Field(description="The punchline to the joke")
    rating: Optional[int] = Field(
        default=None, description="How funny the joke is, from 1 to 10"
    )

chat = ChatLlamaROS(temp=0.6, penalty_last_n=8)

structured_chat = chat.with_structured_output(
    Joke, method="function_calling"
)

prompt = ChatPromptTemplate.from_messages(
    [
        HumanMessagePromptTemplate.from_template(
            template=[
                {"type": "text", "text": "{prompt}"},
            ]
        ),
    ]
)

chain = prompt | structured_chat

res = chain.invoke({"prompt": "Tell me a joke about cats"})

print(f"Response: {res}")

rclpy.shutdown()

chat_llama_ros (Tools)

Click to expand

The current implementation of Tools allows executing tools without requiring a model trained for that task.

from random import randint

import rclpy

from langchain_core.tools import tool
from langchain_core.messages import HumanMessage
from llama_ros_langchain import ChatLlamaROS

rclpy.init()

@tool
def get_inhabitants(city: str) -> int:
    """Get the current temperature of a city"""
    return randint(4_000_000, 8_000_000)


@tool
def get_curr_temperature(city: str) -> int:
    """Get the current temperature of a city"""
    return randint(20, 30)

chat = ChatLlamaROS(temp=0.6, penalty_last_n=8)

messages = [
    HumanMessage(
        "What is the current temperature in Madrid? And its inhabitants?"
    )
]

llm_tools = chat.bind_tools(
    [get_inhabitants, get_curr_temperature], tool_choice='any'
)

all_tools_res = llm_tools.invoke(messages)
messages.append(all_tools_res)

for tool in all_tools_res.tool_calls:
    selected_tool = {
        "get_inhabitants": get_inhabitants, "get_curr_temperature": get_curr_temperature
    }[tool['name']]

    tool_msg = selected_tool.invoke(tool)

    formatted_output = f"{tool['name']}({''.join(tool['args'].values())}) = {tool_msg.content}"

    tool_msg.additional_kwargs = {'args': tool['args']}
    messages.append(tool_msg)

res = llm_tools.invoke(messages)

print(f"Response: {res.content}")

rclpy.shutdown()

chat_llama_ros (Reasoning)

Click to expand

A reasoning model is required, such as Deepseek R1

import time
from random import randint

import rclpy

from langchain_core.messages import HumanMessage
from llama_ros_langchain import ChatLlamaROS

rclpy.init()

chat = ChatLlamaROS(temp=0.6, penalty_last_n=8)

messages = [
    HumanMessage(
        "Here we have a book, a laptop, 9 eggs and a nail. Please tell me how to stack them onto each other in a stable manner."
    )
]

res = chat.invoke(messages)

print(f"Response: {res.content.strip()}")
print(f"Reasoning: {res.additional_kwargs["reasoning_content"]}")

rclpy.shutdown()

chat_llama_ros (Agent)

Click to expand
import time
from random import randint

import rclpy

from langchain_core.tools import tool
from langchain_core.messages import HumanMessage
from langchain.agents import create_agent
from llama_ros_langchain import ChatLlamaROS

rclpy.init()

@tool
def get_inhabitants(city: str) -> int:
    """Get the current temperature of a city"""
    return randint(4_000_000, 8_000_000)


@tool
def get_curr_temperature(city: str) -> int:
    """Get the current temperature of a city"""
    return randint(20, 30)

chat = ChatLlamaROS(temp=0.0)

agent_executor = create_agent(
    chat, [get_inhabitants, get_curr_temperature]
)

response = agent_executor.invoke(
    {
        "messages": [
            HumanMessage(
                content="What is the current temperature in Madrid? And its inhabitants?"
            )
        ]
    }
)

print(f"Response: {response['messages'][-1].content}")

rclpy.shutdown()

Demos

LLM Demo

ros2 launch llama_bringup spaetzle.launch.py
ros2 run llama_demos llama_demo_node

https://github.com/mgonzs13/llama_ros/assets/25979134/9311761b-d900-4e58-b9f8-11c8efefdac4

Speculative Decoding Demo

ros2 launch llama_bringup llama-3-speculative.launch.py
ros2 run llama_demos llama_demo_node

MTP Speculative Decoding Demo

ros2 launch llama_bringup Qwen3.5-MTP.launch.py
ros2 run llama_demos chatllama_demo_node

Embeddings Generation Demo

ros2 llama launch ~/ros2_ws/src/llama_ros/llama_bringup/models/bge-base-en-v1.5.yaml
ros2 run llama_demos llama_embeddings_demo_node

https://github.com/user-attachments/assets/7d722017-27dc-417c-ace7-bf6b747e4ced

Reranking Demo

ros2 llama launch ~/ros2_ws/src/llama_ros/llama_bringup/models/jina-reranker.yaml
ros2 run llama_demos llama_rerank_demo_node

https://github.com/user-attachments/assets/4b4adb4d-7c70-43ea-a2c1-9be57d211484

RAG Demo (LLM + chat template + RAG + Reranking + Stream)

ros2 llama launch ~/ros2_ws/src/llama_ros/llama_bringup/models/bge-base-en-v1.5.yaml
ros2 llama launch ~/ros2_ws/src/llama_ros/llama_bringup/models/jina-reranker.yaml
ros2 llama launch Qwen3.yaml
Click to expand Qwen3.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/Qwen_Qwen3-8B-GGUF
      filename: Qwen_Qwen3-8B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      stopping_words: ["<|im_end|>"]
ros2 run llama_demos llama_rag_demo_node

https://github.com/user-attachments/assets/b4e3957d-1f92-427b-a1a8-cfc76737c0d6

Chat Template Demo

ros2 llama launch MiniCPM-2.6.yaml
Click to expand MiniCPM-2.6.yaml
/**:
  ros__parameters:
    model:
      repo: "openbmb/MiniCPM-V-2_6-gguf"
      filename: "ggml-model-Q4_K_M.gguf"
    mmproj:
      repo: "openbmb/MiniCPM-V-2_6-gguf"
      filename: "mmproj-model-f16.gguf"
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: 20
    cpu:
      n_threads: -1
ros2 run llama_demos chatllama_image_demo_node

ChatLlamaROS demo

VLM Demo

ros2 launch llama_bringup minicpm-2.6.launch.py
ros2 run llama_demos llava_demo_node

https://github.com/mgonzs13/llama_ros/assets/25979134/4a9ef92f-9099-41b4-8350-765336e3503c

Chat Multi-Image Demo

ros2 llama launch MiniCPM-2.6.yaml
Click to expand MiniCPM-2.6.yaml
/**:
  ros__parameters:
    model:
      repo: "openbmb/MiniCPM-V-2_6-gguf"
      filename: "ggml-model-Q4_K_M.gguf"
    mmproj:
      repo: "openbmb/MiniCPM-V-2_6-gguf"
      filename: "mmproj-model-f16.gguf"
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: 20
    cpu:
      n_threads: -1
ros2 run llama_demos chatllama_multi_image_demo_node

Chat Multi-Image (User Input) Demo

ros2 llama launch MiniCPM-2.6.yaml
Click to expand MiniCPM-2.6.yaml
/**:
  ros__parameters:
    model:
      repo: "openbmb/MiniCPM-V-2_6-gguf"
      filename: "ggml-model-Q4_K_M.gguf"
    mmproj:
      repo: "openbmb/MiniCPM-V-2_6-gguf"
      filename: "mmproj-model-f16.gguf"
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: 20
    cpu:
      n_threads: -1
ros2 run llama_demos chatllama_multi_image_user_demo_node

MTMD Audio Demo

ros2 llama launch Qwen2-Audio.yaml
Click to expand Qwen2-Audio.yaml
/**:
  ros__parameters:
    model:
      repo: mradermacher/Qwen2-Audio-7B-Instruct-GGUF
      filename: Qwen2-Audio-7B-Instruct.Q4_K_M.gguf
    mmproj:
      repo: mradermacher/Qwen2-Audio-7B-Instruct-GGUF
      filename: Qwen2-Audio-7B-Instruct.mmproj-f16.gguf
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      system_prompt_type: ChatML
ros2 run llama_demos mtmd_audio_demo_node

Chat Audio Demo

ros2 llama launch Qwen2-Audio.yaml
Click to expand Qwen2-Audio.yaml
/**:
  ros__parameters:
    model:
      repo: mradermacher/Qwen2-Audio-7B-Instruct-GGUF
      filename: Qwen2-Audio-7B-Instruct.Q4_K_M.gguf
    mmproj:
      repo: mradermacher/Qwen2-Audio-7B-Instruct-GGUF
      filename: Qwen2-Audio-7B-Instruct.mmproj-f16.gguf
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
ros2 run llama_demos chatllama_audio_demo_node

Chat Multi-Audio Demo

ros2 llama launch Qwen2-Audio.yaml
Click to expand Qwen2-Audio.yaml
/**:
  ros__parameters:
    model:
      repo: mradermacher/Qwen2-Audio-7B-Instruct-GGUF
      filename: Qwen2-Audio-7B-Instruct.Q4_K_M.gguf
    mmproj:
      repo: mradermacher/Qwen2-Audio-7B-Instruct-GGUF
      filename: Qwen2-Audio-7B-Instruct.mmproj-f16.gguf
    context:
      n_ctx: 8192
      n_batch: 512
      n_predict: 8192
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
ros2 run llama_demos chatllama_multi_audio_demo_node

Chat Structured Output Demo

ros2 llama launch Qwen3.yaml
Click to expand Qwen3.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/Qwen_Qwen3-8B-GGUF
      filename: Qwen_Qwen3-8B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      stopping_words: ["<|im_end|>"]
ros2 run llama_demos chatllama_structured_demo_node

Structured Output ChatLlama

Chat Tools Demo

ros2 llama launch Qwen3.yaml
Click to expand Qwen3.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/Qwen_Qwen3-8B-GGUF
      filename: Qwen_Qwen3-8B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      stopping_words: ["<|im_end|>"]
ros2 run llama_demos chatllama_tools_demo_node

Tools ChatLlama

Streaming Tools Demo

ros2 llama launch Qwen3.yaml
Click to expand Qwen3.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/Qwen_Qwen3-8B-GGUF
      filename: Qwen_Qwen3-8B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      stopping_words: ["<|im_end|>"]
ros2 run llama_demos chatllama_streaming_tools_demo_node

Chat Reasoning Demo (DeepSeek-R1)

ros2 llama launch DeepSeek-R1.yaml
Click to expand DeepSeek-R1.yaml
/**:
  ros__parameters:
    model:
      repo: unsloth/DeepSeek-R1-Distill-Qwen-7B-GGUF
      filename: DeepSeek-R1-Distill-Qwen-7B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: 1
    prompt:
      chat_template_file: llama-cpp-deepseek-r1.jinja
ros2 run llama_demos chatllama_reasoning_demo_node

DeepSeekR1 ChatLlama

Reasoning + Tools Demo

ros2 llama launch Qwen3.yaml
Click to expand Qwen3.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/Qwen_Qwen3-8B-GGUF
      filename: Qwen_Qwen3-8B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      stopping_words: ["<|im_end|>"]
ros2 run llama_demos chatllama_reasoning_tools_demo_node

PDDL Demo

ros2 llama launch Qwen3.yaml
Click to expand Qwen3.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/Qwen_Qwen3-8B-GGUF
      filename: Qwen_Qwen3-8B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      stopping_words: ["<|im_end|>"]
ros2 run llama_demos chatllama_pddl_demo_node

Agent Demo

ros2 llama launch Qwen3.yaml
Click to expand Qwen3.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/Qwen_Qwen3-8B-GGUF
      filename: Qwen_Qwen3-8B-Q4_K_M.gguf
    context:
      n_ctx: 4096
      n_batch: 256
      n_predict: -1
    gpu:
      n_gpu_layers: -1
    cpu:
      n_threads: -1
    prompt:
      stopping_words: ["<|im_end|>"]
ros2 run llama_demos chatllama_agent_demo_node

Agent ChatLlama

Parallel Slots Demo

This demo shows how to use multiple parallel slots (context.n_parallel) to process several requests concurrently via continuous batching. Launch the model with n_parallel: 4:

ros2 llama launch SmolLM2-slots.yaml
Click to expand SmolLM2-slots.yaml
/**:
  ros__parameters:
    model:
      repo: bartowski/SmolLM2-1.7B-Instruct-GGUF
      filename: SmolLM2-1.7B-Instruct-Q4_K_L.gguf
    context:
      n_ctx: 2048
      n_batch: 8
      n_predict: 2048
      n_parallel: 4
    gpu:
      n_gpu_layers: 0
    cpu:
      n_threads: -1
    prompt:
      system_prompt_type: ChatML
ros2 run llama_demos llama_slots_demo_node
audio
cpp
embeddings
ggml
gguf
gpt
langchain
llama
llamacpp
llava
llavacpp
llm
multimodal
rerank
reranking
ros2
vlm

Contributors

mgonzs13

990 commits

agonzc34

14 commits

Alvvalencia

1 commits

b0rh

1 commits

Languages

C++

74.6%

Python

22.3%

CMake

2.9%