pocketflow/docs/flow.md

5.0 KiB
Raw Blame History

layout title nav_order
default Flow 2

Flow

In Mini LLM Flow, a Flow orchestrates how Nodes connect and run, based on Actions returned from each Nodes post() method. You can chain Nodes in a sequence or create branching logic depending on the Action string.

Action-based Transitions

Each Nodes post(shared, prep_res, exec_res) returns a string called Action. By default, if post() doesnt explicitly return anything, we treat that as "default".

You define transitions with the syntax:

node_a >> node_b
  • This means if node_a.post() returns "default" (or None), go to node_b.
node_a - "action_name" >> node_b
  • This means if node_a.post() returns "action_name", go to node_b.

Its possible to create loops, branching, or multi-step flows. You can also chain with multiple Actions from a single node to different successors:

# Define nodes for order processing
validate_order = ValidateOrderNode()
check_inventory = CheckInventoryNode()
process_payment = ProcessPaymentNode()
send_confirmation = SendConfirmationNode()
notify_backorder = NotifyBackorderNode()

# Define the flow
validate_order - "valid" >> check_inventory
validate_order - "invalid" >> send_confirmation  # Send rejection confirmation

check_inventory - "in_stock" >> process_payment
check_inventory - "out_of_stock" >> notify_backorder

process_payment - "success" >> send_confirmation
process_payment - "failure" >> send_confirmation  # Send payment failure notice
flowchart TD
    validate[Validate Order] -->|valid| inventory[Check Inventory]
    validate -->|invalid| confirm[Send Confirmation]
    
    inventory -->|in_stock| payment[Process Payment]
    inventory -->|out_of_stock| backorder[Notify Backorder]
    
    payment -->|success| confirm
    payment -->|failure| confirm

    style validate fill:#d4f1f9
    style confirm fill:#d4f1f9

Creating a Flow

A Flow begins with a start node (or flow). You call Flow(start=some_node) to specify the entry point. When you call flow.run(shared), it executes the first node, looks at its post() return Action, follows the corresponding transition, and continues until theres no next node or you explicitly stop.

flow = Flow(start=node_a)

Example: Simple Sequence

Heres a minimal flow of two nodes in a chain:

node_a >> node_b
flow = Flow(start=node_a)
flow.run(shared)
  • When you run the flow, it executes node_a.
  • Suppose node_a.post() returns "default".
  • The flow then sees "default" Action is linked to node_b and runs node_b.
  • If node_b.post() returns "default" but we didnt define node_b >> something_else, the flow ends there.

Example: Branching & Looping

Suppose FindRelevantFile can return three possible Actions in its post():

  • "end": means no question, so stop.
  • "answer": means we have a relevant file, move to AnswerQuestion.
  • "retry": means no relevant file found, try again.

We can wire them:

find_relevant_file - "end"    >> no_op_node
find_relevant_file - "answer" >> answer_question
find_relevant_file - "retry"  >> find_relevant_file
flow = Flow(start=find_relevant_file)
  1. If FindRelevantFile.post() returns "answer", the flow calls answer_question.
  2. If FindRelevantFile.post() returns "retry", it loops back to itself.
  3. If "end", it goes to no_op_node. If no_op_node has no further transitions, the flow stops.

Running Individual Nodes vs. Running a Flow

  • node.run(shared): Just runs that node alone (calls prep(), exec(), post()), returns an Action. Does not proceed automatically to the successor. This is mainly for debugging or testing a single node.
  • flow.run(shared): Executes from the start node, follows Actions to the next node, and so on until the flow cant continue (no next node or no next Action).

Always use flow.run(...) in production to ensure the full pipeline runs correctly.

Nested Flows

A Flow can act like a Node. That means you can do:

some_flow >> another_node
or treat some_flow as a node inside a larger flow. This helps you compose complex pipelines by nesting smaller flows.

Example Code

Below is a short snippet combining these ideas:

# Define nodes
find_file = FindRelevantFile()
answer    = AnswerQuestion()
no_op     = NoOp()

# Define transitions
find_file - "answer" >> answer
find_file - "retry"  >> find_file
find_file - "end"    >> no_op

# Build the Flow
qa_flow = Flow(start=find_file)

# Run
qa_flow.run(shared)

When find_files post() returns "answer", we proceed to answer. If it returns "retry", we loop back. If "end", we move on to no_op.


Thats Flow in a nutshell:

  • Actions determine which node runs next.
  • Flow runs the pipeline from the start node to completion.
  • You can chain nodes in a linear sequence or build loops and branches.
  • Nodes can themselves be entire flows, allowing nested graph structures.