Files
doczyai-pipelines/documentation/CONTEXT_CACHING_IMPLEMENTATION.md
Katon Minhas 0d00d581b1 Merged in DEV (pull request #913)
DEV

* Apply formatting fix

* Merged in DAIP2-1898-one-to-one-issues-filename-tin-auto-renewal-and-contract-title (pull request #888)

DAIP2-1898 one to one issues filename tin auto renewal and contract title

* contract title fixes

* Add instruction to strip hyphens from TIN and NPI

* prompt update

* Merge branch 'bugfix/auto-renewal-term' into bugfix/DAIP2-1699-issue-tracker-fixes-one-to-one-dates-prov-info

* removed print statements

* pipeline error fixed

* signed_ind logic changed

* signatory_ind logic updated

* prompt update

* prompt update

* pipeline error fixed

* Merge branch 'DEV' into bugfix/DAIP2-1699-issue-tracker-fixes-one-to-one-dates-prov-info

* Merge branch 'DEV' into bugfix/DAIP2-1699-issue-tracker-fixes-one-to-one-dates-prov-info

* requested changes applied

* test case added

* prompt update

* contract title prompt update

* prompt update

* Merge branch 'DEV' into DAIP2-1898-one-to-one-issues-filename-tin-auto-renewal-and-contract-title


Approved-by: Siddhant Medar

* Merged in feature/DAIP2-1803-add-aarete-derived-provider-name (pull request #884)

Feature/DAIP2-1803 add aarete derived provider name

* Merged DEV into feature/DAIP2-1562-add-aarete_derived_payer_name

* state logic added in clustering

* removed print statements

* pull request updates

* black format fix

* Merged DEV into feature/DAIP2-1562-add-aarete_derived_payer_name

* added scalability feature and optimization

* black format

* Pull Request Changes

* generalised funcs from aarete derived payer name

* updated remove states and updated docstring for build similarity matrix

* derived payer name functionality added

* config and main file changes

* sync dev into ADD AARETE DERIVED PROVIDER GROUP NAME FULL

* updated derived_provider name

* pipeline fixes

* Merged DEV into feature/DAIP2-1803-add-aarete-derived-provider-name

* config changes

* field name updated to AARETE_DERIVED_PROVIDER_NAME

* Merged DEV into feature/DAIP2-1803-add-aarete-derived-provider-name

* black format fix

* Fix docstr…
* Merged in improve-logging (pull request #886)

Improve logging

* Add timing blocks for comprehensive pipeline logging

- Add timing_utils.timed_block() to key extraction functions in one_to_n_funcs.py:
  - exhibit_level sub-functions (prompt_exhibit_level, dynamic_primary, etc.)
  - reimbursement_level extraction and cleaning
  - breakout functions (methodology_breakout, special_case_breakout)
  - carveout_and_special_case parallel processing
  - one_to_n_cleaning sub-steps (crosswalk, lob_relationship, split_reimb_dates)

- Add timing to dynamic_funcs.py:
  - dynamic_assignment parallel processing

- Add timing to postprocess.py:
  - standard_postprocess, contract_config_postprocess, dashboard_postprocess

- Add timing to preprocess.py:
  - exhibit_chunking sub-steps (get_exhibit_pages, link_exhibit_pages, chunk_by_exhibit)

- Add info-level logging statements for completed operations with row/item counts

* Standardize logging levels and remove deprecated code

DAIP2-1798: Ensure logging statements are at …
* Merged in bugfix/DAIP2-1913-lesser-of-indicator-issues (pull request #889)

Bugfix/DAIP2-1913 lesser of indicator issues

* contract title fixes

* Add instruction to strip hyphens from TIN and NPI

* prompt update

* Merge branch 'bugfix/auto-renewal-term' into bugfix/DAIP2-1699-issue-tracker-fixes-one-to-one-dates-prov-info

* removed print statements

* pipeline error fixed

* signed_ind logic changed

* signatory_ind logic updated

* prompt update

* prompt update

* pipeline error fixed

* Merge branch 'DEV' into bugfix/DAIP2-1699-issue-tracker-fixes-one-to-one-dates-prov-info

* Merge branch 'DEV' into bugfix/DAIP2-1699-issue-tracker-fixes-one-to-one-dates-prov-info

* requested changes applied

* test case added

* prompt update

* contract title prompt update

* prompt update

* Merge branch 'DEV' into DAIP2-1898-one-to-one-issues-filename-tin-auto-renewal-and-contract-title

* handle nested cases of lesser_of and greater_of

* Merge branch 'DEV' into bugfix/DAIP2-1913-lesser-of-indicator-issues

* pi…
* Merged in bugfix/reimb_primary (pull request #890)

Update reimbursement prompts for consistent PMPM handling, time-unit dedup, and validation improvements

* Update reimbursement prompts for consistent PMPM handling, time-unit dedup, and validation improvements

- REIMBURSEMENT_PRIMARY: append unit of measure (PMPM, per visit, etc.) from table headers into REIMB_TERM
- METHODOLOGY_BREAKOUT: collapse mathematically equivalent time-unit rates into single entry
- VALIDATE_REIMBURSEMENTS: add umbrella terms as valid service terms, accept CPT/HCPCS percentage as concrete rate, narrow COB disqualifier to primary subject only

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>


Approved-by: Siddhant Medar

* Merged in feature/update-postprocessing-columns (pull request #893)

move column order to final step

* move column order to final step

* Black


Approved-by: Siddhant Medar

* Merged in bugfix/update-postprocessing-paths (pull request #896)

Update postprocessing paths

* Update postprocessing paths


Approved-by: Siddhant Medar

* Merged in feature/TIN_stats_update (pull request #898)

Feature/TIN stats update

* Tin_stats_report

* black formatting

* minor changes

* black format applied

* Addressed the katons comments

* Merged DEV into feature/TIN_stats_update

* black reformat


Approved-by: Katon Minhas

* Merged main into DEV

* Merged in feature/exhibit-smart-chunking (pull request #883)

Feature/exhibit smart chunking

* exhibit processing per page

* header dict deduplication

* dedup prompt refinment

* refinment for header extraction proecess

* Merge remote-tracking branch 'origin/DEV' into feature/exhibit-smart-chunking

* merge updates

* minor fix

* prompt fix for reimb type

* COB defenition for clear understanding

* black formatting

* remove quit statement

* pipiline test

* pipeline test

* black formatting

* Merge remote-tracking branch 'origin/DEV' into feature/exhibit-smart-chunking

* black formating

* Merge remote-tracking branch 'origin/DEV' into feature/exhibit-smart-chunking

* typo

* PR comment fixes

* exhibit funcs refactored

* black formatting

* Refactor exhibit chunking config into dedicated class

Created ExhibitChunkingConfig class to centralize exhibit smart chunking
configuration parameters (DEFAULT_SUBCHUNK_SIZE, MIN_PARENT_CHUNK_SIZE,
CHUNK_RELEVANCE_THRESHOLD). This improves code organization …
* Merged in bugfix/DAIP2-1870-dynamic-issues (pull request #892)

Bugfix/DAIP2-1870 dynamic issues

* updated list format appending

* fill bill type from claim type cd

* Fixed remaining format fixes

* Merged DEV into bugfix/DAIP2-1870-dynamic-issues

* changed crosswalk mapping from PRODUCT to AARETE_DERIVED_PRODUCT

* Merged DEV into bugfix/DAIP2-1870-dynamic-issues

* updating LOB field values as well from PRODUCT AND PROGRAM

* updated apply crosswalk for reverse mapping

* Merged DEV into bugfix/DAIP2-1870-dynamic-issues

* added QHP and BHP

* removed lob reverse mapping

* Merged DEV into bugfix/DAIP2-1870-dynamic-issues

* Remove Bill Type/Claim Type fill

* Merged DEV into bugfix/DAIP2-1870-dynamic-issues

* Black format

* Merged DEV into bugfix/DAIP2-1870-dynamic-issues


Approved-by: Katon Minhas

* Merged in bugfix/prov_info_json_fixes (pull request #899)

Bugfix/prov info json fixes

* fix: robust PROV_INFO_JSON sanitization and TIN backfill logic

json_utils:
- Add sanitize_prov_info_json with layered parsing (JSON, literal_eval,
  empty-value-after-colon fix, best-effort dict extraction).
- Add _normalize_prov_entries and _prov_value_to_str for uniform
  str-valued output; flatten list values, strip TIN hyphens.
- format_prov_info_json now delegates to sanitize_prov_info_json.

postprocessing_funcs:
- Add fill_prov_info_tin_from_filename_tin for TIN backfill.
- Add validate_and_reformat_date (pipe-wrapped, datetime strings).
- Add format_as_json_list (pipe-delimited, comma-separated, quote
  stripping).

postprocess:
- Integrate new postprocessing helpers into pipeline flow.

postprocess_existing_output:
- Support CSV and Excel input, configurable paths, fillna for CSV.

tests:
- Add test_json_parsers.py for PROV_INFO_JSON parsing coverage.
- Add test_postprocess.py for date/list formatting and defau…
* Merged in bugfix/reimb_primary_issues (pull request #900)

Bugfix/reimb primary issues

* Update lesser of distribution prompt to preserve reimb term langauge

* Added prompt change to extract correct service when there are multiple sub-rates; Updated validate reimb term to prevent filtering out erm with valid rate

* Make reimb primary prompt change

* Revert "Make reimb primary prompt change"

This reverts commit 55f7d73b9cb523097c96ea50b6614c1db53b46d2.


Approved-by: Katon Minhas

* Merged in dtc_report (pull request #902)

Dtc report

* dtc_report_added

* lint format fixed

* Changed regex location call


Approved-by: Katon Minhas

* Merged in feature/historical-cost-analysis (pull request #901)

Feature/historical cost analysis

* Initial commit

* Finalize cost_analysis

* Black format

* Merged DEV into feature/historical-cost-analysis

* Refactor

* Black

* Merged DEV into feature/historical-cost-analysis


Approved-by: Siddhant Medar

* Merged in feature/ai-pr-review-agent (pull request #906)

Add AI code review agent to pull request pipeline

* Add AI code review agent to pull request pipeline

Adds a pull-requests pipeline that runs CI checks (lint, type check,
unit tests) followed by an AI code review step. The AI review uses
OIDC to authenticate with AWS Bedrock - no hardcoded AWS keys. It
clones the code-review-agent repo and posts a review comment on the PR.

* Fix AI code review step: install git in python:3.12-slim image

* Trigger pipeline

* Trigger pipeline

* Trigger pipeline

* Trigger pipeline

* Trigger pipeline

* Trigger pipeline

* Trigger pipeline

* Remove debug token decode line

* Update guide: all checklist items complete, agent working

* Remove guide file from repo

* Trigger pipeline


Approved-by: Katon Minhas

* Merged in DAIP2-1980-aarete-derived-effective-dt-issues (pull request #904)

DAIP2-1980 aarete derived effective dt issues

* fixed earlier of a and b

* prompt update

* prompt shortened

* test changes reverted

* Merge branch 'DEV' into DAIP2-1980-aarete-derived-effective-dt-issues

* test changes reverted

* Merged DEV into DAIP2-1980-aarete-derived-effective-dt-issues

* Fix effective date prompt

* Replace em-dashes with readable version


Approved-by: Katon Minhas

* Merged in feature/DAIP2-2023-eliminate-full-context-processing (pull request #905)

Feature/DAIP2-2023 eliminate full context processing

* testing full context fields

* remove full context processing

* merge Dev with DAIP2-2-23

* full context removal in client codes

* AARETE_DERIVED_PROVIDER_NAME field changes

* Merged DEV into feature/DAIP2-2023-eliminate-full-context-processing

* optimized provider name

* black format fix

* contract title fixes

* PAYER NAME AUTO RENEWAL IND fixes

* Merged DEV into feature/DAIP2-2023-eliminate-full-context-processing

* Merge branch 'DEV' into feature/DAIP2-2023-eliminate-full-context-processing

* Remove prints


Approved-by: Katon Minhas

* Merged in feature/code_optimization (pull request #903)

Feature/code optimization

* Ran Black

* made a small change in code_last_check, fixed so it returns string and not single char

* Made changes to make sure that default_ind postprocess only happens to the cc output and not dashboard

* Merge bugfix/default_ind_postprocess into feature/code_optimization

- Parent-child: child_rank column init and cols_to_keep filter
- Postprocess: default_ind only on cc output
- code_last_check: parser str/list return handling + exception logging
- Prompt: FIELD ASSIGNMENT for code extraction (no CRITICAL prefix)

* More prompt changes and debugging print statements

* Added system to group same service term + bill type cd + claim type cd and then parallelize the code extraction (will improve consistency)

* Revert one-time PROV_INFO_JSON ad hoc logic; retain json_utils and output format

- Remove temporary postprocess step that filled empty TIN in PROV_INFO_JSON from
  FILENAME_TIN (fill_prov_info_tin_from_filename_ti…
* Merged in DAIP2-2121-prov-info-fields-issue-fixes (pull request #908)

empty prov_info_json fixed

* empty prov_info_json fixed

* Merged DEV into DAIP2-2121-prov-info-fields-issue-fixes

* format of PROV_OTHER_TIN fixed

* Revert "format of PROV_OTHER_TIN fixed"

This reverts commit 580847de03265520b1b4fad473bbf38ef1573753.

* formatting and deduplication

* pipeline error fixed

* test cases added

* pipeline error fixed


Approved-by: Katon Minhas

* Merged in feature/context-caching (pull request #909)

Feature/context caching

* Initial commit - context caching for DYNAMIC_PRIMARY

* implement context caching for all relevant prompts

* Remove option to not context cache

* IndentationError fixed

* Merge branch 'DEV' into feature/context-caching

* Merge and format

* Move documentation

* Merged DEV into feature/context-caching

* Update unit tests

* Merged DEV into feature/context-caching

* Update signatures

* Fix test coverage gap


Approved-by: Praneel Panchigar
Approved-by: Karan Desai

* Merged in bugfix/DAIP2-2138-reimbursement-primary-testing (pull request #910)

Bugfix/DAIP2-2138 reimbursement primary testing

* updated table instructions for reimb term extraction

* updated split tables to include header rows

* issue fix

* Merged DEV into bugfix/DAIP2-2138-reimbursement-primary-testing

* black format fix


Approved-by: Katon Minhas

* Merged in feature/doczy_reports (pull request #911)

Feature/doczy reports

* Added post_doczy_reports

* black format fix

* Merged DEV into feature/doczy_reports

* fixed code review


Approved-by: Katon Minhas

* Merged in feature/median-cost-analysis (pull request #912)

Add median

* Add median


Approved-by: Siddhant Medar


Approved-by: Siddhant Medar
2026-03-16 19:39:05 +00:00

10 KiB
Raw Permalink Blame History

Context Caching Implementation - Complete

Summary

Successfully implemented context caching for 6 high-value prompts across all 3 client pipelines. This enables Anthropic's prompt caching at the exhibit/context level, where the same context is cached and reused across multiple field extractions, reducing token costs by ~84% for repeated context processing.

Prompts with Context Caching

  1. DYNAMIC_PRIMARY (pilot) - Primary term field extraction
  2. EXHIBIT_LEVEL - Exhibit-level metadata extraction
  3. DYNAMIC_ASSIGNMENT - Dynamic term assignment to exhibit rows
  4. REIMB_DATES_ASSIGNMENT - Reimbursement date assignment (specialized)
  5. LESSER_OF_DISTRIBUTION - Lesser-of logic distribution across codes
  6. LESSER_OF_CHECK - Lesser-of presence validation

Pipelines Updated

  • bcbs_promise - All 5 applicable functions updated
  • clover - All 5 applicable functions updated
  • saas - All 5 applicable functions updated

What Changed

1. Extended LLM API (llm_utils.py)

Added context_for_caching parameter throughout the call chain:

  • invoke_claude() - New optional parameter
  • _build_claude_3_request_body() - Structures multi-block messages with cache control
  • get_cache_key() - Includes context in cache key generation
  • local_claude_3_and_up() - Passes parameter through
  • ec2_claude_3_and_up() - Passes parameter through

Key Innovation: Messages now support multiple content blocks where specific blocks can be marked for caching:

"messages": [{
  "role": "user",
  "content": [
    {
      "type": "text",
      "text": "Large exhibit text (40k tokens)",
      "cache_control": {"type": "ephemeral"}  # CACHED
    },
    {
      "type": "text",
      "text": "Field-specific question (200 tokens)"  # NOT CACHED
    }
  ]
}]

2. Updated Existing Prompt Templates (prompt_templates.py)

Updated 6 existing functions to always split prompts into cacheable and fresh components:

  1. DYNAMIC_PRIMARY() - Caches exhibit text, field question stays fresh
  2. EXHIBIT_LEVEL() - Caches exhibit text, field questions stay fresh
  3. DYNAMIC_ASSIGNMENT() - Caches exhibit simplified text, term questions stay fresh
  4. REIMB_DATES_ASSIGNMENT() - Specialized for REIMB_DATES assignment
  5. LESSER_OF_DISTRIBUTION() - Caches exhibit text and cross-exhibit context
  6. LESSER_OF_CHECK() - Caches exhibit title context

Each returns (context_text, prompt, parser) instead of (prompt, parser).

These functions now always return (context_text, prompt, parser) for context caching.

3. Updated All Client Prompt Calls

Updated functions across all 3 pipelines:

bcbs_promise/prompts/prompt_calls.py:

  • prompt_exhibit_level()
  • prompt_dynamic_primary()
  • prompt_dynamic_assignment()
  • prompt_lesser_of_distribution()
  • prompt_lesser_of_check()

clover/prompts/prompt_calls.py:

  • prompt_exhibit_level()
  • prompt_dynamic_primary()
  • prompt_dynamic_assignment()
  • prompt_lesser_of_distribution()
  • prompt_lesser_of_check()

saas/prompts/prompt_calls.py:

  • prompt_exhibit_level()
  • prompt_dynamic_primary()
  • prompt_dynamic_assignment()
  • prompt_lesser_of_distribution()
  • prompt_lesser_of_check()

Each function now:

  1. Uses the original template function (always split for caching)
  2. Receives (context_text, prompt, parser) tuple
  3. Passes context_for_caching=context_text to invoke_claude()
  4. Logs context length for monitoring

Cost Impact Analysis

Current Structure (Before)

  1. System message (cached): Field extraction instruction (~2k tokens)
  2. User message (NOT cached): Combined exhibit + field question (~40k tokens)

For 20 fields on same exhibit:

  • Instruction: 2k × 1 creation = cached once ✓
  • Content: 40k × 20 calls = 800k tokens at $0.003/1k = $2.40

New Structure (After)

  1. System message (cached): Field extraction instruction (~2k tokens)
  2. User message block 1 (cached): Exhibit context (~40k tokens)
  3. User message block 2 (not cached): Field question (~200 tokens)

For 20 fields on same exhibit:

  • Instruction: 2k × 1 creation = cached once ✓
  • Context: 40k × 1 creation at $0.00375/1k = $0.15
  • Context: 40k × 19 reads at $0.0003/1k = $0.228
  • Field questions: 20 × 200 tokens at $0.003/1k = $0.012
  • Total: $0.39 (84% cost reduction)

Break-Even Analysis

  • 1st field: Pay 25% premium for cache creation
  • 2nd field: Start saving with 90% cheaper cache reads
  • 3+ fields: Massive savings accumulate

How It Works

Caching Layers (Claude API)

Layer 1: System Instruction (cached) ← Already implemented
    ↓
Layer 2: Exhibit Context (cached) ← NEW - This implementation
    ↓
Layer 3: Field Question (fresh) ← Changes per call

Flow Example

# Processing LOB field for exhibit
context_text, prompt, parser = DYNAMIC_PRIMARY(
    exhibit_text="[40k token exhibit]",
    field_name="LOB",
  field_prompt="Line of Business definition",
)

llm_utils.invoke_claude(
    prompt=prompt,  # Just the field question
    context_for_caching=context_text,  # Exhibit text (cached)
    instruction=DYNAMIC_PRIMARY_INSTRUCTION(),  # Rules (already cached)
    cache=True
)
# First call: Cache creation for exhibit
# Cost: (2k instruction + 40k context) × cache multiplier + 200 tokens fresh

# Processing PROGRAM field for SAME exhibit
context_text, prompt, parser = DYNAMIC_PRIMARY(
    exhibit_text="[SAME 40k token exhibit]",  # Same content
    field_name="PROGRAM", 
  field_prompt="Program definition",
)

llm_utils.invoke_claude(
    prompt=prompt,  # Different field question
    context_for_caching=context_text,  # SAME exhibit (cache hit!)
    instruction=DYNAMIC_PRIMARY_INSTRUCTION(),
    cache=True
)
# Second call: Cache read for exhibit
# Cost: (2k + 40k) × cache read rate (90% cheaper) + 200 tokens fresh

Testing

Created comprehensive test suite in src/tests/test_context_caching.py:

test_dynamic_primary_returns_three_values() - Validates always-split signature
test_dynamic_primary_original_still_works() - Backward compatibility
test_build_request_body_with_context_caching() - Message structure verification
test_build_request_body_without_context_caching() - Fallback behavior
test_cache_key_includes_context() - Cache key uniqueness

Monitoring & Validation

To verify the implementation is working:

  1. Check usage logs for cache metrics:

    # In usage_tracking.py logs, look for:
    cache_creation_tokens: 40000  # First call
    cache_read_tokens: 40000      # Subsequent calls
    
  2. Monitor cost per file in usage reports:

    • Should see dramatic cost reduction for files with many dynamic fields
    • Exhibits with 10+ fields should show 80%+ savings on exhibit processing
  3. Log analysis:

    DEBUG: Context length for caching: 42567 chars
    

    This confirms context is being passed to caching layer.

Implementation Status

Completed

All high-value prompts have been migrated to context caching across all 3 client pipelines:

  1. DYNAMIC_PRIMARY - Primary term field extraction (pilot implementation)
  2. EXHIBIT_LEVEL - Exhibit-level metadata extraction
  3. DYNAMIC_ASSIGNMENT - Dynamic term assignment to exhibit rows
  4. REIMB_DATES_ASSIGNMENT - Reimbursement date assignment (specialized)
  5. LESSER_OF_DISTRIBUTION - Lesser-of logic distribution across codes
  6. LESSER_OF_CHECK - Lesser-of presence validation

Cost Savings: Estimated 80-85% reduction in token costs for repeated exhibit/context processing across these 6 prompts.

Future Considerations

Lower Priority Candidates (evaluate after monitoring current implementation):

  • METHODOLOGY_BREAKOUT - Could cache reimbursement terms for multiple breakout operations
  • Other exhibit-level prompts - If processing changes to single-field-at-a-time pattern

Monitoring Required:

  • Track cache hit rates and actual cost savings in production
  • Validate that 5-minute cache TTL aligns with typical processing patterns
  • Identify any additional prompts with repeated context usage patterns

Implementation Pattern (For Future Extensions)

For any new prompt to extend:

  1. Update [PROMPT_NAME]() to return (context, prompt, parser)
  2. Update corresponding prompt_[name]() function to use caching version
  3. Pass context via context_for_caching parameter
  4. Monitor cache metrics to validate savings

Backward Compatibility

Original DYNAMIC_PRIMARY() function remains unchanged
Other templates continue to work without modification
context_for_caching parameter is optional (defaults to None)
When None, behavior is identical to previous implementation
All tests should pass without modification

Files Modified

Core Infrastructure:

Pipeline Updates (All 3 Clients):

Testing & Documentation:

Technical Notes

  • Anthropic prompt caching requires minimum 1024 tokens for cache block
  • Cache TTL is 5 minutes for ephemeral type
  • Only works with Claude 3.5+ Sonnet v2 models (checked via _supports_prompt_cache())
  • Cache keys include both instruction and context to ensure uniqueness
  • Multiple content blocks in user messages is supported by Bedrock Messages API