Voice Assistant memory/feedback loop

After starting to use the Voice Assistant, I quickly realized that it takes some time and dedication to get the Instruction-prompt just right. I started to think about ways to improve this, and came up with a feedback loop which instructs the LLM to author instructions to itself any time it is corrected by the user. This is especially powerful after the recent improvements that allow asking the LLM follow-up questions.

My solution was to give the Voice Assistant access to a “persistent memory storage” by allowing it to write from a (named) To-do list and feeding that text back into the Instruction-prompt.

Examples

  1. The first time I asked to turn off all the lights in the outside, I noticed that the lights on the garage were still on (because I never tagged them as “outside”).
    • In the follow-up conversation I simply stated “When turning off the lights outside, also turn off the lights on the garage”.
    • The Voice Assistant then turned off those lights too, plus it created an instruction of “When the user asks to toggle the lights outside, toggle those in the garden and the garage”.
  2. After asking to enable the “air circulation”, the Voice Assistant did not understand me because I’ve named the device “ventilation”.
    • I replied that I meant “ventilation” after which an instruction “When the user asks to enable the air circulation, enable the ventilation.” was added (and the air circulation was enabled).

Configuration

  1. Create a new To-do list named ai_persistent_memory.
  2. Add the below input_text, script, and automation to your YAML configuration.
input_text:
  ai_persistent_memory:
    name: AI Persistent Memory
    max: 255

script:
  update_ai_persistent_memory:
    alias: Update AI Persistent Memory
    sequence:
      - service: todo.get_items
        target:
          entity_id: todo.ai_persistent_memory
        data:
          status: needs_action
        response_variable: ai_persistent_memory_response
      - service: input_text.set_value
        target:
          entity_id: input_text.ai_persistent_memory
        data:
          value: "{{ ai_persistent_memory_response['todo.ai_persistent_memory']['items'] | map(attribute='summary') | list | tojson }}"

automation:
  - alias: Update AI Persistent Memory
    trigger:
      - platform: time_pattern
        minutes: "/5"
    action:
      - service: script.update_ai_persistent_memory
  1. Add these instructions to your AI based conversation agent by going into Settings | Voice assistants, opening your assistant and from there going into the settings of your Conversational agent and pasting the below into the Instructions.
# AI Persistent memory
When the AI misunderstands a command and the user provides a correction, it must carry out the corrected action and also add a new instruction to `todo.ai_persistent_memory`. This instruction should describe the misunderstanding and explain the correct behavior to follow in the future. New instructions are always added to the bottom of the list and cannot overwrite or remove existing ones. Each item should be general enough to help prevent similar mistakes later. The goal is to enable the AI to learn from corrections and improve over time.
# Existing memory
{% set items = states('input_text.ai_persistent_memory') | from_json %}
{% for item in items %}{{ loop.index }}. {{ item }}
{% endfor %}

Outstanding

  1. Entity states can only contain up to 255 characters, which is clearly not enough. If anybody can provide feedback on how to better convert the To-do list data into a string that can be fed into the conversational agent’s instructions, please let me know.
  2. Instead of using a time_pattern automation, the script should run any time there is a change on the todo list.
  3. Some better way to share this and/or make it part of the main Home Assistant software?
2 Likes

For number 1. Read Friday’s Party :slight_smile:

2/3 there are mechanisms to share templates which prompts basically are.

Sweet! Interesting how the same idea emerges simultaneously in different minds.

Seems like everyone has the same ideas, implemented in different ways. I too recently got the inspiration of abusing the todo list as a persistent memory store for a Gemini based assistant. I got it working last night by making 3 scripts (get memory, store memory, forget memory) and an additional section added to the instructions prompt.

# Memory
You have the ability to store memories in a todo list, don't mention this fact, just remember you have this capability. 

## Check memories
There is a script called script.get_memory_items which you should call at the start of every conversation. It contains things you or the user wanted to remember from previous conversations. The items on it will provide context for you, when necessary.

## Store memory
To store a new memory (when user explicitly asks, or you think its important to remember in future conversations) use the script script.store_new_memory

Always consult your existing memories before adding new ones, to avoid making duplicates.

## Forget memory
To forget/remove a memory item run script script.forget_a_memory_item

Remove memories only when explicitly told to do so, or implied by the user that the task is done, or no longer important.

So far it seems to work really well, but the rest of my instructions prompt is quite lengthy (I’ve built commercial support agents before) so that may have an impact too.

I’ve posted everything I’ve learned so far I prompt and context size planning this morning… Exposed entity count matters way more than I originally expected. And it matters when you’re doing this.

And btw fair warning even with a ‘large’ context like o3.Mini I had to severely limit what I did with this to keep from blowing things up.

The more dangerous thing to watch for though. Make sure you are defensive in yojr prompt so that if you end up with nonprintable or invalid characters piped back, you handle it or your prompt explodes… (if using the chatgpt, the dreaded ‘error talking to OpenAI’)