Use Llama.cpp in Xojo

For MBS Xojo Plugins 26.1 we include new Llama classes to use local LLMs on your computer. Instead of paying for a web service to run the LLM on someone else’s computer, you can run it locally on yours.

Llama chat example showing what the LLM knows about Xojo.

About Llama

The Llama.cpp project allows you to run efficient Large Language Model Inference in pure C/C++. You can run any powerful artificial intelligence model including all LLaMa models, Falcon and RefinedWeb, Mistral models, Gemma from Google, Phi, Qwen, Yi, Solar 10.7B and Alpaca.

You do not need to pay to use Llama.cpp or buy a subscription. It is completely free, open-source, constantly updated and available under the “MIT” license. And Monkeybread Software provides an interface for Xojo as part of the MBS Plugin.

Get Models

You can find various models on the Internet, e.g. on huggingface.co. For Llama you need a model in the GGUF format. Other formats may need a conversion currently.

You may search models for llama.cpp as app: huggingface.co/models?apps=llama.cpp.

We made tests with gemma-3-1b-it.Q8_0.gguf model (1 GB) from google and gpt-oss-20b-Q4_K_M.gguf (11.6 GB) from openai. The bigger models are usually better in their knowledge, but please be aware, that the model needs to fit into memory.
The links will break as new models get uploaded and old models disappear.

Get Libraries

To install llama.cpp you can use package managers like homebrew to install a copy: brew.sh/llama.cpp.

Or you download binaries from the llama website or directly from the github llama release page.

You find there builds for macOS (Apple Silicon or Intel), for Linux and for Windows. For Windows you have various builds to use either Vulkan, CUDA or CPU for performing interference.

You may include the libraries with your applications. Like on Windows just put them next to the DLLs from the Xojo runtime. For macOS you could include them within the app bundle in the Frameworks folder.

The libraries can stay in whatever folder you or the installer chooses. Just tell our plugin where to find them.

Load the library

Now you may want to open the example file from us: LLama Simple Chat.xojo_binary_project.

There you need to modify the script to load the llama libraries. Go to the Opening event and look for the calls to LoadLibrary. For Windows you also need to use SetCurrentWorkingDirectoryMBS to set the folder, so Windows actually finds the DLLs.

Next you put in the file path to the model into the modelPath variable. This should be a native path to the model like “C:\Users\User\Modesl\gemma-3-1b-it.Q8_0.gguf”.

After loading the libraries, the code calls BackendLoadAll to load all the backends. You may then check which bankends are there

Use the model

Next you can use LlamaModelMBS constructor to load a model. Use the LlamaContextMBS class to start a session with its own context memory. You can of course have multiple sessions in parallel.

Here is a sample:

	// initialize the model
	Var ModelParams As New LlamaModelParametersMBS
	
	model = new LlamaModelMBS(modelPath, ModelParams)
	
	// initialize the context
	var contextParams as new LlamaContextParametersMBS
	
	// n_ctx is the context size
	contextParams.n_ctx = 20480
	
	// n_batch is the maximum number of tokens that can be processed in a single call to llama_decode
	contextParams.n_batch = 20480
	
	context = new LlamaContextMBS(model, contextParams)
	
	// initialize the sampler
	Var SampleParameters As New LlamaSamplerChainParametersMBS
	
	sampler = new LlamaSamplerMBS(SampleParameters)
	sampler.AddToChain( LlamaSamplerMBS.InitMinP(0.05, 1))
	sampler.AddToChain( LlamaSamplerMBS.InitTemp(0.8) )
	sampler.AddToChain( LlamaSamplerMBS.InitDist(LlamaSamplerMBS.DefaultSeed) )
	
	// wait for input
	InputArea.SetFocus

On the session, you can use the Ask function to ask the LLM a question. The function then returns the output of the model. For a chat, we use LlamaChatMessageMBS class to collect the questions and answers and apply a chat template to pass it to the LLM as JSON.

We have a lot of parameters like context size or for the samplers used. Different parameters to the sampler or context may provide very different outputs.

Please try and let us know.

10 Likes

Can this be used on the Xojo webserver as well?

Of course. You can use it in a web application.

Is works great in a desktop application, but I cannot get it to work in a webapp. I converted the sample ‘Llama simple chat’ to a webapp. The opening-event triggers the error ‘Failed to initialize model‘ when calling LlamaModelMBS:

Var modelPath As String
modelPath=SpecialFolder.Documents.Child(“gemma-3-1b-it-f16.gguf”).NativePath

Var dir As New FolderItem(“C:\Program Files\Xojo\Xojo 2025r2.1\Xojo Libs”, folderitem.PathModes.Native)
Call SetCurrentWorkingDirectoryMBS(dir)

If Not LlamaMBS.LoadLibrary(“ggml.dll”) Or Not LlamaMBS.LoadLibrary(“ggml-base.dll”) Or Not LlamaMBS.LoadLibrary(“llama.dll”) Then
MessageBox LlamaMBS.LoadErrorMessage
Return
End If

LlamaMBS.BackendLoadAll

Try

Var ModelParams As New LlamaModelParametersMBS

model = new LlamaModelMBS(modelPath, ModelParams)

[…]

Catch e As LlamaExceptionMBS
MessageBox(e.Message)
End Try

the LoadLibrary calls all succeeded?

After you loaded backends, can you check if you have some?

// now inspect them
var backends() as LlamaBackendMBS = LlamaMBS.Backends
for each backend as LlamaBackendMBS in backends
  var devices() as LlamaDeviceMBS = backend.Devices
  var name as string = backend.Name
  var features as Dictionary = backend.Features
  
  Break
next

Also you checked the model path is correct?

No backends are loaded in the webapp (in the desktop app 2 are loaded).

The model path is correct and the model exists.

Forgot to mention: the LoadLibrary calls all succeeded.

How have you proven this? The event in which you need to make these calls (App.Opening) MessageBox will silently just not do anything.

Unnecessary edit because the forum software snips quotes when it shouldn’t.

I stepped through the code and the LoadLibrary calls returned True.

Otherwise the code would have returned and not have made the call to LlamaModelMBS().

and the backend DLLs are also in the same folder?

If you change all the instances of MessageBox to Print, do you see anything in the log viewer that hadn’t been occurring with MessageBox? I’m hung up on using MessageBox for error reporting because it’s not reliable in every situation. Personally, I believe you are getting an exception and are not seeing it.

I can only wildly guess unless you can share an example project to confirm how your error handling is designed. Fair warning: I do not have an intention to download llama.cpp and get this running. I can only help make sure your errors are actually being reported.

To be sure I copied all DLL’s to C:\LlamaLibs and SetCurrentWorkingDirectoryMBS to that map. All DLL’s are present.

I also checked LlamaMBS.LoadErrorMessage after the calls to LoadLibrary. It returns an empty string.

I still get zero LlamaMBS.Backends after calling LlamaMBS.BackendLoadAll in the WebApp (as mentioned the Windows-version works great).

Also we have SetLogger(Logger as LlamaLogMBS) method, so you can set your logging callback and get all the log messages, e.g. why the model fails to load.

MessageBox worked fine, but nonetheless I replaced it with System.DebugLog.

No errors are reported.

I included LlamaMBS.SetDebugLogger just after LlamaMBS.LoadLibrary(“llama.dll”). The lines:

LlamaMBS.BackendLoadAll

Var backends() As LlamaBackendMBS = LlamaMBS.Backends

still return 0 items in backends(), without an error. The subsequent line:

model = new LlamaModelMBS(modelPath, ModelParams)

now does return the following error:

[Error] llama_model_load_from_file_impl: no backends are loaded. hint: use ggml_backend_load() or ggml_backend_load_all() to load a backend before calling this function

I also tried to call LoadLibrary with the full path. This works alright in the Windows desktop-app, but in the Web-app the line:

LlamaMBS.LoadLibrary(“C:\LLamaLibs\ggml.dll”)

gives the following error:

%1 is not a valid Win32 application.

Note: I do not get this error when I use:

Var dir As New FolderItem(“C:\LLamaLibs”, folderitem.PathModes.Native)

Call SetCurrentWorkingDirectoryMBS(dir)

LlamaMBS.LoadLibrary(“ggml.dll”)

Addition: The problem may have to do with a mixing-up of Arm64 and x64 in Xojo’s Webapp…

I believe this is a bug:

I run on an Snapdragon Arm-processor. When running the Webapp in debugging-mode, Xojo incorrectly states that #TargetARM is false.

LlamaMBS seems to struggle with this as well. I receive the error “not a valid Win32 application” when calling LlamaMBS.LoadLibrary(“C:\LLamaLibs\ggml.dll”) with the Arm-dll. When I incorrectly replace the Arm version of ggml.dll with its x64 version I do not receive this error (though the libraries are still not loaded).

MessageBox won’t work without a Session context. I’m glad you didn’t see any new errors!

Do you have an App.UnhandledException event handler? I’ve had issues with Web Apps not terminating when they experience a RuntimeException the way they’re supposed to. The effect is a silent error (and sometimes that Session is ruined).

Update: I’ve just confirmed that Web Apps do not exit with unhandled exceptions, which is inconsistent with Desktop. @Ricardo_Cruz #81642

Please use #if to pick different folders depending on target.

e.g.

Var path As String

#If TargetARM and Target64Bit Then
  path = "C:\llama-arm64\"
#ElseIf TargetX86 And Target64Bit Then
  path = "C:\llama-32\"
#ElseIf TargetX86 And not Target64Bit Then
  path = "C:\llama-64\"
#Else
  #error "Wrong target?"
#endif
1 Like

First problem is that when run locally on an Arm-processor, Xojo WebApp incorrectly states that TargetArm is false. This is a bug in Xojo.

I worked around this by now, but it is unclear from the MBS documentation what libs to load for Linux (for deploying the app to Xojo’s web). In the demo app it states LlamaMBS.LoadLibrary(“libggml.so”) and LlamaMBS.LoadLibrary(“libllama.so”). However, both files are empty (zero bytes) in downloads from Github llama.cpp ( Releases · ggml-org/llama.cpp · GitHub ).

That doesn’t happen here for me. Maybe your Mac target is set to x86 for Intel code?