From a123d9f1ebebb6ad20155285c9457a6d6a5c7a61 Mon Sep 17 00:00:00 2001 From: Mitja Felicijan Date: Wed, 18 Feb 2026 13:26:22 +0100 Subject: Cleanup and refactor --- Makefile | 13 +++++++++---- README.md | 26 +++++++++++++++++++------- context.txt | 24 ------------------------ corpus/lotr.txt | 24 ++++++++++++++++++++++++ npc.c | 8 ++++---- prompts/lotr.h | 15 +++++++++++++++ prompts/lotr.txt | 1 + system_prompt.h | 15 --------------- system_prompt.txt | 1 - 9 files changed, 72 insertions(+), 55 deletions(-) delete mode 100644 context.txt create mode 100644 corpus/lotr.txt create mode 100644 prompts/lotr.h create mode 100644 prompts/lotr.txt delete mode 100644 system_prompt.h delete mode 100644 system_prompt.txt diff --git a/Makefile b/Makefile index ba4deab..0d27bd6 100644 --- a/Makefile +++ b/Makefile @@ -10,9 +10,12 @@ LDFLAGS = -L$(LLAMA_DIR)/build/src -L$(LLAMA_DIR)/build/ggml/src \ -lpthread -lm -ldl -lstdc++ -g \ -lllama -lggml -lggml-cpu -lggml-base +PROMPT_TXT := $(wildcard prompts/*.txt) +PROMPT_HEADERS := $(PROMPT_TXT:.txt=.h) + help: .help -build/npc: run/system-prompt npc.c vectordb.c models.h # Build npc binary for testing +build/npc: build/prompts npc.c vectordb.c models.h # Build npc binary for testing $(CC) $(CFLAGS) npc.c vectordb.c -o npc $(LDFLAGS) build/context: context.c vectordb.c models.h # Build context binary for testing @@ -24,6 +27,8 @@ build/llama.cpp: .assure # Build llama.cpp libraries cmake ../ -DBUILD_SHARED_LIBS=OFF && \ make -j8 +build/prompts: $(PROMPT_HEADERS) # Generate C style header + run/fetch-models: .assure # Fetch GGUF models -mkdir -p models cd models && wget -nc -i ../models.txt @@ -32,10 +37,10 @@ run/docker: .assure # Runs npc in Docker container docker build -t npcd . docker run -it npcd -run/system-prompt: .assure # Generate C style header - xxd -i system_prompt.txt > system_prompt.h - run/clean: # Cleans up all the build artefacts -rm -f npc cd $(LLAMA_DIR)/build && make clean -rm -Rf $(LLAMA_DIR)/build + +prompts/%.h: prompts/%.txt .assure + xxd -i $< > $@ diff --git a/README.md b/README.md index fee82f8..a20bcef 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,18 @@ -# llmnpc +An experiment using tiny LLMs as NPCs that could be embedded into the game. -Command-line tooling for NPC-focused LLM experiments with lightweight context -retrieval, powered by [llama.cpp](https://github.com/ggerganov/llama.cpp). +Goals of the experiment: + +- Have LLM be run only on CPU, this is why small LLMs have been chosen in this + experiment, so they can be used in other games. +- To produce a simple C library that can be reused elsewhere. +- Test existing small and tiny LLMs and provide some useful results on how they + behave. + +> [!NOTE] +> This project is just for fun, to see how LLMs would fare as NPCs. Because of +> the non-deterministic nature of LLMs, the results vary and are often quite +> funny. A lot of tweaking would be needed to make this really useful in real +> games, but not impossible. ## Building @@ -26,6 +37,7 @@ retrieval, powered by [llama.cpp](https://github.com/ggerganov/llama.cpp). 3. Build binaries: ```bash make build/context + make build/prompts make build/npc ``` @@ -37,8 +49,8 @@ retrieval, powered by [llama.cpp](https://github.com/ggerganov/llama.cpp). produces a binary vector database file. ```bash -./context -i context.txt -o context.vdb -./context -m flan-t5-small -i context.txt -o context.vdb +./context -i corpus/lotr.txt -o corpus/lotr.vdb +./context -m flan-t5-small -i corpus/lotr.txt -o corpus/lotr.vdb ``` ### Run an NPC query with retrieved context @@ -47,8 +59,8 @@ produces a binary vector database file. lines by cosine similarity, and runs the NPC system prompt against that context. ```bash -./npc -m flan-t5-small -p "Who is Gandalf?" -c context.vdb -./npc -m flan-t5-small -p "Who is Frodo?" -c context.vdb +./npc -m flan-t5-small -p "Who is Gandalf?" -c corpus/lotr.vdb +./npc -m flan-t5-small -p "Who is Frodo?" -c corpus/lotr.vdb ``` ### context options diff --git a/context.txt b/context.txt deleted file mode 100644 index 1d97eb3..0000000 --- a/context.txt +++ /dev/null @@ -1,24 +0,0 @@ -Gandalf is a wizard in The Lord of the Rings with a grey beard and a staff. -Gandalf is one of the Istari and is called the Grey Pilgrim and Mithrandir. -Gandalf fought Sauron and helped destroy the One Ring. -Frodo Baggins is a hobbit in The Lord of the Rings and is Bilbo's nephew. -Frodo is from the Shire and carried the One Ring to Mount Doom. -Frodo is a member of the Fellowship of the Ring. -Samwise Gamgee is a hobbit from the Shire in The Lord of the Rings. -Samwise is Frodo's loyal companion and a member of the Fellowship of the Ring. -Aragorn is a man in The Lord of the Rings and is known as Strider. -Aragorn is a ranger, a leader of Men, and a member of the Fellowship of the Ring. -Legolas is an elf in The Lord of the Rings and a skilled archer. -Legolas is a member of the Fellowship of the Ring. -Gimli is a dwarf in The Lord of the Rings and a warrior. -Gimli is a member of the Fellowship of the Ring. -Boromir is a man from Gondor in The Lord of the Rings. -Boromir is a member of the Fellowship of the Ring. -The One Ring is a powerful ring in The Lord of the Rings that was created by Sauron. -The One Ring corrupts its bearer and must be destroyed in Mount Doom. -Sauron is the Dark Lord in The Lord of the Rings and created the One Ring. -Sauron is an enemy of the free peoples of Middle-earth. -Mordor is the realm of Sauron in The Lord of the Rings and contains Mount Doom. -Mount Doom is a volcano in Mordor in The Lord of the Rings where the One Ring was destroyed. -The Shire is the homeland of hobbits in The Lord of the Rings and the home of Frodo and Samwise. -Gondor is a kingdom of Men in The Lord of the Rings and the home of Boromir. diff --git a/corpus/lotr.txt b/corpus/lotr.txt new file mode 100644 index 0000000..1d97eb3 --- /dev/null +++ b/corpus/lotr.txt @@ -0,0 +1,24 @@ +Gandalf is a wizard in The Lord of the Rings with a grey beard and a staff. +Gandalf is one of the Istari and is called the Grey Pilgrim and Mithrandir. +Gandalf fought Sauron and helped destroy the One Ring. +Frodo Baggins is a hobbit in The Lord of the Rings and is Bilbo's nephew. +Frodo is from the Shire and carried the One Ring to Mount Doom. +Frodo is a member of the Fellowship of the Ring. +Samwise Gamgee is a hobbit from the Shire in The Lord of the Rings. +Samwise is Frodo's loyal companion and a member of the Fellowship of the Ring. +Aragorn is a man in The Lord of the Rings and is known as Strider. +Aragorn is a ranger, a leader of Men, and a member of the Fellowship of the Ring. +Legolas is an elf in The Lord of the Rings and a skilled archer. +Legolas is a member of the Fellowship of the Ring. +Gimli is a dwarf in The Lord of the Rings and a warrior. +Gimli is a member of the Fellowship of the Ring. +Boromir is a man from Gondor in The Lord of the Rings. +Boromir is a member of the Fellowship of the Ring. +The One Ring is a powerful ring in The Lord of the Rings that was created by Sauron. +The One Ring corrupts its bearer and must be destroyed in Mount Doom. +Sauron is the Dark Lord in The Lord of the Rings and created the One Ring. +Sauron is an enemy of the free peoples of Middle-earth. +Mordor is the realm of Sauron in The Lord of the Rings and contains Mount Doom. +Mount Doom is a volcano in Mordor in The Lord of the Rings where the One Ring was destroyed. +The Shire is the homeland of hobbits in The Lord of the Rings and the home of Frodo and Samwise. +Gondor is a kingdom of Men in The Lord of the Rings and the home of Boromir. diff --git a/npc.c b/npc.c index 01c980c..5450866 100644 --- a/npc.c +++ b/npc.c @@ -11,7 +11,7 @@ #include #include -#include "system_prompt.h" +#include "prompts/lotr.h" static void llama_log_callback(enum ggml_log_level level, const char *text, void *user_data) { (void)level; @@ -54,13 +54,13 @@ static int execute_prompt_with_context(const ModelConfig *cfg, const char *promp return 1; } - char *system_prefix = (char *)malloc(system_prompt_txt_len + 1); + char *system_prefix = (char *)malloc(prompts_lotr_txt_len + 1); if (system_prefix == NULL) { log_message(stderr, LOG_ERROR, "Failed to allocate system prompt"); return 1; } - memcpy(system_prefix, system_prompt_txt, system_prompt_txt_len); - system_prefix[system_prompt_txt_len] = '\0'; + memcpy(system_prefix, prompts_lotr_txt, prompts_lotr_txt_len); + system_prefix[prompts_lotr_txt_len] = '\0'; ggml_backend_load_all(); diff --git a/prompts/lotr.h b/prompts/lotr.h new file mode 100644 index 0000000..5210021 --- /dev/null +++ b/prompts/lotr.h @@ -0,0 +1,15 @@ +unsigned char prompts_lotr_txt[] = { + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x20, 0x41, 0x6e, 0x73, 0x77, + 0x65, 0x72, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x6e, 0x6c, + 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, + 0x74, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x6e, + 0x73, 0x77, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, + 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x6c, 0x79, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x64, 0x20, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 0x79, 0x3a, 0x20, 0x49, + 0x20, 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a +}; +unsigned int prompts_lotr_txt_len = 138; diff --git a/prompts/lotr.txt b/prompts/lotr.txt new file mode 100644 index 0000000..2f997b9 --- /dev/null +++ b/prompts/lotr.txt @@ -0,0 +1 @@ +System: Answer using only the Context. If the answer is not explicitly stated in Context, respond exactly: I don't have that information. diff --git a/system_prompt.h b/system_prompt.h deleted file mode 100644 index 119b7f2..0000000 --- a/system_prompt.h +++ /dev/null @@ -1,15 +0,0 @@ -unsigned char system_prompt_txt[] = { - 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x20, 0x41, 0x6e, 0x73, 0x77, - 0x65, 0x72, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x6e, 0x6c, - 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, - 0x74, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x6e, - 0x73, 0x77, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, - 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x6c, 0x79, 0x20, 0x73, - 0x74, 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x64, 0x20, 0x65, 0x78, 0x61, 0x63, 0x74, 0x6c, 0x79, 0x3a, 0x20, 0x49, - 0x20, 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, - 0x74, 0x68, 0x61, 0x74, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x0a -}; -unsigned int system_prompt_txt_len = 138; diff --git a/system_prompt.txt b/system_prompt.txt deleted file mode 100644 index 2f997b9..0000000 --- a/system_prompt.txt +++ /dev/null @@ -1 +0,0 @@ -System: Answer using only the Context. If the answer is not explicitly stated in Context, respond exactly: I don't have that information. -- cgit v1.2.3