Skip to content

Commit

Permalink
Finish falkorDB notebook
Browse files Browse the repository at this point in the history
  • Loading branch information
YoanSallami committed Sep 19, 2024
1 parent 00b619b commit 8b0ffff
Show file tree
Hide file tree
Showing 22 changed files with 844 additions and 212 deletions.
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@
- [Using External Tools](notebooks/using_external_tools.ipynb)
- [Add Documents (on the fly)](notebooks/updating_documents.ipynb)
- [Add Facts (on the fly)](notebooks/updating_facts.ipynb)
- [Interactive ReACT](notebooks/interactive_react.ipynb)
- [ReACT Agent](notebooks/react_agent.ipynb)
- [Reflexion Agent](notebooks/reflexion_agent.ipynb)
- [Using FalkorDB](notebooks/using_falkordb.ipynb)

## What is HybridAGI?

Expand Down Expand Up @@ -139,9 +142,11 @@ You can add more tools by using the `FunctionTool` and python functions like now

### Graph Databases Integrations

- Local Graph Memory for rapid prototyping based on [NetworkX](https://networkx.org/)
- [FalkorDB](https://www.falkordb.com/) low latency in-memory hybrid vector/graph database (coming soon)
- [Kuzu](https://kuzudb.com/) A highly scalable, extremely fast, easy-to-use embeddable graph database (coming soon)
- Local Graph Memory for rapid prototyping based on [NetworkX](https://networkx.org/).
- [FalkorDB](https://www.falkordb.com/) low latency in-memory hybrid vector/graph database.
- [Kuzu](https://kuzudb.com/) A highly scalable, extremely fast, easy-to-use embeddable graph database (coming soon).

We accept the contributions for more database integrations. Feel free to join the discord channel for more information!

### LLM Agent as Graph VS LLM Agent as Graph Interpreter

Expand Down
26 changes: 26 additions & 0 deletions docs/Core API/Data Types/Agent Output.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Agent Output

This data structure represent the output of the Agent (e.g. the execution of a graph program).

`FinishReason`: The different reasons for the end of a program.

`AgentOuput`: The output returned by the Agent system.

## Definition

```python
class FinishReason(str, Enum):
MaxIters = "max_iters"
Finished = "finished"
Error = "error"

class AgentOutput(BaseModel, dspy.Prediction):
finish_reason: FinishReason = Field(description="The finish reason", default=FinishReason.Finished)
final_answer: str = Field(description="The final answer or error if any", default="")
program_trace: AgentStepList = Field(description="The resulting program trace", default_factory=AgentStepList)
session: InteractionSession = Field(description="The resulting interaction session", default_factory=InteractionSession)

def __init__(self, **kwargs):
BaseModel.__init__(self, **kwargs)
dspy.Prediction.__init__(self, **kwargs)
```
64 changes: 64 additions & 0 deletions docs/Core API/Data Types/Agent State.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Agent State

This data structure represent the state of the Agent, which contains a stack allowing the agent to jump to other programs by calling them.

`ProgramState`: Represents the state of an executed program.

`AgentState`: Represents the state of the agent.

## Definition

```python

class ProgramState(BaseModel):
current_program: GraphProgram = Field(description="The current program")
current_step: Union[Control, Action, Decision, Program] = Field(description="The current step")

class AgentState(BaseModel):
current_hop: int = Field(description="The current hop", default=0)
decision_hop: int = Field(description="The current decision hop", default=0)
program_trace: AgentStepList = Field(description="The program trace", default_factory=AgentStepList)
program_stack: Iterable[ProgramState] = Field(description="The program stack", default=deque())
objective: Query = Field(description="The user objective query", default_factory=Query)
final_answer: str = Field(description="The agent final answer", default="")
variables: Dict[str, Any] = Field(description="The variables of the program", default={})
session: InteractionSession = Field(description="The current interaction session", default_factory=InteractionSession)

def get_current_state(self) -> Optional[ProgramState]:
"""Method to get the current program state"""
if len(self.program_stack) > 0:
return self.program_stack[-1]
return None

def get_current_program(self) -> Optional[GraphProgram]:
"""Method to retreive the current program from the stack"""
if len(self.program_stack) > 0:
return self.program_stack[-1].current_program
return None

def get_current_step(self) -> Optional[Union[Control, Action, Decision, Program]]:
"""Method to retreive the current node from the stack"""
if len(self.program_stack) > 0:
return self.program_stack[-1].current_step
return None

def set_current_step(self, step: Union[Control, Action, Decision, Program]):
"""Method to set the current node from the stack"""
if len(self.program_stack) > 0:
self.program_stack[-1].current_step = step
else:
raise ValueError("Cannot set the current step when program finished")

def call_program(self, program: GraphProgram):
"""Method to call a program"""
self.program_stack.append(
ProgramState(
current_program = program,
current_step = program.get_starting_step(),
)
)

def end_program(self):
"""Method to end the current program (pop the stack)"""
self.program_stack.pop()
```
100 changes: 100 additions & 0 deletions docs/Core API/Data Types/Agent Step.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Agent Step

Here is represented the datastructure used by the Agent System, usually you don't have to worry about it because it is handled automatically by the system. But for documentation purpose, here are the definition of the corresponding structure.

`AgentStep`: Represents a step performed by the Agent to be stored into memory.

`AgentStepList`: Represents a list of steps performed by the Agent.

`QueryWithSteps`: Represents a query associated with a ste list used by the action retrivers and rerankers.

## Definition

```python

class AgentStepType(str, Enum):
Action = "Action"
Decision = "Decision"
ProgramCall = "ProgramCall"
ProgramEnd = "ProgramEnd"

ACTION_TEMPLATE = \
"""--- Step {hop} ---
Action Purpose: {purpose}
Action: {prediction}"""

DECISION_TEMPLATE = \
"""--- Step {hop} ---
Decision Purpose: {purpose}
Decision: {choice}"""

CALL_PROGRAM_TEMPLATE = \
"""--- Step {hop} ---
Call Program: {program}
Program Purpose: {purpose}"""

END_PROGRAM_TEMPLATE = \
"""--- Step {hop} ---
End Program: {program}"""

class AgentStep(BaseModel):
id: Union[UUID, str] = Field(description="Unique identifier for a step", default_factory=uuid4)
parent_id: Optional[Union[UUID, str]] = Field(description="The previous step id if any", default=None)
hop: int = Field(description="The step hop", default=0)
step_type: AgentStepType = Field(description="The step type")
inputs: Optional[Dict[str, Any]] = Field(description="The inputs of the step", default=None)
outputs: Optional[Dict[str, Any]] = Field(description="The outputs of the step", default=None)
vector: Optional[List[float]] = Field(description="Vector representation of the step", default=None)
metadata: Optional[Dict[str, Any]] = Field(description="Additional information about the step", default=None)
created_at: datetime = Field(description="Time when the step was created", default_factory=datetime.now)

def __str__(self):
if self.inputs is None:
self.inputs = {}

if self.step_type == AgentStepType.Action:
return ACTION_TEMPLATE.format(
hop=self.hop,
purpose=self.inputs.get("purpose", ""),
prediction=json.dumps(self.outputs, indent=2),
)
elif self.step_type == AgentStepType.Decision:
return DECISION_TEMPLATE.format(
hop=self.hop,
purpose=self.inputs.get("purpose", ""),
choice=self.outputs.get("choice", ""),
)
elif self.step_type == AgentStepType.ProgramCall:
return CALL_PROGRAM_TEMPLATE.format(
hop=self.hop,
purpose=self.inputs.get("purpose", ""),
program=self.inputs.get("program", ""),
)
elif self.step_type == AgentStepType.ProgramEnd:
return END_PROGRAM_TEMPLATE.format(
hop=self.hop,
program=self.inputs.get("program", ""),
)
else:
raise ValueError("Invalid type for AgentStep")

def to_dict(self):
return {"step": str(self)}

class AgentStepList(BaseModel, dspy.Prediction):
steps: List[AgentStep] = Field(description="List of agent steps", default=[])

def __init__(self, **kwargs):
BaseModel.__init__(self, **kwargs)
dspy.Prediction.__init__(self, **kwargs)

def to_dict(self):
return {"steps": [s.to_dict() for s in self.steps]}

class QueryWithSteps(BaseModel, dspy.Prediction):
queries: QueryList = Field(description="The input query list", default_factory=QueryList)
steps: List[AgentStep] = Field(description="List of agent steps", default=[])

def to_dict(self):
return {"queries": [q.query for q in self.queries.queries], "steps": [s.to_dict() for s in self.steps]}
```
20 changes: 14 additions & 6 deletions docs/Core API/Data Types/Document.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

Documents are the atomic data used in HybridAGI's Document Memory, they are used to represent textual data and their chunks in the system. Allowing the system to implement vector-only [Retrieval Augmented Generation](https://en.wikipedia.org/wiki/Retrieval-augmented_generation) systems.

`Document`: Represent an unstructured textual data to be processed or saved into memory
`Document`: Represent an unstructured textual data to be processed or saved into memory.

`DocumentList`: A list of documents to be processed or saved into memory
`DocumentList`: A list of documents to be processed or saved into memory.

`QueryWithDocuments`: A list of document associated with a Query used by the retrievers and rerankers.

## Definition

```python

class Document(BaseModel):
id: Union[UUID, str] = Field(description="Unique identifier for the document", default_factory=uuid4)
text: str = Field(description="The actual text content of the document")
Expand All @@ -33,12 +34,21 @@ class DocumentList(BaseModel, dspy.Prediction):
def to_dict(self):
return {"documents": [d.to_dict() for d in self.docs]}

class QueryWithDocuments(BaseModel, dspy.Prediction):
queries: QueryList = Field(description="The input query list", default_factory=QueryList)
docs: Optional[List[Document]] = Field(description="List of documents", default=[])

def __init__(self, **kwargs):
BaseModel.__init__(self, **kwargs)
dspy.Prediction.__init__(self, **kwargs)

def to_dict(self):
return {"queries": [q.query for q in self.queries.queries], "documents": [d.to_dict() for d in self.docs]}
```

## Usage

```python

input_data = \
[
{
Expand All @@ -60,6 +70,4 @@ for data in input_data:
metadata={"title": data["title"]},
)
)

>>>
```
25 changes: 24 additions & 1 deletion docs/Core API/Data Types/Fact.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Fact

Facts are the atomic data of a [Knowledge Graph](https://en.wikipedia.org/wiki/Knowledge_graph). They represent the relations between two entities (a subject and object). They are the basis of knowledge based systems and allowing to represent precise and formal knowledge. With them you can implement [Knowledge Graph based Retrieval Augmented Generation]().
Facts are the atomic data of a [Knowledge Graph](https://en.wikipedia.org/wiki/Knowledge_graph). They represent the relations between two entities (respectively a subject and an object). They are the basis of knowledge based systems they allow to represent precise and formal knowledge. With them you can implement Knowledge Graph based Retrieval Augmented Generation.

`Entity`: Represent an entity like a person, object, place or document to be processed or saved into memory

Expand Down Expand Up @@ -44,6 +44,17 @@ class EntityList(BaseModel, dspy.Prediction):
def to_dict(self):
return {"entities": [e.to_dict() for e in self.entities]}

class QueryWithEntities(BaseModel, dspy.Prediction):
queries: QueryList = Field(description="The input query list", default_factory=QueryList)
entities: List[Entity] = Field(description="List of entities", default=[])

def __init__(self, **kwargs):
BaseModel.__init__(self, **kwargs)
dspy.Prediction.__init__(self, **kwargs)

def to_dict(self):
return {"queries": [q.query for q in self.queries.queries], "entities": [e.to_dict() for e in self.entities]}

class Relationship(BaseModel):
id: Union[UUID, str] = Field(description="Unique identifier for the relation", default_factory=uuid4)
name: str = Field(description="Relationship name")
Expand Down Expand Up @@ -117,9 +128,21 @@ class FactList(BaseModel, dspy.Prediction):
def to_dict(self):
return {"facts": [f.to_dict() for f in self.facts]}

class QueryWithFacts(BaseModel, dspy.Prediction):
queries: QueryList = Field(description="The input query list", default_factory=QueryList)
facts: Optional[List[Fact]] = Field(description="List of facts", default=[])

def __init__(self, **kwargs):
BaseModel.__init__(self, **kwargs)
dspy.Prediction.__init__(self, **kwargs)

def to_dict(self):
return {"queries": [q.query for q in self.queries.queries], "facts": [f.to_dict() for f in self.facts]}

```

## Usage

```
```
Loading

0 comments on commit 8b0ffff

Please sign in to comment.