graphrag_sdk 0.3.0__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/PKG-INFO +46 -16
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/README.md +44 -15
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/agents/kg_agent.py +1 -1
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/chat_session.py +36 -10
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/fixtures/prompts.py +5 -4
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/kg.py +58 -10
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/models/azure_openai.py +32 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/models/gemini.py +23 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/models/ollama.py +32 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/models/openai.py +32 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/orchestrator/orchestrator.py +5 -5
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/steps/graph_query_step.py +12 -21
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/steps/qa_step.py +5 -6
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/pyproject.toml +2 -1
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/LICENSE +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/__init__.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/agents/__init__.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/agents/agent.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/attribute.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/document.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/document_loaders/__init__.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/document_loaders/csv.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/document_loaders/html.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/document_loaders/jsonl.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/document_loaders/pdf.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/document_loaders/text.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/document_loaders/url.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/entity.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/fixtures/regex.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/helpers.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/model_config.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/models/__init__.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/models/model.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/ontology.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/orchestrator/__init__.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/orchestrator/execution_plan.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/orchestrator/orchestrator_decision.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/orchestrator/orchestrator_runner.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/orchestrator/step.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/orchestrator/step_result.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/orchestrator/steps/__init__.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/orchestrator/steps/agent.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/orchestrator/steps/parallel.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/orchestrator/steps/summary.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/orchestrator/steps/user_input.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/relation.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/source.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/steps/Step.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/steps/create_ontology_step.py +0 -0
- {graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/steps/extract_data_step.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: graphrag_sdk
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary:
|
|
5
5
|
Home-page: http://RAG-SDK.readthedocs.io
|
|
6
6
|
License: MIT
|
|
@@ -32,6 +32,7 @@ Requires-Dist: pypdf (>=4.2.0,<5.0.0)
|
|
|
32
32
|
Requires-Dist: python-abc (>=0.2.0,<0.3.0)
|
|
33
33
|
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
|
34
34
|
Requires-Dist: ratelimit (>=2.2.1,<3.0.0)
|
|
35
|
+
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
|
35
36
|
Requires-Dist: typing-extensions (>=4.12.1,<5.0.0)
|
|
36
37
|
Requires-Dist: vertexai (>=1.49.0,<2.0.0) ; extra == "all" or extra == "vertexai"
|
|
37
38
|
Project-URL: Repository, https://github.com/FalkorDB/GraphRAG-SDK
|
|
@@ -86,19 +87,9 @@ docker run -p 6379:6379 -p 3000:3000 -it --rm -v ./data:/data falkordb/falkordb
|
|
|
86
87
|
Currently, this SDK supports the following LLMs API:
|
|
87
88
|
|
|
88
89
|
* [OpenAI](https://openai.com/index/openai-api) Recommended model:`gpt-4o`
|
|
89
|
-
* [
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
<details>
|
|
94
|
-
<summary>.env</summary>
|
|
95
|
-
|
|
96
|
-
```
|
|
97
|
-
OPENAI_API_KEY="OPENAI_API_KEY"
|
|
98
|
-
GOOGLE_API_KEY="GOOGLE_API_KEY"
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
</details>
|
|
90
|
+
* [Google](https://makersuite.google.com/app/apikey) Recommended model:`gemini-1.5-flash-001`
|
|
91
|
+
* [Azure-OpenAI](https://ai.azure.com) Recommended model:`gpt-4o`
|
|
92
|
+
* [Ollama](https://ollama.com/) Available only to the Q&A step. Recommended models: `llama3`. Ollama models are suitable for the Q&A step only (after the knowledge graph (KG) created).
|
|
102
93
|
|
|
103
94
|
## Basic Usage
|
|
104
95
|
|
|
@@ -219,9 +210,9 @@ After generating the initial ontology, you can review it and make any necessary
|
|
|
219
210
|
|
|
220
211
|
Once you are satisfied with the ontology, you can proceed to use it for creating and managing your Knowledge Graph (KG).
|
|
221
212
|
|
|
222
|
-
### Knowledge Graph
|
|
213
|
+
### Knowledge Graph Agent
|
|
223
214
|
|
|
224
|
-
Now, you can use the SDK to create a Knowledge Graph (KG) from your sources and ontology.
|
|
215
|
+
Now, you can use the SDK to create a Knowledge Graph (KG) from your sources and ontology for Q&A.
|
|
225
216
|
|
|
226
217
|
```python
|
|
227
218
|
# After approving the ontology, load it from disk.
|
|
@@ -240,6 +231,45 @@ kg.process_sources(sources)
|
|
|
240
231
|
|
|
241
232
|
You can update the KG at any time by processing more sources with the `process_sources` method.
|
|
242
233
|
|
|
234
|
+
#### Configurable Prompts
|
|
235
|
+
When creating your Knowledge Graph (KG) agent, you can customize the prompts to tailor its behavior. This step is optional but can enhance functionality.
|
|
236
|
+
|
|
237
|
+
There are five types of prompts:
|
|
238
|
+
|
|
239
|
+
1. **`cypher_system_instruction`**
|
|
240
|
+
- System instructions for the Cypher generation step.
|
|
241
|
+
- **Note:** Ensure your prompt includes `{ontology}`.
|
|
242
|
+
|
|
243
|
+
2. **`qa_system_instruction`**
|
|
244
|
+
- System instructions for the Q&A step.
|
|
245
|
+
|
|
246
|
+
3. **`cypher_gen_prompt`**
|
|
247
|
+
- The prompt used during the Cypher generation step.
|
|
248
|
+
- **Note:** Include `{question}` in your prompt.
|
|
249
|
+
|
|
250
|
+
4. **`cypher_gen_prompt_history`**
|
|
251
|
+
- The prompt for Cypher generation when history needs to be considered.
|
|
252
|
+
- **Note:** Include `{question}` and `{last_answer}` in your prompt.
|
|
253
|
+
|
|
254
|
+
5. **`qa_prompt`**
|
|
255
|
+
- The prompt used during the Q&A step.
|
|
256
|
+
- **Note:** Include `{question}`, `{context}`, and `{cypher}` in your prompt.
|
|
257
|
+
|
|
258
|
+
Here’s an example configuration:
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
kg = KnowledgeGraph(
|
|
262
|
+
name="kg_name",
|
|
263
|
+
model_config=KnowledgeGraphModelConfig.with_model(model),
|
|
264
|
+
ontology=ontology,
|
|
265
|
+
cypher_system_instruction=cypher_system_instruction,
|
|
266
|
+
qa_system_instruction=qa_system_instruction,
|
|
267
|
+
cypher_gen_prompt=cypher_gen_prompt,
|
|
268
|
+
cypher_gen_prompt_history=cypher_gen_prompt_history,
|
|
269
|
+
qa_prompt=qa_prompt
|
|
270
|
+
)
|
|
271
|
+
```
|
|
272
|
+
|
|
243
273
|
### Graph RAG
|
|
244
274
|
|
|
245
275
|
At this point, you have a Knowledge Graph that can be queried using this SDK. Use the method `chat_session` for start a conversation.
|
|
@@ -47,19 +47,9 @@ docker run -p 6379:6379 -p 3000:3000 -it --rm -v ./data:/data falkordb/falkordb
|
|
|
47
47
|
Currently, this SDK supports the following LLMs API:
|
|
48
48
|
|
|
49
49
|
* [OpenAI](https://openai.com/index/openai-api) Recommended model:`gpt-4o`
|
|
50
|
-
* [
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
<details>
|
|
55
|
-
<summary>.env</summary>
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
OPENAI_API_KEY="OPENAI_API_KEY"
|
|
59
|
-
GOOGLE_API_KEY="GOOGLE_API_KEY"
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
</details>
|
|
50
|
+
* [Google](https://makersuite.google.com/app/apikey) Recommended model:`gemini-1.5-flash-001`
|
|
51
|
+
* [Azure-OpenAI](https://ai.azure.com) Recommended model:`gpt-4o`
|
|
52
|
+
* [Ollama](https://ollama.com/) Available only to the Q&A step. Recommended models: `llama3`. Ollama models are suitable for the Q&A step only (after the knowledge graph (KG) created).
|
|
63
53
|
|
|
64
54
|
## Basic Usage
|
|
65
55
|
|
|
@@ -180,9 +170,9 @@ After generating the initial ontology, you can review it and make any necessary
|
|
|
180
170
|
|
|
181
171
|
Once you are satisfied with the ontology, you can proceed to use it for creating and managing your Knowledge Graph (KG).
|
|
182
172
|
|
|
183
|
-
### Knowledge Graph
|
|
173
|
+
### Knowledge Graph Agent
|
|
184
174
|
|
|
185
|
-
Now, you can use the SDK to create a Knowledge Graph (KG) from your sources and ontology.
|
|
175
|
+
Now, you can use the SDK to create a Knowledge Graph (KG) from your sources and ontology for Q&A.
|
|
186
176
|
|
|
187
177
|
```python
|
|
188
178
|
# After approving the ontology, load it from disk.
|
|
@@ -201,6 +191,45 @@ kg.process_sources(sources)
|
|
|
201
191
|
|
|
202
192
|
You can update the KG at any time by processing more sources with the `process_sources` method.
|
|
203
193
|
|
|
194
|
+
#### Configurable Prompts
|
|
195
|
+
When creating your Knowledge Graph (KG) agent, you can customize the prompts to tailor its behavior. This step is optional but can enhance functionality.
|
|
196
|
+
|
|
197
|
+
There are five types of prompts:
|
|
198
|
+
|
|
199
|
+
1. **`cypher_system_instruction`**
|
|
200
|
+
- System instructions for the Cypher generation step.
|
|
201
|
+
- **Note:** Ensure your prompt includes `{ontology}`.
|
|
202
|
+
|
|
203
|
+
2. **`qa_system_instruction`**
|
|
204
|
+
- System instructions for the Q&A step.
|
|
205
|
+
|
|
206
|
+
3. **`cypher_gen_prompt`**
|
|
207
|
+
- The prompt used during the Cypher generation step.
|
|
208
|
+
- **Note:** Include `{question}` in your prompt.
|
|
209
|
+
|
|
210
|
+
4. **`cypher_gen_prompt_history`**
|
|
211
|
+
- The prompt for Cypher generation when history needs to be considered.
|
|
212
|
+
- **Note:** Include `{question}` and `{last_answer}` in your prompt.
|
|
213
|
+
|
|
214
|
+
5. **`qa_prompt`**
|
|
215
|
+
- The prompt used during the Q&A step.
|
|
216
|
+
- **Note:** Include `{question}`, `{context}`, and `{cypher}` in your prompt.
|
|
217
|
+
|
|
218
|
+
Here’s an example configuration:
|
|
219
|
+
|
|
220
|
+
```python
|
|
221
|
+
kg = KnowledgeGraph(
|
|
222
|
+
name="kg_name",
|
|
223
|
+
model_config=KnowledgeGraphModelConfig.with_model(model),
|
|
224
|
+
ontology=ontology,
|
|
225
|
+
cypher_system_instruction=cypher_system_instruction,
|
|
226
|
+
qa_system_instruction=qa_system_instruction,
|
|
227
|
+
cypher_gen_prompt=cypher_gen_prompt,
|
|
228
|
+
cypher_gen_prompt_history=cypher_gen_prompt_history,
|
|
229
|
+
qa_prompt=qa_prompt
|
|
230
|
+
)
|
|
231
|
+
```
|
|
232
|
+
|
|
204
233
|
### Graph RAG
|
|
205
234
|
|
|
206
235
|
At this point, you have a Knowledge Graph that can be queried using this SDK. Use the method `chat_session` for start a conversation.
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
from falkordb import Graph
|
|
1
2
|
from graphrag_sdk.ontology import Ontology
|
|
3
|
+
from graphrag_sdk.steps.qa_step import QAStep
|
|
2
4
|
from graphrag_sdk.model_config import KnowledgeGraphModelConfig
|
|
3
5
|
from graphrag_sdk.steps.graph_query_step import GraphQueryGenerationStep
|
|
4
|
-
from graphrag_sdk.steps.qa_step import QAStep
|
|
5
|
-
from graphrag_sdk.fixtures.prompts import GRAPH_QA_SYSTEM, CYPHER_GEN_SYSTEM
|
|
6
|
-
from falkordb import Graph
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
class ChatSession:
|
|
@@ -25,7 +24,9 @@ class ChatSession:
|
|
|
25
24
|
>>> chat_session.send_message("What is the capital of France?")
|
|
26
25
|
"""
|
|
27
26
|
|
|
28
|
-
def __init__(self, model_config: KnowledgeGraphModelConfig, ontology: Ontology, graph: Graph
|
|
27
|
+
def __init__(self, model_config: KnowledgeGraphModelConfig, ontology: Ontology, graph: Graph,
|
|
28
|
+
cypher_system_instruction: str, qa_system_instruction: str,
|
|
29
|
+
cypher_gen_prompt: str, qa_prompt: str, cypher_gen_prompt_history: str):
|
|
29
30
|
"""
|
|
30
31
|
Initializes a new ChatSession object.
|
|
31
32
|
|
|
@@ -44,14 +45,21 @@ class ChatSession:
|
|
|
44
45
|
self.model_config = model_config
|
|
45
46
|
self.graph = graph
|
|
46
47
|
self.ontology = ontology
|
|
48
|
+
cypher_system_instruction = cypher_system_instruction.format(ontology=str(ontology.to_json()))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
self.cypher_prompt = cypher_gen_prompt
|
|
52
|
+
self.qa_prompt = qa_prompt
|
|
53
|
+
self.cypher_prompt_with_history = cypher_gen_prompt_history
|
|
54
|
+
|
|
47
55
|
self.cypher_chat_session = (
|
|
48
56
|
model_config.cypher_generation.with_system_instruction(
|
|
49
|
-
|
|
57
|
+
cypher_system_instruction
|
|
50
58
|
).start_chat()
|
|
51
59
|
)
|
|
52
60
|
self.qa_chat_session = model_config.qa.with_system_instruction(
|
|
53
|
-
|
|
54
|
-
|
|
61
|
+
qa_system_instruction
|
|
62
|
+
).start_chat()
|
|
55
63
|
self.last_answer = None
|
|
56
64
|
|
|
57
65
|
def send_message(self, message: str):
|
|
@@ -62,24 +70,42 @@ class ChatSession:
|
|
|
62
70
|
message (str): The message to send.
|
|
63
71
|
|
|
64
72
|
Returns:
|
|
65
|
-
|
|
73
|
+
dict: The response to the message in the following format:
|
|
74
|
+
{"question": message,
|
|
75
|
+
"response": answer,
|
|
76
|
+
"context": context,
|
|
77
|
+
"cypher": cypher}
|
|
66
78
|
"""
|
|
67
79
|
cypher_step = GraphQueryGenerationStep(
|
|
68
80
|
graph=self.graph,
|
|
69
81
|
chat_session=self.cypher_chat_session,
|
|
70
82
|
ontology=self.ontology,
|
|
71
83
|
last_answer=self.last_answer,
|
|
84
|
+
cypher_prompt=self.cypher_prompt,
|
|
85
|
+
cypher_prompt_with_history=self.cypher_prompt_with_history
|
|
72
86
|
)
|
|
73
87
|
|
|
74
88
|
(context, cypher) = cypher_step.run(message)
|
|
75
89
|
|
|
76
90
|
if not cypher or len(cypher) == 0:
|
|
77
|
-
return
|
|
91
|
+
return {
|
|
92
|
+
"question": message,
|
|
93
|
+
"response": "I am sorry, I could not find the answer to your question",
|
|
94
|
+
"context": None,
|
|
95
|
+
"cypher": None
|
|
96
|
+
}
|
|
78
97
|
|
|
79
98
|
qa_step = QAStep(
|
|
80
99
|
chat_session=self.qa_chat_session,
|
|
100
|
+
qa_prompt=self.qa_prompt,
|
|
81
101
|
)
|
|
82
102
|
|
|
83
103
|
answer = qa_step.run(message, cypher, context)
|
|
84
104
|
self.last_answer = answer
|
|
85
|
-
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
"question": message,
|
|
108
|
+
"response": answer,
|
|
109
|
+
"context": context,
|
|
110
|
+
"cypher": cypher
|
|
111
|
+
}
|
|
@@ -429,7 +429,7 @@ Single-Pair minimal-weight paths: Find minimal-weight paths between a pair of en
|
|
|
429
429
|
Single-Source minimal-weight paths: Find minimal-weight paths from a given source entity using algo.SSpaths().
|
|
430
430
|
|
|
431
431
|
Ontology:
|
|
432
|
-
|
|
432
|
+
{ontology}
|
|
433
433
|
|
|
434
434
|
|
|
435
435
|
For example, given the question "Which managers own Neo4j stocks?", the OpenCypher statement should look like this:
|
|
@@ -441,9 +441,10 @@ RETURN m, s
|
|
|
441
441
|
"""
|
|
442
442
|
|
|
443
443
|
CYPHER_GEN_PROMPT = """
|
|
444
|
-
Using the ontology provided, generate an OpenCypher statement to query the graph database returning all relevant entities, relationships, and attributes to answer the question below
|
|
445
|
-
If you cannot generate a OpenCypher statement for any reason, return an empty
|
|
444
|
+
Using the ontology provided, generate an OpenCypher statement to query the graph database returning all relevant entities, relationships, and attributes to answer the question below.
|
|
445
|
+
If you cannot generate a OpenCypher statement for any reason, return an empty response.
|
|
446
446
|
Respect the order of the relationships, the arrows should always point from the "source" to the "target".
|
|
447
|
+
Please think if your answer is a valid Cypher query, and correct it if it is not.
|
|
447
448
|
|
|
448
449
|
Question: {question}
|
|
449
450
|
"""
|
|
@@ -481,8 +482,8 @@ The information part contains the provided information that you must use to cons
|
|
|
481
482
|
The provided information is authoritative, you must never doubt it or try to use your internal knowledge to correct it.
|
|
482
483
|
Make the answer sound as a response to the question. Do not mention that you based the result on the given information.
|
|
483
484
|
Do not answer more than the question asks for.
|
|
484
|
-
Here is an example:
|
|
485
485
|
|
|
486
|
+
Here is an example:
|
|
486
487
|
Question: Which managers own Neo4j stocks?
|
|
487
488
|
Context:[manager:CTL LLC, manager:JANE STREET GROUP LLC]
|
|
488
489
|
Helpful Answer: CTL LLC, JANE STREET GROUP LLC owns Neo4j stocks.
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
|
|
2
|
+
import warnings
|
|
3
3
|
from falkordb import FalkorDB
|
|
4
|
+
from graphrag_sdk.ontology import Ontology
|
|
4
5
|
from graphrag_sdk.source import AbstractSource
|
|
5
|
-
from graphrag_sdk.model_config import KnowledgeGraphModelConfig
|
|
6
|
-
from graphrag_sdk.steps.extract_data_step import ExtractDataStep
|
|
7
|
-
from graphrag_sdk.steps.graph_query_step import GraphQueryGenerationStep
|
|
8
|
-
from graphrag_sdk.fixtures.prompts import GRAPH_QA_SYSTEM, CYPHER_GEN_SYSTEM
|
|
9
|
-
from graphrag_sdk.steps.qa_step import QAStep
|
|
10
6
|
from graphrag_sdk.chat_session import ChatSession
|
|
11
|
-
from graphrag_sdk.helpers import map_dict_to_cypher_properties
|
|
12
7
|
from graphrag_sdk.attribute import AttributeType, Attribute
|
|
13
|
-
from graphrag_sdk.
|
|
8
|
+
from graphrag_sdk.helpers import map_dict_to_cypher_properties
|
|
9
|
+
from graphrag_sdk.model_config import KnowledgeGraphModelConfig
|
|
10
|
+
from graphrag_sdk.steps.extract_data_step import ExtractDataStep
|
|
11
|
+
from graphrag_sdk.fixtures.prompts import (GRAPH_QA_SYSTEM, CYPHER_GEN_SYSTEM,
|
|
12
|
+
CYPHER_GEN_PROMPT, GRAPH_QA_PROMPT, CYPHER_GEN_PROMPT_WITH_HISTORY)
|
|
14
13
|
|
|
15
14
|
logger = logging.getLogger(__name__)
|
|
16
15
|
logger.setLevel(logging.DEBUG)
|
|
@@ -31,6 +30,11 @@ class KnowledgeGraph:
|
|
|
31
30
|
port: int = 6379,
|
|
32
31
|
username: str | None = None,
|
|
33
32
|
password: str | None = None,
|
|
33
|
+
cypher_system_instruction: str = None,
|
|
34
|
+
qa_system_instruction: str = None,
|
|
35
|
+
cypher_gen_prompt: str = None,
|
|
36
|
+
qa_prompt: str = None,
|
|
37
|
+
cypher_gen_prompt_history: str = None,
|
|
34
38
|
):
|
|
35
39
|
"""
|
|
36
40
|
Initialize Knowledge Graph
|
|
@@ -43,6 +47,11 @@ class KnowledgeGraph:
|
|
|
43
47
|
username (str|None): FalkorDB username.
|
|
44
48
|
password (str|None): FalkorDB password.
|
|
45
49
|
ontology (Ontology|None): Ontology to use.
|
|
50
|
+
cypher_system_instruction (str|None): Cypher system instruction. Make sure you have {ontology} in the instruction.
|
|
51
|
+
qa_system_instruction (str|None): QA system instruction.
|
|
52
|
+
cypher_gen_prompt (str|None): Cypher generation prompt. Make sure you have {question} in the prompt.
|
|
53
|
+
qa_prompt (str|None): QA prompt. Make sure you have {question}, {context} and {cypher} in the prompt.
|
|
54
|
+
cypher_gen_prompt_history (str|None): Cypher generation prompt with history. Make sure you have {question} and {last_answer} in the prompt.
|
|
46
55
|
"""
|
|
47
56
|
|
|
48
57
|
if not isinstance(name, str) or name == "":
|
|
@@ -57,6 +66,44 @@ class KnowledgeGraph:
|
|
|
57
66
|
self._model_config = model_config
|
|
58
67
|
self.sources = set([])
|
|
59
68
|
|
|
69
|
+
if cypher_system_instruction is None:
|
|
70
|
+
cypher_system_instruction = CYPHER_GEN_SYSTEM
|
|
71
|
+
else:
|
|
72
|
+
if "{ontology}" not in cypher_system_instruction:
|
|
73
|
+
warnings.warn("Cypher system instruction should contain {ontology}", category=UserWarning)
|
|
74
|
+
|
|
75
|
+
if qa_system_instruction is None:
|
|
76
|
+
qa_system_instruction = GRAPH_QA_SYSTEM
|
|
77
|
+
|
|
78
|
+
if cypher_gen_prompt is None:
|
|
79
|
+
cypher_gen_prompt = CYPHER_GEN_PROMPT
|
|
80
|
+
else:
|
|
81
|
+
if "{question}" not in cypher_gen_prompt:
|
|
82
|
+
raise Exception("Cypher generation prompt should contain {question}")
|
|
83
|
+
|
|
84
|
+
if qa_prompt is None:
|
|
85
|
+
qa_prompt = GRAPH_QA_PROMPT
|
|
86
|
+
else:
|
|
87
|
+
if "{question}" not in qa_prompt or "{context}" not in qa_prompt:
|
|
88
|
+
raise Exception("QA prompt should contain {question} and {context}")
|
|
89
|
+
if "{cypher}" not in qa_prompt:
|
|
90
|
+
warnings.warn("QA prompt should contain {cypher}", category=UserWarning)
|
|
91
|
+
|
|
92
|
+
if cypher_gen_prompt_history is None:
|
|
93
|
+
cypher_gen_prompt_history = CYPHER_GEN_PROMPT_WITH_HISTORY
|
|
94
|
+
else:
|
|
95
|
+
if "{question}" not in cypher_gen_prompt_history:
|
|
96
|
+
raise Exception("Cypher generation prompt with history should contain {question}")
|
|
97
|
+
if "{last_answer}" not in cypher_gen_prompt_history:
|
|
98
|
+
warnings.warn("Cypher generation prompt with history should contain {last_answer}", category=UserWarning)
|
|
99
|
+
|
|
100
|
+
# Assign the validated values
|
|
101
|
+
self.cypher_system_instruction = cypher_system_instruction
|
|
102
|
+
self.qa_system_instruction = qa_system_instruction
|
|
103
|
+
self.cypher_gen_prompt = cypher_gen_prompt
|
|
104
|
+
self.qa_prompt = qa_prompt
|
|
105
|
+
self.cypher_gen_prompt_history = cypher_gen_prompt_history
|
|
106
|
+
|
|
60
107
|
# Attributes
|
|
61
108
|
|
|
62
109
|
@property
|
|
@@ -135,8 +182,9 @@ class KnowledgeGraph:
|
|
|
135
182
|
setattr(self, key, None)
|
|
136
183
|
|
|
137
184
|
def chat_session(self) -> ChatSession:
|
|
138
|
-
|
|
139
|
-
|
|
185
|
+
chat_session = ChatSession(self._model_config, self.ontology, self.graph, self.cypher_system_instruction,
|
|
186
|
+
self.qa_system_instruction, self.cypher_gen_prompt, self.qa_prompt, self.cypher_gen_prompt_history)
|
|
187
|
+
return chat_session
|
|
140
188
|
def add_node(self, entity: str, attributes: dict):
|
|
141
189
|
"""
|
|
142
190
|
Add a node to the knowledge graph, checking if it matches the ontology
|
|
@@ -227,3 +227,35 @@ class AzureOpenAiChatSession(GenerativeModelChatSession):
|
|
|
227
227
|
config['response_format'] = { "type": "json_object" }
|
|
228
228
|
|
|
229
229
|
return config
|
|
230
|
+
|
|
231
|
+
def delete_last_message(self):
|
|
232
|
+
"""
|
|
233
|
+
Deletes the last message exchange (user message and assistant response) from the chat history.
|
|
234
|
+
Preserves the system message if present.
|
|
235
|
+
|
|
236
|
+
Example:
|
|
237
|
+
Before:
|
|
238
|
+
[
|
|
239
|
+
{"role": "system", "content": "System message"},
|
|
240
|
+
{"role": "user", "content": "User message"},
|
|
241
|
+
{"role": "assistant", "content": "Assistant response"},
|
|
242
|
+
]
|
|
243
|
+
After:
|
|
244
|
+
[
|
|
245
|
+
{"role": "system", "content": "System message"},
|
|
246
|
+
]
|
|
247
|
+
|
|
248
|
+
Note: Does nothing if the chat history is empty or contains only a system message.
|
|
249
|
+
"""
|
|
250
|
+
# Keep at least the system message if present
|
|
251
|
+
min_length = 1 if self._model.system_instruction else 0
|
|
252
|
+
if len(self._history) - 2 >= min_length:
|
|
253
|
+
self._history.pop()
|
|
254
|
+
self._history.pop()
|
|
255
|
+
else:
|
|
256
|
+
# Reset to initial state with just system message if present
|
|
257
|
+
self._history = (
|
|
258
|
+
[{"role": "system", "content": self._model.system_instruction}]
|
|
259
|
+
if self._model.system_instruction is not None
|
|
260
|
+
else []
|
|
261
|
+
)
|
|
@@ -117,3 +117,26 @@ class GeminiChatSession(GenerativeModelChatSession):
|
|
|
117
117
|
"temperature": 0
|
|
118
118
|
}
|
|
119
119
|
return self._model._generation_config
|
|
120
|
+
|
|
121
|
+
def delete_last_message(self):
|
|
122
|
+
"""
|
|
123
|
+
Deletes the last message exchange (user message and assistant response) from the chat history.
|
|
124
|
+
Preserves the system message if present.
|
|
125
|
+
|
|
126
|
+
Example:
|
|
127
|
+
Before:
|
|
128
|
+
[
|
|
129
|
+
{"role": "user", "content": "User message"},
|
|
130
|
+
{"role": "assistant", "content": "Assistant response"},
|
|
131
|
+
]
|
|
132
|
+
After:
|
|
133
|
+
[]
|
|
134
|
+
|
|
135
|
+
Note: Does nothing if the chat history is empty or contains only a system message.
|
|
136
|
+
"""
|
|
137
|
+
if len(self._chat_session.history) >= 2:
|
|
138
|
+
self._chat_session.history.pop()
|
|
139
|
+
self._chat_session.history.pop()
|
|
140
|
+
else:
|
|
141
|
+
self._chat_session.history = []
|
|
142
|
+
|
|
@@ -216,3 +216,35 @@ class OllamaChatSession(GenerativeModelChatSession):
|
|
|
216
216
|
config['format'] = 'json'
|
|
217
217
|
|
|
218
218
|
return config
|
|
219
|
+
|
|
220
|
+
def delete_last_message(self):
|
|
221
|
+
"""
|
|
222
|
+
Deletes the last message exchange (user message and assistant response) from the chat history.
|
|
223
|
+
Preserves the system message if present.
|
|
224
|
+
|
|
225
|
+
Example:
|
|
226
|
+
Before:
|
|
227
|
+
[
|
|
228
|
+
{"role": "system", "content": "System message"},
|
|
229
|
+
{"role": "user", "content": "User message"},
|
|
230
|
+
{"role": "assistant", "content": "Assistant response"},
|
|
231
|
+
]
|
|
232
|
+
After:
|
|
233
|
+
[
|
|
234
|
+
{"role": "system", "content": "System message"},
|
|
235
|
+
]
|
|
236
|
+
|
|
237
|
+
Note: Does nothing if the chat history is empty or contains only a system message.
|
|
238
|
+
"""
|
|
239
|
+
# Keep at least the system message if present
|
|
240
|
+
min_length = 1 if self._model.system_instruction else 0
|
|
241
|
+
if len(self._chat_history) - 2 >= min_length:
|
|
242
|
+
self._chat_history.pop()
|
|
243
|
+
self._chat_history.pop()
|
|
244
|
+
else:
|
|
245
|
+
# Reset to initial state with just system message if present
|
|
246
|
+
self._chat_history = (
|
|
247
|
+
[{"role": "system", "content": self._model.system_instruction}]
|
|
248
|
+
if self._model.system_instruction is not None
|
|
249
|
+
else []
|
|
250
|
+
)
|
|
@@ -106,3 +106,35 @@ class OpenAiChatSession(GenerativeModelChatSession):
|
|
|
106
106
|
config['response_format'] = { "type": "json_object" }
|
|
107
107
|
|
|
108
108
|
return config
|
|
109
|
+
|
|
110
|
+
def delete_last_message(self):
|
|
111
|
+
"""
|
|
112
|
+
Deletes the last message exchange (user message and assistant response) from the chat history.
|
|
113
|
+
Preserves the system message if present.
|
|
114
|
+
|
|
115
|
+
Example:
|
|
116
|
+
Before:
|
|
117
|
+
[
|
|
118
|
+
{"role": "system", "content": "System message"},
|
|
119
|
+
{"role": "user", "content": "User message"},
|
|
120
|
+
{"role": "assistant", "content": "Assistant response"},
|
|
121
|
+
]
|
|
122
|
+
After:
|
|
123
|
+
[
|
|
124
|
+
{"role": "system", "content": "System message"},
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
Note: Does nothing if the chat history is empty or contains only a system message.
|
|
128
|
+
"""
|
|
129
|
+
# Keep at least the system message if present
|
|
130
|
+
min_length = 1 if self._model.system_instruction else 0
|
|
131
|
+
if len(self._history) - 2 >= min_length:
|
|
132
|
+
self._history.pop()
|
|
133
|
+
self._history.pop()
|
|
134
|
+
else:
|
|
135
|
+
# Reset to initial state with just system message if present
|
|
136
|
+
self._history = (
|
|
137
|
+
[{"role": "system", "content": self._model.system_instruction}]
|
|
138
|
+
if self._model.system_instruction is not None
|
|
139
|
+
else []
|
|
140
|
+
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
from graphrag_sdk.models import GenerativeModel
|
|
2
1
|
from graphrag_sdk.agents import Agent
|
|
2
|
+
from graphrag_sdk.models import GenerativeModel
|
|
3
|
+
from graphrag_sdk.models.model import OutputMethod
|
|
3
4
|
from .orchestrator_runner import OrchestratorRunner
|
|
4
5
|
from graphrag_sdk.fixtures.prompts import (
|
|
5
6
|
ORCHESTRATOR_SYSTEM,
|
|
@@ -16,13 +17,12 @@ logger = logging.getLogger(__name__)
|
|
|
16
17
|
|
|
17
18
|
class Orchestrator:
|
|
18
19
|
|
|
19
|
-
_agents = []
|
|
20
|
-
_chat = None
|
|
21
|
-
|
|
22
20
|
def __init__(self, model: GenerativeModel, backstory: str = ""):
|
|
23
21
|
self._model = model
|
|
24
22
|
self._backstory = backstory
|
|
25
|
-
|
|
23
|
+
self._agents = []
|
|
24
|
+
self._chat = None
|
|
25
|
+
|
|
26
26
|
def _get_chat(self):
|
|
27
27
|
if self._chat is None:
|
|
28
28
|
self._chat = self._model.with_system_instruction(
|
|
@@ -1,21 +1,15 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from falkordb import Graph
|
|
1
3
|
from graphrag_sdk.steps.Step import Step
|
|
2
4
|
from graphrag_sdk.ontology import Ontology
|
|
3
5
|
from graphrag_sdk.models import (
|
|
4
6
|
GenerativeModelChatSession,
|
|
5
7
|
)
|
|
6
|
-
from graphrag_sdk.fixtures.prompts import (
|
|
7
|
-
CYPHER_GEN_SYSTEM,
|
|
8
|
-
CYPHER_GEN_PROMPT,
|
|
9
|
-
CYPHER_GEN_PROMPT_WITH_ERROR,
|
|
10
|
-
CYPHER_GEN_PROMPT_WITH_HISTORY,
|
|
11
|
-
)
|
|
12
|
-
import logging
|
|
13
8
|
from graphrag_sdk.helpers import (
|
|
14
9
|
extract_cypher,
|
|
15
10
|
validate_cypher,
|
|
16
11
|
stringify_falkordb_response,
|
|
17
12
|
)
|
|
18
|
-
from falkordb import Graph
|
|
19
13
|
|
|
20
14
|
logger = logging.getLogger(__name__)
|
|
21
15
|
logger.setLevel(logging.DEBUG)
|
|
@@ -33,28 +27,26 @@ class GraphQueryGenerationStep(Step):
|
|
|
33
27
|
chat_session: GenerativeModelChatSession,
|
|
34
28
|
config: dict = None,
|
|
35
29
|
last_answer: str = None,
|
|
30
|
+
cypher_prompt: str = None,
|
|
31
|
+
cypher_prompt_with_history: str = None,
|
|
36
32
|
) -> None:
|
|
37
33
|
self.ontology = ontology
|
|
38
34
|
self.config = config or {}
|
|
39
35
|
self.graph = graph
|
|
40
36
|
self.chat_session = chat_session
|
|
41
37
|
self.last_answer = last_answer
|
|
38
|
+
self.cypher_prompt = cypher_prompt
|
|
39
|
+
self.cypher_prompt_with_history = cypher_prompt_with_history
|
|
42
40
|
|
|
43
|
-
def run(self, question: str, retries: int =
|
|
44
|
-
error = False
|
|
45
|
-
|
|
41
|
+
def run(self, question: str, retries: int = 10):
|
|
46
42
|
cypher = ""
|
|
47
|
-
|
|
43
|
+
for i in range(retries):
|
|
48
44
|
try:
|
|
49
45
|
cypher_prompt = (
|
|
50
|
-
(
|
|
46
|
+
(self.cypher_prompt.format(question=question)
|
|
51
47
|
if self.last_answer is None
|
|
52
|
-
else
|
|
53
|
-
|
|
54
|
-
else CYPHER_GEN_PROMPT_WITH_ERROR.format(
|
|
55
|
-
question=question, error=error
|
|
56
|
-
)
|
|
57
|
-
)
|
|
48
|
+
else self.cypher_prompt_with_history.format(question=question, last_answer=self.last_answer))
|
|
49
|
+
)
|
|
58
50
|
logger.debug(f"Cypher Prompt: {cypher_prompt}")
|
|
59
51
|
cypher_statement_response = self.chat_session.send_message(
|
|
60
52
|
cypher_prompt,
|
|
@@ -67,7 +59,6 @@ class GraphQueryGenerationStep(Step):
|
|
|
67
59
|
return (None, None)
|
|
68
60
|
|
|
69
61
|
validation_errors = validate_cypher(cypher, self.ontology)
|
|
70
|
-
# print(f"Is valid: {is_valid}")
|
|
71
62
|
if validation_errors is not None:
|
|
72
63
|
raise Exception("\n".join(validation_errors))
|
|
73
64
|
|
|
@@ -82,6 +73,6 @@ class GraphQueryGenerationStep(Step):
|
|
|
82
73
|
except Exception as e:
|
|
83
74
|
logger.debug(f"Error: {e}")
|
|
84
75
|
error = e
|
|
85
|
-
|
|
76
|
+
self.chat_session.delete_last_message()
|
|
86
77
|
|
|
87
78
|
raise Exception("Failed to generate Cypher query: " + str(error))
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from graphrag_sdk.steps.Step import Step
|
|
2
3
|
from graphrag_sdk.models import GenerativeModelChatSession
|
|
3
4
|
|
|
4
|
-
from graphrag_sdk.fixtures.prompts import GRAPH_QA_SYSTEM, GRAPH_QA_PROMPT
|
|
5
|
-
import logging
|
|
6
|
-
|
|
7
5
|
logger = logging.getLogger(__name__)
|
|
8
6
|
logger.setLevel(logging.DEBUG)
|
|
9
7
|
|
|
@@ -17,17 +15,18 @@ class QAStep(Step):
|
|
|
17
15
|
self,
|
|
18
16
|
chat_session: GenerativeModelChatSession,
|
|
19
17
|
config: dict = None,
|
|
18
|
+
qa_prompt: str = None,
|
|
20
19
|
) -> None:
|
|
21
20
|
self.config = config or {}
|
|
22
21
|
self.chat_session = chat_session
|
|
22
|
+
self.qa_prompt = qa_prompt
|
|
23
23
|
|
|
24
24
|
def run(self, question: str, cypher: str, context: str):
|
|
25
|
-
|
|
26
|
-
qa_prompt = GRAPH_QA_PROMPT.format(
|
|
25
|
+
qa_prompt = self.qa_prompt.format(
|
|
27
26
|
context=context, cypher=cypher, question=question
|
|
28
27
|
)
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
logger.debug(f"QA Prompt: {qa_prompt}")
|
|
31
30
|
qa_response = self.chat_session.send_message(qa_prompt)
|
|
32
31
|
|
|
33
32
|
return qa_response.text
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "graphrag_sdk"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.2"
|
|
4
4
|
license = "MIT"
|
|
5
5
|
description = ""
|
|
6
6
|
authors = ["FalkorDB <info@falkordb.com>"]
|
|
@@ -16,6 +16,7 @@ typing-extensions = "^4.12.1"
|
|
|
16
16
|
bs4 = "^0.0.2"
|
|
17
17
|
pypdf = "^4.2.0"
|
|
18
18
|
backoff = "^2.2.1"
|
|
19
|
+
requests = "^2.32.3"
|
|
19
20
|
python-abc = "^0.2.0"
|
|
20
21
|
ratelimit = "^2.2.1"
|
|
21
22
|
python-dotenv = "^1.0.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{graphrag_sdk-0.3.0 → graphrag_sdk-0.3.2}/graphrag_sdk/orchestrator/orchestrator_decision.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|