Building a guided conversational chatbot with GraphRAG
The GraphRAG service in AnalyticDB for PostgreSQL uses decision trees to power multi-turn, guided customer service conversations. Instead of free-form retrieval augmented generation (RAG), GraphRAG navigates a structured question tree to narrow down user problems and deliver precise solutions—making it well suited for after-sales support, fault diagnosis, and other scenarios where the conversation path is known in advance.
How it works
A decision tree organizes diagnostic knowledge as a hierarchy of questions and answers:
Root node: the opening question
Internal nodes: follow-up questions that narrow the problem
Branches: the user's possible responses
Leaf nodes: the final resolution or action
GraphRAG stores this tree as a knowledge graph in AnalyticDB for PostgreSQL and uses semantic similarity to match user replies to the correct branch at each turn. When a user's reply is semantically closer to a node deeper in the tree than to the immediate next step, GraphRAG can skip intermediate questions and jump directly to the relevant node. This reduces unnecessary back-and-forth while still delivering the right answer.
A simple air conditioner decision tree looks like this:
How semantic matching works at runtime:
At each conversation turn, GraphRAG runs two searches in parallel:
Local search: finds the best-matching child node of the current node
Global search: finds the best-matching node across the entire tree
If the global search score exceeds the local search score by at least global_distance_threshold (default: 0.1), GraphRAG jumps directly to the globally matched node, skipping intermediate steps. Adjust this threshold to control how aggressively GraphRAG takes shortcuts: lower values trigger jumps more readily, higher values keep the conversation on the sequential path.
Prerequisites
Before you begin, make sure you have:
An AnalyticDB for PostgreSQL 7.0 instance with minor engine version 7.2.1.3 or later
Versions 7.3.0.0 and 7.3.1.0 do not support the
adbpg_graphragextension. To check your instance's minor engine version, go to the Basic Information page in the AnalyticDB for PostgreSQL console. To upgrade, see Update the minor engine version.The
plpython3uandageextensions installed (see Install extensions)The
adbpg_graphragextension installed by technical support (see step 3 below)
Install extensions
On instances with minor engine version 7.2.1.4 or later, plpython3u, age, and adbpg_graphrag are installed automatically. Skip to adding ag_catalog to the search path.
For earlier versions, install the three extensions in order:
1. Verify the plpython3u extension
The plpython3u extension is installed by default. Confirm it is active in your target database:
SELECT * FROM pg_extension WHERE extname = 'plpython3u';Expected output:
oid | extname | extowner | extnamespace | extrelocatable | extversion | extconfig | extcondition
-------+------------+----------+--------------+----------------+------------+-----------+--------------
14674 | plpython3u | 10 | 11 | f | 1.0 | |
(1 row)If no rows are returned, install the plpython3u extension before continuing.
2. Configure the age extension
Install the Apache AGE extension, then add ag_catalog to the search path so you can run graph queries without schema-qualifying every statement.
For the current session only:
SET search_path TO "$user", public, ag_catalog;Permanently for the database:
ALTER DATABASE <database_name> SET search_path TO "$user", public, ag_catalog;To let other users run graph queries, grant them access to the ag_catalog schema. Use the initial account or a privileged user with the RDS_SUPERUSER role:
GRANT USAGE ON SCHEMA ag_catalog TO <username>;3. Install the adbpg_graphrag extension
The adbpg_graphrag extension depends on plpython3u and age. Contact technical support to install it after confirming those two extensions are active.
Set up GraphRAG
Step 1: Initialize the service
Call adbpg_graphrag.initialize with a JSON configuration object to set up the service.
SELECT adbpg_graphrag.initialize(config json);Parameters
| Parameter | Description | Default |
|---|---|---|
llm_model | Large language model (LLM) used for conversation | qwen-max-2025-01-25 |
embedding_model | Embedding model used for similarity search | text-embedding-v3 |
language | Language for responses. Options: English, Simplified Chinese | English |
entity_types | Entity node types to extract when building the knowledge graph | — |
relationship_types | Relationship edge types to extract when building the knowledge graph | — |
first_node_content | Opening message sent at the start of every conversation | Hello, how can I help you? |
end_node_content | Closing message sent after the final resolution is reached | Are there any other questions? |
global_distance_threshold | Controls jump navigation. If the global search score exceeds the local search score by at least this value, GraphRAG skips intermediate nodes and jumps to the globally matched node. Lower values trigger jumps more aggressively; higher values keep the conversation closer to the sequential path. | 0.1 |
Step 2: Import a decision tree
Decision trees are imported as Markdown-formatted text. Indentation defines the parent-child relationship between nodes.
Air conditioner example tree:
Hello, how can I help you?
The air conditioner's cooling effect is poor
Is the machine not blowing air or not cooling
The machine is not cooling
Please provide the operating mode of the air conditioner
Cooling mode
Has the filter not been cleaned for a long time
Yes
Please clean the filter and then observe the cooling performance of the air conditioner
No
Please call our repair hotline, a maintenance engineer will visit for inspection
Non-cooling mode
Please switch to cooling mode
The machine is not blowing air
Does the air conditioner display a sensor fault
Yes
Please power off the air conditioner for 3 minutes and restart it, to see if it returns to normal
No
Please call our repair hotline, a maintenance engineer will visit for inspection
No more issues
CompleteTwo import methods are available:
Import directly
Pass the tree content directly to upload_decision_tree:
SELECT adbpg_graphrag.upload_decision_tree(original_content text, root_content text);| Parameter | Description |
|---|---|
original_content | All tree content excluding the root node |
root_content | The root node text |
Example:
SELECT adbpg_graphrag.upload_decision_tree(
'The air conditioner''s cooling effect is poor
Is the machine not blowing air or not cooling
The machine is not cooling
Please provide the operating mode of the air conditioner
Cooling mode
Has the filter not been cleaned for a long time
Yes
Please clean the filter and then observe the cooling performance of the air conditioner
No
Please call our repair hotline, a maintenance engineer will visit for inspection
Non-cooling mode
Please switch to cooling mode
The machine is not blowing air
Does the air conditioner display a sensor fault
Yes
Please power off the air conditioner for 3 minutes and restart it, to see if it returns to normal
No
Please call our repair hotline, a maintenance engineer will visit for inspection
No more issues
Complete',
'Hello, how can I help you?'
);Import from a table
For larger trees or programmatic workflows, store the tree in a table first.
Create the table and insert the tree content:
CREATE TABLE documents_text (id integer, original_content text); INSERT INTO documents_text VALUES (1, 'The air conditioner''s cooling effect is poor Is the machine not blowing air or not cooling The machine is not cooling Please provide the operating mode of the air conditioner Cooling mode Has the filter not been cleaned for a long time Yes Please clean the filter and then observe the cooling performance of the air conditioner No Please call our repair hotline, a maintenance engineer will visit for inspection Non-cooling mode Please switch to cooling mode The machine is not blowing air Does the air conditioner display a sensor fault Yes Please power off the air conditioner for 3 minutes and restart it, to see if it returns to normal No Please call our repair hotline, a maintenance engineer will visit for inspection No more issues Complete');Import the tree from the table:
SELECT adbpg_graphrag.upload_decision_tree(original_content, 'Hello, how can I help you?') FROM documents_text WHERE id = 1;
Run multi-turn conversations
All conversations use adbpg_graphrag.query('user input', 'tree'). GraphRAG maintains session state between calls and advances the tree based on semantic matching.
Sequential conversation
Each response follows the next node in the tree:
Round 1:
SELECT adbpg_graphrag.query('Hello', 'tree'); query
--------------------------
Hello, how can I help you?
(1 row)Round 2:
SELECT adbpg_graphrag.query('The air conditioner is not cooling', 'tree'); query
--------------------------------
Is the machine not blowing air or not cooling
(1 row)Round 3:
SELECT adbpg_graphrag.query('The air conditioner is not blowing air', 'tree'); query
---------------------------
Does the air conditioner display a sensor fault
(1 row)Round 4:
SELECT adbpg_graphrag.query('Yes', 'tree'); query
-----------------------------------------
Please power off the air conditioner for 3 minutes and restart it, to see if it returns to normal
(1 row)Round 5:
SELECT adbpg_graphrag.query('OK', 'tree'); query
--------------------------
Do you have any other questions?
(1 row)Jump navigation
When a user's reply is semantically closer to a deeper node than to the immediate next question, GraphRAG jumps directly to that node—skipping intermediate steps. The global_distance_threshold parameter controls how sensitive this behavior is.
Round 1:
SELECT adbpg_graphrag.query('Hello', 'tree'); query
--------------------------
Hello, how can I help you?
(1 row)Round 2 — the user describes the problem specifically, so GraphRAG jumps past the intermediate question:
SELECT adbpg_graphrag.query('The machine is not blowing air', 'tree'); query
---------------------------
Does the air conditioner display a sensor fault
(1 row)Round 3:
SELECT adbpg_graphrag.query('It shows F1 error code', 'tree'); query
--------------------------------------------
Please call our repair hotline, a maintenance engineer will visit for inspection
(1 row)Round 4:
SELECT adbpg_graphrag.query('good', 'tree'); query
--------------------------
Do you have any other questions?
(1 row)Reset the conversation
To start a new conversation, clear the session state:
SELECT adbpg_graphrag.reset_tree_query(); reset_tree_query
-------------------------------
Successful! Reset Tree Query.
(1 row)Manage decision trees
After importing a tree, you can add or remove subtrees without reimporting the entire tree.
All tree management operations require the entity_id of the target node. Get it using one of these methods:
Age-Viewer: Open the Age-Viewer visualization tool and hover over the node.
Cypher query: Run the following to list all nodes and their IDs:
SELECT * FROM cypher('chunk_entity_relation', $$ MATCH (V)-[R:DIRECTED]-(V2) RETURN V, R, V2 $$) AS (V agtype, R agtype, V2 agtype);
Add a subtree
Append a new subtree under an existing node:
SELECT adbpg_graphrag.append_decision_tree(context text, root_node_id text);| Parameter | Description |
|---|---|
context | Markdown-formatted subtree content to append |
root_node_id | The entity_id of the node to attach the subtree to |
Delete a subtree
Remove a node and all its descendants:
SELECT adbpg_graphrag.delete_decision_tree(root_node_entity text);| Parameter | Description |
|---|---|
root_node_entity | The entity_id of the subtree root to delete |