ईमेल से JSON निकालना: स्कीमा वैलिडिटी सच्चाई की गारंटी क्यों नहीं है और ऑटोमेशन को कैसे सुरक्षित रखें
JSON Schema के सिंटैक्टिक अनुपालन से निकाले गए डेटा की तथ्यात्मक सटीकता की गारंटी क्यों नहीं मिलती, और आंतरिक प्रोडक्शन सिस्टम में मानों को रूट करने से पहले दो-चरणीय एप्लिकेशन वैलिडेशन पाइपलाइन कैसे बनाएं।
विषय-सूची

आधुनिक LLMs में Structured Outputs मोड एक बुनियादी इंजीनियरिंग समस्या का समाधान करता है: यह गारंटी देता है कि मॉडल की प्रतिक्रियाएँ सख्ती से JSON Schema अनुबंध या Pydantic मॉडल का पालन करें। हालांकि, एक वैध स्कीमा केवल दस्तावेज़ के सिंटैक्टिक आकार (syntactic shape) की गारंटी देता है, उसकी सामग्री की तथ्यात्मक सच्चाई (factual truth) की नहीं।
Structured Outputs पर आधिकारिक Google Gemini API documentation on Structured Outputs स्पष्ट रूप से चेतावनी देता है कि आउटपुट सिंटैक्टिक रूप से सही होने पर भी डेवलपर्स को एप्लिकेशन स्तर पर मानों को वैलिडेट करना चाहिए और सिमेंटिक विसंगतियों को संभालना चाहिए। एक स्कीमा आपके पार्सर को JSONDecodeError एक्सेप्शन से तो बचा लेता है, लेकिन यह मतिभ्रम (hallucinations), गलत निष्कर्षों (faulty inferences) और अनदेखी की गई मोडल शर्तों (overlooked modal qualifications) के सामने असहाय है।
नीचे आने वाले कस्टमर सपोर्ट ईमेल की प्रोसेसिंग का एक एंड-टू-एंड परिदृश्य प्रस्तुत है: एपीआई में रॉ टेक्स्ट भेजने से लेकर एप्लिकेशन-स्तरीय सिमेंटिक वैलिडेशन और सुरक्षित फ़ील्ड रूटिंग तक।
1. इनपुट डेटा: एक अस्पष्ट सपोर्ट ईमेल
प्राकृतिक भाषा की सामान्य अस्पष्टताओं—सशर्त समय-सीमाओं (conditional deadlines) और असत्यापित मान्यताओं (unverified assumptions)—को दर्शाने के लिए जानबूझकर तैयार किए गए एक काल्पनिक सपोर्ट ईमेल पर विचार करें:
email_text = """От: alex.m@partner-example.com
Тема: Проблема с выгрузкой отчетов и планы по релизу
Привет! У нас со вчерашнего дня сбоит генерация PDF в биллинге.
Мы хотели бы закрыть этот вопрос как можно быстрее, в идеале к концу недели,
но если ваш релиз 2.4 задерживается, то крайний срок сдвигается на следующий вторник.
Кстати, затронут ли европейский кластер платежей eu-central-1, мы пока точно не знаем — коллеги еще перепроверяют трейсы."""
इस टेक्स्ट में दो महत्वपूर्ण बारीकियाँ शामिल हैं:
- सशर्त समय-सीमा (Conditional deadline): देय तिथि एक बाहरी कारक (release 2.4 में देरी) पर निर्भर करती है और इसे किसी निश्चित कैलेंडर तिथि के बजाय सापेक्ष रूप से (“अगले मंगलवार”) व्यक्त किया गया है।
- अपुष्ट तथ्य (Unconfirmed fact):
eu-central-1क्लस्टर का उल्लेख केवल एक खुले प्रश्न और ट्रेस सत्यापन के अधीन एक परिकल्पना के रूप में किया गया है। स्ट्रिंग को बिना किसी आंतरिक लाइन ब्रेक के स्वरूपित किया गया है, जिससे सटीक सबस्ट्रिंग मिलान संभव हो सके।
2. Pydantic स्कीमा और Interactions API के माध्यम से इनवोकेशन
आइए Pydantic का उपयोग करके निष्कर्षण अनुबंध (extraction contract) को परिभाषित करें और आधिकारिक Google GenAI SDK इंटरफ़ेस के माध्यम से मॉडल को कॉल करें।
from typing import Optional
from google import genai
from pydantic import BaseModel, Field
class TicketExtraction(BaseModel):
issue_summary: str = Field(
description="Краткая суть проблемы."
)
deadline_iso: Optional[str] = Field(
default=None,
description="Однозначно зафиксированный срок в формате YYYY-MM-DD. Если дата не определена точно или зависит от условий, вернуть null."
)
deadline_context: Optional[str] = Field(
default=None,
description="Оговорки, условия или контекст, сопровождающие срок."
)
affected_cluster: Optional[str] = Field(
default=None,
description="Точно подтвержденный затронутый кластер или сервис. Если факт не подтвержден или выражено сомнение, вернуть null."
)
raw_quote: Optional[str] = Field(
default=None,
description="Точная цитата из текста, обосновывающая извлеченные факты."
)
client = genai.Client()
prompt = f"""Извлеки параметры инцидента из письма.
Строго следуй правилу: если автор выражает сомнение или значение зависит от условий,
записывай в соответствующее поле null, а контекст выноси в deadline_context.
Письмо:
{email_text}"""
interaction = client.interactions.create(
model="gemini-3.8-flash",
input=prompt,
response_format={
"type": "text",
"mime_type": "application/json",
"schema": TicketExtraction.model_json_schema(),
},
)
live_extraction = TicketExtraction.model_validate_json(interaction.output_text)
3. उदाहरणात्मक विफलता: सिंटैक्टिक सफलता के साथ सिमेंटिक विफलता
नीचे दिया गया स्निपेट किसी विशिष्ट एपीआई रन के गारंटीकृत आउटपुट के बजाय एक काल्पनिक, विशिष्ट तार्किक विफलता को दर्शाता है। यह दिखाता है कि कैसे एक मॉडल प्रॉम्प्ट में निर्धारित सिमेंटिक बाधाओं की अनदेखी करते हुए औपचारिक रूप से वैध JSON लौटा सकता है।
{
"issue_summary": "Сбой генерации PDF в биллинге",
"deadline_iso": "следующий вторник",
"deadline_context": "в идеале к концу недели, но если релиз 2.4 задерживается, то следующий вторник",
"affected_cluster": "eu-central-1",
"raw_quote": "затронут ли европейский кластер платежей eu-central-1, мы пока точно не знаем"
}
JSON Schema वैलिडेटर और Pydantic लाइब्रेरी के दृष्टिकोण से यह ऑब्जेक्ट त्रुटिहीन है: सभी कुंजियाँ मौजूद हैं और प्रकार मेल खाते हैं। हालांकि, डाउनस्ट्रीम ऑटोमेशन के लिए इसमें गंभीर त्रुटियाँ हैं:
- स्ट्रिंग प्रकार मनमाने टेक्स्ट की अनुमति क्यों देते हैं:
जेनरेट किए गए स्कीमा में
Optional[str]फ़ील्ड एकanyOfसंरचना या प्रकार संघ (stringऔरnull) बन जाता है। स्कीमा वैलिडेटर के लिए"следующий вторник"मान पूरी तरह से वैध स्ट्रिंग है।descriptionके अंदर दिए गए टेक्स्ट निर्देश पार्सर स्तर पर कोई प्रतिबंध नहीं लगाते, जिससे किसी भी गैर-खाली स्ट्रिंग को वैलिडेशन पास करने की अनुमति मिल जाती है। - एक परिकल्पना को स्थापित तथ्य में बदलना:
मॉडल ने बयान की संदेहास्पद और अनुमानात्मक प्रकृति को नजरअंदाज करते हुए
eu-central-1पहचानकर्ता को निकाल लिया। - निर्देश-आधारित
nullमानों की अविश्वसनीयता: अनिश्चितता की स्थिति मेंnullलौटाने के सख्त प्रॉम्प्ट निर्देश भी अक्सर इकाई निष्कर्षण (entity extraction) की प्रवृत्तियों के आगे विफल हो जाते हैं, खासकर जब स्रोत टेक्स्ट में किसी इकाई का नाम स्पष्ट रूप से दिखाई देता है।
4. बुनियादी जाँचों की सीमाएँ: उद्धरण, स्टॉप वर्ड्स और इन्फ्रास्ट्रक्चर रजिस्ट्रियाँ
डेवलपर्स अक्सर अनुमानों (heuristics) का उपयोग करके एलएलएम की सिमेंटिक अविश्वसनीयता की भरपाई करने का प्रयास करते हैं। यहाँ बताया गया है कि बुनियादी तकनीकें गारंटी देने में क्यों विफल रहती हैं:
- उद्धरण उपस्थिति सत्यापन (
raw_quote in email_text): हमारे उदाहरण में, वाक्यांश"затронут ли европейский кластер платежей eu-central-1, мы пока точно не знаем"ईमेल का एक सटीक, निरंतर सबस्ट्रिंग है, इसलिए यह जाँचTrueमें मूल्यांकित होती है। हालांकि, टेक्स्ट में शाब्दिक उपस्थिति केवल यह साबित करती है कि उद्धरण मतिभ्रमित नहीं था; सिमेंटिक रूप से, यह बिल्कुल विपरीत साबित करता है: लेखक अनिश्चित है कि क्या वास्तव में कोई आउटेज हुआ है। - अनुमानित स्टॉप-वर्ड मिलान:
संकेतक शब्दों (जैसे
"ли"जैसे कण, या"возможно","не знаем"जैसे वाक्यांश) की खोज करना बेहद नाजुक दृष्टिकोण है। छोटे मार्कर आसानी से अन्य शब्दों के भीतर या पूरी तरह से अलग मोडल अर्थ रखने वाले वाक्यों में गलत सकारात्मक (false positives) परिणाम दे सकते हैं। - इन्फ्रास्ट्रक्चर अनुमति सूची (Allowed Clusters) के विरुद्ध सत्यापन:
आंतरिक सर्वर रजिस्ट्री के विरुद्ध
eu-central-1को सत्यापित करना केवल यह पुष्टि करता है कि ऐसा क्लस्टर मौजूद है (इकाई की पहचान)। यह यह साबित नहीं करता कि उस नोड पर वास्तव में कोई आउटेज या घटना घटी है (विफलता की घटना)। बाहरी विश्वसनीय साक्ष्य (जैसे मॉनिटरिंग सिग्नल या पुष्ट अलर्ट) के बिना, आने वाले ईमेल में किसी भी क्लस्टर का उल्लेख एक असत्यापित परिकल्पना ही बना रहता है।
5. एप्लिकेशन वैलिडेशन पाइपलाइन और सुरक्षित रूटिंग
आंतरिक डाउनस्ट्रीम सिस्टम में विफलताओं को रोकने के लिए, एप्लिकेशन को एक दूसरा वैलिडेशन स्तर लागू करना होगा। यह स्तर स्वतंत्र रूप से तिथि प्रारूपों की पुष्टि करता है, संदिग्ध संस्थाओं को बाहर करता है, और अपूर्ण या अस्पष्ट डेटा को मानव समीक्षक के पास रूट करता है।
पायथन का date.fromisoformat() हेल्पर अकेले YYYY-MM-DD प्रारूप के सख्त अनुपालन की गारंटी नहीं देता (आधुनिक पायथन संस्करण विस्तारित आईएसओ स्ट्रिंग्स स्वीकार करते हैं)। इसलिए, प्रारूप जाँचों में एक सख्त रेगुलर एक्सप्रेशन और उसके बाद कैलेंडर पार्सिंग का संयोजन होना चाहिए।
इस वैलिडेटर की कार्यप्रणाली को प्रदर्शित करने के लिए, हम अपने काल्पनिक अमान्य JSON से इनिशियलाइज़ किए गए एक अलग demo_extraction ऑब्जेक्ट का उपयोग करते हैं।
import re
from datetime import date
from typing import Any, Optional
from pydantic import BaseModel, Field
class ValidationResult(BaseModel):
is_safe_for_automation: bool
confirmed_deadline: Optional[date] = None
confirmed_cluster: Optional[str] = None
review_reasons: list[str] = Field(default_factory=list)
downstream_payload: dict[str, Any] = Field(default_factory=dict)
def validate_and_route_ticket(
extracted: TicketExtraction,
source_text: str
) -> ValidationResult:
reasons: list[str] = []
if extracted.raw_quote and extracted.raw_quote not in source_text:
reasons.append("Указанная цитата отсутствует в исходном письме.")
parsed_date: Optional[date] = None
if extracted.deadline_iso:
if not re.fullmatch(r"\d{4}-\d{2}-\d{2}", extracted.deadline_iso):
reasons.append(
f"Значение deadline_iso не соответствует строгому формату YYYY-MM-DD: '{extracted.deadline_iso}'."
)
else:
try:
parsed_date = date.fromisoformat(extracted.deadline_iso)
except ValueError:
reasons.append(
f"Значение deadline_iso содержит недопустимую календарную дату: '{extracted.deadline_iso}'."
)
parsed_date = None
if parsed_date and extracted.deadline_context:
reasons.append(
f"Срок {parsed_date.isoformat()} сопровождается оговорками ('{extracted.deadline_context}') и требует ручного согласования."
)
parsed_date = None
validated_cluster: Optional[str] = None
if extracted.affected_cluster:
reasons.append(
f"Кластер '{extracted.affected_cluster}' упомянут в письме как предположение; без внешнего подтверждения из мониторинга требуется проверка оператором."
)
needs_manual_review = len(reasons) > 0 or parsed_date is None or validated_cluster is None
safe_payload = {
"summary": extracted.issue_summary,
"deadline": parsed_date.isoformat() if parsed_date else None,
"cluster": validated_cluster,
"routing_status": "MANUAL_REVIEW" if needs_manual_review else "AUTO_APPROVED",
}
return ValidationResult(
is_safe_for_automation=not needs_manual_review,
confirmed_deadline=parsed_date,
confirmed_cluster=validated_cluster,
review_reasons=reasons,
downstream_payload=safe_payload,
)
hypothetical_bad_json = """{
"issue_summary": "Сбой генерации PDF в биллинге",
"deadline_iso": "следующий вторник",
"deadline_context": "в идеале к концу недели, но если релиз 2.4 задерживается, то следующий вторник",
"affected_cluster": "eu-central-1",
"raw_quote": "затронут ли европейский кластер платежей eu-central-1, мы пока точно не знаем"
}"""
demo_extraction = TicketExtraction.model_validate_json(hypothetical_bad_json)
decision = validate_and_route_ticket(demo_extraction, email_text)
6. अंतिम स्थिति: मैनुअल समीक्षा और फ़ील्ड पृथक्करण
एप्लिकेशन वैलिडेशन निष्पादित होने के बाद, decision ऑब्जेक्ट एक सख्त रूप से नियंत्रित स्थिति में परिवर्तित हो जाता है:
{
"is_safe_for_automation": false,
"confirmed_deadline": null,
"confirmed_cluster": null,
"review_reasons": [
"Значение deadline_iso не соответствует строгому формату YYYY-MM-DD: 'следующий вторник'.",
"Кластер 'eu-central-1' упомянут в письме как предположение; без внешнего подтверждения из мониторинга требуется проверка оператором."
],
"downstream_payload": {
"summary": "Сбой генерации PDF в биллинге",
"deadline": null,
"cluster": null,
"routing_status": "MANUAL_REVIEW"
}
}
विश्वास स्तर के आधार पर फ़ील्ड ट्राइएज
| फ़ील्ड | रूटिंग स्थिति | औचित्य |
|---|---|---|
summary | ड्राफ़्ट टिकट | बिलिंग PDF जनरेशन की समस्या स्पष्ट रूप से बताई गई है। इस फ़ील्ड को किसी इश्यू ट्रैकर में प्रारंभिक टिकट विवरण के रूप में दर्ज करना सुरक्षित है। |
cluster | ब्लॉक (null) | क्लस्टर का उल्लेख लेखक द्वारा की गई एक अपुष्ट धारणा है। झूठे अलार्म से बचने के लिए इन्फ्रास्ट्रक्चर ऑन-कॉल रोटेशन में इसके स्वचालित असाइनमेंट को ब्लॉक कर दिया गया है। |
deadline | ब्लॉक (null) | असंरचित वाक्यांश कोई कैलेंडर तिथि नहीं है, और समय-सीमा स्वयं सशर्त है। इसे स्वचालित रूप से किसी सख्त SLA से जोड़ना ब्लॉक कर दिया गया है। |
routing_status | ऑपरेटर कतार | MANUAL_REVIEW स्थिति दर्शाती है कि स्वचालित ट्रिगर्स को निलंबित कर दिया गया है, और समीक्षा कारणों की विस्तृत सूची के साथ टिकट को टीयर-1 एजेंट के पास रूट कर दिया गया है। |
किसी भी SLA गणना, प्राथमिकता वृद्धि (priority escalation), या विशिष्ट इंजीनियरिंग टीमों को रूटिंग से पहले मानव सत्यापन अनिवार्य है। एप्लिकेशन रिपोर्ट की गई समस्या सारांश युक्त एक ड्राफ़्ट टिकट उत्पन्न कर सकता है, लेकिन ऑपरेटर द्वारा स्पष्ट रूप से पुष्टि किए जाने तक महत्वपूर्ण घटना विशेषताएँ असाइन नहीं की जाती हैं।
सारांश
स्ट्रक्चर्ड आउटपुट्स स्कीमा-स्तरीय फ़ॉर्मेट स्थिरता सुनिश्चित करते हैं, जिससे डाउनस्ट्रीम कोड अप्रत्याशित सिंटैक्स त्रुटियों से सुरक्षित रहता है। हालांकि, किसी स्कीमा अनुबंध का पालन करना डेटा की सच्चाई के बराबर नहीं है। व्यावसायिक प्रक्रियाओं में LLMs को सुरक्षित रूप से एकीकृत करने के लिए दो-स्तरीय आर्किटेक्चर की आवश्यकता होती है: API सीमा पर सिंटैक्टिक प्रवर्तन, एप्लिकेशन कोड के भीतर सख्त रेगेक्स और टाइप वैलिडेशन, तथा अनिश्चित फ़ील्ड्स को अनिवार्य रूप से ह्यूमन-इन-द-लूप समीक्षा कतारों में क्वारंटाइन करना।