# सुरक्षित AI agent context के लिए API response minimization

AI agents को अपने छुए हुए हर object की कॉपी नहीं चाहिए। उन्हें अगला निर्णय लेने, कार्रवाई करने और परिणाम बताने के लिए पर्याप्त जानकारी चाहिए। जब API किसी ऐसे agent को पूरा customer record, invoice, ticket, repository setting या incident object लौटाता है जिसे केवल ID और status चाहिए, तो API data exposure की समस्या पहले ही बढ़ा चुका होता है।

इसे नजरअंदाज करना आसान है, क्योंकि request read-only, authenticated और TLS से सुरक्षित हो सकती है। इनमें से कोई बात आगे होने वाली प्रक्रिया को नहीं बदलती। Response agent transcript, tool trace, model request, local cache, bug report या human review queue में जा सकता है। अगर agent उसे पढ़ सकता है, तो मानकर चलें कि वह agent context का हिस्सा बन चुका है।

व्यावहारिक समाधान है API response minimization: हर agent task के लिए सबसे छोटा उपयोगी response तय करें, उस shape को आसानी से request करने योग्य बनाएं और व्यापक data को human scrutiny वाला अपवाद बनाएं। बात JSON को सुंदर बनाने की नहीं है। लक्ष्य यह है कि किसी सामान्य automated call के बाद personal, financial और operational data के अनावश्यक रूप से दिखाई देने वाली जगहों की संख्या घटे।

## Authenticated read भी जरूरत से बहुत अधिक data उजागर कर सकता है

Read access writes को सीमित करती है। वह copying, summarizing, quoting या data को गलती से किसी दूसरे tool को भेजने से नहीं रोकती। Teams अक्सर किसी agent को "read-only" कहकर मान लेते हैं कि जोखिम तय हो गया। इससे केवल एक तरह का जोखिम नियंत्रित होता है।

मान लीजिए किसी agent को overdue invoices पहचानकर follow-up task खोलना है। उसे invoice ID, account ID, due date, amount, currency और collection state चाहिए। सामान्य invoice endpoint billing और shipping addresses, tax identifiers, payment processor references, line item descriptions, finance user का internal memo और पूरा payment history भी लौटा सकता है। हर अतिरिक्त फ़ील्ड एक ऐसा तथ्य है जिसे agent जरूरत न होने पर भी दोहरा सकता है।

Operational data में भी यही समस्या है। किसी deployment के पूरा होने की जांच करने वाले task को service name, build identifier, state और failure category की जरूरत हो सकती है। उसे आमतौर पर hostnames, internal addresses, command output, incident comments या unrelated configuration वाला पूरा environment export नहीं चाहिए।

लोग जिस फर्क को अक्सर मिला देते हैं, वह महत्वपूर्ण है: authorization बताता है कि caller किसी resource तक पहुंच सकता है या नहीं; minimization बताता है कि इस खास काम के लिए उस resource का कितना हिस्सा caller को मिलेगा। `invoice:123` पढ़ने की अनुमति वाला token सही तरीके से authorized हो सकता है, फिर भी उसे invoice का असुरक्षित representation मिल सकता है।

IETF का RFC 9110 representations को ऐसी जानकारी बताता है जो किसी resource की वर्तमान या इच्छित स्थिति को दर्शाने के लिए होती है। वह हर resource के लिए एक maximal representation जरूरी नहीं करता। Design के लिए यह उपयोगी गुंजाइश है। किसी resource का summary representation, operational representation और finance representation हो सकता है, बशर्ते API हर contract को स्पष्ट बनाए।

"ignore personal data" जैसे prompt instruction पर निर्भर न रहें। Prompts व्यवहार को प्रभावित करते हैं, response shape exposure को नियंत्रित करता है। अगर endpoint home address भेजता है, तो agent उसे नजरअंदाज करने का निर्णय लेने से पहले ही प्राप्त कर चुका है।

## शुरुआत उस काम से करें जिसे agent को पूरा करना है

सुरक्षित response contract किसी मौजूदा database model से नहीं, बल्कि उस निर्णय से शुरू होता है जो agent को लेना है। Task को एक वाक्य में लिखें और फिर वे तथ्य सूचीबद्ध करें जो कार्रवाई बदलते हैं। बाकी हर फ़ील्ड की मौजूदगी का कारण होना चाहिए।

मिसाल के लिए, failed build jobs को retry करने वाले agent को ऐसा response चाहिए हो सकता है:

```json
{
  "job_id": "job_4821",
  "state": "failed",
  "retryable": true,
  "failure_class": "transient_dependency",
  "attempts_remaining": 1
}
```

Retry की अनुमति है या नहीं, यह तय करने के लिए उसे पूरा build log नहीं चाहिए। अगर बाद में किसी human को diagnostics चाहिए, तो अलग endpoint दें, जिसका audience सीमित हो और जिसे fetch करने का स्पष्ट कारण हो। Log endpoint में bounded ranges भी होनी चाहिए, क्योंकि full logs में अक्सर tokens, customer inputs, paths और configuration के हिस्से आ जाते हैं।

Endpoints बदलने से पहले एक छोटी task matrix बनाएं। इससे वे बातचीत शुरू होती हैं जो वरना अस्पष्ट रहती हैं:

| Agent task | निर्णय वाले फ़ील्ड | कार्रवाई वाले फ़ील्ड | डिफ़ॉल्ट रूप से बाहर रखे गए फ़ील्ड |
| --- | --- | --- | --- |
| Support follow-up बनाना | ticket ID, priority, category | account ID, assignee queue | message body, attachments, internal notes |
| Job retry करना | job ID, state, retryable | retry token या job ID | पूरा log, environment values |
| Overdue invoice flag करना | invoice ID, due date, amount, state | account ID | address, tax data, payment references |
| Service health जांचना | service ID, state, error class | incident ID | host details, raw diagnostics |

कोई फ़ील्ड तभी response में होना चाहिए जब वह agent की चुनी हुई branch बदले, action request में दिखाई दे या user-facing report में जरूरी हो। "बाद में काम आ सकता है" अच्छा कारण नहीं है। इसी सोच से list endpoints में पचास फ़ील्ड जुड़ते जाते हैं और किसी को पता नहीं रहता कि उनमें से किस पर कौन निर्भर है।

यह अभ्यास उन फ़ील्ड को भी सामने लाता है जिन्हें disclose करने के बजाय compute करना चाहिए। Agent को यह जानने के लिए payroll record नहीं चाहिए कि expense approval के लिए manager जरूरी है या नहीं। `approval_required: true` लौटाएं। Deployment आगे बढ़ सकता है या नहीं, यह जानने के लिए हर entitlement देने की जरूरत नहीं है। `deployment_permitted: false` और एक स्थिर reason code लौटाएं।

यह security through obscurity नहीं है। यह एक सोचा-समझा API contract है, जो underlying record सौंपे बिना caller को जरूरी परिणाम देता है।

## Default objects database rows नहीं, summaries होने चाहिए

सबसे भरोसेमंद design में सामान्य list और lookup calls डिफ़ॉल्ट रूप से सुरक्षित summary देते हैं। Detailed representations को स्पष्ट, अलग से authorized और दुर्लभ बनाएं। हर caller से restrictive query option याद रखने की अपेक्षा अंततः विफल होगी, खासकर जब कोई library उसे छोड़ देने वाला convenience method जोड़ दे।

Customer summary ऐसा दिख सकता है:

```json
{
  "id": "cus_7f31",
  "display_name": "Northwind Parts",
  "account_state": "active",
  "open_invoice_count": 2,
  "support_tier": "standard"
}
```

`email`, `phone`, street address, tax identifier, payment instrument metadata या free-form notes केवल इसलिए न लौटाएं कि customer row में वे मौजूद हैं। Billing application के लिए इनमें से कुछ फ़ील्ड जरूरी हो सकते हैं। Operations agent के summary contract में उनकी जगह नहीं है।

दो उपयोगी patterns हैं। `GET /customers/{id}/summary` जैसा अलग summary endpoint सीधा और audit करने में आसान है। `GET /customers/{id}?view=summary` जैसा projection parameter भी काम कर सकता है, अगर views का fixed और documented set हो। दोनों ऐसे endpoint से बेहतर हैं जो सब कुछ लौटाता है और हर client से अनावश्यक data को नजरअंदाज करने की उम्मीद करता है।

Agent-facing credentials के लिए generic `expand=*` या `include=all` switch से बचें। Debugging के समय यह सबसे आसान रास्ता बनता है और फिर production में रह जाता है, क्योंकि इसे हटाना जोखिम भरा लगता है। Detail representation जरूरी हो तो उसे task के नाम पर रखें: `view=collections`, `view=deployment_status` या `view=case_triage`। Task names design review करवाते हैं। "All" उससे बच निकलता है।

अक्सर कहा जाता है कि अलग views से code दोहरता है। कुछ mapping code दोहरता जरूर है, लेकिन यह उस जांच की तुलना में छोटी कीमत है जिसमें पता लगाना पड़े कि tool transcript में tax number या internal incident note क्यों है। Mapping layer ownership दर्ज करने और agent view से sensitive columns बाहर रखने के वादे को test करने की जगह भी है।

## Field selection को allowlist से चलाएं, parser trick से नहीं

`fields` parameter response छोटा कर सकता है, लेकिन तभी जब server उसे strict allowlist माने। ढीला parser सुविधा को data extraction interface बना देता है।

यह request उचित है:

```text
GET /v1/invoices?state=overdue&fields=id,account_id,due_date,amount,currency,collection_state&limit=25
```

Server को इस endpoint और credential के लिए अनुमत फ़ील्ड ही लौटाने चाहिए। Caller `billing_address` या `payment_reference` मांगे तो स्पष्ट error के साथ request अस्वीकार करें। संवेदनशील फ़ील्ड चुपचाप न जोड़ें और `customer.*` जैसे मनमाने nested paths स्वीकार न करें।

Response contract में व्यवहार को स्पष्ट रूप से लिखा जा सकता है:

```json
{
  "error": {
    "code": "unsupported_field",
    "message": "Field 'payment_reference' is not available in the agent invoice view",
    "allowed_fields": [
      "id",
      "account_id",
      "due_date",
      "amount",
      "currency",
      "collection_state"
    ]
  }
}
```

Error को भी सावधानी से बनाना चाहिए। Rejected field की value, आसपास के record data, stack trace, किसी दूसरे service का raw query text या database error कभी शामिल न करें। Error bodies अक्सर अनजाने में दूसरा API बन जाती हैं, खासकर जब incident जल्दी सुलझाने के लिए engineers उन्हें बहुत verbose बना देते हैं।

GraphQL को भी इसी तरह जांचें। लोग मानते हैं कि clients केवल नामित फ़ील्ड मांग सकते हैं, जो मददगार है, लेकिन schema फिर भी sensitive fields उजागर कर सकता है, nested relations records की संख्या बढ़ा सकती हैं और aliases किसी query को समझना कठिन बना सकते हैं। Depth और complexity limits लगाएं, environment के अनुसार introspection को बंद या सीमित करें और केवल top-level objects नहीं, बल्कि fields को भी authorize करें। इससे भी महत्वपूर्ण है कि कुछ स्वीकृत tasks के लिए agent schema या persisted queries बनाएं। Broad schema और विनम्र instruction मिलकर narrow interface नहीं बनाते।

OWASP API Security Top 10 broken object property level authorization की ओर ध्यान दिलाता है। चिंता अक्सर इस रूप में बताई जाती है कि caller को ऐसा property मिल रहा है जिसे उसे कभी access नहीं करना चाहिए। Agent use एक और failure mode जोड़ता है: caller को तकनीकी रूप से access मिल सकता है, लेकिन task को उस property की जरूरत नहीं है और उसे model context में distribute नहीं किया जाना चाहिए। दोनों tests रखें। पूछें, "क्या यह credential इसे पढ़ सकता है?" और फिर पूछें, "इस task को अभी इसकी जरूरत क्यों है?"

## Pagination मात्रा नियंत्रित करती है, filters प्रासंगिकता

दस records वाला response अपने आप छोटा नहीं होता। अगर हर record में बड़ा nested object या लंबा text field है, तो pagination leak को केवल व्यवस्थित pages में बांटती है।

ऐसे filters इस्तेमाल करें जो agent के काम को व्यक्त करें। Collections agent को निश्चित state और date range में overdue invoices खोजनी चाहिए। उसे हर invoice list करके locally तय नहीं करना चाहिए कि कौन सी महत्वपूर्ण है। Deployment agent को हर environment query करके result में खोजने के बजाय एक service और current release के बारे में पूछना चाहिए।

Cursor pagination के response shape पर भी ध्यान दें। Cursor opaque होना चाहिए और उसमें email address, account name, unencrypted filter values या ordering बताने वाली internal database key नहीं होनी चाहिए। Clients cursors को logs और tickets में डाल देंगे। उन्हें travel करने वाले data की तरह संभालें।

Agent credentials के लिए page limits सीमित रखें। छोटा limit केवल token use नहीं घटाता। यह एक pause point देता है, जहां agent summary देख सकता है, relevant record चुन सकता है और targeted follow-up call कर सकता है। यह उस स्थिति से सुरक्षित है जिसमें task "इस customer की जांच करो" से शुरू होते ही पूरी account history load कर दी जाए।

Search endpoint को हर matching detail लौटाने की अनुमति न समझें। Search को आमतौर पर result card लौटाना चाहिए: stable ID, label, state और संभव हो तो match reason। Record चुनने के बाद caller permitted detail view fetch कर सकता है। यह two-call pattern बड़े result object जितना सुविधाजनक नहीं लगता, लेकिन sensitive information के transfer को स्पष्ट और reviewable बनाता है।

## Free text और nested records के लिए अलग सीमा रखें

Structured fields को classify करना humans द्वारा लिखे गए text की तुलना में आसान है। Free-text fields में नाम, phone numbers, गलती से paste किए गए credentials, आरोप, health details, legal advice और internal opinions आ सकते हैं। Schema review में ticket का `description` harmless लगता है, जब तक कोई वास्तविक सप्ताह के tickets पढ़ न ले।

Autonomous workflows के लिए comments, notes, descriptions, attachments, logs और message bodies को डिफ़ॉल्ट रूप से sensitive मानें। जहां action चुनने के लिए इतना पर्याप्त हो, वहां category, server-generated short classification या count लौटाएं। उदाहरण के लिए, agent को message की जगह `has_customer_reply: true` और `latest_message_at` चाहिए हो सकते हैं।

Retrieval के बाद model से मनमाने text को redact करने के लिए न कहें। यह उपाय लोकप्रिय है क्योंकि इससे एक broad endpoint बनाए रखना आसान लगता है। इसमें दो समस्याएं हैं। पहली, raw content redaction से पहले ही agent context में पहुंच चुका होता है। दूसरी, model-generated redaction probabilistic है, इसलिए partial name, account number या quote बच सकता है।

अगर task को सचमुच text चाहिए, तो request पर कड़ी सीमाएं लगाएं। पूरी thread के बजाय ID से एक message fetch करें। Server द्वारा लागू की गई निश्चित character limit मांगें। जब तक user ने specific retrieval को मंजूरी न दी हो, attachment content हटाएं। Truncation होने पर client को `content_truncated: true` जैसी स्पष्ट सूचना दें, ताकि agent missing details गढ़े नहीं।

Nested data इसी failure का शांत रूप है। `customer`, `contacts`, `invoices`, `payments` और `events` वाला response application code में एक object जैसा दिख सकता है। Exposure के लिहाज से यह independent datasets का bundle है। हर relation के लिए अलग endpoints या स्पष्ट allowlisted expansions जरूरी करें। फिर केवल sparse record वाले happy path को नहीं, बल्कि सबसे खराब सामान्य query को test करें।

## Error handling और observability leak को फिर से बना सकते हैं

Teams अक्सर successful response को सीमित कर देती हैं और फिर original payload को debug logs, tracing attributes, retry queues और exception reports में copy कर देती हैं। Data कहीं और चला गया है, exposure कम नहीं हुआ।

पूरे call path की जांच करें। कम से कम agent tool wrapper, HTTP client debug mode, request recorder, distributed tracing configuration, error reporting service, job queue, local transcript storage और support workflow देखें। जो जगहें "केवल metadata" log करने का दावा करती हैं, उनका सीधे test करें।

Nonproduction environment में एक canary record चलाएं। उन fields में अलग दिखने वाली fake values डालें जिन्हें agent context तक कभी नहीं पहुंचना चाहिए, जैसे `CANARY_BILLING_ADDRESS_927` और `CANARY_INTERNAL_NOTE_927`। वास्तविक agent task चलाएं और फिर सभी स्वीकृत log तथा trace stores में उन strings को खोजें। Failed request, timeout और malformed response के लिए भी दोहराएं। Success-path tests accidental payload capture के अधिकांश मामले नहीं पकड़ते।

एक उपयोगी call journal content की कॉपी किए बिना action दर्ज करता है:

```json
{
  "time": "2025-03-08T14:03:12Z",
  "caller": "release-agent",
  "operation": "GET /v1/jobs/{id}/retry-status",
  "resource_id": "job_4821",
  "response_view": "retry_status",
  "field_set": ["job_id", "state", "retryable", "failure_class"],
  "result_count": 1,
  "outcome": "200"
}
```

Identifiers केवल वहीं record करें जहां आपके retention और access rules इसकी अनुमति देते हों। अधिक जोखिम वाले systems में keyed reference या short-lived correlation ID रखें। अगर original value छोटे और आसानी से अनुमान लगाए जा सकने वाले domain से आती है, तो hash भी leak कर सकता है। इसलिए attacker के लिए संभावित enumeration पर विचार किए बिना hashing को redaction न कहें।

Server boundary पर outbound error messages को sanitize करें। Database driver failed SQL fragment दिखा सकता है। Upstream service error envelope में पूरा record भेज सकती है। आपका API इन failures को stable public codes में बदले, detailed diagnostics restricted store में रखे और डिफ़ॉल्ट रूप से agent-facing errors में response body शामिल न करे।

## Agent gateway में capability और disclosure अलग रखें

Action gateway को credential रखना और request चलाना चाहिए, लेकिन उसे यह नहीं मानना चाहिए कि उस credential को मिलने वाला हर response agent context के लिए उपयुक्त है। Secret isolation और response minimization एक ही call के अलग हिस्सों को नियंत्रित करते हैं।

Sallyport API और SSH secrets को अपने encrypted vault में रखता है और secret को स्वयं दिखाने के बजाय action results agent को लौटाता है। इससे credential सुरक्षित रहता है, लेकिन API owner को अब भी तय करना होगा कि result में अनावश्यक account record, command output या operational detail तो नहीं है।

जहां संभव हो, हर agent task के लिए named request template दें। Template method, host, path shape, permitted query fields, page limit और accepted response view तय करता है। Release-status template एक service ID स्वीकार कर छोटा status object लौटा सकता है। केवल इसलिए arbitrary URL और arbitrary `fields` expression स्वीकार न करें कि दोनों pass through करना आसान है।

यहीं broad proxy सोच समस्या पैदा करती है। Generic HTTP forwarder development में उपयोगी हो सकता है, लेकिन वह "इस deployment को check करो" और "हर artifact log download करो" के बीच फर्क नहीं व्यक्त कर सकता। Intent को callable action में रखें। किसी नए task को अधिक data की जरूरत हो तो API change या नया template जरूरी करें। यही friction महत्वपूर्ण है: किसी को बताना होगा कि अतिरिक्त data context में क्यों जाना चाहिए।

Exceptions के लिए human approval की भूमिका बनी रहती है। अगर किसी case को हल करने के लिए agent को एक support message का content चाहिए, तो destination और scope देखकर कोई व्यक्ति उस खास call को मंजूर कर सकता है। Approval को narrow responses का सामान्य विकल्प न बनाएं। लोग incident के दौरान परिचित cards को जल्दी approve करते हैं और बार-बार की approvals उन्हें पढ़ना बंद करना सिखा देती हैं।

## Contract में fields की अनुपस्थिति को भी test करें

अधिकांश API tests expected fields के होने की जांच करते हैं। Agent-facing APIs में यह भी test होना चाहिए कि forbidden fields मौजूद न हों, fallback path में भी नहीं।

हर response view के साथ denylist test रखें। Nested relations और free text समेत वास्तविक field names इस्तेमाल करें। ORM default, shared DTO या eager-loaded relation के कारण बाद में serialization में कोई field जुड़ जाए तो test fail होना चाहिए।

```python
forbidden = {
    "email",
    "phone",
    "billing_address",
    "tax_id",
    "payment_reference",
    "internal_note",
    "attachments",
}

body = get_invoice_agent_view("inv_1042")
assert forbidden.isdisjoint(body.keys())
assert "customer" not in body
assert "events" not in body
```

यह सरल test केवल top-level fields पकड़ता है। पूरे JSON tree को walk करने वाले serialization tests जोड़ें और list, search, error तथा export endpoints को अलग-अलग test करें। सबसे बड़ा leak अक्सर collection response से आता है, जहां कुछ lines code बचाने के लिए full detail serializer reuse कर लिया जाता है।

Contract tests को response size boundaries भी जांचनी चाहिए। सख्त byte limit हर object के लिए उपयुक्त नहीं होगी, लेकिन उचित ceiling तब alert देगा जब कोई developer unbounded text field या relation जोड़ दे। इसे long notes और कई child records वाले fixture के साथ चलाएं, वरना test झूठा भरोसा देगा।

Changes की समीक्षा तीन सीधे सवालों से करें: इस field को किस agent task की जरूरत है? कौन सा response view इसे शामिल करता है? कौन सा test साबित करता है कि यह बाकी सभी जगहों पर अनुपस्थित रहता है? अगर author जवाब नहीं दे सकता, तो broadly callable endpoint में field merge न करें।

## विशेष detail retrieval को स्पष्ट और अस्थायी बनाएं

कुछ काम सचमुच sensitive detail मांगते हैं। Fraud review, account recovery, security investigation और कठिन support case केवल summaries पर नहीं चल सकते। बात इससे इनकार करने की नहीं है। Detail retrieval को स्पष्ट, अल्पकालिक और ठीक उसी record तक सीमित बनाएं।

ऐसा अलग endpoint या action इस्तेमाल करें जो stable record ID और घोषित purpose ले। जितना जरूरी हो उतना ही छोटा हिस्सा लौटाएं, जैसे एक disputed payment field या चुना हुआ customer message। केवल इसलिए full account export की अनुमति न दें कि उसी case में एक disputed charge है।

अधिक जोखिम वाले retrieval के लिए व्यक्ति से individual call को मंजूर करवाएं और caller, purpose, view, record reference तथा outcome दर्ज करें। Audit record को sensitive response body से अलग रखें। आपको यह जानना जरूरी है कि retrieval हुआ, लेकिन जानकारी की एक और सहज कॉपी बनाना जरूरी नहीं है।

परिपक्व API सुरक्षित रास्ते को आसान बनाती है। Summary views के स्पष्ट नाम, अच्छा documentation और स्थिर fields होने चाहिए। Broad detail endpoints अधिक जिम्मेदारी वाले होने के कारण सोच-समझकर इस्तेमाल किए जाने चाहिए। अगर आपका agent बार-बार किसी sensitive field की मांग करता है, तो exception को सामान्य न बना दें। Task design पर फिर से विचार करें और पूछें कि server-side decision या redacted derived value से काम चल सकता है या नहीं।

पहला उपयोगी audit आमतौर पर वह list endpoint होता है, जिससे हर कोई पहले से डरता है, वह नहीं। एक वास्तविक agent task लें, उसके इस्तेमाल किए हर field को चिह्नित करें और उस सूची की तुलना मिले हुए response से करें। जो हिस्सा इस्तेमाल नहीं हुआ, वही आपका अगला API change है।
