Getting Started
Welcome to BrainyFlow! This framework helps you build powerful, modular AI applications using a simple yet expressive abstraction based on nested directed graphs.
1. Installation
First, ensure you have BrainyFlow installed:
pip install brainyflow
For more installation options, see the Installation Guide.
2. Core Concepts
BrainyFlow is built around a minimalist yet powerful abstraction that separates data flow from computation:
Node: The fundamental building block that performs a single task with a clear lifecycle (
prep
→exec
→post
).Flow: Orchestrates nodes in a directed graph, supporting branching, looping, and nesting.
Memory: Manages state, separating it into a shared
global
store and a forkablelocal
store for isolated data flow between nodes.
3. Your First Flow
Let's build a simple Question-Answering flow to demonstrate BrainyFlow's core concepts:
Step 1: Design Your Flow
Our flow will have two nodes:
GetQuestionNode
: Captures the user's questionAnswerNode
: Generates an answer using an LLM
Step 2: Implement the Nodes
import asyncio
from brainyflow import Node, Flow, Memory
from utils import call_llm # Your LLM implementation
class GetQuestionNode(Node):
async def prep(self, memory):
"""Get text input from user."""
memory.question = input("Enter your question: ")
class AnswerNode(Node):
async def prep(self, memory):
"""Extract the question from memory."""
return memory.question
async def exec(self, question: str | None):
"""Call LLM to generate an answer."""
prompt = f"Answer the following question: {question}"
return await call_llm(prompt)
async def post(self, memory, prep_res: str | None, exec_res: str):
"""Store the answer in memory."""
memory.answer = exec_res
print(f"AnswerNode: Stored answer '{exec_res}'")
Step 3: Connect the Nodes into a Flow
from .nodes import GetQuestionNode, AnswerNode # defined in the previous step
from brainyflow import Flow
def create_qa_flow():
get_question_node = GetQuestionNode()
answer_node = AnswerNode()
# Connect nodes get_question_node → answer_node using the default action
get_question_node >> answer_node # >> is Pythonic syntax sugar for .next(node)
# Create the Flow, specifying the starting node
return Flow(start=get_question_node)
Step 4: Run the Flow
import asyncio
from .flow import create_qa_flow # defined in the previous step
async def main():
memory = {} # Initialize empty memory (which acts as the global store)
qa_flow = create_qa_flow()
print("Running QA Flow...")
# Run the flow, passing the initial global store.
# The flow modifies the memory object in place.
# The run method returns the final execution tree (we ignore it here).
await qa_flow.run(memory)
# Access the results stored in the global store
print("\n--- Flow Complete ---")
print(f"Question: {memory.question}")
print(f"Answer: {memory.answer}")
if __name__ == '__main__':
asyncio.run(main())
4. Key Design Principles
BrainyFlow follows these core design principles:
Separation of Concerns: Data storage (the
memory
object managing global/local stores) is separate from computation logic (Node
classes).Explicit Data Flow: Data dependencies between steps are clear and traceable through
memory
access inprep
/post
and the results passed betweenprep
→exec
→post
.Composability: Complex systems (
Flow
s) are built from simple, reusable components (Node
s), and Flows themselves can be nested within other Flows.Minimalism: The framework provides only essential abstractions (
Node
,Flow
,Memory
), avoiding vendor-specific implementations or excessive boilerplate.
5. Next Steps
Now that you understand the basics, explore these resources to build sophisticated applications:
Core Abstractions: Dive deeper into nodes, flows, and communication
Design Patterns: Learn more complex patterns like Agents, RAG, and MapReduce
Agentic Coding Guide: Best practices for human-AI collaborative development
If you prefer, jump straight into our example projects:
Last updated