Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hybrid Search Engine

Codebase hợp nhất các ý tưởng tốt nhất trong các thử nghiệm search/RAG cùng repository, nhưng tách phần điều phối khỏi vendor SDK để dễ test và thay thế hạ tầng.

Phần được kế thừa và cải tiến

Nguồn Điểm giữ lại Cách triển khai trong codebase mới
GeneralRAG Query augmentation, semantic + text search QueryAnalyzer và pipeline hybrid
DeepRAG Multi-query, tìm chunk phân cấp, carry kết quả tầng trước DeepSearchseed_vectors
LegalRAG Phân lớp semantic/syntax, bộ lọc domain/thời gian interfaces.py, SearchFilters, typed models
ChaosSearchEngine Package layout theo trách nhiệm Dùng modules/core/pipelines, public API ở __init__.py
LegalSearchEngine BaseSearch/DeepSearch, reference search, rerank cuối Hai pipeline dùng chung orchestration, sửa luồng reference

Các lỗi phổ biến của bản cũ cũng được loại bỏ: không dùng mutable default, không set() trên dict, không ghép sai query với embedding, không mutate kết quả provider, không hard-code credential/endpoint và không gọi embedding khi query đã được phân loại là không liên quan.

Kiến trúc

src/hybrid_search/
├── connectors/     # DatabaseConnector: Elasticsearch, FAISS, Milvus, Qdrant
├── core/           # Dedupe, merge và score normalization thuần Python
├── modules/
│   ├── decompose/  # Query classification, rewrite, decomposition
│   ├── retrieval/  # Dense/Elasticsearch/metadata retrieval + fusion
│   └── rerank/     # Per-query threshold/top-K + optional Base score
├── utils/          # Helper đơn giản, không phải module nghiệp vụ
├── pipelines/      # Ghép decompose -> retrieval -> rerank
├── config.py       # Cấu hình hành vi pipeline
├── models.py       # Pydantic domain models có validation, immutable
└── interfaces.py   # Protocol cho LLM/embed/retrieve/rerank providers

Phiên bản 0.2 có thêm EvidenceSearch dành cho chunk giàu feature:

  • dense vector của nội dung: Milvus, FAISS, Qdrant hoặc connector khác;
  • dense vector của summary;
  • sparse/full-text: Elasticsearch multi-match/BM25;
  • domain, entity, relation, số hiệu và reference;
  • vị trí gốc: văn bản, phần, chương, mục, điều, đoạn và trang.

Mô hình dữ liệu và luồng retrieval được mô tả chi tiết tại docs/RICH_RETRIEVAL.md.

Ranh giới giữa database connector và chiến lược pipeline được mô tả tại docs/DATABASE_CONNECTOR.md.

Phần giải thích rõ từng score, per-query RRF, Evidence, union/dedup và Base score optional nằm tại docs/FUSION_AND_EVIDENCE_SCORING.md.

Phần đang nghiên cứu về calibration, Answerability, Constraint Match và EvidenceScore nhiều aspect nằm tại docs/research.md.

Luồng EvidenceSearch hiện tại:

Q -> decompose q_i
  -> mỗi q_i search dense_content + dense_summary + sparse
  -> RRF riêng cho q_i
  -> cross-encoder(q_i, chunk)
  -> threshold + top-K riêng cho q_i
  -> Evidence -> union/dedup chunk
  -> Base score optional để sắp xếp

Luồng baseline:

query -> analyze/rewrite -> multi-query embeddings -> document retrieval
      -> semantic chunks + full-text + references -> dedupe -> rerank -> normalize

DeepSearch duyệt các lớp tài liệu theo thứ tự. Kết quả tốt của lớp trước được giữ làm seed_vectors cho lớp sau, sau đó toàn bộ kết quả mới được rerank lần cuối.

Các data/config object đều kế thừa Pydantic BaseModel, cấm field lạ và immutable sau khi khởi tạo. Vì vậy payload từ API có thể đi qua model_validate(...), còn output có thể dùng model_dump() mà vẫn giữ type rõ ràng giữa các module.

Chạy nhanh

Không cần database hay model service bên ngoài; cài package (bao gồm Pydantic) rồi chạy:

cd HybridSearchEngine
PYTHONPATH=src python example/example.py
PYTHONPATH=src python example/evidence_search.py
PYTHONPATH=src python -m unittest discover -s tests -v
from hybrid_search import ChunkLocation, DecomposeModule, KnowledgeChunk
from hybrid_search.connectors import InMemoryDatabaseConnector
from hybrid_search.modules import RerankModule, RetrievalModule
from hybrid_search.pipelines import EvidenceSearch
from hybrid_search.utils import HashEmbedder, SimpleChunkScorer

chunks = (
    KnowledgeChunk(
        id="doc-1:20",
        text="Điều 20 quy định thời hạn hợp đồng.",
        location=ChunkLocation(document_id="doc-1", article="Điều 20"),
    ),
)

database = InMemoryDatabaseConnector(chunks)
await database.connect()
retrieval_module = RetrievalModule(
    embedder=HashEmbedder(),
    dense_database=database,
    chunks=chunks,
)
rerank_module = RerankModule(scorer=SimpleChunkScorer())
searcher = EvidenceSearch(
    decompose_module=DecomposeModule(),
    retrieval_module=retrieval_module,
    rerank_module=rerank_module,
)
response = await searcher.search("thời hạn hợp đồng")
print(response.to_dict())

Ví dụ nhanh không truyền sparse_database, vì vậy sparse channel được tắt; không còn lexical sparse fallback trong Python. Khi chạy thật, truyền ElasticsearchDatabaseConnector như dưới đây.

Gắn hạ tầng thật

Tạo module cho từng contract trong interfaces.py:

  • QueryAnalyzer: OpenAI-compatible structured output.
  • Embedder: Triton hoặc embedding service.
  • DatabaseConnector: Elasticsearch, FAISS, Milvus hoặc Qdrant.
  • FullTextRetriever: Elasticsearch.
  • ChunkScorer: Vietnamese reranker, Cohere hoặc Triton rerank endpoint.

Sau đó inject module/connector vào pipeline. Endpoint, credential và collection name nằm trong connector config/environment; pipeline chỉ biết interface chung.

FAISS tùy chọn

pip install -e '.[faiss]'
pip install -e '.[elasticsearch]'
from hybrid_search.connectors import FaissDatabaseConnector
from hybrid_search.connectors import ElasticsearchConfig, ElasticsearchDatabaseConnector
from hybrid_search.modules import RerankModule, RetrievalModule
from hybrid_search.pipelines import EvidenceSearch

database = FaissDatabaseConnector(chunks)
elasticsearch = ElasticsearchDatabaseConnector(
    ElasticsearchConfig(
        hosts=("http://localhost:9200",),
        index_name="chunks",
    )
)
await database.connect()
await elasticsearch.connect()
retrieval_module = RetrievalModule(
    dense_database=database,
    sparse_database=elasticsearch,
    chunks=chunks,
    embedder=production_embedder,
)
rerank_module = RerankModule(scorer=cross_encoder)
searcher = EvidenceSearch(
    decompose_module=decomposing_analyzer,
    retrieval_module=retrieval_module,
    rerank_module=rerank_module,
)

FaissDatabaseConnector hỗ trợ index content và summary riêng, cosine similarity, metadata post-filter và index factory (Flat, HNSW,Flat, IVF...). Với dữ liệu lớn, nên shard theo domain/document type thay vì quét toàn index khi áp dụng filter.

ElasticsearchDatabaseConnector dùng multi_match trên text, summary, entity và số hiệu. BM25 raw score được giữ trong provenance; fusion chỉ dùng rank nên không cộng trực tiếp BM25 với cosine.

About

Where i implement my idea about finding and searching information

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages