Nodes¶
Nodes are the fundamental components of a graph, each encapsulating a specific unit of work or control logic.
Concepts and Techniques¶
Graph Node: Fundamental processing unit that encapsulates work, control logic or specific operations.
Node Lifecycle: Sequence of events that occurs during execution: Before → Execute → After.
IGraphNode Interface: Base contract that all nodes must implement for system integration.
Node Types¶
Function Nodes¶
// Encapsulates a Semantic Kernel function
var functionNode = new FunctionGraphNode(
function: kernel.GetFunction("analyze_document"),
name: "analyze_document",
description: "Analyzes the content of a document"
);
Characteristics:
* Encapsulation: Wraps KernelFunction
* Synchronous Execution: Direct function processing
* Shared State: Access to global GraphState
* Metrics: Automatic performance collection
Conditional Nodes¶
// Node that makes decisions based on conditions
var conditionalNode = new ConditionalGraphNode(
condition: async (state) => {
var score = state.GetValue<double>("confidence");
return score > 0.8;
},
name: "confidence_gate",
description: "Filters results by confidence level"
);
Characteristics: * Condition Evaluation: Boolean expressions over state * Dynamic Routing: Runtime decisions * SK Templates: Use of Semantic Kernel functions for decisions * Fallbacks: Fallback strategies for unmet conditions
Reasoning Nodes¶
// Node that implements reasoning patterns
var reasoningNode = new ReasoningGraphNode(
kernel: kernel,
prompt: "Analyze the problem and suggest a solution",
maxSteps: 5,
name: "problem_solver",
description: "Solves problems using step-by-step reasoning"
);
Characteristics: * Chain of Thought: Step-by-step reasoning * Few-shot Learning: Examples to guide reasoning * Result Validation: Quality verification of responses * Controlled Iteration: Limits to avoid infinite loops
Loop Nodes¶
// Node that implements controlled iterations
var loopNode = new ReActLoopGraphNode(
kernel: kernel,
objective: "Classify all documents",
maxIterations: 10,
name: "document_classifier",
description: "Iteratively classifies documents"
);
Characteristics: * ReAct Pattern: Observation → Thinking → Action * Clear Objectives: Specific goals for each iteration * Iteration Control: Limits to avoid infinite loops * Persistent State: Context maintenance between iterations
Observation Nodes¶
// Node that observes and records information
var observationNode = new ObservationGraphNode(
observer: new ConsoleObserver(),
name: "console_logger",
description: "Records observations in console"
);
Characteristics: * Passive Observation: Does not modify state * Logging: Recording of execution information * Metrics: Performance data collection * Debug: Troubleshooting support
Subgraph Nodes¶
// Node that encapsulates another graph
var subgraphNode = new SubgraphGraphNode(
subgraph: documentAnalysisGraph,
name: "document_analysis",
description: "Complete document analysis pipeline"
);
Characteristics: * Composition: Reuse of existing graphs * Encapsulation: Clean interface for complex graphs * Isolated State: Variable scope control * Reusability: Reusable modules in different contexts
Error Handler Nodes¶
// Node that handles exceptions and failures
var errorHandlerNode = new ErrorHandlerGraphNode(
errorPolicy: new RetryPolicy(maxRetries: 3),
name: "error_handler",
description: "Handles errors and implements retry policies"
);
Characteristics: * Error Policies: Retry, backoff, circuit breaker * Recovery: Strategies for handling failures * Logging: Detailed error recording * Fallbacks: Alternatives when main operation fails
Human Approval Nodes¶
// Node that pauses for human interaction
var approvalNode = new HumanApprovalGraphNode(
channel: new ConsoleHumanInteractionChannel(),
timeout: TimeSpan.FromMinutes(30),
name: "human_approval",
description: "Waits for human approval to continue"
);
Characteristics: * Human Interaction: Pause for human input * Timeouts: Time limits for response * Multiple Channels: Console, web, email * Audit: Recording of human decisions
Node Lifecycle¶
Before Phase¶
public override async Task BeforeExecutionAsync(GraphExecutionContext context)
{
// Input validation
await ValidateInputAsync(context.State);
// Resource initialization
await InitializeResourcesAsync();
// Start logging
_logger.LogInformation($"Starting execution of node {Id}");
}
Execute Phase¶
public override async Task<GraphExecutionResult> ExecuteAsync(GraphExecutionContext context)
{
try
{
// Main execution
var result = await ProcessAsync(context.State);
// State update
context.State.SetValue("output", result);
return GraphExecutionResult.Success(result);
}
catch (Exception ex)
{
return GraphExecutionResult.Failure(ex);
}
}
After Phase¶
public override async Task AfterExecutionAsync(GraphExecutionContext context)
{
// Resource cleanup
await CleanupResourcesAsync();
// Performance logging
_logger.LogInformation($"Node {Id} completed in {context.ExecutionTime}");
// Counter updates
UpdateExecutionMetrics(context);
}
Configuration and Options¶
Node Options¶
var nodeOptions = new GraphNodeOptions
{
EnableMetrics = true,
EnableLogging = true,
MaxExecutionTime = TimeSpan.FromMinutes(5),
RetryPolicy = new ExponentialBackoffRetryPolicy(maxRetries: 3),
CircuitBreaker = new CircuitBreakerOptions
{
FailureThreshold = 5,
RecoveryTimeout = TimeSpan.FromMinutes(1)
}
};
Input/Output Validation¶
var inputSchema = new GraphNodeInputSchema
{
Required = new[] { "document", "language" },
Optional = new[] { "confidence_threshold" },
Types = new Dictionary<string, Type>
{
["document"] = typeof(string),
["language"] = typeof(string),
["confidence_threshold"] = typeof(double)
}
};
var outputSchema = new GraphNodeOutputSchema
{
Properties = new[] { "analysis_result", "confidence_score" },
Types = new Dictionary<string, Type>
{
["analysis_result"] = typeof(string),
["confidence_score"] = typeof(double)
}
};
Monitoring and Observability¶
Node Metrics¶
var nodeMetrics = new NodeExecutionMetrics
{
ExecutionCount = 150,
AverageExecutionTime = TimeSpan.FromMilliseconds(250),
SuccessRate = 0.98,
LastExecutionTime = DateTime.UtcNow,
ErrorCount = 3,
ResourceUsage = new ResourceUsageMetrics()
};
Structured Logging¶
_logger.LogInformation("Node execution started", new
{
NodeId = Id,
NodeType = GetType().Name,
InputKeys = context.State.GetKeys(),
ExecutionId = context.ExecutionId,
Timestamp = DateTime.UtcNow
});
See Also¶
References¶
IGraphNode
: Base interface for all nodesFunctionGraphNode
: Node that encapsulates SK functionsConditionalGraphNode
: Node for conditional decisionsReasoningGraphNode
: Node for step-by-step reasoningReActLoopGraphNode
: Node for ReAct loopsObservationGraphNode
: Node for observation and loggingSubgraphGraphNode
: Node that encapsulates other graphsErrorHandlerGraphNode
: Node for error handlingHumanApprovalGraphNode
: Node for human interaction