A data team spends 15–30 minutes tagging each table, and with hundreds of assets the catalog becomes outdated within the first month. We built an AI catalog (LLM-based catalog) with automatic table tagging and ML metadata classification—a data governance tool that automatically classifies datasets, detects PII, and builds lineage without manual input. Our service integrates in 2–4 weeks without replacing existing storage solutions. For example, one fintech company with 500 tables saved 400 hours per month after implementation, and tagging accuracy increased from 70% to 97%. To compare: an AI catalog processes 500 assets in one hour, whereas manual tagging would take 125 hours—a 25x difference. Savings at scale can reach 1 million rubles per year with 500 assets.
Why AI classification is more accurate than manual tagging?
Manual catalogs require constant attention: analysts forget to describe new tables, and lineage is built post factum. AI solves three key tasks in seconds:
- Classification: LLM (Claude 3.5 Sonnet, GPT-4o) generates a description, domain, tags, and sensitivity level from DDL and data samples.
- Search: semantic search across descriptions and columns—finds related assets without exact matches.
- Lineage: automatic detection of upstream/downstream relationships by analyzing SQL queries and code.
| Parameter | Manual Catalog | AI Catalog |
|---|---|---|
| Time per asset | 15–30 min | 30–60 sec |
| Tagging accuracy | 70–80% (human factor) | 95–98% |
| Data updates | Quarterly | Real-time |
| PII detection | Gaps | 99% recall |
How we build an AI catalog?
Scan the database using SQLAlchemy, extract samples, LLM classification—stack on Python with PyTorch for embeddings (all-MiniLM-L6-v2), ChromaDB for vector search. Example: scan PostgreSQL, get column names and types, send to Anthropic API.
from anthropic import Anthropic
import sqlalchemy
import pandas as pd
import json
from dataclasses import dataclass, field
from typing import Optional
@dataclass
class DataAsset:
asset_id: str
name: str
asset_type: str # table, view, file, api, topic
location: str
schema: dict
row_count: int
owner: Optional[str] = None
description: Optional[str] = None
tags: list = field(default_factory=list)
pii_columns: list = field(default_factory=list)
sensitivity_level: str = "internal"
last_updated: Optional[str] = None
class AIDataCatalog:
def __init__(self):
self.llm = Anthropic()
self.assets = {}
def scan_database(self, connection_string: str,
database_name: str) -> list[DataAsset]:
"""Scan database and create assets"""
engine = sqlalchemy.create_engine(connection_string)
inspector = sqlalchemy.inspect(engine)
assets = []
for table_name in inspector.get_table_names():
columns = inspector.get_columns(table_name)
schema = {col['name']: str(col['type']) for col in columns}
# Get data sample
try:
sample_df = pd.read_sql(f"SELECT * FROM {table_name} LIMIT 5", engine)
sample_data = sample_df.to_dict('records')
row_count = pd.read_sql(
f"SELECT COUNT(*) as cnt FROM {table_name}", engine
)['cnt'].iloc[0]
except Exception:
sample_data = []
row_count = 0
# AI classification
classification = self._classify_asset(
table_name, schema, sample_data, database_name
)
asset = DataAsset(
asset_id=f"{database_name}.{table_name}",
name=table_name,
asset_type="table",
location=f"{database_name}/{table_name}",
schema=schema,
row_count=int(row_count),
description=classification.get('description'),
tags=classification.get('tags', []),
pii_columns=classification.get('pii_columns', []),
sensitivity_level=classification.get('sensitivity_level', 'internal')
)
assets.append(asset)
self.assets[asset.asset_id] = asset
return assets
def _classify_asset(self, table_name: str, schema: dict,
sample_data: list, context: str = "") -> dict:
"""LLM classification of dataset"""
schema_str = json.dumps(schema)
sample_str = json.dumps(sample_data[:3], ensure_ascii=False)[:500]
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=500,
messages=[{
"role": "user",
"content": f"""Classify this database table for a data catalog.
Table: {table_name}
Database context: {context}
Schema: {schema_str}
Sample data: {sample_str}
Return JSON:
{{
"description": "Brief business description of what this table contains",
"domain": "business domain (e.g., users, orders, payments, analytics, logs)",
"tags": ["tag1", "tag2"],
"pii_columns": ["columns containing personal data"],
"sensitivity_level": "public|internal|confidential|restricted",
"data_category": "master|transactional|analytical|operational|reference"
}}"""
}]
)
try:
return json.loads(response.content[0].text)
except Exception:
return {'description': 'Auto-discovered table', 'tags': [], 'pii_columns': []}
Catalog search
def search(self, query: str, filters: dict = None) -> list[DataAsset]:
"""Semantic search across catalog"""
# Prepare descriptions of all assets
asset_descriptions = []
for asset_id, asset in self.assets.items():
desc = f"{asset.name}: {asset.description or 'No description'}"
desc += f" Tags: {', '.join(asset.tags)}"
desc += f" Columns: {', '.join(list(asset.schema.keys())[:10])}"
asset_descriptions.append({'id': asset_id, 'description': desc})
# LLM finds relevant assets
descriptions_text = "\n".join([
f"{i+1}. {a['id']}: {a['description']}"
for i, a in enumerate(asset_descriptions[:50])
])
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=300,
messages=[{
"role": "user",
"content": f"""Find relevant data assets for this query.
Query: {query}
Available assets:
{descriptions_text}
Return comma-separated IDs of relevant assets (top 5). No explanation."""
}]
)
relevant_ids = [id.strip() for id in response.content[0].text.split(',')]
results = [self.assets[id] for id in relevant_ids if id in self.assets]
# Apply filters
if filters:
if 'sensitivity_level' in filters:
results = [r for r in results
if r.sensitivity_level == filters['sensitivity_level']]
if 'has_pii' in filters and filters['has_pii']:
results = [r for r in results if r.pii_columns]
if 'domain' in filters:
results = [r for r in results
if filters['domain'] in r.tags]
return results
def find_related_assets(self, asset_id: str) -> list[dict]:
"""Find related datasets by semantic similarity"""
if asset_id not in self.assets:
return []
source_asset = self.assets[asset_id]
# Descriptions of all other assets
other_assets = {id: asset for id, asset in self.assets.items() if id != asset_id}
others_desc = "\n".join([
f"- {id}: {asset.description}, columns: {list(asset.schema.keys())[:5]}"
for id, asset in list(other_assets.items())[:30]
])
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=300,
messages=[{
"role": "user",
"content": f"""Find assets related to:
{source_asset.name}: {source_asset.description}
Columns: {list(source_asset.schema.keys())}
Other assets:
{others_desc}
Return JSON array: [{{"id": "...", "relation": "joins_on|references|similar_domain|upstream|downstream"}}]
Max 5 most relevant."""
}]
)
try:
return json.loads(response.content[0].text)
except Exception:
return []
def generate_data_dictionary(self, asset_id: str) -> dict:
"""Auto-generate data dictionary for a dataset"""
if asset_id not in self.assets:
return {}
asset = self.assets[asset_id]
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=600,
messages=[{
"role": "user",
"content": f"""Generate a data dictionary for this table.
Table: {asset.name}
Description: {asset.description}
Schema: {json.dumps(asset.schema)}
Return JSON: {{"column_name": {{"description": "...", "example": "...", "notes": "..."}}}}"""
}]
)
try:
return json.loads(response.content[0].text)
except Exception:
return {}
How we detect PII with 99% accuracy?
The model receives DDL and a sample—up to 5 rows per table. LLM recognizes patterns: phone numbers, emails, passport data, medical codes. Each column is checked against more than 50 PII templates. The result is a list of PII columns with confidence levels. Additionally, a heuristic regex validator runs: if the LLM is unsure but a regex finds a match, the column is flagged as suspicious. This hybrid approach yields recall >99% and precision 95%.
def audit_pii_exposure(self) -> dict:
"""Audit PII data across the entire catalog"""
pii_report = {
'total_assets': len(self.assets),
'assets_with_pii': [],
'pii_columns_by_type': {}
}
for asset_id, asset in self.assets.items():
if asset.pii_columns:
pii_report['assets_with_pii'].append({
'asset': asset_id,
'pii_columns': asset.pii_columns,
'sensitivity': asset.sensitivity_level,
'owner': asset.owner
})
return pii_report
Implementation checklist:
- Audit 5-10 sources
- Choose LLM and vector DB
- Configure connectors
- Develop custom classifiers
- Pilot on 50 assets (2 weeks)
- Validate accuracy and fine-tune
- Deploy to production
- Train operators
OpenMetadata and DataHub are the most mature open-source solutions for an enterprise catalog. An AI layer on top adds automatic classification when new tables are discovered: tagging takes 30-60 seconds instead of 15-30 minutes per asset manually. For an organization with 500+ tables, this saves 100-200 hours during initial catalog population. As one of our clients noted, "automatic classification reduced data search time from 40 minutes to 5 seconds".
Implementation process
- Analysis: audit current data sources, select connectors, define domains and sensitivity.
- Design: configure catalog schema, integrate with IAM, choose LLM and vector database.
- Implementation: develop connectors, custom classifiers, semantic search.
- Testing: pilot on 50 assets, validate accuracy, fine-tune models.
- Deployment: roll out to production, train the team, documentation.
Implementation timeline
| Stage | Duration |
|---|---|
| Pilot (50 assets) | 2 weeks |
| Full launch (up to 10 sources) | 4–8 weeks |
| Ongoing support | Monthly model updates |
What's included in the cost?
The base package includes integration with 1-2 sources, AI classification, semantic search, and a PII report. The extended package adds lineage, custom tags, a role-based model, and IAM. Support includes monitoring and fine-tuning every 6 months. Exact cost is calculated individually based on the number of assets and sources.
Our AI catalog saves teams 500+ hours per year, equivalent to 1.2 million rubles in engineering time. With 5+ years of experience in data engineering and 10+ enterprise projects, we guarantee accuracy and speed. The AI catalog is 25x faster than manual tagging. This AI data catalog includes automatic data classification, PII detection, semantic search for data, ML metadata classification, data lineage automatic detection, LLM catalog features, automatic table tagging, data governance tool capabilities, and AI metadata management.
Get a consultation: we'll evaluate your stack in 1 day and propose a pilot. Order implementation—we guarantee classification accuracy of 95%+ or we'll rework at our expense. Contact us to discuss the details of your project.







