Best Practices for Dynamic User Modeling with LangGraph

Hello. I am new to the community and am interested in dynamic user modeling for use cases like adaptive explanation, the custom-tailoring of unfolding explanatory dialogues for individual users.

I am wondering about best practices for dynamic user modeling using LangGraph. By “dynamic”, I mean that user models could be both updated and queried at runtime. I am envisioning nodes, edges, and invoked tools as being capable of updating and querying user models.

There are many different kinds of user models to consider, in these regards, including, but not limited to: string dictionaries, object graphs, knowledge graphs, finite-state machines, dynamic Bayesian networks, deep user models, cognitive architectures, personal online data storage (e.g., Solid pods), agents encapsulating user models, and combinations of these.

With respect to developing and building software using LangGraph that is capable of updating and querying user models, I have, thus far, considered five approaches.

Firstly, one could initialize, utilize, and finalize a global object for a user model of the current user and use this global object throughout their software project.

Secondly, dynamic user models could be attached to state. However, with the serialization and deserialization of state, this may be a wrong approach for more complex user models.

Thirdly, dynamic user models could be attached to configuration. Perhaps one could obtain and access user models from the configuration parameter available for nodes, edges, and invoked tools?

Fourthly, user models could be a topic for memory, short-term and long-term memory, intra-session and inter-session storage.

Fifthly, user models could be made available via their own new parameter available for nodes, edges, and invoked tools.

Is any one of these indicated approaches, or any other approach, the best practice for updating and querying dynamic user models in software projects using LangGraph? Are there any open-source examples or projects to explore with respect to these topics? Thank you.

Hello @AdamSobieski welcome to the langchain community.

I would suggest using a layered approach: not one of the five options alone:

  1. Session / dialogue context uses Graph state + checkpointer as its mechanism, and is used for messages, current turn, and working hypotheses within a thread.
  2. Persistent user model uses Store (long-term memory) as its mechanism, and is used for profiles, preferences, and facts that survive across threads.
  3. Runtime dependencies uses Runtime / context_schema as its mechanism, and is used for user_id, DB clients, and user-model service handles.
  4. Avoid global singletons, as they break concurrency, testing, and deployment.

How to evaluate the five approaches

  1. Global object: Avoid. Not thread-safe, hard to test, doesn’t work with parallel invocations or LangGraph Server.

  2. State: Good for simple, serializable, session-scoped data (e.g. current explanation level). Not for complex or large user models: state is checkpointed every step, must be JSON-serializable, and is thread-scoped unless you also use a Store.

  3. Configuration / context: Good for injecting identity and services (user_id, a UserModelService, DB connection), not for storing the evolving model itself. Pass user_id via context; read/write the model via runtime.store or an injected service.

  4. Memory (Store + checkpointer): This is the primary best practice for dynamic user modeling. The Store holds cross-thread, namespaced data (e.g. ("memories", user_id)). Nodes and tools access it via runtime.store.search() / runtime.store.put().

  5. New dedicated parameter: You don’t need one; Runtime already exposes context, store, and execution metadata to nodes and tools.

For complex user models (graphs, FSMs, cognitive architectures)

  • Keep the canonical model outside graph state (external DB, graph DB, or Store as serialized JSON/docs).
  • Put only summaries or pointers in state when the graph needs them for routing.
  • Inject a service via context_schema for heavy logic (e.g. UserModelService.update() / .query()).
  • For LLM-maintained profiles, consider a structured profile document updated incrementally: see memory profiles.

Doc Reference:

I hope this helps you out in understanding Langgraph and how you could use it in potentially modelling Complex User models using the framework.