Embeddings
Generate vector embeddings from text to enable semantic search, clustering, and similarity comparison.
Quick Start
class MyAgent < ApplicationAgent
embed_with :openai, model: "text-embedding-3-small"
def vectorize
embed(input: params[:text])
end
end
response = MyAgent.with(text: "Hello world").vectorize.embed_now
vector = response.data.first[:embedding] # => [0.123, -0.456, ...]2
3
4
5
6
7
8
9
10
Basic Usage
Generate embeddings using embed with synchronous or asynchronous execution:
response = ApplicationAgent.embed(
input: "The quick brown fox",
model: "text-embedding-3-small"
).embed_now
vector = response.data.first[:embedding]2
3
4
5
job = ApplicationAgent.embed(
input: "Long document text",
model: "text-embedding-3-small"
).embed_later(
queue: :embeddings,
priority: 10
)2
3
4
5
6
7
response = ApplicationAgent.embed(
input: [ "First text", "Second text", "Third text" ],
model: "text-embedding-3-small"
).embed_now
vectors = response.data.pluck(:embedding)2
3
4
5
6
Response Structure
Embedding responses contain the vector data:
response = ApplicationAgent.embed(
input: "Sample text",
model: "text-embedding-3-small"
).embed_now
# Access embedding vector
vector = response.data.first[:embedding] # Array of floats
# Check dimensions
vector.size # => 1536 (varies by model)2
3
4
5
6
7
8
9
10
Configuration
Configure the embedding provider using embed_with:
class EmbeddingAgent < ApplicationAgent
embed_with :openai, model: "text-embedding-3-small"
end
response = EmbeddingAgent.embed(input: "Your text").embed_now2
3
4
5
Mixing Providers
Use different providers for prompting and embeddings:
class HybridAgent < ApplicationAgent
generate_with :anthropic, model: "claude-3-5-sonnet-20241022"
embed_with :openai, model: "text-embedding-3-small"
end
# Use Anthropic for chat
chat_response = HybridAgent.prompt(message: "Hello").generate_now
# Use OpenAI for embeddings
embed_response = HybridAgent.embed(input: "Hello").embed_now2
3
4
5
6
7
8
9
10
This lets you choose the best provider for each task—for example, using Anthropic's Claude for reasoning while leveraging OpenAI's specialized embedding models.
Provider-Specific Options
OpenAI
class OpenAIAgent < ApplicationAgent
embed_with :openai,
model: "text-embedding-3-small",
dimensions: 512 # Reduce from default 1536
end2
3
4
5
Ollama
class OllamaAgent < ApplicationAgent
embed_with :ollama,
model: "nomic-embed-text",
host: "http://localhost:11434"
end2
3
4
5
See OpenAI Provider and Ollama Provider for more options.
Callbacks
Process embeddings with before and after callbacks:
class TrackedAgent < ApplicationAgent
embed_with :openai, model: "text-embedding-3-small"
before_embed :log_start
after_embed :log_complete
private
def log_start
Rails.logger.info "Starting embedding generation"
end
def log_complete
Rails.logger.info "Embedding complete"
end
end
response = TrackedAgent.embed(input: "Text").embed_now
# Logs before and after generation2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
See Callbacks for more on callback functionality.
Similarity Search
Compare text similarity using cosine similarity:
def cosine_similarity(vec1, vec2)
dot_product = vec1.zip(vec2).map { |a, b| a * b }.sum
magnitude1 = Math.sqrt(vec1.map { |v| v**2 }.sum)
magnitude2 = Math.sqrt(vec2.map { |v| v**2 }.sum)
dot_product / (magnitude1 * magnitude2)
end
documents = [
"The cat sat on the mat",
"Dogs are loyal companions",
"Machine learning is a subset of AI",
"The feline rested on the rug"
]
# Generate embeddings
response = ApplicationAgent.embed(
input: documents,
model: "text-embedding-3-small"
).embed_now
embeddings = response.data.map { |item| item[:embedding] }
# Query
query = "cat on mat"
query_embedding = ApplicationAgent.embed(
input: query,
model: "text-embedding-3-small"
).embed_now.data.first[:embedding]
# Calculate similarities
results = embeddings.map.with_index do |embedding, i|
similarity = cosine_similarity(query_embedding, embedding)
{ document: documents[i], similarity: }
end.sort_by { |r| -r[:similarity] }
results.first[:document] # => "The cat sat on the mat"2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Model Dimensions
Different models produce different embedding dimensions:
# OpenAI text-embedding-3-small: 1536 dimensions (default)
# OpenAI text-embedding-3-large: 3072 dimensions
# OpenAI text-embedding-ada-002: 1536 dimensions
# Ollama nomic-embed-text: 768 dimensions
response = ApplicationAgent.embed(
input: "Test",
model: "text-embedding-3-small"
).embed_now
dimensions = response.data.first[:embedding].size2
3
4
5
6
7
8
9
10
class CompactAgent < ApplicationAgent
embed_with :openai,
model: "text-embedding-3-small",
dimensions: 512 # Smaller, faster
end2
3
4
5
Related Documentation
- Agents - Understanding the agent lifecycle
- Actions - Overview of agent capabilities
- Generation - Understanding the generation workflow
- Callbacks - Before and after embedding hooks
- Configuration - Configure embedding behavior
- Testing - Test embedding functionality
- OpenAI Provider - OpenAI embedding models
- Ollama Provider - Local embedding generation