Access Denied You don’t have permission to access “http://zeenews.india.com/technology/govt-mandates-caller-name-display-service-for-telecom-users-from-nov-1-3076094.html” on this server. Reference #18.eff43717.1792058959.1760270b https://errors.edgesuite.net/18.eff43717.1792058959.1760270b
Access Denied
Access Denied You don’t have permission to access “http://zeenews.india.com/technology/openai-finds-hidden-recording-device-in-office-employee-arrested-after-fbi-referral-3076009.html” on this server. Reference #18.eff43717.1791981668.e0bfcbe https://errors.edgesuite.net/18.eff43717.1791981668.e0bfcbe
Access Denied
Access Denied You don’t have permission to access “http://zeenews.india.com/technology/google-launches-gemini-4-argon-targets-complex-coding-cybersecurity-and-scientific-research-3076007.html” on this server. Reference #18.eff43717.1791976460.d767670 https://errors.edgesuite.net/18.eff43717.1791976460.d767670
Access Denied
Access Denied You don’t have permission to access “http://zeenews.india.com/technology/mckinsey-flags-looming-ai-spending-surge-for-us-agencies-as-subsidised-deals-give-way-to-market-pricing-3075304.html” on this server. Reference #18.c4f43717.1791564228.8116091d https://errors.edgesuite.net/18.c4f43717.1791564228.8116091d
Access Denied
Access Denied You don’t have permission to access “http://zeenews.india.com/technology/no-more-plain-text-answers-chatgpts-new-intelligent-ui-now-builds-calculators-maps-and-diagrams-in-your-chat-3075162.html” on this server. Reference #18.c4f43717.1791483835.74a9240b https://errors.edgesuite.net/18.c4f43717.1791483835.74a9240b
From iPhone 17 to Voltas AC: 13 Best Deals in Flipkart Big Billion Days 2026
13 Deals Worth Buying Now, From iPhone 17 to M5 MacBook AirThe festive shopping season is here, and Flipkart Big Billion Days 2026 is bringing attractive offer prices across smartphones, laptops, tablets, televisions and home appliances. For consumers who have been waiting to upgrade, the sale could be the right time to make that purchase rather than wait for another round of discounts.With prices influenced by factors such as component costs, currency movements and supply, there is no guarantee that a future sale will bring a better deal. Flipkart Plus and Black members get early access on October 8, while the sale opens for everyone on October 9.Here are 13 products that stand out this year.1. iPhone 17 offer price: ₹79,999*MRP: ₹99,900The iPhone 17 256GB is available at an effective offer price of ₹79,999*, making it ₹19,901 lower than its MRP. The effective price includes applicable bank and exchange benefits. Eligible customers can also get additional exchange benefits.For buyers already considering the iPhone 17, this is one of the strongest prices available during the sale. There is little reason to wait for a lower price after Big Billion Days.2. iPhone 15 offer price: ₹63,999*The iPhone 15 remains a compelling option for consumers who want an iPhone without paying flagship prices. It comes with a 6.1 inch OLED display, Dynamic Island and Ceramic Shield protection.At an offer price of ₹63,999*, it provides a more affordable way to enter Apple’s smartphone ecosystem.3. Samsung Galaxy S25 FE offer price: ₹46,999MRP: ₹89,999The Samsung Galaxy S25 FE gets a major price reduction during Big Billion Days. The phone features a 6.7 inch Dynamic AMOLED 2X display, AI features and a triple camera setup.At an offer price of ₹46,999, it is among the most notable premium smartphone deals in the sale.4. Samsung Galaxy S25 offer price: ₹57,999MRP: ₹1,04,999The Samsung Galaxy S25 is available at an offer price of ₹57,999. It comes with a 6.2 inch display, Snapdragon 8 Elite processor and a 50 megapixel Pro camera.With EMI options starting at approximately ₹6,444 per month, the offer makes Samsung’s flagship experience considerably more accessible.5. MacBook Air with M5 offer price: ₹1,24,990*MRP: ₹1,49,900Apple’s MacBook Air with the M5 chip is another major highlight. The 16GB RAM and 512GB storage configuration is available at an offer price of ₹1,24,990* during the sale.Eligible customers can also access exchange benefits of up to ₹50,000* and No Cost EMI for up to 12 months. For buyers already planning to purchase the M5 MacBook Air, waiting beyond this sale is unlikely to offer a better price.6. AirPods Pro 3 offer price: ₹21,399*MRP: ₹25,900The AirPods Pro 3 are available at an offer price of ₹21,399*, making them an attractive option for Apple users looking for premium wireless earbuds.For consumers already using Apple devices, the integration across the ecosystem adds to the appeal of the deal.7. Samsung Galaxy Tab S10 FE+ offer price: ₹43,999MRP: ₹64,999The Samsung Galaxy Tab S10 FE+ is available at an offer price of ₹43,999. Buyers can choose between Wi Fi and 5G options, while eligible customers can also receive exchange benefits and No Cost EMI.It is a strong option for consumers looking for a large screen device for entertainment, work or study.8. Samsung Galaxy Watch8 offer price: ₹16,999*MRP: ₹34,999The Samsung Galaxy Watch8 gets an offer price of ₹16,999*, making it one of the more attractive smartwatch deals during the sale.The watch offers personalised health coaching and eligible buyers can also get exchange benefits of up to ₹12,000.Big Billion Days deals for the homeThe discounts extend beyond smartphones and personal gadgets, with several televisions and large appliances also getting significant offer prices.9. Samsung 55 inch Mini LED Smart TV offer price: ₹36,999*The 2026 Samsung 55 inch Mini LED Smart TV is available at an offer price of ₹36,999*. It comes with Premium Mini LED technology, the NQ4 AI Gen2 processor and 144Hz gaming support.Consumers can also get exchange benefits of up to ₹7,000 and No Cost EMI on eligible purchases.10. LG 55 inch Nano 4K Smart TV offer price: ₹36,240*The LG 55 inch Nano 4K Smart TV is available at an offer price of ₹36,240*. It features the Alpha 7 AI Processor Gen9 along with Google Gemini and Copilot AI.LG is also offering five years of webOS updates, giving buyers a television designed to remain supported for longer.11. Samsung 9kg Front Load Washing Machine offer price: ₹29,249*MRP: ₹50,990The Samsung 9kg Front Load Washing Machine is available at an offer price of ₹29,249*. It comes with AI EcoBubble, Wi Fi connectivity, Hygiene Steam and a Digital Inverter.Eligible buyers can also get exchange benefits of up to ₹4,000.12. Samsung 653L Side by Side Refrigerator offer price: ₹65,990*MRP: ₹1,21,000The Samsung 653L Side by Side Refrigerator gets an offer price of ₹65,990*. It features AI Smart Energy Savings and a convertible freezer.Exchange benefits of up to ₹6,000 are also available for eligible customers.13. Voltas 1.42 Ton 3 Star AC offer price: ₹28,990*MRP: ₹60,990The Voltas 1.42 Ton 3 Star AC is available at an offer price of ₹28,990*. It features Long Air Throw and comes with an exchange benefit of up to ₹6,500 for eligible buyers.For households planning an AC purchase, the combination of the offer price and exchange benefit makes this a deal worth considering.More ways to save during Big Billion DaysThe advertised offer prices are not the only savings available during the sale. Eligible Axis Bank and ICICI Bank cardholders can get a 10 percent instant discount on applicable purchases. Additional benefits are also available with the Flipkart Axis Bank co branded card, subject to applicable terms.Smartphone buyers can get exchange benefits of up to ₹16,000*, while No Cost EMI options start at ₹500 per month* and can extend up to 24 months on eligible products.Some eligible products can also be delivered through Flipkart Minutes, depending on location and availability.Is it worth waiting for another sale?For consumers who have already decided to upgrade, waiting for another sale may not make sense. These Big Billion Days offer prices are among the strongest available for the
Adding Temporal Reasoning to Graph-RAG: Tracking Fact Freshness and Staleness
In this article, you will learn how to add a lightweight temporal reasoning layer to a Graph-RAG system so that it can distinguish fresh facts from stale ones. Topics we will cover include: How to extend standard subject-predicate-object triples into time-stamped quadruples stored in a simple temporal graph. How to calculate recency weights with exponential decay and use them to rank conflicting facts as of a given query date. How to tune the half-life parameter and integrate the temporal graph into a deterministic 3-tiered Graph-RAG retrieval pipeline. Introduction and Motivation In a previous article, Building a Deterministic 3-Tiered Graph-RAG System, we addressed the challenge of handling conflicting information in RAG (Retrieval-Augmented Generation) architectures. In particular, we built a hierarchy to manage conflicting information by giving “fresh” facts top priority over less-fresh ones. Throughout that journey, a key question arose: how does our graph-based RAG system know exactly what is fresh? Standard knowledge graphs treat facts as “timeless,” context-independent SPO (subject-predicate-object) triples, such as (Company, HAS_CEO, Alice). This approach doesn’t quite fit the real world we live in, where things are messy and change constantly: what if Alice switched jobs and is no longer CEO? Feeding these facts to an LLM without temporal context is the perfect recipe for hallucinations, resulting in confusing or factually incorrect responses. To tackle this challenge, this article shows the key steps to build a dedicated, lightweight temporal reasoning engine for Graph-RAG through a few simple Python functions. We also discuss its integration with the 3-tiered Graph-RAG system built previously. The key idea consists of upgrading standard triples into time-stamped quadruples and calculating recency weights that indicate degrees of “fact freshness.” Ready? Let’s go! A New, Temporal Journey, Step by Step The first step is to extend standard SPO triples into “temporal quads,” where the fourth dimension introduces time, concretely a timestamp: (Subject, Predicate, Object, Timestamp). The following Python class is defined to hold our new, extended knowledge, also called a temporal graph. If you are working in a notebook environment, simply paste this code into your first code cell: import datetime import math class TemporalGraph: def __init__(self): # Data will be stored in this knowledge base as: Subject -> Predicate -> List of (Object, Date) self.knowledge_base = {} def add_fact(self, subject, predicate, obj, date_string): “””Adds a time-stamped fact to the graph.””” # Converting string to a comparable date object fact_date = datetime.datetime.strptime(date_string, “%Y-%m-%d”).date() if subject not in self.knowledge_base: self.knowledge_base[subject] = {} if predicate not in self.knowledge_base[subject]: self.knowledge_base[subject][predicate] = [] self.knowledge_base[subject][predicate].append((obj, fact_date)) print(f”Added: {subject} {predicate} {obj} (as of {date_string})”) # Initializing our graph tg = TemporalGraph() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import datetime import math class TemporalGraph: def __init__(self): # Data will be stored in this knowledge base as: Subject -> Predicate -> List of (Object, Date) self.knowledge_base = {} def add_fact(self, subject, predicate, obj, date_string): “”“Adds a time-stamped fact to the graph.”“” # Converting string to a comparable date object fact_date = datetime.datetime.strptime(date_string, “%Y-%m-%d”).date() if subject not in self.knowledge_base: self.knowledge_base[subject] = {} if predicate not in self.knowledge_base[subject]: self.knowledge_base[subject][predicate] = [] self.knowledge_base[subject][predicate].append((obj, fact_date)) print(f“Added: {subject} {predicate} {obj} (as of {date_string})”) # Initializing our graph tg = TemporalGraph() Now it’s time to populate our newly created temporal graph, tg, following a real-world scenario where facts change at light speed … well, maybe not that fast, but still rapidly! If we were tracking the leadership roles in a tech company during a chaotic week full of changes, we could have something like: # A timeline of shifting facts tg.add_fact(“TechCorp”, “HAS_CEO”, “Alice”, “2021-01-15”) tg.add_fact(“TechCorp”, “HAS_CEO”, “Bob”, “2023-11-17”) tg.add_fact(“TechCorp”, “HAS_CEO”, “Charlie”, “2023-11-19”) tg.add_fact(“TechCorp”, “HAS_CEO”, “Bob”, “2023-11-21”) # Bob came back! # Adding also a static fact for a bit of contrast tg.add_fact(“TechCorp”, “FOUNDED_IN”, “San Francisco”, “2010-05-01”) # A timeline of shifting facts tg.add_fact(“TechCorp”, “HAS_CEO”, “Alice”, “2021-01-15”) tg.add_fact(“TechCorp”, “HAS_CEO”, “Bob”, “2023-11-17”) tg.add_fact(“TechCorp”, “HAS_CEO”, “Charlie”, “2023-11-19”) tg.add_fact(“TechCorp”, “HAS_CEO”, “Bob”, “2023-11-21”) # Bob came back! # Adding also a static fact for a bit of contrast tg.add_fact(“TechCorp”, “FOUNDED_IN”, “San Francisco”, “2010-05-01”) Output: Added: TechCorp HAS_CEO Alice (as of 2021-01-15) Added: TechCorp HAS_CEO Bob (as of 2023-11-17) Added: TechCorp HAS_CEO Charlie (as of 2023-11-19) Added: TechCorp HAS_CEO Bob (as of 2023-11-21) Added: TechCorp FOUNDED_IN San Francisco (as of 2010-05-01) Added: TechCorp HAS_CEO Alice (as of 2021–01–15) Added: TechCorp HAS_CEO Bob (as of 2023–11–17) Added: TechCorp HAS_CEO Charlie (as of 2023–11–19) Added: TechCorp HAS_CEO Bob (as of 2023–11–21) Added: TechCorp FOUNDED_IN San Francisco (as of 2010–05–01) Bear in mind that in a standard RAG system, a search like “Who acts as the CEO of TechCorp?” would likely retrieve Alice, Bob, and Charlie, all at once! Thus, we need a mechanism to assign truthfulness weights to facts, and it’s simpler than you might think. Calculating recency weights is the key to resolving possible conflicts mathematically. We just want a mechanism that says: “hey, this fact is newer than that one, so it’s more likely to constitute today’s truth.” A smart approach to do this is based on exponential decay, which consists of assigning a half-life time window to facts. For instance, if the half-life is set to one year (365 days), then a fact that is one year old will carry a weight of 0.5. Meanwhile, a fact asserted today would carry a weight of 1.0. These two functions are designed to introduce the aforementioned weight scoring logic to our temporal graph: def calculate_recency_weight(fact_date, query_date, half_life_days=365): “”” Calculates a score between 0 and 1 based on how old the fact is. Using exponential decay: weight = (0.5) ^ (age_in_days / half_life) “”” age_in_days = (query_date – fact_date).days # If the fact is from the future relative to our query, it is capped at 1.0 if age_in_days < 0: return 1.0 weight = 0.5 ** (age_in_days / half_life_days) return round(weight, 4) def query_temporal_graph(graph, subject, predicate, as_of_date_str, half_life_days=365): “””Queries the graph and ranks
AI Agent Observability: Logging, Tracing, and Debugging Explained
In this article, you will learn what AI agent observability means, why traditional monitoring tools fall short for agentic systems, and how to implement structured logging, distributed tracing, and practical debugging workflows for AI agents. Topics we will cover include: Why AI agents fail in ways that look like success, and why that makes standard monitoring tools insufficient. How to implement structured logging and OpenTelemetry-based tracing for agent runs, tool calls, and model inference steps. How to read trace waterfalls, track token costs with metrics, and use that data to debug real agent failures. An agent handling customer support tickets closes one out with a clean, professional, entirely wrong answer. It called the refund-lookup tool once, then called it again with slightly different arguments a few seconds later, then answered confidently based on the second result instead of the first. Nothing crashed. No error fired. The uptime dashboard shows green the entire time. The only reason anyone finds out is a customer replying two days later, confused, and by then nobody can reconstruct what actually happened inside that run. That failure is the whole reason this article exists. A traditional service either returns an error 200 or throws something you can grep for. An agent can do neither and still be completely wrong, and the tooling built for the first kind of system is close to blind to the second. This article walks through what actually needs to change — logging, tracing, and debugging — one at a time, with real code. What AI Agent Observability Actually Means AI agent observability is the practice of capturing every model call, tool execution, and reasoning step an agent makes as structured data, so that when something goes wrong, you can reconstruct exactly what happened and why, rather than guessing or re-running the same prompt and hoping the problem repeats itself. It borrows from the three pillars observability engineers already know — logs, metrics, and traces — but the reason it needs its own name and its own discipline comes down to how agents actually fail. Aryan Kargwal, a researcher in the field, put it plainly in coverage from Digital Applied’s 2026 observability guide: agentic systems fail in ways that look like success — incorrect but well-formed outputs, unnecessary tool calls, or actions that are syntactically valid but semantically wrong. None of that trips an error handler. A health check reporting “up” tells you almost nothing useful about whether the agent actually did the right thing on any given run. Why Agents Break the Traditional Monitoring Model It’s worth being specific about the mechanics here, because “agents are unpredictable” undersells exactly what changes. The same input doesn’t reliably produce the same behavior anymore. Temperature settings, retrieval results, and which tools happen to be available can all shift the path an agent takes, so the same prompt can trigger a genuinely different sequence of tool calls on two consecutive runs. A single “it worked when I tested it” trace tells you almost nothing about what the distribution of real runs actually looks like. Cost and latency stop correlating with request count and start correlating with tokens instead. A single “slow” request might be consuming ten times the normal token budget, and a monitoring setup built around requests-per-second is structurally blind to that. Multi-step chains compound the problem: one user request might trigger several model calls, a handful of tool calls, and a couple of retrieval lookups, and each one is an independent point of failure that a single aggregate error metric can’t distinguish between. And prompts themselves routinely carry real personal or confidential information, which means naive logging that dumps full prompt text into a backend creates a genuine compliance problem before it has created any debugging value at all. A side-by-side comparison of the two worlds makes the shift concrete: Signal Traditional app LLM / AI agent Latency driver CPU, I/O, network Token count, model size, context window Cost unit Requests per second Tokens consumed Failure mode Exception, timeout Hallucination, context overflow, tool error Debug artifact Stack trace Prompt, completion, and the reasoning chain between them Logging Start with the most familiar pillar, because it’s still the foundation everything else builds on, just applied differently. For an agent, the events worth logging are specific: which tool got called and with what arguments, what came back, how many tokens a given step consumed, how long each hop took, and any error along the way — and all of it structured rather than written as free-text sentences a human has to parse later. The detail that actually makes agent logging useful is tying every log line back to the specific run it came from. A log statement that just says “tool call failed” is nearly worthless at 2 am when three different users triggered three different runs in the same minute. Attaching the current trace ID to every log line — something OpenTelemetry does automatically once tracing is set up — is what turns a pile of scattered log statements into something you can filter down to the exact run that broke. import logging from opentelemetry import trace # Standard Python logging, nothing exotic here logger = logging.getLogger(“agent”) logging.basicConfig(level=logging.INFO) tracer = trace.get_tracer(“agent-service”) def call_tool(tool_name: str, arguments: dict): # get_current_span() pulls whatever span is active right now, # so the log line below can be tied back to the exact trace # and step it happened inside span = trace.get_current_span() trace_id = format(span.get_span_context().trace_id, “032x”) logger.info( “tool_call_started”, extra={ “trace_id”: trace_id, “tool_name”: tool_name, “arguments”: arguments, }, ) try: result = execute_tool(tool_name, arguments) logger.info( “tool_call_succeeded”, extra={“trace_id”: trace_id, “tool_name”: tool_name, “result_length”: len(str(result))}, ) return result except Exception as e: logger.error( “tool_call_failed”, extra={“trace_id”: trace_id, “tool_name”: tool_name, “error”: str(e)}, ) raise 1 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 36 37 38 import logging from opentelemetry import trace
Access Denied
Access Denied You don’t have permission to access “http://zeenews.india.com/technology/whatsapp-parental-controls-can-parents-read-their-teens-whatsapp-chats-know-here-3074130.html” on this server. Reference #18.eff43717.1790835490.3a5e5382 https://errors.edgesuite.net/18.eff43717.1790835490.3a5e5382
Monitoring Embedding Drift in Production Scikit-LLM Pipelines
In this article, you will learn what embedding drift is, why it matters for production large language models, and how to implement two practical techniques to detect it. Topics we will cover include: The key approaches for detecting embedding drift in production machine learning systems, including model-based detection, centroid distance, and dimensionality reduction combined with statistical tests. How to implement a domain classifier and a centroid distance method using scikit-learn on simulated 384-dimensional embeddings. How to apply these same drift detection techniques to real text embeddings generated with a SentenceTransformer model via Scikit-LLM. Introduction When a large language model (LLM) hits production, the story is far from over. User behavior inevitably evolves in the real world, and so does the data consumed by the model, typically encoded into numerical text representations called embeddings for its internal processing. Therefore, it is crucial to track so-called embedding drifts to ascertain when a deployed model needs an update. However, traditional drift detection metrics designed for tabular data often fail when applied to high-dimensional embeddings. This article starts by providing a brief outline of top techniques for detecting embedding drift, followed by an illustrative implementation of two of them, both simulation-based and in conjunction with the Scikit-LLM library for embedding generation. Techniques for Effective Embedding Drift Detection Below we list three key approaches for accurately identifying embedding drift that have been remarkably put into practice in production LLMs: Model-based detection: This consists of training a domain-specific classifier, usually a binary classifier that has learned to distinguish between baseline data and new (drifted) production data. A model capable of easily telling them apart will be able to signal drifts when they occur. Centroid distance: Following classical anomaly detection algorithms, this strategy boils down to calculating the distance (often cosine for embedding data) between the center of mass of your baseline embedding vectors and that of new, incoming embedding vectors. Combining dimensionality reduction and statistical tests: This method entails compressing the embeddings to a lower dimension using UMAP or PCA, after which we apply standard drift tests such as Kolmogorov-Smirnov. Interested in exploring further how they work? Let’s examine how to implement the core logic behind two of these techniques based on an open-source stack. Illustrating Drift Detection on Simulated Embeddings Let’s build a mathematical foundation for two of the listed techniques using standard scikit-learn and simulated embeddings first. We generate an initial, random set of embeddings, after which we create another synthetic set — this time containing “production embeddings” that shift from the original embeddings’ mean to simulate the existence of data drift. import numpy as np # Simulating 384-dimensional embeddings (e.g. standard sentence-transformers output) n_samples = 500 n_features = 384 # 1. Referencing Embeddings (Baseline / Training Data) # Imagine this is the data your LLM/Vector DB was originally populated with np.random.seed(42) X_reference = np.random.normal(loc=0.0, scale=1.0, size=(n_samples, n_features)) # 2. Production Embeddings (New Data) # The original mean is shifted to loc=0.3 to simulate data drift (e.g. new topic emerging) X_production = np.random.normal(loc=0.3, scale=1.0, size=(n_samples, n_features)) import numpy as np # Simulating 384-dimensional embeddings (e.g. standard sentence-transformers output) n_samples = 500 n_features = 384 # 1. Referencing Embeddings (Baseline / Training Data) # Imagine this is the data your LLM/Vector DB was originally populated with np.random.seed(42) X_reference = np.random.normal(loc=0.0, scale=1.0, size=(n_samples, n_features)) # 2. Production Embeddings (New Data) # The original mean is shifted to loc=0.3 to simulate data drift (e.g. new topic emerging) X_production = np.random.normal(loc=0.3, scale=1.0, size=(n_samples, n_features)) Next, we train a domain classifier based on random forests to separate baseline data (labeled 0) from new, production data (labeled 1). If the accuracy metric — for instance, ROC-AUC — signals a high value, e.g. above 0.65, the classifier will trigger a drift alert. from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import roc_auc_score # 1. Assigning labels: 0 for reference, baseline embeddings; 1 for production embeddings y_reference = np.zeros(n_samples) y_production = np.ones(n_samples) # 2. Combining into a single dataset X_combined = np.vstack((X_reference, X_production)) y_combined = np.hstack((y_reference, y_production)) # 3. Randomly splitting into train and test sets for the drift detector X_train, X_test, y_train, y_test = train_test_split( X_combined, y_combined, test_size=0.3, random_state=42 ) # 4. Training a lightweight Random Forest classifier drift_classifier = RandomForestClassifier(n_estimators=50, max_depth=5, random_state=42) drift_classifier.fit(X_train, y_train) # 5. Evaluating the classifier using ROC-AUC y_pred_proba = drift_classifier.predict_proba(X_test)[:, 1] roc_auc = roc_auc_score(y_test, y_pred_proba) print(f”Domain Classifier ROC-AUC Score: {roc_auc:.3f}”) # 6. Alerting Logic # If the metric score is around 0.5 it means the model can’t tell the datasets apart (no drift detected). # Meanwhile, a score closer to 1.0 means they are easily distinguishable (high drift). if roc_auc > 0.65: print(“ALERT: Significant embedding drift detected! Trigger retraining/review pipeline.”) else: print(“System stable: Distributions are sufficiently similar.”) 1 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 from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import roc_auc_score # 1. Assigning labels: 0 for reference, baseline embeddings; 1 for production embeddings y_reference = np.zeros(n_samples) y_production = np.ones(n_samples) # 2. Combining into a single dataset X_combined = np.vstack((X_reference, X_production)) y_combined = np.hstack((y_reference, y_production)) # 3. Randomly splitting into train and test sets for the drift detector X_train, X_test, y_train, y_test = train_test_split( X_combined, y_combined, test_size=0.3, random_state=42 ) # 4. Training a lightweight Random Forest classifier drift_classifier = RandomForestClassifier(n_estimators=50, max_depth=5, random_state=42) drift_classifier.fit(X_train, y_train) # 5. Evaluating the classifier using ROC-AUC y_pred_proba = drift_classifier.predict_proba(X_test)[:, 1] roc_auc = roc_auc_score(y_test, y_pred_proba) print(f“Domain Classifier ROC-AUC Score: {roc_auc:.3f}”) # 6. Alerting Logic # If the metric score is around 0.5 it means the model can’t tell the datasets apart (no drift detected). # Meanwhile, a score closer to 1.0 means they are easily distinguishable (high drift). if roc_auc > 0.65: print(“ALERT: Significant embedding drift detected! Trigger retraining/review pipeline.”) else: print(“System stable: Distributions are sufficiently similar.”)