# Difference Between Chat, Ask, and Source_Chat LangGraph Graphs in Open Notebook

> Understand the difference between chat, ask, and source_chat LangGraph graphs in Open Notebook. Explore simple chat, research workflows, and source-aware responses.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: deep-dive
- Published: 2026-06-18

---

**The `chat`, `ask`, and `source_chat` graphs in Open Notebook represent three distinct conversational architectures: simple one-turn chat, multi-step research workflows with vector search, and source-aware contextualized responses.**

Open Notebook utilizes LangGraph to power its conversational AI features, implementing three specialized graphs that handle different interaction patterns. Each graph serves a unique purpose within the `lfnovo/open-notebook` repository, from simple message exchanges to complex research workflows that retrieve and synthesize information. Understanding the difference between these LangGraph implementations helps developers select the appropriate backend for specific user interactions.

## The Chat Graph: Simple Conversational Flow

The `chat` graph handles basic one-turn conversational interactions with or without a notebook context. Located in [`open_notebook/graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/chat.py), this graph provides the most straightforward entry point for generic chat functionality.

### State Structure and Implementation

The graph operates on `ThreadState`, a TypedDict that stores the message list, an optional `Notebook` object, raw `context`, `context_config`, and a potential `model_override`. Unlike the other graphs, `chat` does not fetch additional data sources or insights.

The primary node `call_model_with_messages` builds a system prompt using the `chat/system` Jinja template, appends user messages, and provisions a LangChain chat model via `provision_langchain_model`. The implementation returns a cleaned AI reply without additional context retrieval.

```python

# open_notebook/graphs/chat.py (simplified)

from open_notebook.graphs.chat import graph as chat_graph

async def chat_endpoint(state: dict, model_id: str):
    # State conforms to ThreadState

    result = await chat_graph.ainvoke(
        state, 
        config={"configurable": {"model_id": model_id}}
    )
    return result["messages"]  # AIMessage ready for client

```

## The Ask Graph: Multi-Step Research Workflows

The `ask` graph implements a sophisticated "question-answer" workflow designed for research tasks. Defined in [`open_notebook/graphs/ask.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/ask.py), this graph orchestrates strategy generation, vector searches, and answer synthesis through multiple coordinated steps.

### Strategy Generation and State Management

The graph uses `ThreadState` to store the original question, a generated `Strategy` object, intermediate answers, and the final response. It also utilizes `SubGraphState` within the `provide_answer` sub-graph to manage search terms, instructions, raw results, and retrieved IDs.

The workflow begins with `call_model_with_messages` prompting the model using the `ask/entry` template to produce a JSON-encoded `Strategy`. The `trigger_queries` node then creates **Send** edges to the `provide_answer` sub-graph for each search defined in the strategy.

### Vector Search and Answer Synthesis

Within the sub-graph, `provide_answer` executes vector searches using `vector_search` from [`open_notebook/domain/notebook.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/domain/notebook.py), then processes results using a second LLM call with the `ask/query_process` template. Finally, `write_final_answer` stitches all intermediate responses into a cohesive final answer using the `ask/final_answer` template.

Notably, the `ask` graph provisions three distinct models (`strategy_model`, `answer_model`, `final_answer_model`) allowing each step to utilize specialized LLM configurations.

```python

# open_notebook/graphs/ask.py (simplified)

from open_notebook.graphs.ask import graph as ask_graph

async def ask_endpoint(question: str):
    initial_state = {"question": question}
    # Orchestrates strategy, searches, and final answer

    result = await ask_graph.ainvoke(initial_state)
    return result["final_answer"]

```

## The Source_Chat Graph: Source-Aware Contextual Responses

The `source_chat` graph enables conversations grounded in specific sources such as PDFs, web pages, or notebook entries. Implemented in [`open_notebook/graphs/source_chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/source_chat.py), this graph enriches responses with source-specific insights and metadata.

### Context Building and State Structure

Operating on `SourceChatState`, the graph maintains the message list, target `source_id`, optional `Source` object, `SourceInsight` list, built `context` string, and `context_indicators` map. The state structure explicitly tracks which pieces of context were utilized during generation.

The `call_model_with_source_context` node leverages `ContextBuilder` from [`open_notebook/utils/context_builder.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/utils/context_builder.py) to construct rich source-specific context. This context includes insights, optional notes, and metadata, which is then rendered into a system prompt via the `source_chat/system` template.

### Execution Flow

After provisioning a chat-type model (max 8192 tokens) through `provision_langchain_model`, the graph invokes the LLM with the enriched context and returns the cleaned reply. The state is subsequently enriched with `source`, `insights`, formatted context, and usage indicators.

```python

# open_notebook/graphs/source_chat.py (simplified)

from open_notebook.graphs.source_chat import source_chat_graph

async def source_chat_endpoint(source_id: str, messages: list):
    state = {
        "source_id": source_id,
        "messages": messages,
    }
    result = await source_chat_graph.ainvoke(state)
    return result["messages"]  # Reply with source context

```

## Key Architectural Differences

Understanding the distinction between these three LangGraph implementations requires examining their execution models, state complexity, and context handling:

**State Complexity**
- **Chat**: Uses minimal `ThreadState` with basic message and notebook references
- **Ask**: Employs `ThreadState` plus `SubGraphState` for complex multi-step research workflows  
- **Source_Chat**: Utilizes `SourceChatState` with rich domain-specific fields for source tracking

**Context Retrieval**
- **Chat**: No additional context retrieval beyond optional notebook objects
- **Ask**: Dynamically builds search context through vector searches during execution
- **Source_Chat**: Pre-builds comprehensive context via `ContextBuilder` before model invocation

**Execution Model**
- **Chat and Source_Chat**: Execute from synchronous entry points, spinning up temporary event loops for async provisioning
- **Ask**: Fully async to accommodate `await` operations for vector searches and multiple LLM calls

**Model Provisioning**
All three graphs use `provision_langchain_model` from [`open_notebook/ai/provision.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/ai/provision.py), but `ask` uniquely provisions three separate model instances for different workflow stages, while `chat` and `source_chat` use single chat-type models.

## Summary

- **Chat Graph** ([`open_notebook/graphs/chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/chat.py)): Provides simple one-turn conversational responses using minimal state and no external data retrieval
- **Ask Graph** ([`open_notebook/graphs/ask.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/ask.py)): Implements multi-step research workflows with strategy generation, vector searches, and synthesized answers using `ThreadState` and `SubGraphState`
- **Source_Chat Graph** ([`open_notebook/graphs/source_chat.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/graphs/source_chat.py)): Delivers source-aware responses by building rich context through `ContextBuilder` and tracking insight utilization via `SourceChatState`

## Frequently Asked Questions

### When should I use the ask graph versus the chat graph?

Use the `ask` graph when you need to perform research across multiple sources and synthesize information into a comprehensive answer. The `ask` graph generates search strategies, executes vector searches, and processes results through multiple LLM calls. Use the `chat` graph for simple conversational exchanges where you only need a direct response to user messages without retrieving external documents or sources.

### What makes source_chat different from standard chat implementations?

The `source_chat` graph differs from standard chat by accepting a specific `source_id` and building enriched context using `ContextBuilder` before model invocation. While the `chat` graph operates on generic `ThreadState` with minimal context, `source_chat` uses `SourceChatState` to track `SourceInsight` objects, context indicators, and metadata from a specific source. This ensures responses are grounded in the particular document or entry referenced by the user.

### How does the ask graph handle multiple search queries?

The `ask` graph processes multiple queries through LangGraph's **Send** edges. After the `trigger_queries` node generates a strategy, it creates parallel execution paths to the `provide_answer` sub-graph for each search term. Each sub-graph execution performs its own vector search and LLM processing independently, with results aggregated in the parent state's intermediate answers list before `write_final_answer` synthesizes the final response.

### Can I customize the model used for each graph?

Yes, all three graphs support model customization through the `provision_langchain_model` function in [`open_notebook/ai/provision.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/ai/provision.py). The `chat` and `source_chat` graphs accept a `model_override` parameter in their state, while the `ask` graph explicitly provisions three different models (`strategy_model`, `answer_model`, `final_answer_model`) allowing you to assign different LLM configurations to strategy generation, individual answer synthesis, and final answer composition respectively.