Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GraphRAG demo with SwarmAgents #141

Merged
merged 24 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a2408d3
GraphRAG Demo: Data Setup
AgentGenie Dec 3, 2024
2537fbf
Added ability to connect to existing knowledge graph, falkordb added …
marklysze Dec 3, 2024
5ae2fcc
Tweaked order in init
marklysze Dec 3, 2024
4d17b4a
Merge remote-tracking branch 'origin/main' into graphrag_demo
marklysze Dec 4, 2024
bf81c00
Add one more Roman restaurant to the data
AgentGenie Dec 4, 2024
b61c223
Update to FalkorDB GraphRAG agent to utilise conversation history for…
marklysze Dec 4, 2024
ebc2eda
Merge branch 'graphrag_demo' of https://github.com/ag2ai/ag2 into gra…
marklysze Dec 4, 2024
b33d8bb
FalkorDB notebook example and updated examples listing
marklysze Dec 4, 2024
3f2b8d0
Notebook tidy.
marklysze Dec 4, 2024
92679e6
Save knowledge graph ontology for future access.
AgentGenie Dec 4, 2024
fd0811b
Fetch travel time and update Itinerary for route_timing_agent
AgentGenie Dec 4, 2024
aea0c1a
Fix Ontology save and load, use a separate table for ontology storage.
AgentGenie Dec 4, 2024
d05812c
Demo notebook updated - runs through
marklysze Dec 4, 2024
5f12bfa
Merge branch 'graphrag_demo' of https://github.com/ag2ai/ag2 into gra…
marklysze Dec 4, 2024
fa8cf6a
Fix reference: falkor_db to falkordb
marklysze Dec 5, 2024
2b1481d
Tidy of notebook
marklysze Dec 5, 2024
83650b3
Add TODO for FalkorDB LLM API cost calculation
AgentGenie Dec 5, 2024
6e85696
Notebook with execution
marklysze Dec 5, 2024
f7a824e
Merge branch 'graphrag_demo' of https://github.com/ag2ai/ag2 into gra…
marklysze Dec 5, 2024
9e3a95c
Remove unnecessary comment from notebook
marklysze Dec 5, 2024
8067e64
Notebook demo update
marklysze Dec 5, 2024
4484772
Final demo notebook
marklysze Dec 5, 2024
7de0408
Added itinerary output in notebook
marklysze Dec 5, 2024
abcfaa4
Added metadata to notebook
marklysze Dec 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ repos:
website/docs/tutorial/code-executors.ipynb |
website/docs/topics/code-execution/custom-executor.ipynb |
website/docs/topics/non-openai-models/cloud-gemini.ipynb |
notebook/.*
notebook/.* |
test/agentchat/contrib/graph_rag/trip_planner_data/.*
)$
# See https://jaredkhan.com/blog/mypy-pre-commit
- repo: local
Expand Down
64 changes: 59 additions & 5 deletions autogen/agentchat/contrib/graph_rag/falkor_graph_query_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
# SPDX-License-Identifier: Apache-2.0

import os
from dataclasses import dataclass, field
import warnings
from typing import List

from falkordb import FalkorDB, Graph
from graphrag_sdk import KnowledgeGraph, Source
from graphrag_sdk.model_config import KnowledgeGraphModelConfig
from graphrag_sdk.models import GenerativeModel
Expand Down Expand Up @@ -35,6 +36,8 @@ def __init__(
Initialize a FalkorDB knowledge graph.
Please also refer to https://github.com/FalkorDB/GraphRAG-SDK/blob/main/graphrag_sdk/kg.py

TODO: Fix LLM API cost calculation for FalkorDB useages.

Args:
name (str): Knowledge graph name.
host (str): FalkorDB hostname.
Expand All @@ -53,8 +56,38 @@ def __init__(
self.model = model
self.model_config = KnowledgeGraphModelConfig.with_model(model)
self.ontology = ontology
self.knowledge_graph = None
self.falkordb = FalkorDB(host=self.host, port=self.port, username=self.username, password=self.password)

def connect_db(self):
"""
Connect to an existing knowledge graph.
"""
if self.name in self.falkordb.list_graphs():
try:
self.ontology = self._load_ontology_from_db(self.name)
except Exception:
warnings.warn("Graph Ontology is not loaded.")

if self.ontology is None:
raise ValueError(f"Ontology of the knowledge graph '{self.name}' can't be None.")

self.knowledge_graph = KnowledgeGraph(
name=self.name,
host=self.host,
port=self.port,
username=self.username,
password=self.password,
model_config=self.model_config,
ontology=self.ontology,
marklysze marked this conversation as resolved.
Show resolved Hide resolved
)

# Establishing a chat session will maintain the history
self._chat_session = self.knowledge_graph.chat_session()
else:
raise ValueError(f"Knowledge graph '{self.name}' does not exist")

def init_db(self, input_doc: List[Document] | None):
def init_db(self, input_doc: List[Document]):
"""
Build the knowledge graph with input documents.
"""
Expand All @@ -81,10 +114,16 @@ def init_db(self, input_doc: List[Document] | None):
ontology=self.ontology,
)

# Establish a chat session, this will maintain the history
self._chat_session = self.knowledge_graph.chat_session()
self.knowledge_graph.process_sources(sources)

# Establishing a chat session will maintain the history
self._chat_session = self.knowledge_graph.chat_session()

# Save Ontology to graph for future access.
self._save_ontology_to_db(self.name, self.ontology)
else:
raise ValueError("No input documents could be loaded.")

def add_records(self, new_records: List) -> bool:
raise NotImplementedError("This method is not supported by FalkorDB SDK yet.")

Expand All @@ -101,11 +140,26 @@ def query(self, question: str, n_results: int = 1, **kwargs) -> GraphStoreQueryR
Returns: FalkorGraphQueryResult
"""
if self.knowledge_graph is None:
raise ValueError("Knowledge graph is not created.")
raise ValueError("Knowledge graph has not been selected or created.")

response = self._chat_session.send_message(question)

# History will be considered when querying by setting the last_answer
self._chat_session.last_answer = response["response"]

return GraphStoreQueryResult(answer=response["response"], results=[])

def __get_ontology_storage_graph(self, graph_name: str) -> Graph:
ontology_table_name = graph_name + "_ontology"
return self.falkordb.select_graph(ontology_table_name)

def _save_ontology_to_db(self, graph_name: str, ontology: Ontology):
"""
Save graph ontology to a separate table with {graph_name}_ontology
"""
graph = self.__get_ontology_storage_graph(graph_name)
ontology.save_to_graph(graph)

def _load_ontology_from_db(self, graph_name: str) -> Ontology:
graph = self.__get_ontology_storage_graph(graph_name)
return Ontology.from_graph(graph)
42 changes: 33 additions & 9 deletions autogen/agentchat/contrib/graph_rag/falkor_graph_rag_capability.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ def _reply_using_falkordb_query(
Query FalkorDB and return the message. Internally, it utilises OpenAI to generate a reply based on the given messages.
The history with FalkorDB is also logged and updated.

The agent's system message will be incorporated into the query, if it's not blank.

If no results are found, a default message is returned: "I'm sorry, I don't have an answer for that."

Args:
Expand All @@ -66,16 +68,38 @@ def _reply_using_falkordb_query(
Returns:
A tuple containing a boolean indicating success and the assistant's reply.
"""
question = self._get_last_question(messages[-1])
# question = self._get_last_question(messages[-1])
question = self._messages_summary(messages, recipient.system_message)
result: GraphStoreQueryResult = self.query_engine.query(question)

return True, result.answer if result.answer else "I'm sorry, I don't have an answer for that."

def _get_last_question(self, message: Union[Dict, str]):
"""Retrieves the last message from the conversation history."""
if isinstance(message, str):
return message
if isinstance(message, Dict):
if "content" in message:
return message["content"]
return None
def _messages_summary(self, messages: Union[Dict, str], system_message: str) -> str:
"""Summarize the messages in the conversation history. Excluding any message with 'tool_calls' and 'tool_responses'
Includes the 'name' (if it exists) and the 'content', with a new line between each one, like:
customer:
<content>

agent:
<content>
"""

if isinstance(messages, str):
if system_message:
summary = f"IMPORTANT: {system_message}\nContext:\n\n{messages}"
else:
return messages

elif isinstance(messages, List):
summary = ""
for message in messages:
if "content" in message and "tool_calls" not in message and "tool_responses" not in message:
summary += f"{message.get('name', '')}: {message.get('content','')}\n\n"

if system_message:
summary = f"IMPORTANT: {system_message}\nContext:\n\n{summary}"

return summary

else:
raise ValueError("Invalid messages format. Must be a list of messages or a string.")
Loading
Loading