Skip to main content

import DocInfo from '@site/src/components/DocInfo';

FSD: M65 - Redaction and Contextual Abstraction Service

Status: 🔄 Enhancement Proposal | Version: 2.0 | Last Updated: 2025-11-11

1. Overview

This document specifies the functional requirements for enhancing the Redaction and Contextual Abstraction Service. The service's primary purpose is to enable the use of Large Language Models (LLMs) with sensitive or proprietary data. This enhancement focuses on token efficiency optimization and unified API design based on tokenization research findings.

1.1 Scope

  • Current Implementation: python-services/redaction-engine-service/ (v1.0)
  • Target State: Token-efficient placeholders with unified /redact + new /unredact endpoint
  • Key Driver: Reduce LLM token costs by 60-80% through optimized placeholder design

See docs/strategy-and-research/redaction-tokenization.md for detailed analysis of:

  • Subword tokenization mechanics (BPE, WordPiece)
  • Placeholder token efficiency comparison
  • Session map architecture rationale

2. Current State Analysis

2.1 Existing Implementation

Service Location: python-services/redaction-engine-service/app.py

Current Endpoints:

  • POST /redact - Sanitizes text with UUID-based placeholders
  • POST /abstractize - Converts entities to category tokens
  • POST /metadata-for-llm - Generates metadata injection strings
  • GET /health - Health check

Current Placeholder Strategy:

# Example from app.py:219-220
redacted_val_with_id = f"{base_redacted_val}_{unique_id}"
# Result: "[REDACTED_EMAIL]_a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8"

2.2 Token Efficiency Problem

Current Tokenization:

Input:    "Contact john@acme.com"
Redacted: "Contact [REDACTED_EMAIL]_a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8"
Tokens: ["Contact", " ", "[", "REDA", "CTED", "_", "EMAIL", "]", "_", "a", "1", "b", "2", ... ]
= ~40 tokens per entity

Target Tokenization:

Input:    "Contact john@acme.com"
Redacted: "Contact Email1"
Tokens: ["Contact", " ", "Email", "1"]
= 4 tokens per entity

Cost Impact: 90% token reduction per redacted entity

2.3 Gap Analysis

FeatureCurrent StateTarget StatePriority
Placeholder Format[REDACTED_EMAIL]_uuid (40 tokens)Email1 (2 tokens)🔴 Critical
Session StateReturned as redaction_mappingReturned as session_map🟡 Medium
Unredaction❌ Not implementedPOST /unredact endpoint🔴 Critical
Unified APISeparate /redact + /abstractizeSingle /redact with metadata🟢 Low
Metadata Injection✅ Already implemented (plain text + JSON)✅ Keep as-is✅ Complete

3. Target Architecture: The "Session Map" Approach

The service will follow the "Session Map" architecture to ensure security, efficiency, and high-quality LLM performance. The workflow is as follows:

  1. Processing: The service receives raw text. It identifies sensitive entities and replaces them with short, unique placeholders (e.g., Brand1, Person1). Note: Research shows Brand1 (2 tokens) is more efficient than BRAND_1 (3 tokens) due to PascalCase being common in training data.
  2. State Management: During processing, the service generates a session_map object. This map links each placeholder to its original value and is returned to the calling client. This map is never sent to the LLM.
  3. Context Generation: For entities with known attributes, the service generates a plain-text metadata_injection string to be included in the LLM's system prompt.
  4. LLM Interaction: The client sends the sanitized_text and metadata_injection to the LLM.
  5. Unredaction: The client receives the response from the LLM and sends it, along with the original session_map, to the service's unredaction endpoint to restore the original sensitive values.

3. Functional Requirements

The service will expose two primary endpoints. The existing /redact endpoint will be refactored, and a new /unredact endpoint will be created.

3.1. Unified Processing Endpoint: POST /redact

This endpoint handles the entire redaction and context-generation process.

  • Request Body:
    {
    "text": "<The raw input string to be processed>",
    "tenant_id": "<The ID of the tenant to apply rules for>"
    }
  • Processing Logic:
    1. Identify all sensitive entities in the text based on tenant-specific rules (PII, proprietary patterns, customer names, etc.).
    2. For each unique entity found, generate a token-efficient placeholder (e.g., [TYPE]_[COUNT], like EMAIL_1). These placeholders must be designed to be unambiguous and distinct from natural language to ensure the unredaction logic can operate reliably.
    3. Construct the session_map object, linking each placeholder to its original value and type.
    4. Use the ContextualAbstractionManager to generate the metadata_injection string for all identified entities that have contextual metadata.
    5. Produce the sanitized_text by replacing the original entities with their corresponding placeholders.
  • Response Body:
    {
    "sanitized_text": "<Text with placeholders>",
    "session_map": {
    "PLACEHOLDER_1": { "original": "value1", "type": "TYPE_A", "sensitivity": "low" },
    "PLACEHOLDER_2": { "original": "value2", "type": "TYPE_B", "sensitivity": "high" }
    },
    "metadata_injection": "<Plain-text context for the LLM system prompt>"
    }

3.2. Unredaction Endpoint: POST /unredact

This endpoint restores the original text from an LLM response.

  • Request Body:
    {
    "text": "<The LLM's response, containing placeholders>",
    "session_map": {
    "PLACEHOLDER_1": { "original": "value1", ... },
    "PLACEHOLDER_2": { "original": "value2", ... }
    }
    }
  • Processing Logic:
    1. Iterate through the session_map keys (placeholders).
    2. For each placeholder, perform a robust, case-insensitive replacement on the input text.
    3. The replacement logic must be "word-aware" to correctly handle placeholders adjacent to common punctuation (e.g., ., ,, ?, )) without affecting partial-string matches. A regular expression using word boundaries (e.g., \b) is the recommended approach.
  • Response Body:
    {
    "unredacted_text": "<The LLM's response with original values restored>"
    }

4. Non-Functional Requirements

  • Performance: The service must have low latency to be used in near real-time applications. Caching for tenant-specific rules and data will be critical.
  • Security: The session_map contains sensitive data and must be handled securely by the calling client. It should not be logged or stored unnecessarily.
  • Statelessness: The service itself remains stateless. The state (session_map) is owned and managed by the client, which aligns with modern cloud-native principles.

5. End-to-End Example

Complete Workflow

Step 1: Client calls /redact

POST /redact
{
"text": "Contact john@acme.com about ACME Corp's Q4 revenue of $2.5M",
"tenant_id": "tenant-123"
}

Step 2: Service Response

{
"sanitized_text": "Contact Email1 about Brand1's Q4 revenue of Currency1",
"session_map": {
"Email1": {
"original": "john@acme.com",
"type": "EMAIL",
"sensitivity": "high"
},
"Brand1": {
"original": "ACME Corp",
"type": "BRAND",
"sensitivity": "low"
},
"Currency1": {
"original": "$2.5M",
"type": "CURRENCY",
"sensitivity": "medium"
}
},
"metadata_injection": "Brand1 is a B2B software company in the enterprise SaaS space with 35% margin."
}

Step 3: Client constructs LLM Prompt

System: You are analyzing business communications. Context:
Brand1 is a B2B software company in the enterprise SaaS space with 35% margin.

User: Contact Email1 about Brand1's Q4 revenue of Currency1

Step 4: LLM Responds

"I'll draft an email to Email1 discussing Brand1's strong Q4 performance (Currency1 represents 15% growth YoY)."

Step 5: Client calls /unredact

POST /unredact
{
"text": "I'll draft an email to Email1 discussing Brand1's strong Q4 performance (Currency1 represents 15% growth YoY).",
"session_map": { /* same as from /redact */ }
}

Step 6: Service Response

{
"unredacted_text": "I'll draft an email to john@acme.com discussing ACME Corp's strong Q4 performance ($2.5M represents 15% growth YoY)."
}

6. Migration Strategy

6.1 Backward Compatibility

Approach: Dual-format support during transition period

# app.py enhancement
def get_placeholder_format(tenant_config):
"""Allow per-tenant format selection"""
if tenant_config.get('use_v2_placeholders'):
return 'efficient' # Brand1, Email1
return 'legacy' # [REDACTED_BRAND]_uuid

6.2 Migration Phases

Phase 1: Implement v2 (Week 1-2)

  • Add counter-based placeholder generation
  • Implement /unredact endpoint
  • Add format selection parameter to /redact
  • Deploy as opt-in feature

Phase 2: Testing (Week 3)

  • Internal testing with ChainAlign tenant
  • A/B cost comparison (UUID vs. counters)
  • Validate unredaction accuracy

Phase 3: Gradual Rollout (Week 4-6)

  • Enable v2 for new tenants by default
  • Migrate existing tenants one-by-one
  • Monitor token cost reductions

Phase 4: Deprecation (Month 3)

  • Announce deprecation of UUID format
  • Provide 90-day migration window
  • Remove legacy code in v3.0 release

6.3 Risk Mitigation

Risk: Placeholder collision in existing text Mitigation: Pre-scan for collision, use session-specific prefixes if detected

Risk: Case-sensitivity in unredaction Mitigation: Implement case-insensitive + word-boundary regex (already specified in FSD)

Risk: LLM hallucinates non-existent placeholders Mitigation: Return unmapped_placeholders array in /unredact response for logging


7. Success Metrics

MetricBaseline (v1)Target (v2)Measurement
Avg tokens/entity402-3Log analysis
Token cost reductionN/A60-80%Monthly billing
Unredaction accuracyN/A99.9%Automated tests
API latency (p95)<500ms<500msMonitoring

8. References