Merged in feature/update-caching (pull request #856)

Feature/update caching

* Enable prompt caching for CODE_LAST_CHECK, FILL_BILL_TYPE, DUAL_LOB_CHECK, and GROUPER_BREAKOUT

- Add CODE_LAST_CHECK_INSTRUCTION() for service specificity classification
- Add FILL_BILL_TYPE_INSTRUCTION() for bill type code determination
- Add DUAL_LOB_CHECK_INSTRUCTION() for Medicare/Medicaid classification
- Update code_funcs.py to use caching for CODE_LAST_CHECK, FILL_BILL_TYPE, GROUPER_BREAKOUT
- Update postprocessing_funcs.py to use caching for DUAL_LOB_CHECK
- Add new instructions to get_cacheable_instructions() for cache warming
- Add unit tests for new instruction functions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* Fix postprocessing_funcs to remove invalid columns

* Merge branch 'main' into feature/lesser-table-caching-refactor-hybrid

* Apply black formatting to 11 files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* Fix import paths in testbed files

* Merge main into feature/update-caching

* Add SPLIT_REIMB_DATES_INSTRUCTION for prompt caching

* Merged main into feature/update-caching

* Merge remote-tracking branch 'origin/main' into feature/update-caching

* Merge branch 'feature/update-caching' of https://bitbucket.org/aarete/doczy.ai into feature/update-caching

* Add CODE_* instruction functions for prompt caching

* Merged main into feature/update-caching

* Merged main into feature/update-caching

* Maximize prompt caching by moving static content to instructions

- Refactored 12+ prompt functions to move static rules/examples to _INSTRUCTION()
- VALIDATE_REIMBURSEMENTS: Moved 45+ lines of validation rules to instruction
- DATE_FIX: Moved conversion rules and examples to instruction
- EXHIBIT_LEVEL, EXHIBIT_TITLE_MATCH, EXHIBIT_HEADER, EXHIBIT_LINKAGE: Moved rules
- FEE_SCHEDULE_BREAKOUT, GROUPER_BREAKOUT: Moved extraction rules
- CHECK_PROVIDER_NAME_MATCH: Moved matching rules to instruction
- LOB_RELATIONSHIP: Consolidated split instructions
- DERIVED_TERM_DATE: Moved calculation logic to instruction
- DYNAMIC_PRIMARY: Created separate HEADER and TEXT instructions
- Created new REIMB_DATES_ASSIGNMENT_INSTRUCTION with all date rules
- Updated get_cacheable_instructions() with new instruction functions
- Updated all callers in saas, clover, bcbs_promise pipelines

This enables ~90% cost savings via Claude API prompt caching by ensuring
static instruction text is cached and only dynamic content varies.

* Remove Dynamic Primary Header

* Standardize prompt caching across all LLM prompts for ~90% cost savings

Move static content to _INSTRUCTION() functions for caching:
- METHODOLOGY_BREAKOUT: 8 field definitions with resolved valid_values
- FEE_SCHEDULE_BREAKOUT: 3 field definitions
- GROUPER_BREAKOUT: 11 field definitions
- OUTLIER_BREAKOUT: 8 field definitions
- CODE_EXPLICIT: 8 field definitions
- EXHIBIT_HEADER: static header markers list
- CARVEOUT_CHECK: carveout and special case definitions
- SPECIAL_CASE_ASSIGNMENT: task rules and output format

Update callers to use cache=True, instruction, and usage_label params.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* Apply black formatting to prompt_templates.py

* Update unit tests for prompt caching changes

- Fix function signatures in tests (METHODOLOGY_BREAKOUT, FEE_SCHEDULE_BREAKOUT, GROUPER_BREAKOUT, CODE_EXPLICIT)
- Add tests for CARVEOUT_CHECK and EXHIBIT_HEADER prompts
- Add TestInstructionFieldContent class to verify instruction functions contain field definitions
- Add tests for CARVEOUT_CHECK_INSTRUCTION and CODE_EXPLICIT_INSTRUCTION

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* Refactor instructions to load fields from investment_prompts.json and Constants

Address PR review feedback:
- Add _get_constants() helper for lazy Constants instantiation
- Add _get_fields_text() helper to load fields from investment_prompts.json
- METHODOLOGY_BREAKOUT_INSTRUCTION: Load fields via FieldSet
- FEE_SCHEDULE_BREAKOUT_INSTRUCTION: Load fields via FieldSet
- GROUPER_BREAKOUT_INSTRUCTION: Load fields via FieldSet
- OUTLIER_BREAKOUT_INSTRUCTION: Load fields via FieldSet
- EXHIBIT_HEADER_INSTRUCTION: Load markers from Constants.EXHIBIT_HEADER_MARKERS
- CARVEOUT_CHECK_INSTRUCTION: Load carveouts from Constants.VALID_CARVEOUTS,
  special cases from investment_prompts.json
- CODE_EXPLICIT_INSTRUCTION: Keep hardcoded (no code_explicit field_type in JSON)

Update tests to match actual field names from investment_prompts.json.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* Merge main into feature/update-caching

* Remove deprecated dynamic_primary_header

* Update CODE_EXPLICIT_INSTRUCTION to load fields from investment_prompts.json

Use field_type=code_primary_breakout to load code fields dynamically.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* Merged main into feature/update-caching

* Merge main into feature/update-caching

* Merge branch 'feature/update-caching' of https://bitbucket.org/aarete/doczy.ai into feature/update-caching


Approved-by: Katon Minhas
This commit is contained in:
Faizan Mohiuddin
2026-01-30 23:23:37 +00:00
committed by Katon Minhas
parent ff8ec57ed0
commit 90bed0d5f6
10 changed files with 887 additions and 558 deletions
+28 -8
View File
@@ -105,14 +105,14 @@ def code_explicit(service, methodology, filename):
Returns an empty dictionary if the service string is empty.
"""
# Prompt
code_primary_questions = FieldSet(
file_path=config.FIELD_JSON_PATH, field_type="code_primary_breakout"
).print_prompt_dict()
# Prompt - field definitions are now included in CODE_EXPLICIT_INSTRUCTION() for caching
claude_answer_raw = llm_utils.invoke_claude(
prompt_templates.CODE_EXPLICIT(service, methodology, code_primary_questions),
prompt_templates.CODE_EXPLICIT(service, methodology),
"sonnet_latest",
filename,
cache=True,
instruction=prompt_templates.CODE_EXPLICIT_INSTRUCTION(),
usage_label="CODE_EXPLICIT",
)
code_answer_dict = string_utils.universal_json_load(claude_answer_raw)
return code_answer_dict
@@ -143,6 +143,8 @@ def code_category(service, proc_category, hcpcs_level2_mapping, filename):
prompt_templates.CODE_CATEGORY(service, matching_values),
"sonnet_latest",
filename,
cache=True,
instruction=prompt_templates.CODE_CATEGORY_INSTRUCTION(),
)
claude_answer_final = string_utils.universal_json_load(
claude_answer_raw
@@ -176,7 +178,11 @@ def code_implicit_special(service, filename):
"""
claude_answer_raw = llm_utils.invoke_claude(
prompt_templates.CODE_IMPLICIT_SPECIAL(service), "sonnet_latest", filename
prompt_templates.CODE_IMPLICIT_SPECIAL(service),
"sonnet_latest",
filename,
cache=True,
instruction=prompt_templates.CODE_IMPLICIT_SPECIAL_INSTRUCTION(),
)
claude_answer_final = string_utils.extract_text_from_delimiters(
claude_answer_raw, Delimiter.PIPE
@@ -350,6 +356,8 @@ def code_implicit_rag(service, implicit_run_dict, filename, constants):
prompt_templates.CODE_IMPLICIT(service, level_dict["match_list"]),
"sonnet_latest",
filename,
cache=True,
instruction=prompt_templates.CODE_IMPLICIT_INSTRUCTION(),
)
try:
@@ -430,7 +438,11 @@ def code_last_check(service, filename):
"""
claude_answer_raw = llm_utils.invoke_claude(
prompt_templates.CODE_LAST_CHECK(service), "sonnet_latest", filename
prompt_templates.CODE_LAST_CHECK(service),
"sonnet_latest",
filename,
cache=True,
instruction=prompt_templates.CODE_LAST_CHECK_INSTRUCTION(),
)
claude_answer_final = string_utils.extract_text_from_delimiters(
claude_answer_raw, Delimiter.PIPE
@@ -470,6 +482,8 @@ def fill_bill_type(
),
"sonnet_latest",
"",
cache=True,
instruction=prompt_templates.FILL_BILL_TYPE_INSTRUCTION(),
)
claude_answer_final = string_utils.universal_json_load(claude_answer_raw)
@@ -484,6 +498,8 @@ def fill_bill_type(
),
"sonnet_latest",
"",
cache=True,
instruction=prompt_templates.FILL_BILL_TYPE_INSTRUCTION(),
)
claude_answer_final = string_utils.universal_json_load(claude_answer_raw)
@@ -843,7 +859,11 @@ def grouper_breakout(results_with_code: pd.DataFrame):
GROUPER_QUESTIONS,
)
claude_answer_raw = llm_utils.invoke_claude(
grouper_breakout_prompt, "sonnet_latest", ""
grouper_breakout_prompt,
"sonnet_latest",
"",
cache=True,
instruction=prompt_templates.GROUPER_BREAKOUT_INSTRUCTION(),
)
try:
grouper_answer = string_utils.universal_json_load(claude_answer_raw)