How to build a graph¶
This guide explains the fundamental steps for creating and configuring graphs in SemanticKernel.Graph. You'll learn how to define nodes, connect them with conditional edges, and execute the resulting workflow.
Overview¶
Building a graph involves several key steps:
- Create and configure a
Kernel
with the necessary plugins and functions - Define nodes (functions, conditionals, loops) that represent your workflow steps
- Connect nodes with conditional edges that control execution flow
- Execute with
GraphExecutor
to run the complete workflow
Step-by-Step Process¶
1. Create and Configure Kernel¶
Start by creating a Semantic Kernel instance with graph support enabled. The examples in this repository use a minimal kernel configured for graph scenarios.
using Microsoft.SemanticKernel;
using SemanticKernel.Graph.Core;
using SemanticKernel.Graph.Nodes;
// Create a kernel and enable graph support for examples
var kernel = Kernel.CreateBuilder()
.AddGraphSupport()
.Build();
2. Define Graph Nodes¶
Create nodes that represent different steps in your workflow. For small runnable documentation snippets we provide lightweight kernel functions wrapped into FunctionGraphNode
instances:
// Create lightweight kernel functions for demo purposes
var fnA = KernelFunctionFactory.CreateFromMethod((KernelArguments args) =>
{
// Returns a simple greeting message
return "Hello from A";
}, "FnA");
var fnB = KernelFunctionFactory.CreateFromMethod((KernelArguments args) =>
{
// Echoes previous message from the graph state
var prev = args.ContainsName("message") ? args["message"]?.ToString() : string.Empty;
return $"B received: {prev}";
}, "FnB");
// Wrap functions into graph nodes
var nodeA = new FunctionGraphNode(fnA, "nodeA", "Start node A");
var nodeB = new FunctionGraphNode(fnB, "nodeB", "Receiver node B");
3. Connect Nodes with Edges¶
Define the flow between nodes using the GraphExecutor
API. For the minimal example above we connect nodeA
to nodeB
and set the start node:
var graph = new GraphExecutor("ExampleGraph", "A tiny demo graph for docs");
// Add nodes to the graph
graph.AddNode(nodeA).AddNode(nodeB);
// Connect A -> B and set start node
graph.Connect("nodeA", "nodeB");
graph.SetStartNode("nodeA");
4. Execute the Graph¶
Run the complete workflow using ExecuteAsync
. The example uses KernelArguments
as initial graph state and prints the final result.
// Prepare initial kernel arguments / graph state
var args = new KernelArguments();
args["message"] = "Initial message";
// Execute graph
var result = await graph.ExecuteAsync(kernel, args, CancellationToken.None);
Console.WriteLine("Graph execution completed.");
Console.WriteLine($"Final result: {result.GetValue<string>()}");
Alternative Builder Pattern¶
For simpler graphs, you can use the fluent builder pattern:
var graph = GraphBuilder.Create()
.AddFunctionNode("plan", kernel, "Planner", "Plan")
.When(state => state.GetString("needs_analysis") == "yes")
.AddFunctionNode("analyze", kernel, "Analyzer", "Analyze")
.AddFunctionNode("act", kernel, "Executor", "Act")
.Build();
Advanced Patterns¶
Conditional Execution¶
Use conditional edges to create complex branching logic:
graph.AddConditionalEdge("start", "branch_a",
condition: state => state.GetInt("priority") > 5)
.AddConditionalEdge("start", "branch_b",
condition: state => state.GetInt("priority") <= 5);
Loop Control¶
Implement loops with iteration limits:
var loopNode = new WhileGraphNode(
condition: state => state.GetInt("attempt") < 3,
maxIterations: 5,
nodeId: "retry_loop"
);
graph.AddNode(loopNode)
.AddEdge("start", "retry_loop")
.AddEdge("retry_loop", "process");
Error Handling¶
Add error handling nodes to your workflow:
var errorHandler = new ErrorHandlerGraphNode(
errorTypes: new[] { ErrorType.Transient, ErrorType.External },
recoveryAction: RecoveryAction.Retry,
maxRetries: 3,
nodeId: "error_handler"
);
graph.AddNode(errorHandler)
.AddEdge("process", "error_handler")
.AddEdge("error_handler", "fallback");
Best Practices¶
Node Design¶
- Single Responsibility: Each node should have one clear purpose
- Meaningful Names: Use descriptive node IDs that explain their function
- State Management: Design nodes to work with the graph state effectively
- Error Handling: Include error handling nodes for robust workflows
Graph Structure¶
- Logical Flow: Organize nodes in a logical sequence
- Conditional Logic: Use conditional edges for dynamic routing
- Loop Prevention: Set appropriate iteration limits to prevent infinite loops
- Start Node: Always define a clear starting point
Performance Considerations¶
- Node Efficiency: Optimize individual node performance
- State Size: Keep graph state manageable for memory efficiency
- Parallel Execution: Use parallel nodes where possible for better performance
- Caching: Implement caching for expensive operations
Troubleshooting¶
Common Issues¶
Graph not executing: Ensure you've set a start node with SetStartNode()
Nodes not connected: Verify all edges are properly defined with AddEdge()
or AddConditionalEdge()
Infinite loops: Check loop conditions and set appropriate maxIterations
State not persisting: Use GraphState
for persistent state across nodes
Debugging Tips¶
- Enable logging to trace execution flow
- Use breakpoints in conditional logic
- Inspect state at each node execution
- Validate graph integrity before execution
Concepts and Techniques¶
GraphExecutor: The main class responsible for executing graph workflows. It manages node execution order, state transitions, and error handling throughout the workflow lifecycle.
FunctionGraphNode: A graph node that wraps and executes Semantic Kernel functions. It handles input/output mapping between the graph state and the underlying kernel function.
ConditionalGraphNode: A node that evaluates predicates to determine execution flow. It enables dynamic routing based on the current state of the graph.
ConditionalEdge: A connection between nodes that includes a condition for execution. It allows for complex branching logic and dynamic workflow paths.
GraphState: A wrapper around KernelArguments that provides additional metadata, execution history, and validation capabilities for graph workflows.
See Also¶
- First Graph in 5 Minutes - Quick start guide for building your first graph
- Conditional Nodes - Learn about branching and conditional execution
- Loops - Implement iterative workflows with loop nodes
- State Management - Understand how to manage data flow between nodes
- Graph Execution - Learn about the execution lifecycle and flow control
- Examples: Basic Graph Building - Complete working examples of graph construction