18 — Graph-Based Agent Architecture¶
Understand how graph-based architectures are used to design controllable, stateful, reliable, and production-ready AI Agents using explicit nodes, edges, state, decision points, tools, and execution policies.
📖 Overview¶
Traditional AI applications often follow a simple request-response model:
Agent systems require a more sophisticated execution model:
As agent complexity increases, implicit control flow becomes difficult to understand, test, secure, and operate.
Graph-based agent architecture addresses this problem by making the execution model explicit:
The graph becomes the orchestration layer responsible for controlling how the agent moves through its execution lifecycle.
🎯 Learning Objectives¶
After completing this chapter, you will be able to:
- Understand graph-based agent architecture
- Understand the relationship between agents and graphs
- Design stateful agent execution
- Model agent reasoning and action loops
- Design nodes and transitions
- Implement conditional routing
- Design tool execution boundaries
- Build bounded agent loops
- Separate deterministic control from LLM reasoning
- Design human-in-the-loop agent workflows
- Handle failures and retries
- Design agent state and persistence
- Apply security controls to agent graphs
- Design observable agent architectures
- Understand production graph design patterns
- Avoid common graph-based agent anti-patterns
1. Why Agent Architecture Needs Explicit Control¶
A simple agent can be represented as:
But enterprise agents may require:
Authentication
↓
Authorization
↓
Input Validation
↓
Planning
↓
Reasoning
↓
Tool Selection
↓
Tool Authorization
↓
Tool Execution
↓
Observation
↓
Validation
↓
Retry / Escalation
↓
Response
The more steps an agent performs, the more important explicit orchestration becomes.
2. Graph-Based Agent Model¶
A graph-based agent represents execution as:
┌──────────────┐
│ START │
└──────┬───────┘
↓
┌──────────────┐
│ Analyze │
└──────┬───────┘
↓
┌──────────────┐
│ Reason │
└──────┬───────┘
↓
┌──────────────┐
│ Decide │
└───┬──────┬───┘
│ │
Tool Done
│ │
↓ ↓
┌───────┐ END
│ Tool │
└───┬───┘
↓
┌──────────────┐
│ Observation │
└──────┬───────┘
↓
Reason
The graph defines the control flow while the LLM provides intelligent decisions inside selected nodes.
3. Agent vs Graph¶
These concepts should not be confused.
An AI Agent is a behavioral system capable of deciding what actions to take to achieve a goal.
A Graph is an orchestration representation used to control execution.
Therefore:
while:
A graph can therefore implement:
4. Agent Without Explicit Graph¶
A conceptual agent loop:
This can work for simple systems.
However, production systems need explicit controls around:
5. Agent With Graph¶
The same behavior can be represented explicitly:
This provides a visible execution model.
6. Core Architecture¶
A production graph-based agent can be decomposed into:
Agent Graph
│
┌─────────────┼─────────────┐
↓ ↓ ↓
State Nodes Edges
│ │ │
│ ├── Reason │
│ ├── Tool │
│ ├── Validate │
│ └── Review │
│ │
└──────────── Execution ────┘
7. Major Components¶
State¶
Stores execution context.
Nodes¶
Perform work.
Edges¶
Control transitions.
8. Agent State¶
State is the memory of the current execution.
Example:
class AgentState(TypedDict):
query: str
goal: str
plan: list
messages: list
tool_calls: list
observations: list
attempts: int
status: str
final_answer: str
A production implementation should keep state intentionally scoped.
Avoid creating a state object containing every possible piece of application data.
9. State Lifecycle¶
flowchart LR
A[Initial State] --> B[Reasoning]
B --> C[Decision]
C --> D[Tool Execution]
D --> E[Observation]
E --> F[State Update]
F --> B
F --> G[Final State]
State evolves as the agent progresses.
10. State vs Memory¶
State and memory are related but not identical.
State¶
Memory¶
For example:
while:
11. Agent Execution State¶
A useful state model:
AgentState
├── Input
├── Goal
├── Plan
├── Messages
├── Tool Requests
├── Tool Results
├── Validation
├── Attempts
└── Status
12. Nodes as Capabilities¶
Nodes should represent meaningful capabilities.
Examples:
validate_input
create_plan
reason
retrieve_context
select_tool
authorize_tool
execute_tool
validate_result
human_review
generate_response
Avoid creating nodes merely because a function exists.
13. Node Responsibility¶
A good node follows:
Example:
should not also:
Keep responsibilities separated.
14. Deterministic and Intelligent Nodes¶
A graph can combine both.
Deterministic¶
Intelligent¶
This produces a powerful architecture:
15. Control Plane vs Intelligence Plane¶
A useful enterprise architecture:
┌───────────────────────────────┐
│ Control Plane │
│ │
│ Graph │
│ Policies │
│ Authorization │
│ Limits │
│ Retry │
│ Timeout │
└───────────────┬───────────────┘
│
↓
┌───────────────────────────────┐
│ Intelligence Plane │
│ │
│ LLM │
│ Reasoning │
│ Planning │
│ Classification │
│ Tool Selection │
└───────────────────────────────┘
This separation is important for enterprise reliability.
16. Why Deterministic Controls Matter¶
Do not rely on:
as the only control.
Instead:
17. Graph-Based Agent Loop¶
The canonical agent loop is:
In graph form:
flowchart TD
A[Reason] --> B[Decide]
B --> C{Action?}
C -->|Tool| D[Execute Tool]
D --> E[Observe]
E --> A
C -->|Complete| F[Validate]
F --> G[END]
18. Planning Node¶
Complex tasks may begin with planning.
Example:
"Prepare a customer account report"
Plan:
1. Retrieve customer
2. Retrieve transactions
3. Calculate summary
4. Validate data
5. Generate report
19. Planning Architecture¶
flowchart TD
A[User Goal] --> B[Planner]
B --> C[Plan]
C --> D[Task Executor]
D --> E[Task Result]
E --> F{More Tasks?}
F -->|Yes| D
F -->|No| G[Final Response]
20. Planning vs Dynamic Reasoning¶
Planning can be:
or:
The second approach is useful when the environment changes.
21. Re-Planning¶
Example:
Graph:
flowchart TD
A[Plan] --> B[Search]
B --> C{Useful Result?}
C -->|Yes| D[Continue]
C -->|No| E[Re-plan]
E --> A
Re-planning should be bounded.
22. Tool Selection¶
An agent may have:
The LLM may determine:
But the graph should enforce:
23. Tool Execution Boundary¶
Recommended:
Not:
24. Tool Gateway¶
A Tool Gateway can centralize:
Architecture:
flowchart LR
A[Agent] --> B[Tool Gateway]
B --> C[Authorization]
C --> D[Schema Validation]
D --> E[Rate Limit]
E --> F[Enterprise API]
25. Tool Result Validation¶
Tool output should not automatically become trusted truth.
Use:
Example:
26. Tool Error Handling¶
Tool execution can fail.
flowchart TD
A[Tool Call] --> B{Success?}
B -->|Yes| C[Observation]
B -->|No| D{Retryable?}
D -->|Yes| E[Retry]
D -->|No| F[Fallback]
E --> A
Retries must have limits.
27. Bounded Execution¶
Every autonomous loop should have boundaries.
Use:
Example:
These values are illustrative and should be tuned for the actual workload.
28. Multi-Dimensional Agent Limits¶
A production agent should not rely on a single limit.
29. Human-in-the-Loop¶
High-risk actions should support human intervention.
Example:
30. Human Approval Graph¶
flowchart TD
A[Agent Decision] --> B[Risk Check]
B --> C{High Risk?}
C -->|No| D[Execute]
C -->|Yes| E[Human Approval]
E --> F{Approved?}
F -->|Yes| D
F -->|No| G[Reject]
D --> H[END]
G --> H
31. Risk-Based Routing¶
Not every action requires human approval.
Example:
while:
This creates a risk-aware agent architecture.
32. Agent Risk Tiers¶
Example:
Tier 0
Read-only
Tier 1
Low-impact updates
Tier 2
Business-impacting actions
Tier 3
Financial / irreversible actions
Higher-risk operations should receive stronger controls.
33. Reflection and Validation¶
Agents can validate their own work.
But self-reflection should not be the only quality control for high-risk decisions.
Use deterministic validators wherever possible.
34. Reflection Graph¶
flowchart TD
A[Generate] --> B[Validate]
B --> C{Acceptable?}
C -->|Yes| D[END]
C -->|No| E[Reflection]
E --> A
35. Deterministic Validation¶
Where possible:
This is stronger than:
36. Guardrails Around the Graph¶
A production graph should have guardrails at multiple points:
37. Guardrail Architecture¶
flowchart TB
A[User Input] --> B[Input Guardrail]
B --> C[Agent Graph]
C --> D[Tool Authorization]
D --> E[Tool Execution]
E --> F[Result Validation]
F --> G[Output Guardrail]
G --> H[User Response]
38. State Persistence¶
Long-running agents may need to pause and resume.
Example:
Later:
Persistence makes this possible.
39. Durable Agent Execution¶
flowchart LR
A[Agent] --> B[Checkpoint]
B --> C[Pause]
C --> D[External Event]
D --> E[Restore State]
E --> F[Resume Agent]
F --> G[Complete]
40. State Recovery¶
If a node fails:
This is especially important for:
41. Idempotency¶
Agents may retry operations.
For side effects:
use idempotency.
Example:
This prevents accidental duplicate actions.
42. Agent Execution Identity¶
Each execution should have identifiers such as:
These enable:
43. Multi-Tenant Architecture¶
flowchart TD
A[Request] --> B[Tenant Resolution]
B --> C[Authorization]
C --> D[Agent Graph]
D --> E[Tenant-Isolated State]
D --> F[Tenant-Aware Tools]
D --> G[Tenant-Aware Retrieval]
Never allow:
44. Security Architecture¶
A production graph should enforce:
Security should exist outside the model's reasoning.
45. Secrets Management¶
Agents should never receive raw secrets.
Bad:
Better:
The agent receives capability access, not credentials.
46. Data Privacy¶
Agent state may contain:
Therefore apply:
47. Prompt Injection¶
Agent graphs can encounter untrusted instructions through:
Treat external content as:
and keep control instructions separate.
48. Prompt Injection Boundary¶
flowchart LR
A[Untrusted Content] --> B[Agent Context]
B --> C[LLM]
C --> D[Decision]
D --> E[Policy Validation]
E --> F[Tool]
The model should not directly override deterministic policies.
49. Observability¶
Agent graphs require execution-level tracing.
Track:
50. Agent Trace¶
Example:
Execution: exec-101
START
↓
validate 15ms
↓
plan 420ms
↓
retrieve 140ms
↓
reason 810ms
↓
tool-selection 30ms
↓
customer-api 180ms
↓
observe 15ms
↓
reason 720ms
↓
validate 40ms
↓
END
51. Agent Metrics¶
Track:
Task Completion Rate
Tool Success Rate
Tool Selection Accuracy
Average Iterations
Maximum Iterations
Retry Rate
P95 Latency
Token Usage
Cost
Human Escalation Rate
Failure Rate
52. Agent Quality¶
Agent quality should be evaluated across multiple dimensions:
Task Success
+
Reasoning Quality
+
Tool Selection
+
Tool Arguments
+
Groundedness
+
Safety
+
Cost
+
Latency
53. Agent Evaluation Loop¶
flowchart LR
A[Test Dataset] --> B[Agent]
B --> C[Execution Trace]
C --> D[Evaluator]
D --> E[Metrics]
E --> F[Regression Analysis]
F --> G[Agent Improvement]
G --> B
54. Graph Versioning¶
An agent graph is executable business logic.
Therefore version:
Example:
55. Graph Deployment Lifecycle¶
Development
↓
Unit Tests
↓
Graph Tests
↓
AI Evaluation
↓
Security Tests
↓
Performance Tests
↓
Staging
↓
Canary
↓
Production
56. Canary Deployment¶
A new graph version can receive a small percentage of traffic.
Compare:
before increasing traffic.
57. Rollback¶
If the new graph performs poorly:
Rollback should include:
where applicable.
58. Graph Testing Strategy¶
Test at multiple levels:
59. Node Tests¶
Example:
def test_validate_input():
state = {
"query": "hello"
}
result = validate_input(state)
assert result["status"] == "valid"
Nodes should ideally be independently testable.
60. Graph Tests¶
Test:
For conditional graphs, test all important paths.
61. Failure Tests¶
Simulate:
LLM Timeout
Tool Timeout
Rate Limit
Invalid Tool Arguments
Unauthorized Tool
Empty Retrieval
Validation Failure
Checkpoint Failure
Verify:
62. Load Testing¶
Agent graphs can generate variable workloads.
Measure:
63. Cost Controls¶
Agent loops can multiply LLM calls.
Use:
Example:
These are illustrative limits, not universal defaults.
64. Backpressure¶
If downstream services become overloaded:
the system should apply:
Agents should not amplify infrastructure overload.
65. Circuit Breaker¶
For unstable external services:
If failure rate becomes high:
This protects downstream systems.
66. Agent Reliability Architecture¶
flowchart TB
A[Agent] --> B[Tool Gateway]
B --> C[Circuit Breaker]
C --> D[Rate Limiter]
D --> E[Enterprise Service]
E --> F[Response]
F --> G[Validation]
G --> A
67. Deterministic Workflow + Agent¶
One of the strongest enterprise patterns is:
Example:
This limits autonomy to the areas where it provides value.
68. Bounded Agent Pattern¶
flowchart TD
A[Workflow] --> B[Bounded Agent]
B --> C{Task Complete?}
C -->|Yes| D[Validation]
C -->|No| E[Tool]
E --> B
D --> F[Workflow]
F --> G[END]
69. Agent Supervisor Pattern¶
A supervisor can route work to specialized agents.
Detailed multi-agent architectures belong to the later Agentic AI & Multi-Agent Systems module.
For Part VIII, the focus remains on the framework and graph orchestration mechanics.
70. LangGraph + LlamaIndex¶
The two frameworks can complement each other.
Example:
flowchart TB
A[LangGraph Agent] --> B{Capability}
B -->|Knowledge| C[LlamaIndex RAG]
B -->|Customer| D[Customer Tool]
B -->|Ticket| E[Ticket Tool]
C --> F[(Vector Store)]
D --> G[Customer API]
E --> H[Ticket API]
This allows:
71. Capability-Based Architecture¶
A framework-neutral enterprise architecture can use ports:
Agent Application
│
├── Orchestration Port
│ ↓
│ LangGraph Adapter
│
├── Knowledge Port
│ ↓
│ LlamaIndex Adapter
│
├── LLM Port
│ ↓
│ Provider Adapter
│
└── Tool Port
↓
Tool Gateway
This reduces framework coupling.
72. Graph as an Execution Contract¶
A graph can act as an explicit contract describing:
Allowed Nodes
Allowed Transitions
Allowed Tools
Termination Conditions
Failure Paths
Approval Points
This is valuable in regulated enterprise systems.
73. Graph as a Policy Boundary¶
Example:
Graph:
The LLM cannot bypass the graph's policy boundary.
74. Graph Complexity¶
Graph architecture itself can become complex.
Poor:
Better:
75. Subgraphs¶
Large systems can be decomposed into smaller graph components.
Example:
Conceptually:
flowchart TB
A[Main Agent Graph] --> B[Retrieval Subgraph]
A --> C[Research Subgraph]
A --> D[Approval Subgraph]
B --> E[Return]
C --> E
D --> E
E --> A
Subgraphs can improve modularity when boundaries are well-defined.
76. Graph Composition¶
A composed architecture:
Each subgraph should have:
77. Common Anti-Patterns¶
Anti-Pattern 1 — LLM Controls Everything¶
Problem:
78. Anti-Pattern 2 — Giant Agent Graph¶
Problem:
Prefer bounded domains.
79. Anti-Pattern 3 — Unbounded Autonomy¶
Always enforce execution boundaries.
80. Anti-Pattern 4 — Business Rules in Prompts¶
Avoid:
as the only enforcement mechanism.
Prefer:
81. Anti-Pattern 5 — Shared Global State¶
Avoid:
Prefer:
82. Anti-Pattern 6 — No Idempotency¶
Avoid:
Use:
for side-effecting operations.
83. Anti-Pattern 7 — No Observability¶
Avoid:
with no information about:
84. Production Architecture Checklist¶
Graph Design¶
- [ ] Clear node responsibilities
- [ ] Explicit transitions
- [ ] Minimal state
- [ ] Bounded loops
- [ ] Explicit termination
- [ ] Modular subgraphs
Agent¶
- [ ] Planning strategy
- [ ] Reasoning strategy
- [ ] Tool selection
- [ ] Tool validation
- [ ] Reflection / validation
- [ ] Maximum iterations
Reliability¶
- [ ] Timeouts
- [ ] Retries
- [ ] Backoff
- [ ] Circuit breakers
- [ ] Idempotency
- [ ] Checkpointing
- [ ] Recovery
Security¶
- [ ] Authentication
- [ ] Authorization
- [ ] Tool authorization
- [ ] Tenant isolation
- [ ] Secret management
- [ ] Prompt injection protection
- [ ] Audit
Operations¶
- [ ] Distributed tracing
- [ ] Node metrics
- [ ] Agent metrics
- [ ] Cost tracking
- [ ] Alerts
- [ ] Graph versioning
- [ ] Rollback
85. Key Takeaways¶
- Graph-based architecture makes agent execution explicit.
- Agents and graphs are related but are not the same concept.
- Agents provide intelligent behavior while graphs provide orchestration.
- State represents the current execution context.
- Nodes should represent meaningful capabilities.
- Edges define valid transitions.
- Conditional edges enable dynamic routing.
- Loops enable iterative reasoning and tool use.
- Autonomous loops must always be bounded.
- Deterministic controls should surround LLM decisions.
- Tool access should pass through authorization and validation boundaries.
- Human approval is useful for high-risk operations.
- Checkpointing enables long-running and recoverable execution.
- Idempotency protects side-effecting operations during retries.
- Tenant isolation must be explicit.
- Agent state should never become an uncontrolled global object.
- Observability must expose graph, node, tool, model, and state transitions.
- Agent evaluation should measure both task success and operational behavior.
- Graphs should be versioned like production business logic.
- Large graphs should be decomposed into bounded subgraphs.
- LangGraph can provide orchestration while LlamaIndex provides retrieval and data capabilities.
- Capability-based architecture can reduce framework coupling.
- The strongest enterprise pattern is often deterministic workflow + bounded agent + deterministic validation.
- The objective is not maximum autonomy.
- The objective is controlled autonomy with measurable outcomes.
📝 Quick Revision Notes¶
Graph-Based Agent¶
Agent Loop¶
Enterprise Agent Loop¶
Bounded Autonomy¶
Reliable Agent¶
Framework Separation¶
LangGraph
↓
Orchestration
LlamaIndex
↓
RAG / Retrieval
LLM Provider
↓
Generation
Tool Gateway
↓
Enterprise APIs
❓ Interview Questions¶
Beginner¶
- What is graph-based agent architecture?
- What is the difference between an AI Agent and a graph?
- What are nodes and edges?
- What is graph state?
- Why are conditional edges useful?
- Why are loops useful for agents?
- What is a bounded agent loop?
- Why is tool authorization necessary?
- What is checkpointing?
- What is the difference between state and memory?
Intermediate¶
- How would you design an agent graph?
- How would you model an agent reasoning loop?
- How would you implement conditional tool routing?
- How would you prevent infinite agent loops?
- How would you implement retry and backoff?
- How would you design agent state?
- How would you implement human approval?
- How would you secure tool execution?
- How would you implement tenant isolation?
- How would you monitor graph execution?
- How would you test graph branches?
- How would you design agent checkpointing?
- How would you combine deterministic workflows and agents?
- How would you integrate LlamaIndex with LangGraph?
Advanced¶
- Design a production-grade graph-based enterprise agent.
- How would you separate the control plane from the intelligence plane?
- How would you prevent an LLM from bypassing business policies?
- How would you design a Tool Gateway for graph-based agents?
- How would you design durable agent execution?
- How would you recover a graph after infrastructure failure?
- How would you evolve agent state schemas safely?
- How would you design multi-tenant agent execution?
- How would you prevent duplicate side effects during retries?
- How would you design agent cost controls?
- How would you design observability for a multi-node agent graph?
- How would you test every important agent execution path?
- How would you design bounded autonomy?
- How would you decompose a large agent graph into subgraphs?
- How would you reduce framework coupling?
- When should you use a deterministic workflow instead of an agent?
- How would you design a LangGraph + LlamaIndex enterprise architecture?
- How would you safely deploy a new graph version?
- How would you implement canary deployment for agents?
- How would you design graph-level security boundaries?
- How would you measure whether an agent is actually improving business outcomes?
🛠️ Practical Exercise¶
Build an enterprise customer-support agent with:
1. Query Validation
2. Intent Classification
3. Knowledge Retrieval
4. Agent Reasoning
5. Tool Selection
6. Tool Authorization
7. Tool Execution
8. Result Validation
9. Human Approval for High-Risk Actions
10. Final Response
Architecture:
flowchart TD
A[START] --> B[Validate]
B --> C[Classify]
C --> D[Retrieve]
D --> E[Reason]
E --> F{Tool Required?}
F -->|No| G[Validate Answer]
F -->|Yes| H[Tool Authorization]
H --> I[Execute Tool]
I --> J[Validate Result]
J --> E
G --> K{High Risk?}
K -->|No| L[END]
K -->|Yes| M[Human Approval]
M --> N{Approved?}
N -->|Yes| L
N -->|No| O[Reject]
O --> L
Add:
Maximum 5 agent iterations
Maximum 10 tool calls
120-second execution timeout
Retry for transient tool failures
Checkpointing
Audit logging
🧪 Evaluation Exercise¶
Create at least:
Include:
Simple Requests
Multi-Step Requests
Tool Calls
RAG Queries
Tool Failures
LLM Failures
Authorization Failures
Human Approval
Rejection
Timeout
Retry
State Recovery
Measure:
Task Completion Rate
Tool Selection Accuracy
Tool Argument Accuracy
Graph Path Accuracy
Failure Recovery Rate
Average Iterations
P95 Latency
Token Usage
Cost
Human Escalation Rate
🚀 Production Architecture Exercise¶
Design a production platform:
flowchart TB
U[User] --> API[API Gateway]
API --> AUTH[Identity & Authorization]
AUTH --> APP[Agent Application]
APP --> LG[LangGraph Runtime]
LG --> PLAN[Planning Node]
PLAN --> REASON[Reasoning Node]
REASON --> ROUTE{Decision}
ROUTE -->|Knowledge| RAG[LlamaIndex RAG]
ROUTE -->|Tool| TG[Tool Gateway]
ROUTE -->|Approval| HUMAN[Human Approval]
RAG --> VS[(Vector Store)]
TG --> POLICY[Tool Policy]
POLICY --> SERVICES[Enterprise Services]
HUMAN --> ROUTE
SERVICES --> OBS[Observation]
RAG --> OBS
OBS --> REASON
LG --> STATE[(Checkpoint / State Store)]
LG --> TRACE[Observability]
LG --> AUDIT[Audit]
LG --> COST[Cost Controls]
The platform must support:
Multi-Tenancy
High Availability
Long-Running Execution
Human Approval
Tool Authorization
RAG
Multiple LLM Providers
Observability
Audit
Cost Controls
Rollback
🧠 Architecture Challenge¶
Design a Banking Operations Agent that can:
1. Search customer information
2. Retrieve bank policies
3. Analyze transactions
4. Create support tickets
5. Recommend actions
6. Execute low-risk operations
7. Request human approval for high-risk operations
The agent must never directly execute an irreversible operation solely because the LLM requested it.
Design the graph with:
Then identify:
What is deterministic?
What is LLM-driven?
What is persisted?
What is audited?
What requires human approval?
What can be automatically retried?
📚 References & Further Reading¶
Recommended areas for further study:
- LangGraph Architecture
- Graph-Based Agent Orchestration
- Stateful Agent Systems
- Agent Planning
- Agent Reasoning
- Tool Calling
- Human-in-the-Loop Systems
- Durable Execution
- Checkpointing
- Agent Evaluation
- Agent Observability
- AI Security
- Tool Authorization
- Enterprise Workflow Architecture
- LlamaIndex RAG
- LangGraph + LlamaIndex Integration
- Capability-Based Architecture
- Ports & Adapters Architecture
- Multi-Tenant AI Systems
- AI FinOps
- Distributed Systems Reliability
LangGraph and the surrounding AI framework ecosystem evolve rapidly. Verify the current APIs, state semantics, persistence mechanisms, checkpointing behavior, graph execution model, and deployment recommendations against the official documentation for the exact versions used in production.
🧭 Chapter Navigation¶
⬅️ Previous: 17. LangGraph Fundamentals
📚 Part VIII Index: AI Engineering Frameworks & Tooling
➡️ Next: 19. LangGraph State and Checkpointing
Enterprise AI Engineering Handbook
Building Production-Grade Enterprise AI Systems — One Chapter at a Time.