LangGraph + AzureChatOpenAI + Azure Redis Cache Premium + RedisSaver — full history restored, but Azure sees it as one user block instead of role-separated turns

’m using LangGraph with an AzureChatOpenAI chat model and persistence via Azure Redis Cache Premium and a custom RedisSaver checkpointer.

  • My state has:
    messages: Annotated[list[BaseMessage], add_messages]

  • so add_messages should merge turns automatically between runs.

  • redis_client = Redis(host=..., port=6380, ssl=True, password=...)
    checkpointer = RedisSaver(redis_client=redis_client)
    graph = StateGraph(...).compile(checkpointer=checkpointer)
    
    
  • In my node, I call the chat model like this:

  • tool_llm = llm.bind_tools(tools)
    response = tool_llm.invoke(state["messages"])
    
    
  • only send the new HumanMessage on each .invoke() and the checkpointer restores the full conversation from Redis. I can see the whole dialogue in state["messages"] before calling the model.

The problem:
Even though state["messages"] contains the complete HumanMessage / AIMessage sequence from all previous turns, the debug log shows AzureChatOpenAI being passed a flattened single string with "Human: ... AI: ... Human: ...", instead of a proper messages=[{"role":"user","content":...}, {"role":"assistant","content":...}] array.

This means the chat model sees it as one user message, not separate turns — so queries like “What was my last question?” fail with “I don’t have access to previous interactions”, even though the history is in state.

Question:

  • How can I make AzureChatOpenAI (with LangGraph and RedisSaver) send my restored state["messages"] as role‑separated chat turns in the API payload, not as one concatenated block?

  • Is there a specific call pattern or option needed in .invoke() to preserve the roles when passing a list of message objects?

Environment:

  • LangGraph:0.6.3

  • LangChain Core: 0 .3.72 (for BaseMessage, HumanMessage, etc.)

  • Python: 3.x

  • Azure Chat model: gpt-4o-2024-08-06

  • Checkpointer: RedisSaver with Azure Redis Cache Premium (non‑Enterprise)

I’d guess this issue is with your custom RedisSaver checkpointer. In your flow the checkpointer restores the state, so I’d guess there’s a problem in the way RedisSaver is storing the results. Do you mind attaching which implementation you used or adding more detail on that front for triage?