Day 2 (Tuesday): Data Pipeline and Core Agent Build
Tuesday is build day. I start with the data pipeline because everything downstream depends on it.
Morning: Build the Data Pipeline
The pipeline handles ingestion, transformation, and storage. For most workflows, I use a combination of n8n for orchestration and custom TypeScript for the AI-specific logic:
// pipeline/ingest.ts
import Anthropic from '@anthropic-ai/sdk';
const anthropic = new Anthropic();
interface ExtractionResult {
vendor_name: string;
invoice_number: string;
date: string;
line_items: LineItem[];
total_amount: number;
currency: string;
confidence: number;
}
async function extractInvoiceData(
documentBase64: string,
mimeType: string
): Promise<ExtractionResult> {
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 2048,
messages: [
{
role: 'user',
content: [
{
type: 'document',
source: { type: 'base64', media_type: mimeType, data: documentBase64 }
},
{
type: 'text',
text: `Extract all invoice data from this document. Return JSON with:
vendor_name, invoice_number, date (ISO 8601), line_items (description, quantity, unit_price, total),
total_amount, currency. Include a confidence score 0-1.
If any field is ambiguous, set confidence lower and include "ambiguous_fields" array.`
}
]
}
]
});
return JSON.parse(response.content[0].type === 'text' ? response.content[0].text : '');
}
Afternoon: Wire Up the Core Agent
With extraction working, I connect the remaining steps — validation, enrichment, and routing. The n8n workflow looks like this:
{
"name": "Invoice Processing Agent",
"nodes": [
{
"name": "Email Trigger",
"type": "n8n-nodes-base.emailTrigger",
"parameters": {
"mailbox": "invoices@company.com",
"filters": { "hasAttachment": true }
}
},
{
"name": "Extract with AI",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://api.internal/extract-invoice",
"method": "POST",
"body": "={{ JSON.stringify({ document: $json.attachments[0] }) }}"
}
},
{
"name": "Validate Against Rules",
"type": "n8n-nodes-base.function",
"parameters": {
"functionCode": "const data = $input.all()[0].json;\nconst valid = data.confidence > 0.95 && data.total_amount > 0;\nreturn [{ json: { ...data, valid, needs_review: !valid } }];"
}
},
{
"name": "Route Decision",
"type": "n8n-nodes-base.switch",
"parameters": {
"rules": [
{ "condition": "={{ $json.needs_review }}", "output": "Human Review" },
{ "condition": "={{ $json.total_amount > 10000 }}", "output": "Manager Approval" },
{ "condition": "={{ true }}", "output": "Auto Approve" }
]
}
}
]
}
End of Day 2 deliverable: A working pipeline that can ingest a document, extract data via AI, validate it, and route it. It is ugly. It does not handle errors gracefully. But data flows from input to output.