11import os
22import json
3+ import re
34
45from langchain_core .documents import Document
56from langchain_core .runnables import RunnableConfig
67from typing import List , Optional
78from agent .components .retrieval .endpoint_retrieval .components .states import OutputState
89from agent .components .retrieval .retriever_config import get_retriever
910from agent .components .retrieval .endpoint_retrieval .components .chains import retrieval_grader , endpoint_question_rewriter
11+ from database .document_schemas import EndpointDocumentSchema
1012from dotenv import load_dotenv
1113
1214load_dotenv ()
1517DEFAULT_BATCH_SIZE = int (os .getenv ("ENDPOINT_RETRIEVER_BATCH_SIZE" , "5" ))
1618DEFAULT_RETRY_THRESHOLD = int (os .getenv ("ENDPOINT_RETRIEVER_RETRY_THRESHOLD" , "2" ))
1719DEFAULT_MAX_RETRIES = int (os .getenv ("ENDPOINT_RETRIEVER_MAX_RETRIES" , "2" ))
20+ # Enable compact grading format by default (significant token savings)
21+ DEFAULT_USE_COMPACT_GRADING = os .getenv ("ENDPOINT_RETRIEVER_COMPACT_GRADING" , "true" ).lower () == "true"
1822
1923
20- def get_retrieval_config (config : Optional [RunnableConfig ]) -> tuple [int , int , int ]:
24+ def get_retrieval_config (config : Optional [RunnableConfig ]) -> tuple [int , int , int , bool ]:
2125 """Extract retrieval config from RunnableConfig or use defaults.
2226
2327 Config can be passed via: graph.ainvoke(input, config={"configurable": {"batch_size": 10}})
@@ -27,6 +31,7 @@ def get_retrieval_config(config: Optional[RunnableConfig]) -> tuple[int, int, in
2731 configurable .get ("batch_size" , DEFAULT_BATCH_SIZE ),
2832 configurable .get ("retry_threshold" , DEFAULT_RETRY_THRESHOLD ),
2933 configurable .get ("max_retries" , DEFAULT_MAX_RETRIES ),
34+ configurable .get ("use_compact_grading" , DEFAULT_USE_COMPACT_GRADING ),
3035 )
3136
3237
@@ -59,6 +64,27 @@ def deduplicate_documents(documents: List[Document]) -> List[Document]:
5964 return unique
6065
6166
67+ def get_compact_grading_content (doc : Document ) -> str :
68+ """
69+ Extract compact content for LLM grading to reduce token usage.
70+
71+ Falls back to full content if compact extraction fails.
72+ """
73+ try :
74+ schema = EndpointDocumentSchema .from_document (doc .page_content , doc .metadata )
75+ return schema .to_grading_content ()
76+ except Exception :
77+ # Fallback: use metadata + truncated content
78+ meta = doc .metadata
79+ parts = [
80+ f"{ meta .get ('method' , '' )} { meta .get ('path' , '' )} " ,
81+ f"Summary: { meta .get ('summary' , '' )} " if meta .get ('summary' ) else "" ,
82+ f"Tags: { meta .get ('tags' , '' )} " if meta .get ('tags' ) else "" ,
83+ ]
84+ compact = "\n " .join (p for p in parts if p )
85+ return compact if compact .strip () else doc .page_content [:500 ]
86+
87+
6288async def retrieve_endpoints (state , config : RunnableConfig = None ):
6389 """
6490 Retrieve documents
@@ -71,7 +97,7 @@ async def retrieve_endpoints(state, config: RunnableConfig = None):
7197 state (dict): New key added to state, documents, that contains retrieved documents
7298 """
7399 print ("---RETRIEVE ENDPOINTS---" )
74- batch_size , _ , _ = get_retrieval_config (config )
100+ batch_size , _ , _ , _ = get_retrieval_config (config )
75101 retriever = get_endpoint_retriever (batch_size )
76102
77103 rewritten_question = state .get ("rewritten_question" , "" )
@@ -123,13 +149,24 @@ async def grade_documents(state, config: RunnableConfig = None):
123149 """
124150
125151 print ("---CHECK DOCUMENT RELEVANCE TO QUESTION---" )
126- _ , retry_threshold , _ = get_retrieval_config (config )
152+ _ , retry_threshold , _ , use_compact_grading = get_retrieval_config (config )
127153
128154 question = state ["question" ]
129155 documents = state ["documents" ]
130156
157+ # Build grading inputs - use compact format to reduce token usage
158+ if use_compact_grading :
159+ grading_inputs = [
160+ {"question" : question , "document" : get_compact_grading_content (d )}
161+ for d in documents
162+ ]
163+ else :
164+ grading_inputs = [
165+ {"question" : question , "document" : d .page_content }
166+ for d in documents
167+ ]
168+
131169 # Batch grade all documents in parallel
132- grading_inputs = [{"question" : question , "document" : d .page_content } for d in documents ]
133170 scores = await retrieval_grader .abatch (grading_inputs )
134171
135172 filtered_docs = []
0 commit comments