Build Your First Retrieval Pipeline for LLMs and Agents
In this guide, you'll build a retrieval pipeline that can provide your connected LLM or agent framework with structured, document-based context. You'll upload documents, create a pipeline with retrieval capabilities, and connect it to an LLM — all with runnable code examples.
What You'll Build
By the end of this guide, you'll have:
- An agent-ready pipeline that transforms your content into structured context
- A chatbot that can answer complex questions about your content via your connected LLM
- Familiarity with core Vectorize concepts
Prerequisites
Before you begin, you'll need:
- A Vectorize account
- An API access token (how to create one)
- Your organization ID (see below)
Finding your Organization ID
Your organization ID is in the Vectorize platform URL:
https://platform.vectorize.io/organization/[YOUR-ORG-ID]
For example, if your URL is:
https://platform.vectorize.io/organization/ecf3fa1d-30d0-4df1-8af6-f4852bc851cb
Your organization ID is: ecf3fa1d-30d0-4df1-8af6-f4852bc851cb
API Client Setup
- Python
- Node.js
import vectorize_client as v
import os
# Get credentials from environment variables
organization_id = os.environ.get("VECTORIZE_ORGANIZATION_ID")
api_key = os.environ.get("VECTORIZE_API_KEY")
if not organization_id or not api_key:
raise ValueError("Please set VECTORIZE_ORGANIZATION_ID and VECTORIZE_API_KEY environment variables")
# Initialize the API client
configuration = v.Configuration(
host="https://api.vectorize.io",
api_key={"ApiKeyAuth": api_key}
)
api = v.ApiClient(configuration)
print(f"✅ API client initialized for organization: {organization_id}")
const v = require('@vectorize-io/vectorize-client');
// Get credentials from environment variables
const organizationId = process.env.VECTORIZE_ORGANIZATION_ID;
const apiKey = process.env.VECTORIZE_API_KEY;
if (!organizationId || !apiKey) {
throw new Error("Please set VECTORIZE_ORGANIZATION_ID and VECTORIZE_API_KEY environment variables");
}
// Initialize the API client
const configuration = new v.Configuration({
basePath: 'https://api.vectorize.io',
accessToken: apiKey
});
const apiClient = new v.ApiClient(configuration);
console.log(`✅ API client initialized for organization: ${organizationId}`);
How your LLM (or agent) uses your data
Retrieval-Augmented Generation (RAG) provides the foundation that enables your LLM (and any agent framework you use) to access and use your specific data. Instead of relying solely on general knowledge, agents powered by RAG can:
- Access your documents through intelligent retrieval
- Use structured context to interpret relationships within your content
- Support reasoning across multiple sources via the connected LLM
- Generate informed responses grounded in your actual data
This transforms AI from a general-purpose tool into an intelligent agent workflow that uses your organization's knowledge to provide more relevant, grounded responses.
Step 1: Create a File Upload Connector
A source connector is how you get data into Vectorize. For this guide, we'll use a File Upload connector to upload documents directly:
- Python
- Node.js
import vectorize_client as v
# Create the connectors API client
connectors_api = v.SourceConnectorsApi(apiClient)
try:
# Create a file upload connector
file_upload = v.FileUpload(
name="my-document-upload",
type="FILE_UPLOAD",
config={}
)
request = v.CreateSourceConnectorRequest(file_upload)
response = connectors_api.create_source_connector(
organization_id,
request
)
connector_id = response.connector.id
print(f"✅ Created file upload connector: {connector_id}")
except Exception as e:
print(f"❌ Error creating connector: {e}")
raise
const { SourceConnectorsApi } = vectorize;
// Create the connectors API client
const connectorsApi = new SourceConnectorsApi(apiConfig);
// Creating connectors is an async operation
async function createFileUploadConnector() {
try {
// Create a file upload connector
const fileUpload = {
name: 'my-document-upload',
type: 'FILE_UPLOAD',
config: {} // File upload connectors don't require config
};
const response = await connectorsApi.createSourceConnector({
"your-org-id": "your-org-id",
createSourceConnectorRequest: fileUpload
});
const connectorId = response.connector.id;
console.log(`✅ Created file upload connector: ${connectorId}`);
return connectorId;
} catch (error) {
console.error(`❌ Error creating connector: ${error.message}`);
// Re-throw to let caller handle the error
throw error;
}
}
// Call the async function
const connectorId = await createFileUploadConnector();
Step 2: Upload Your First Document
Now let's upload a document. In this example, we're uploading a simple .txt file. You can upload PDFs, Word docs, or any supported text format - the upload process is the same regardless of file type.
- Python
- Node.js
import vectorize_client as v
import os
import urllib3
# Create uploads API client
uploads_api = v.UploadsApi(apiClient)
try:
# Step 1: Get upload URL
upload_request = v.StartFileUploadToConnectorRequest(
name=file_name,
content_type="text/plain"
)
start_response = uploads_api.start_file_upload_to_connector(
organization_id,
source_connector_id,
start_file_upload_to_connector_request=upload_request
)
# Step 2: Upload file to the URL
http = urllib3.PoolManager()
with open(file_path, "rb") as f:
response = http.request(
"PUT",
start_response.upload_url,
body=f,
headers={
"Content-Type": "text/plain",
"Content-Length": str(os.path.getsize(file_path))
}
)
if response.status == 200:
print(f"✅ Successfully uploaded: {file_name}")
else:
print(f"❌ Upload failed: {response.status}")
except Exception as e:
print(f"❌ Error uploading file: {e}")
raise
const { UploadsApi } = vectorize;
const fs = require('fs');
// Create uploads API client
const uploadsApi = new UploadsApi(apiConfig);
// File uploads require two async steps
async function uploadDocument(connectorId, filePath, fileName) {
try {
// Step 1: Get a pre-signed upload URL from Vectorize
const uploadRequest = {
name: fileName,
contentType: 'text/plain'
};
const startResponse = await uploadsApi.startFileUploadToConnector({
"your-org-id": "your-org-id",
connectorId: connectorId,
startFileUploadToConnectorRequest: uploadRequest
});
// Step 2: Upload file directly to the pre-signed URL
const fileBuffer = fs.readFileSync(filePath);
const fileStats = fs.statSync(filePath);
const response = await fetch(startResponse.uploadUrl, {
method: 'PUT',
body: fileBuffer,
headers: {
'Content-Type': 'text/plain',
'Content-Length': fileStats.size.toString()
}
});
if (response.status === 200) {
console.log(`✅ Successfully uploaded: ${fileName}`);
return true;
} else {
const errorText = await response.text();
throw new Error(`Upload failed with status ${response.status}: ${errorText}`);
}
} catch (error) {
console.error(`❌ Error uploading file: ${error.message}`);
throw error;
}
}
// Call the async function
await uploadDocument(sourceConnectorId, filePath, fileName);
Step 3: Create Your Pipeline
A pipeline transforms your raw documents into structured context that your connected LLM or agent can use for retrieval and answering. Vectorize provides built-in processing and vector storage to enable agent capabilities:
- Python
- Node.js
import vectorize_client as v
# Create pipelines API client
pipelines_api = v.PipelinesApi(apiClient)
try:
# Configure your pipeline
pipeline_config = v.PipelineConfigurationSchema(
pipeline_name="My First Pipeline",
source_connectors=[
v.PipelineSourceConnectorSchema(
id=source_connector_id,
type="FILE_UPLOAD",
config={}
)
],
ai_platform_connector=v.PipelineAIPlatformConnectorSchema(
id=ai_platform_connector_id, # Uses Vectorize's built-in AI
type="VECTORIZE",
config={}
),
destination_connector=v.PipelineDestinationConnectorSchema(
id=destination_connector_id, # Uses Vectorize's built-in vector store
type="VECTORIZE",
config={}
),
schedule=v.ScheduleSchema(type="manual")
)
# Create the pipeline
response = pipelines_api.create_pipeline(
organization_id,
pipeline_config
)
pipeline_id = response.data.id
print(f"✅ Created pipeline: {pipeline_id}")
except Exception as e:
print(f"❌ Error creating pipeline: {e}")
raise
const { PipelinesApi } = vectorize;
// Create pipelines API client
const pipelinesApi = new PipelinesApi(apiConfig);
let pipelineId;
try {
// Configure your pipeline
const pipelineConfig = {
pipelineName: 'My First Pipeline',
sourceConnectors: [
{
id: sourceConnectorId,
type: 'FILE_UPLOAD',
config: {}
}
],
aiPlatformConnector: {
id: aiPlatformConnectorId, // Uses Vectorize's built-in AI
type: 'VECTORIZE',
config: {}
},
destinationConnector: {
id: destinationConnectorId, // Uses Vectorize's built-in vector store
type: 'VECTORIZE',
config: {}
},
schedule: { type: 'manual' }
};
// Create the pipeline
const response = await pipelinesApi.createPipeline({
"your-org-id": "your-org-id",
pipelineConfigurationSchema: pipelineConfig
});
pipelineId = response.data.id;
console.log(`✅ Created pipeline: ${pipelineId}`);
} catch (error) {
console.log(`❌ Error creating pipeline: ${error.message}`);
throw error;
}
What's Happening Here?
When you create a pipeline, you’re building the infrastructure your connected LLM or agent will use for retrieval and context.
- Source Connector: Feeds documents into your pipeline’s retrieval index
- AI Platform Connector: Converts documents into vector embeddings and structured metadata for retrieval
- Destination Connector: Maintains structured, queryable indexes for retrieval (Vectorize's built-in vector store or an external destination)
- Schedule: Controls when your pipeline’s data is refreshed. Changes to source content trigger automatic reprocessing.
This pipeline enables your LLM to not just locate relevant information, but to use richer context for grounded answers.
Step 4: Wait for Processing
Your pipeline needs a few moments to process the uploaded document. Let's monitor its progress:
- Python
- Node.js
import vectorize_client as v
import time
# Create pipelines API client
pipelines_api = v.PipelinesApi(apiClient)
print("Waiting for pipeline to process your document...")
max_wait_time = 300 # 5 minutes
start_time = time.time()
while True:
try:
# Check pipeline status
pipeline = pipelines_api.get_pipeline(organization_id, pipeline_id)
status = pipeline.data.status
# Check if ready
if status == "LISTENING":
print("✅ Pipeline is ready!")
break
elif status == "PROCESSING":
print("⚙️ Still processing...")
elif status in ["ERROR_DEPLOYING", "SHUTDOWN"]:
print(f"❌ Pipeline error: {status}")
break
# Check timeout
if time.time() - start_time > max_wait_time:
print("⏰ Timeout waiting for pipeline")
break
time.sleep(10) # Check every 10 seconds
except Exception as e:
print(f"❌ Error checking status: {e}")
break
const { PipelinesApi } = vectorize;
// Create pipelines API client
const pipelinesApi = new PipelinesApi(apiConfig);
console.log('Waiting for pipeline to process your document...');
const maxWaitTime = 300000; // 5 minutes in milliseconds
const startTime = Date.now();
while (true) {
try {
// Check pipeline status
const pipeline = await pipelinesApi.getPipeline({
"your-org-id": "your-org-id",
pipelineId: pipelineId
});
const status = pipeline.data.status;
// Check if ready
if (status === 'LISTENING') {
console.log('✅ Pipeline is ready!');
break;
} else if (status === 'PROCESSING') {
console.log('⚙️ Still processing...');
} else if (['ERROR_DEPLOYING', 'SHUTDOWN'].includes(status)) {
console.log(`❌ Pipeline error: ${status}`);
break;
}
// Check timeout
if (Date.now() - startTime > maxWaitTime) {
console.log('⏰ Timeout waiting for pipeline');
break;
}
await new Promise(resolve => setTimeout(resolve, 10000)); // Check every 10 seconds
} catch (error) {
console.log(`❌ Error checking status: ${error.message}`);
break;
}
}
Pipeline States
- DEPLOYING: Pipeline is being set up
- PROCESSING: Actively processing documents
- LISTENING: Ready and waiting for queries
For a complete list of pipeline states, see Understanding Pipeline Status.
Step 5: Query Your Pipeline
Once the pipeline is ready, your connected LLM can use it to retrieve relevant context and respond to questions about your content:
- Python
- Node.js
import vectorize_client as v
# Create pipelines API client
pipelines_api = v.PipelinesApi(apiClient)
try:
# Query the pipeline
response = pipelines_api.retrieve_documents(
organization_id,
pipeline_id,
v.RetrieveDocumentsRequest(
question="How to call the API?",
num_results=5
)
)
# Display results
print(f"Found {len(response.documents)} relevant documents:\n")
for i, doc in enumerate(response.documents, 1):
print(f"Result {i}:")
print(f" Content: {doc.text[:200]}...") # Use 'text' instead of 'content'
print(f" Relevance Score: {doc.relevancy}") # Use 'relevancy' instead of 'score'
print(f" Document ID: {doc.id}")
print()
except Exception as e:
print(f"❌ Error querying pipeline: {e}")
raise
const { PipelinesApi } = vectorize;
// Create pipelines API client
const pipelinesApi = new PipelinesApi(apiConfig);
try {
// Query the pipeline
const response = await pipelinesApi.retrieveDocuments({
"your-org-id": "your-org-id",
pipelineId: pipelineId,
retrieveDocumentsRequest: {
question: 'How to call the API?',
numResults: 5
}
});
// Display results
console.log(`Found ${response.documents.length} relevant documents:\n`);
response.documents.forEach((doc, index) => {
console.log(`Result ${index + 1}:`);
console.log(` Content: ${doc.text.substring(0, 200)}...`); // Use 'text' instead of 'content'
console.log(` Relevance Score: ${doc.relevancy}`); // Use 'relevancy' instead of 'score'
console.log(` Document ID: ${doc.id}`);
console.log();
});
} catch (error) {
console.log(`❌ Error querying pipeline: ${error.message}`);
throw error;
}
How Your Pipeline + LLM Process Queries
When you submit a query, the pipeline and LLM:
- Interprets Query: The connected LLM interprets your request using the retrieved context
- Retrieves Context: Finds relevant information across your documents
- Combines Context: The LLM synthesizes retrieved information from multiple sources
- Generates Insight: Provides answers that go beyond simple retrieval
With sufficient retrieved context, your connected LLM can:
- Answer "why" and "how" questions that require reasoning
- Identify patterns and relationships in your data
- Provide recommendations based on your content
- Synthesize insights from disparate sources
Try these types of questions to see retrieval + reasoning in action:
- "What are the implications of...?"
- "How do these concepts relate to each other?"
- "What should we prioritize based on...?"
Understanding Your Results
The query response includes:
- Answer: The LLM-generated response to your question
- Sources: Which document chunks were used
- Relevance score: Based on embedding similarity, indicates how closely the retrieved content matched your query
- Metadata: Additional information about the sources
Step 6: Build Your Custom Chatbot
Now that your pipeline is working, let's create a chatbot that connects your pipeline to an LLM for interactive Q&A.
Download a Custom Chatbot Application
Vectorize can generate a complete chatbot application that showcases your pipeline's capabilities:
- Navigate to your pipeline in the Vectorize platform
- Go to the AI Integrations tab
- Click on Chatbot
- Select your preferred LLM provider (e.g., OpenAI) and model (e.g., gpt-4o)
- Click Download Chatbot ZIP
The downloaded application includes:
- Pre-configured connection to your pipeline
- Your organization ID and endpoints already set up
- Choice of LLM for responses
- Clean, customizable Next.js interface
Note: This application uses your selected LLM provider’s API — you’ll need a valid API key for that provider, and usage may incur costs.
Running Your Chatbot
After downloading:
- Unzip the file and navigate to the project folder
- Configure your environment variables in
.env.development
:OPENAI_API_KEY=sk-...
VECTORIZE_TOKEN=your-vectorize-token - Install and run:
npm install
npm run dev - Open http://localhost:3000 to interact with your chatbot!
You now have a fully functional chatbot that can query your documents via your pipeline and use your connected LLM to generate grounded answers.
What's Next?
Congratulations! You've built your first agent-ready pipeline with Vectorize.
Here are some next steps to enhance your pipeline's capabilities:
- Make Your AI Smarter with Metadata: Use structured metadata to improve retrieval and filtering.
- Understanding Data Pipelines: Deep dive into how agent pipelines work.