1C Platform1cPlatform
AI Comparison

Data Flow Architectures in Agentic AI: Push vs Pull vs Stream

Dr. Sarah Williams
20 min read
December 26, 2024

Introduction

How data flows through your agentic AI system dramatically impacts performance, scalability, and user experience. This guide compares three fundamental data flow patterns and helps you choose the right approach for your architecture.

1. Pull-Based Architecture (Request-Response)

How It Works

Clients actively request data from the AI agent. The agent processes the request and returns a response. This is the traditional synchronous pattern.

Flow:

  1. Client sends request to agent
  2. Agent processes request (calls LLM, queries database, etc.)
  3. Agent returns complete response
  4. Connection closes

Advantages

  • Simple to implement: Standard REST API pattern
  • Easy to debug: Clear request-response pairs
  • Familiar: Developers know this pattern well
  • Stateless: Each request is independent
  • Cacheable: Can cache responses easily

Disadvantages

  • Blocking: Client waits for complete response
  • Timeout risk: Long-running LLM calls may timeout
  • Resource waste: Connection held open during processing
  • Poor UX for slow operations: User sees loading spinner

Best Use Cases

  • Quick queries with fast responses (<2 seconds)
  • Simple CRUD operations
  • APIs consumed by other systems
  • Mobile apps with limited connectivity

Example Implementation

// Express.js pull-based endpoint
app.post('/api/agent/query', async (req, res) => {
  const { prompt } = req.body;
  
  // Process request (this blocks until complete)
  const response = await agent.process(prompt);
  
  // Return complete response
  res.json({ response });
});

// Client code
const response = await fetch('/api/agent/query', {
  method: 'POST',
  body: JSON.stringify({ prompt: 'Summarize this document' })
});
const data = await response.json();
console.log(data.response); // Complete response

2. Push-Based Architecture (Webhooks/Callbacks)

How It Works

Client submits a request and provides a callback URL. The agent processes asynchronously and pushes the result to the callback URL when complete.

Flow:

  1. Client submits request with callback URL
  2. Server immediately returns acknowledgment (202 Accepted)
  3. Agent processes request in background
  4. Agent pushes result to callback URL when done

Advantages

  • Non-blocking: Client doesn't wait for response
  • Handles long operations: No timeout issues
  • Efficient: No resources held during processing
  • Scalable: Easy to queue and batch work

Disadvantages

  • Complex error handling: How to notify client of failures?
  • Requires callback endpoint: Client must expose an endpoint
  • Order not guaranteed: Callbacks may arrive out of order
  • Security complexity: Must authenticate callback requests

Best Use Cases

  • Batch processing (analyze 1000 documents)
  • Long-running operations (>30 seconds)
  • Server-to-server communication
  • Background jobs (report generation, data export)

Example Implementation

// Submit job endpoint
app.post('/api/agent/jobs', async (req, res) => {
  const { prompt, callbackUrl } = req.body;
  
  // Create job and return immediately
  const jobId = await jobQueue.add({ prompt, callbackUrl });
  
  res.status(202).json({ 
    jobId, 
    status: 'processing',
    statusUrl: `/api/agent/jobs/${jobId}`
  });
});

// Worker processes job asynchronously
jobQueue.process(async (job) => {
  const { prompt, callbackUrl } = job.data;
  const response = await agent.process(prompt);
  
  // Push result to callback URL
  await fetch(callbackUrl, {
    method: 'POST',
    body: JSON.stringify({ jobId: job.id, response })
  });
});

3. Streaming Architecture (Server-Sent Events / WebSockets)

How It Works

Persistent connection between client and server. Agent streams partial results as they're generated, providing real-time updates.

Flow:

  1. Client establishes persistent connection (WebSocket/SSE)
  2. Client sends request over connection
  3. Agent streams partial responses as they're generated
  4. Client receives and displays results incrementally
  5. Connection remains open for additional requests

Advantages

  • Real-time feedback: User sees progress immediately
  • Better UX: Token-by-token LLM output (like ChatGPT)
  • Efficient for multiple exchanges: Reuse same connection
  • Bidirectional: Server can push updates anytime
  • Lower latency: No connection overhead per request

Disadvantages

  • Complex implementation: Need WebSocket infrastructure
  • Connection management: Handle disconnects, reconnects
  • Harder to load balance: Sticky sessions required
  • Firewall issues: Some networks block WebSockets
  • Debugging challenges: Harder to inspect streams

Best Use Cases

  • Chat interfaces (conversational AI)
  • Real-time dashboards
  • Collaborative editing
  • Live notifications
  • Games and interactive applications

Example Implementation (Server-Sent Events)

// Express.js SSE endpoint
app.get('/api/agent/stream', async (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');
  
  const prompt = req.query.prompt;
  
  // Stream tokens as they're generated
  await agent.processStream(prompt, (token) => {
    res.write(`data: ${JSON.stringify({ token })}

`);
  });
  
  res.write('data: [DONE]

');
  res.end();
});

// Client code
const eventSource = new EventSource('/api/agent/stream?prompt=...');
eventSource.onmessage = (event) => {
  const { token } = JSON.parse(event.data);
  if (token === '[DONE]') {
    eventSource.close();
  } else {
    displayToken(token); // Show token immediately
  }
};

Hybrid Patterns

Pattern 1: Pull with Polling

Submit request via pull API, get job ID, then poll status endpoint until complete. Combines simplicity of pull with async benefits of push.

  • Best for: Long operations without callback infrastructure
  • Downside: Polling overhead, delayed notifications

Pattern 2: Stream with Fallback

Attempt WebSocket connection, fall back to SSE if blocked, fall back to long polling if SSE fails.

  • Best for: Unreliable networks, maximum compatibility
  • Downside: Complex implementation, multiple code paths

Pattern 3: Push with Status Stream

Submit job with callback URL, but also provide real-time status updates via WebSocket.

  • Best for: Long jobs where user wants live progress
  • Downside: Requires both systems

Comparison Table

FactorPull (Request-Response)Push (Webhooks)Stream (WebSocket/SSE)
ComplexitySimpleMediumComplex
Real-time FeedbackNoNoYes
Handles Long OperationsPoorExcellentGood
Client RequirementsNoneCallback endpointWebSocket support
ScalabilityGoodExcellentMedium
User ExperienceBlockingDelayed notificationInstant feedback

Decision Framework

Choose Pull-Based When:

  • Operations complete in under 2 seconds
  • Building public API for third-party consumers
  • Simplicity is more important than UX
  • Mobile app with intermittent connectivity

Choose Push-Based When:

  • Operations take 30+ seconds
  • Processing batches of items
  • Server-to-server integration
  • Client can expose a callback endpoint

Choose Streaming When:

  • Building interactive chat interface
  • User needs immediate feedback
  • Multiple back-and-forth exchanges
  • Real-time collaboration features

Conclusion

Your data flow architecture should match your use case. For most agentic AI applications, streaming provides the best user experience for interactive scenarios, while push-based architecture excels for batch processing. Don't hesitate to use different patterns for different endpoints in the same system - choose what makes sense for each use case.

Share this article: