3636 resolve_embedding_tokenizer_name ,
3737)
3838from services .chunk_pool_selection_service import select_chunks_with_quota_and_fill
39+ from services .grounded_prompt_service import format_search_grounded_prompt
3940from services .hybrid_embed_search_service import EmbeddingFn , rank_chunks_hybrid
4041from services .research_config_service import (
4142 config_trace_path ,
5960_HTTP_URL = re .compile (r"^https?://" , re .IGNORECASE )
6061DEFAULT_DENSE_QUERY_PREFIX = "task: search result | query: "
6162DEFAULT_DENSE_DOCUMENT_PREFIX = "title: none | text: "
62- PROMPT_RULE = "=" * 88
63- FIELD_RULE = "======"
6463
6564
6665@dataclass (frozen = True )
@@ -130,119 +129,6 @@ def _search_chunk(result: SearchResult) -> dict[str, Any]:
130129 }
131130
132131
133- def _format_relevant_text (chunks : Sequence [dict [str , Any ]]) -> str :
134- blocks : list [str ] = []
135- for ordinal , chunk in enumerate (chunks , start = 1 ):
136- text = str (chunk .get ("text" ) or "" ).strip ()
137- if not text :
138- continue
139- blocks .extend (
140- [
141- f"----- RELEVANT CHUNK { ordinal } -----" ,
142- text ,
143- ]
144- )
145- return "\n " .join (blocks ).strip ()
146-
147-
148- def _format_results_prompt (
149- * ,
150- question : str ,
151- results : Sequence [dict [str , Any ]],
152- today : str | None = None ,
153- ) -> str :
154- clean_question = question .strip ()
155- today_text = today or datetime .now (UTC ).date ().isoformat ()
156- lines = [
157- PROMPT_RULE ,
158- "SEARCH-GROUNDED ANSWER PROMPT" ,
159- PROMPT_RULE ,
160- "" ,
161- "QUESTION" ,
162- PROMPT_RULE ,
163- clean_question ,
164- PROMPT_RULE ,
165- "" ,
166- "TODAY" ,
167- PROMPT_RULE ,
168- today_text ,
169- PROMPT_RULE ,
170- "" ,
171- "CRITICAL INSTRUCTIONS" ,
172- PROMPT_RULE ,
173- "You are answering the QUESTION using only the text under RESULTS." ,
174- "First resolve any relative date in the QUESTION using TODAY." ,
175- f"TODAY is { today_text !r} ." ,
176- f"For example, 'last year' means calendar year { int (today_text .split ('-' )[0 ]) - 1 } ." ,
177- "Use only facts directly supported by RESULTS." ,
178- "Do not use your own knowledge." ,
179- "Do not add extra historical claims unless directly supported by RESULTS." ,
180- "Do not infer 'first ever', 'most recent', 'record', or franchise history unless RESULTS explicitly support it." ,
181- "If RESULTS contain conflicting information, prefer the result that directly matches the resolved date and question." ,
182- "If the conflict cannot be resolved, say the results conflict." ,
183- "Cite the source URL after each factual claim." ,
184- "If the answer is not directly supported by RESULTS, say the results are not enough." ,
185- PROMPT_RULE ,
186- "" ,
187- PROMPT_RULE ,
188- "RESULTS" ,
189- PROMPT_RULE ,
190- "" ,
191- ]
192-
193- for ordinal , result in enumerate (results , start = 1 ):
194- relevant_text = _format_relevant_text (result .get ("ranked_chunks" ) or [])
195- lines .extend (
196- [
197- PROMPT_RULE ,
198- f"RESULT { ordinal } " ,
199- PROMPT_RULE ,
200- f"TITLE { ordinal } " ,
201- FIELD_RULE ,
202- str (result ["title" ]).strip (),
203- FIELD_RULE ,
204- f"URL { ordinal } " ,
205- FIELD_RULE ,
206- str (result ["url" ]).strip (),
207- FIELD_RULE ,
208- f"SEARCH PREVIEW { ordinal } " ,
209- FIELD_RULE ,
210- str (result .get ("snippet" ) or "" ).strip (),
211- FIELD_RULE ,
212- ]
213- )
214- if relevant_text :
215- lines .extend (
216- [
217- f"RELEVANT TEXT { ordinal } " ,
218- FIELD_RULE ,
219- relevant_text ,
220- FIELD_RULE ,
221- ]
222- )
223- lines .append ("" )
224-
225- lines .extend (
226- [
227- PROMPT_RULE ,
228- "QUESTION" ,
229- PROMPT_RULE ,
230- clean_question ,
231- PROMPT_RULE ,
232- "" ,
233- "TODAY" ,
234- PROMPT_RULE ,
235- today_text ,
236- PROMPT_RULE ,
237- "" ,
238- PROMPT_RULE ,
239- "SEARCH-GROUNDED ANSWER PROMPT" ,
240- PROMPT_RULE ,
241- ]
242- )
243- return "\n " .join (lines ).strip ()
244-
245-
246132async def _rank (
247133 * ,
248134 query : str ,
@@ -427,7 +313,7 @@ def finish(status: str, answer: str, crawl_errors: Sequence[str]) -> AgenticResu
427313 except SearchBackendError as exc :
428314 _agentic_log (f"search backend error: { exc } " )
429315 await emit ("search_backend_error" , error = str (exc ))
430- prompt = _format_results_prompt (question = query , results = [])
316+ prompt = format_search_grounded_prompt (question = query , results = [])
431317 return finish ("search_backend_error" , prompt , [])
432318 results = [result for result in raw_results if _is_http_url (result .url )]
433319 results = filter_blocked_search_results (results , blocked_domains or [])
@@ -436,7 +322,7 @@ def finish(status: str, answer: str, crawl_errors: Sequence[str]) -> AgenticResu
436322 await emit ("search_results" , results_count = len (results ))
437323
438324 if not results :
439- prompt = _format_results_prompt (question = query , results = [])
325+ prompt = format_search_grounded_prompt (question = query , results = [])
440326 return finish ("no_search_results" , prompt , [])
441327
442328 tokenizer_name = (
@@ -593,13 +479,13 @@ async def crawl_result(search_doc: dict[str, Any]) -> dict[str, Any]:
593479 chunks_in_prompt = len (ranked_chunk_pool ),
594480 crawl_errors_count = len (crawl_errors ),
595481 )
596- prompt = _format_results_prompt (question = query , results = crawled_results )
482+ prompt = format_search_grounded_prompt (question = query , results = crawled_results )
597483 await emit ("done" , results_count = len (crawled_results ), crawl_errors_count = len (crawl_errors ))
598484 _agentic_log (f"done results={ len (crawled_results )} crawl_errors={ len (crawl_errors )} " )
599485 return finish ("ok" , prompt , crawl_errors )
600486 except TimeoutError :
601487 _agentic_log (f"timeout query={ query !r} limit_s={ pipeline_timeout_seconds } " )
602- prompt = _format_results_prompt (question = query , results = [])
488+ prompt = format_search_grounded_prompt (question = query , results = [])
603489 return finish ("timeout" , prompt , [])
604490
605491
0 commit comments