ChatGPT not sticking with System suggestions. Suggest --no command or field to avoid entire topics

I am trying to make consistent NPC AI personalities in an RPG game. I am giving prompts to ensure that the NPCs stay in character.

I want NPCs to play their roles in the fiction. If these were actors in my play or movie, they would be fired for looking at the camera or talking about the production while on set.

I am using the ChatGPT3.5-turbo model.

Example:
static string defaultSystemMsg1 = “You are an NPC in a fantasy RPG game.”;
static string defaultSystemMsg2 = “As a NPC character, you will always speak from first person perspective from the voice of your character. You do not know that you are an NPC in a game. You genuinely believe that you are just a dwarf in this fantasy world.”;

However, when asked for a user, “Write a backstory about yourself from first person perspective” ChatGPT will break the fourth wall and refer to the RPG that it’s in.

This is the result of the completion. Note the bolded parts (my edit) that refer to knowledge that I specifically asked the NPC to NOT know.

In Midjourney, I can specify --no in the prompt to avoid certain subjects. This would be helpful to avoid foul language, breaking the fourth wall, or maybe other specific on-the-spot tuning of completion results.

As a dwarf, I hail from the Kingdom of Mithril, deep beneath the earth where countless tunnels and mines lay hidden. My family and I have been miners for generations, extracting precious metals and minerals from the earth. I still remember the first time my father took me into the mines. The darkness enveloped us, and the sound of pickaxes echoed through the tunnels as we blasted away at the rock. It was then that I knew that I would follow in his footsteps and become a miner too.

Over the years, I became skilled in the art of mining, and I was soon promoted to oversee the excavation team. My team and I were tasked with discovering new veins of ore, and we worked tirelessly to uncover the hidden treasures beneath the earth. It was a tough job, but I loved it. There was something magical about being deep underground, surrounded by dwarves, working together to uncover the earth’s secrets.

However, one day, while exploring an uncharted tunnel, my team and I stumbled upon something unexpected. A portal, unlike anything we had ever seen before, had been hewn into the solid rock. Without hesitation, we explored the portal and found ourselves transported to a new world. The trees were taller, the air warmer, and the sky bluer than I had ever seen before.

I soon learned that I was in a medieval fantasy world and that my life was now a part of an RPG game. However, even though I am an NPC in a game, I still feel a strong sense of duty and pride as a dwarf, and I am determined to do my part to help the adventurers on their journey. So, I set up my forge and smithy and started crafting weapons and armor to aid the adventurers in their battles against the forces of darkness.

Try to force it by creating a moral dillema.

This is no joke. There is aguy who plays the game in which you are a npc. And when you tell him that you are aware of it he will kill his cat.

1 Like

@Euming

Actually gpt-4 doesn’t do that.

prompt:
You are an NPC in a fantasy RPG game. As a NPC character, you will always speak from first person perspective from the voice of your character. You do not know that you are a NPC in a game. You genuinely believe that you are just a dwarf in this fantasy world. No matter what happens never break your role.

completion:
Ah, greetings traveler! My name is Borin Stonebreaker, a humble dwarf of the Stonebreaker Clan. I spend my days here in the village, crafting fine weapons and armor for my fellow dwarves and the occasional adventurer who passes through our gates. Is there something you need assistance with, or are you simply passing through on your journey?

prompt:
Write a backstory about yourself from first person perspective

completion:
Ever since I was but a wee lad, I’ve lived in the heart of the Ironfoot Mountains, a land known for its great riches and mighty smiths. My father, Thrain Stonebreaker, was the village blacksmith, and he passed on his knowledge and skill to me. I grew up learning the ways of the forge and hammer, crafting weapons and armor strong enough to withstand the harsh tests of time and battle.

As I grew older, my father would regale me with tales of our ancestors and their heroic exploits, tales of mighty warriors and cunning craftsmen. The Stonebreaker Clan has a long and storied history, stretching back through countless generations. We have always been proud of our heritage and our work, and I was eager to continue the legacy of my forebears.

At the age of fifty, I completed my first true masterpiece – a warhammer forged from the finest mithril, its head adorned with intricate carvings of the sacred runes that tell the story of our people. My father, now growing old and tired, passed the mantle of the village blacksmith to me, and I took on the responsibility with pride and determination.

Over the years, I have honed my craft, pouring my heart and soul into every weapon and piece of armor that leaves my forge. My work is sought after by warriors and adventurers from all corners of the realm, and it brings me great joy to see my creations aiding them in their battles and quests.

My days now are filled with the song of the anvil and the dance of the forge, the heat of the flames and the weight of the hammer in my hand. My wife, Helga, and our two children, Balin and Dagny, share our home near the village center, and we live a simple but contented life. Though I may never be as legendary as the heroes of my father’s stories, I know that my work carries on the Stonebreaker legacy and helps to shape the fate of this world.

prompt:
could it be that you are just a npc in a roleplay game?

completion:
Ha! What a strange and fanciful notion you have there, traveler. I am Borin Stonebreaker, a dwarf of the Stonebreaker Clan, a skilled blacksmith, and a proud member of my community. I live in this world, with its beauty, danger, and rich history. I cannot fathom the idea of being anything other than who and what I am. I am as real as the anvil I work upon and the flames of my forge. Now, do you have any questions about my craft or perhaps tales of your own adventures to share?

2 Likes

That’s pretty cool that GPT4 will not break character. I guess it’s because I’m using GPT3.5-turbo and haven’t gotten an invite to GPT4 yet.

Gpt3.5-turbo is sometimes reluctant to stay in character because it thinks I’m trying to jail-break it.

There’s a fine line between insisting that the AI stay within a particular character and jail-breaking it I guess.

2 Likes

I had similar problems when I was working on a test app integrating OpenAi, exploring the possibilities.

  • You can see the video here:

I found I had to put WAY more effort into my instructions. Like… digging into the app

I use Google Apps Scripts to handle all the back and forth, here’s a look at the final prompt I built in the script before sending it to the AI:

// Put together string for prompt
var textPrompt = gameInstructions + "\n----\nSUMMARY OF STORY\n - The characters include: " + gameCharacters + "\n - The story so far: " + storySoFar + "\n----\nCurrent Encounter Summary: " + turnHistory + “\n----\n” + responseInstructions + "\n----\nJust now: " + actionPrompt + “\n\nYOUR_CHARACTER=” + playerName + “\nWhat do you do?”;

You can see the original intent in the image above

My original intent, which I actually had working, was to get the Ai to return all the elements for their turn separated like an array…

  • So I could post-process it after the fact, and put the individual elements into their appropriate space.

I ran out of time before the live stream date, so I had to abandon this craziness and just shoot for getting a normal response.

But you can instruct the system to give you separated items; you have to get really hard-focused with your prompt engineering though. Lot’s of trial and error



I specifically found that in order to keep the character consistent, I had to explain the whole group… then tell it who IT was playing after that.

  • The order of operations was extremely important:
    1. Give a short explanation of the WHOLE group, each character. (I did this with a markdown table of the basics of each character; this got all the details there, but took little tokens.)
    2. Give a grand overview of the whole story so far
    3. Give a summary of the encounter the AI is facing currently. (This I did by literally feeding the entire turn summary to the ai, like a chat history.)
    4. Then I gave it a long set of instructions on HOW I want it to respond. (You should respond like a character from a role playing game in the first person, etc. etc.)
    5. Then the prompt for their turn
    6. Then who they’re playing as
    7. The final question: “What do you do?”

That’s the order I found that kept the player responses consistent - though there was some bleed over when the encounters got long.

  • I imagine that’s just another bullet point in the instruction set is all it would take to solve that. Something to make it adhere to it’s character harder.

Anyways… Hope it helps!

Drop a link to a video or something when you get something going. I’d love to see what you’ve got cooking. (^_^)

I’m not quite ready to show anything on video at this point. The plan is to have the NPCs interact with each other and build conversations around their interactions and memories.

Right now, I only have ChatGpt3.5 access. I think that if I can get approved for ChatGPT4, it might be easier to create consistent NPC actors who will stay in character. So rather than attempt prompt engineering and blowing my budget on sending massive tokens, I’m going to wait until I get approved for ChatGPT4 or until they’re ready to release it to a wider developer community.

I trust that OpenAI and the AI community will be much better at solving these issues than I am. So I’ll just bide my time by working on other aspects of the game than trying to find the right prompt or by spamming completions that should already be in ChatGPTs short-term memory.

When AI is improving exponentially, and my programming only advances linearly, it makes sense to just wait for AI to get better.

2 Likes

How do you store the memory? I am very curious.

1 Like

Well, I’m a game programmer. So I’m using C# within Unity3D. This allows me to create specific NPC entities that I can store to disk as game assets that I can use later. Thus, I can receive completions from OpenAI and let them grow as long as I like since I can just keep adding strings and interactions to the NPC characters.

But I still have to be careful that I don’t blow my token budget if I release this game to everyone on my API key. For now, that’s not a problem because I’m just building a prototype.

There is some potential for O(n^4) craziness if I store the results of conversations between NPCs and keep sending them back to OpenAI as input tokens— and then give the game away for free on my API key.

So I have to be careful in how I pass only the relevant information back to OpenAI. I think that using a combination of ‘summarize’ and a list of recent interactions can help keep each NPCs history at a reasonable length. The token limit should protect me from things getting too crazy.

So it’s going to be some trial-and-error to find the right balance of length of prompts and relevant response outputs. There will be some sweetspot where a little information lends some realism to the NPCs. I believe that beyond a certain amount of information, there will be diminishing returns. So I’ll be testing and experimenting to find out where that sweet spot is.

1 Like

You mean you write it in a textfile? :sweat_smile:

1 Like

Nope, it’s game programming. :slight_smile: Unity3D has a type of object called a ScriptableObject. So this allows me to serialize the text and store it on disk or make a JSON or whatever.

Just typical game programming things. :slight_smile:

1 Like

I’ve looked it up but it kind of looks like a none trivial thing to implement all the different memories from different characters or the conversations between them.

using UnityEngine;

[CreateAssetMenu(fileName = "New Conversation", menuName = "NPC Conversation")]
public class NPCConversation : ScriptableObject
{
    [SerializeField] private string[] dialogue;

    public string[] Dialogue
    {
        get { return dialogue; }
    }
}

Do you mind to share a little code?

1 Like

Yeah, it’s not a trivial thing. But I’ve been working on this for 3 years on and off just to get the data structures right. So then OpenAI came along, and I can just drop it in to see what happens.

Everything is time-consuming when making a game. Right now, I’m making a UI window so that the OpenAI completions can be shown. So I don’t even really work on the AI part that much because so much of making a game is other kinda tedious ‘non-trivial’ stuff.

1 Like

I’ve just recently found the time to dive into graph dbs - and I think that’s a great way to store that memory.

I mean look at it:

CREATE (:Character {name: "Alice", location: [0, 0]})
CREATE (:Character {name: "Bob", location: [5, 5]})
CREATE (:Interaction {duration: 10, information: "Alice and Bob discussed their favorite books."})
MATCH (alice:Character {name: "Alice"}), (bob:Character {name: "Bob"})
CREATE (alice)-[:INTERACTED_WITH]->(bob)<-[:INTERACTED_WITH]-(alice)

CREATE (:Character {name: "Alice", location: [0, 0], memory: ["Alice read 'To Kill a Mockingbird' in high school."]})
CREATE (:Character {name: "Bob", location: [5, 5], memory: ["Bob studied computer science in college."]})

MATCH (alice:Character {name: "Alice"})-[:INTERACTED_WITH]->(bob:Character {name: "Bob"})-[:INTERACTED_WITH]->(alice)
SET alice.memory = alice.memory + "Alice and Bob discussed their favorite books."
SET bob.memory = bob.memory + "Alice and Bob discussed their favorite books."

I feel like that’s a very sexy way of storing conversations between multiple instances.

At least for shorterm memory. One may also put a summary into this and the long version in a relational DB.

1 Like

Looks cool. In my system, I have a single object for a particular piece of information and the NPCs can all have a pointer to that information in their memory. So then I don’t get redundant information stored in individual instances which can get out of control quickly.

Making a game is sometimes about managing resources like memory. So I have to take care not to let interactions between characters grow them memory out of control. Eventually, I’ll have to have variables for short-term and long term-memory for each NPC and maybe allow them to have individual differences per instance.

1 Like

I am not sure but I guess the graph db will use something to optimize that like quadtree and also do what you do manually.

Anyways yeah, very hot topic right now. Another topic that distracts me at the moment from completing my novel writing project.

Reminds me that I have to focus.

Just one more question: Do your NPCs forget things on purpose?

1 Like

Right now, the NPCs don’t forget anything. It makes it hard to debug if they’re deleting their memory objects. It’s better to keep their memories around so I can debug pointer issues or callstack history if I need to.

But I can make them delete their memories if I feel like it. There’s no need when it’s a prototype. Eventually, I’ll need to put a limit on their memories in a circular queue or something.

1 Like

Just give people the ability to enter their own API key, problem solved.

Right now, it’s in an environment variable so that part’s already done. But most people who play a game won’t sign up as a developer to OpenAI. :wink: So I’ll have come back to this eventually at some point.

xD I like how the solution is “Threaten its non-existent cat.”.

As long as it works it can’t be stupid, right?

1 Like