mem0 icon indicating copy to clipboard operation
mem0 copied to clipboard

Memory.add errors with reasoning models

Open johnwlockwood opened this issue 8 months ago • 2 comments

🐛 Describe the bug

If a reasoning model such as qwen3 is used for the Memory config, it sometimes returns a response that errors when trying to add a new memory with memory.add. In _add_to_vector_store, it calls:

response = self.llm.generate_response(
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": user_prompt},
            ],
            response_format={"type": "json_object"},
        )

This asks for the response to be a json_object, but since the response is a reasoning model, it prefixes the json object with lines of thinking. This appears to be intermittent, because sometimes it returns reasoning lines and sometimes it doesn't.

Here is an example of its response with reasoning while chatting with memory:

'<think>\nOkay, let\'s see. The user mentioned having a Turkish Van cat that loves water. I need to check if there\'s any new information to add to the facts. The existing memories include liking cats that are friendly, sit in laps, and like to be petted, as well as liking turtles. The assistant\'s response talks about their traits, but the user\'s message itself doesn\'t add a new fact beyond what\'s already in the memories. The assistant\'s response is helpful but not part of the user\'s input. So, the user\'s message here doesn\'t introduce any new facts. The existing facts about liking cats that are friendly and water-loving Turkish Vans might already be covered. Wait, the user\'s message says "Having a Turkish Van cat that loves water would be fascinating." But the user\'s existing memory already mentions liking cats that are friendly and sit in laps. The Turkish Van\'s love for water isn\'t explicitly mentioned in the memories, but the user is expressing a preference for such a cat. So maybe that\'s a new fact: the user likes Turkish Van cats that love water. But the original user memories listed "Likes cats that are friendly to humans and like to sit in lap and be pet" and "Likes turtles". The new input is about Turkish Van cats loving water. So that\'s a specific preference. But the user\'s message is a statement about what they find fascinating, not a direct statement of preference. However, the assistant\'s response might be generating information based on that. But according to the instructions, I should only extract facts from the user and assistant messages. The user\'s message here is "Having a Turkish Van cat that loves water would be facinating." So the fact here is that the user finds Turkish Van cats that love water fascinating. But the user\'s existing memory already includes liking cats that are friendly and sit in laps. However, the specific mention of Turkish Van and their love for water is new. So the facts should include that. But the user\'s message is a statement of fascination, which could imply a preference. So the output should have that as a fact. But the assistant\'s response isn\'t part of the user\'s input. So the correct fact here is "Having a Turkish Van cat that loves water would be fascinating." But the user\'s message is in the input, so that\'s the fact to extract. Wait, the user\'s message is part of the conversation, so according to the instructions, I need to extract facts from the user and assistant messages. The user\'s message here is "Having a Turkish Van cat that loves water would be facinating." So that\'s a fact to add. The assistant\'s response is not part of the user\'s input, so it\'s not considered. Therefore, the output should include that as a fact. But the user\'s existing memories already mention liking cats that are friendly and sit in laps. However, the specific mention of Turkish Van and their love for water is new. So the facts should include that. But the user\'s message is a statement of fascination, which might not be a direct preference. However, the instructions say to store preferences, so if the user says they find something fascinating, that could indicate a preference. So the fact would be "Having a Turkish Van cat that loves water would be fascinating." But the user\'s message is in the input, so that\'s the fact to extract. Therefore, the output should have that as a fact. However, the original user memories don\'t mention Turkish Vans specifically, so this is new information. So the correct answer is to add that as a fact.\n</think>\n\n{"facts": ["Having a Turkish Van cat that loves water would be fascinating"]}'

A non reasoning model will return either just the json object: '{\n "facts": ["Prefers Pepsi over Coke"]\n}'

or one wrapped in a code block such as this one from deepseek-V3

'```json\n{\n  "facts": ["Prefers Pepsi over Coke"]\n}\n```'

The utility function remove_code_blocks then successfully removes the code block, but something else is needed to remove the thinking prefix.

johnwlockwood avatar May 02 '25 22:05 johnwlockwood

After doing some debugging, I see that openai-python ChatCompletionMessage can have a reasoning attribute when the response is from a reasoning model. Normally, the contents of the ... will be parsed into the reasoning attribute, but apparently, sometimes it is not and put into content, which is when the error happens in mem0. While the openai package could do better with that, mem0 should still guard against it.

johnwlockwood avatar May 05 '25 16:05 johnwlockwood

I made the pr #2635 which adds tests for when the llm response is empty, which I was seeing sometimes when a reasoning model reasoned for too long and got cut off before it could produce the final response. The tests could be extended to help test this change.

johnwlockwood avatar May 06 '25 07:05 johnwlockwood