Guias
Integrando Componentes RAG
Como todos os componentes se conectam para criar um sistema RAG completo
Integrando Componentes RAG
Esta seção explica como todos os componentes se conectam para criar um sistema RAG completo.
Arquitetura de Alto Nível
Como Tudo se Conecta
1. Fluxo de Dados
O fluxo de dados em um sistema RAG completo:
interface RAGSystem {
vectorStore: VectorStore;
chatMemory: ChatMemory;
llmClient: LLM;
agentInstructions: string;
}
async function processQuery(
system: RAGSystem,
query: string,
userId: string
): Promise<string> {
// 1. Obter contexto do histórico
const chatHistory = await system.chatMemory.getMessages(userId);
// 2. Gerar embedding da query
const queryEmbedding = await generateEmbedding(query);
// 3. Buscar documentos relevantes
const relevantDocs = await system.vectorStore.search(queryEmbedding);
// 4. Montar prompt com todos os componentes
const prompt = buildCompletePrompt({
instructions: system.agentInstructions,
chatHistory,
relevantDocs,
query
});
// 5. Gerar resposta
const response = await system.llmClient.complete(prompt);
// 6. Atualizar memória de chat
await system.chatMemory.addMessage(userId, {
role: 'user',
content: query
});
await system.chatMemory.addMessage(userId, {
role: 'assistant',
content: response
});
return response;
}2. Responsabilidades dos Componentes
| Componente | Função | Interface Com |
|---|---|---|
| Base de Conhecimento | Fonte de verdade factual | Banco Vetorial |
| Embeddings | Transformação semântica | LLM API, Banco Vetorial |
| Banco Vetorial | Armazenamento & Recuperação | Backend App |
| Chat Memory | Contexto conversacional | Redis, Backend App |
| Instruções | Comportamento do agente | LLM |
| LLM | Geração de respostas | OpenAI/Anthropic/etc |
3. Construção do Prompt
Um exemplo de como todos os componentes se unem no prompt:
function buildCompletePrompt({
instructions,
chatHistory,
relevantDocs,
query
}: {
instructions: string;
chatHistory: ChatMessage[];
relevantDocs: Document[];
query: string;
}): string {
const historyText = chatHistory
.map(msg => `${msg.role}: ${msg.content}`)
.join('\n');
const docsText = relevantDocs
.map(doc => doc.content)
.join('\n\n');
return `
${instructions}
=== Histórico da Conversa ===
${historyText}
=== Informações Relevantes ===
${docsText}
=== Pergunta Atual ===
Usuário: ${query}
Assistente:
`;
}Implementação em Diferentes Camadas
Camada de Banco de Dados
// Exemplo com MongoDB
class MongoVectorStore implements VectorStore {
constructor(private collection: Collection) {}
async search(embedding: number[], limit = 5): Promise<Document[]> {
return await this.collection.aggregate([
{
$vectorSearch: {
queryVector: embedding,
path: "embedding",
numCandidates: 100,
limit
}
},
{
$project: {
_id: 0,
content: 1,
metadata: 1,
score: { $meta: "vectorSearchScore" }
}
}
]).toArray();
}
async addDocument(doc: Document, embedding: number[]): Promise<void> {
await this.collection.insertOne({
content: doc.content,
metadata: doc.metadata,
embedding
});
}
}Camada de Cache/Memory
// Exemplo com Redis
class RedisMemory implements ChatMemory {
constructor(private redis: Redis, private ttl = 3600) {}
async addMessage(userId: string, message: ChatMessage): Promise<void> {
const key = `chat:${userId}`;
await this.redis.rpush(key, JSON.stringify(message));
await this.redis.expire(key, this.ttl);
}
async getMessages(userId: string): Promise<ChatMessage[]> {
const key = `chat:${userId}`;
const messages = await this.redis.lrange(key, 0, -1);
return messages.map(m => JSON.parse(m));
}
}Camada de API
// Exemplo com Express
function setupRagEndpoints(app: Express, system: RAGSystem) {
app.post('/api/chat', async (req, res) => {
try {
const { message, userId } = req.body;
if (!message || !userId) {
return res.status(400).json({ error: 'Missing required fields' });
}
const response = await processQuery(system, message, userId);
res.json({ response });
} catch (error) {
console.error('Error processing chat:', error);
res.status(500).json({ error: 'Failed to process request' });
}
});
app.get('/api/chat/:userId/history', async (req, res) => {
try {
const { userId } = req.params;
const history = await system.chatMemory.getMessages(userId);
res.json({ history });
} catch (error) {
res.status(500).json({ error: 'Failed to retrieve chat history' });
}
});
}Considerações de Produção
Para sistemas em produção:
1. Monitoramento e Logging
async function processQueryWithMonitoring(
system: RAGSystem,
query: string,
userId: string
): Promise<string> {
const startTime = Date.now();
try {
// Processo normal
const response = await processQuery(system, query, userId);
// Métricas
const duration = Date.now() - startTime;
metrics.recordQueryTime(duration);
metrics.incrementQueryCount();
return response;
} catch (error) {
// Logging de erros
logger.error('Query processing failed', {
userId,
query,
error: error.message,
stack: error.stack
});
metrics.incrementErrorCount();
throw error;
}
}2. Caching de Resultados
async function processQueryWithCache(
system: RAGSystem,
query: string,
userId: string
): Promise<string> {
// Gerar chave de cache
const cacheKey = `query:${createHash(query)}:user:${userId}`;
// Verificar cache
const cachedResult = await cache.get(cacheKey);
if (cachedResult) {
metrics.incrementCacheHit();
return cachedResult;
}
// Processar normalmente se não está em cache
const response = await processQuery(system, query, userId);
// Salvar no cache
await cache.set(cacheKey, response, 3600); // 1 hora TTL
metrics.incrementCacheMiss();
return response;
}3. Escalabilidade
// Configuração para escalabilidade
interface ScalableRAGConfig {
// Vetorial
vectorDb: {
connectionPoolSize: number;
readReplicas: number;
writeTimeout: number;
};
// Cache
redis: {
clusterMode: boolean;
nodes: number;
maxConnections: number;
};
// LLM
llm: {
providerTimeout: number;
maxConcurrentRequests: number;
fallbackProviders: string[];
};
}A integração eficaz de todos esses componentes é o que cria um sistema RAG robusto e eficiente.
Integrando com Sistemas Existentes
A integração de sistemas de IA com aplicações existentes requer planejamento e consideração de vários aspectos.