rag_template / tests /test_llms.py
Guilherme Favaron
Major update: Add hybrid search, reranking, multiple LLMs, and UI improvements
1b447de
"""
Testes para módulo de LLM providers
"""
import pytest
from src.llms.base import BaseLLM
from src.llms.factory import create_llm, get_available_providers, _get_fallback_order
class TestBaseLLM:
"""Testes para classe base BaseLLM"""
def test_validate_parameters_valid(self):
"""Testa validação de parâmetros válidos"""
# Cria mock de BaseLLM
class MockLLM(BaseLLM):
def generate(self, prompt, temperature=0.3, max_tokens=512, **kwargs):
return "mock response"
def is_available(self):
return True
def get_model_info(self):
return {"provider": "mock"}
llm = MockLLM("test-model")
# Testa parâmetros válidos
valid, msg = llm.validate_parameters(0.5, 256)
assert valid is True
assert msg == ""
def test_validate_parameters_invalid_temperature(self):
"""Testa validação com temperature inválida"""
class MockLLM(BaseLLM):
def generate(self, prompt, temperature=0.3, max_tokens=512, **kwargs):
return "mock response"
def is_available(self):
return True
def get_model_info(self):
return {"provider": "mock"}
llm = MockLLM("test-model")
# Temperature muito alta
valid, msg = llm.validate_parameters(3.0, 256)
assert valid is False
assert "Temperature" in msg
# Temperature negativa
valid, msg = llm.validate_parameters(-0.5, 256)
assert valid is False
assert "Temperature" in msg
def test_validate_parameters_invalid_max_tokens(self):
"""Testa validação com max_tokens inválido"""
class MockLLM(BaseLLM):
def generate(self, prompt, temperature=0.3, max_tokens=512, **kwargs):
return "mock response"
def is_available(self):
return True
def get_model_info(self):
return {"provider": "mock"}
llm = MockLLM("test-model")
# Max tokens zero
valid, msg = llm.validate_parameters(0.5, 0)
assert valid is False
assert "tokens" in msg
# Max tokens muito alto
valid, msg = llm.validate_parameters(0.5, 10000)
assert valid is False
assert "tokens" in msg
class TestFactory:
"""Testes para factory de LLM providers"""
def test_get_fallback_order(self):
"""Testa ordem de fallback"""
# Provider primário deve ser primeiro
order = _get_fallback_order("openai")
assert order[0] == "openai"
assert len(order) == 4
# Todos providers devem estar presentes
assert "huggingface" in order
assert "anthropic" in order
assert "ollama" in order
def test_create_llm_without_credentials(self):
"""Testa criação de LLM sem credenciais"""
# Sem credenciais, deve tentar criar mas não estar disponível
llm = create_llm(provider="huggingface", fallback=False)
# LLM criado mas não disponível sem token
if llm:
assert llm.is_available() is False
def test_get_available_providers(self):
"""Testa listagem de providers disponíveis"""
providers = get_available_providers()
# Deve retornar dicionário com todos os providers
assert isinstance(providers, dict)
assert "huggingface" in providers
assert "openai" in providers
assert "anthropic" in providers
assert "ollama" in providers
# Cada provider deve ter estrutura esperada
for provider_name, info in providers.items():
assert "available" in info
assert "info" in info
assert "error" in info
assert isinstance(info["available"], bool)
class TestHuggingFaceLLM:
"""Testes para HuggingFace provider"""
def test_initialization_without_token(self):
"""Testa inicialização sem token"""
from src.llms.huggingface import HuggingFaceLLM
llm = HuggingFaceLLM("test-model", "")
assert llm.is_available() is False
assert llm.model_id == "test-model"
def test_get_model_info(self):
"""Testa obtenção de informações do modelo"""
from src.llms.huggingface import HuggingFaceLLM
llm = HuggingFaceLLM("test-model", "fake-token")
info = llm.get_model_info()
assert info["provider"] == "HuggingFace"
assert info["model_id"] == "test-model"
assert "available" in info
assert info["api_type"] == "Inference API"
class TestOpenAILLM:
"""Testes para OpenAI provider"""
def test_initialization_without_key(self):
"""Testa inicialização sem API key"""
from src.llms.openai import OpenAILLM
llm = OpenAILLM("gpt-3.5-turbo", "")
# Pode ou não estar disponível dependendo se biblioteca instalada
assert llm.model_id == "gpt-3.5-turbo"
def test_get_model_info(self):
"""Testa obtenção de informações do modelo"""
from src.llms.openai import OpenAILLM
llm = OpenAILLM("gpt-4", "fake-key")
info = llm.get_model_info()
assert info["provider"] == "OpenAI"
assert info["model_id"] == "gpt-4"
assert "available" in info
assert info["api_type"] == "Chat Completions"
class TestAnthropicLLM:
"""Testes para Anthropic provider"""
def test_initialization_without_key(self):
"""Testa inicialização sem API key"""
from src.llms.anthropic import AnthropicLLM
llm = AnthropicLLM("claude-3-haiku-20240307", "")
assert llm.model_id == "claude-3-haiku-20240307"
def test_get_model_info(self):
"""Testa obtenção de informações do modelo"""
from src.llms.anthropic import AnthropicLLM
llm = AnthropicLLM("claude-3-sonnet-20240229", "fake-key")
info = llm.get_model_info()
assert info["provider"] == "Anthropic"
assert info["model_id"] == "claude-3-sonnet-20240229"
assert "available" in info
assert info["api_type"] == "Messages API"
class TestOllamaLLM:
"""Testes para Ollama provider"""
def test_initialization(self):
"""Testa inicialização"""
from src.llms.ollama import OllamaLLM
llm = OllamaLLM("llama2", "http://localhost:11434")
assert llm.model_id == "llama2"
assert llm.base_url == "http://localhost:11434"
def test_get_model_info(self):
"""Testa obtenção de informações do modelo"""
from src.llms.ollama import OllamaLLM
llm = OllamaLLM("mistral", "http://localhost:11434")
info = llm.get_model_info()
assert info["provider"] == "Ollama"
assert info["model_id"] == "mistral"
assert "available" in info
assert info["api_type"] == "Local API"
assert info["base_url"] == "http://localhost:11434"