Skip to content

Commit e2d57ee

Browse files
szymondudyczManul from Pathway
authored and
Manul from Pathway
committed
Context documents in Adaptive RAG (#8333)
GitOrigin-RevId: 8e1c8053bb4e00c9814fa010afce3f919b00835c
1 parent 947e69a commit e2d57ee

File tree

5 files changed

+443
-249
lines changed

5 files changed

+443
-249
lines changed

Diff for: docs/2.developers/7.templates/.private_rag_ollama_mistral/article.py

-1
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,6 @@ class InputSchema(pw.Schema):
255255
n_starting_documents=2,
256256
factor=2,
257257
max_iterations=4,
258-
strict_prompt=True, # needed for open source models, instructs LLM to give JSON output strictly
259258
),
260259
)
261260

Diff for: examples/notebooks/showcases/mistral_adaptive_rag_question_answering.ipynb

+154-1
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,160 @@
350350
"id": "25",
351351
"metadata": {},
352352
"outputs": [
353+
{
354+
"data": {
355+
"application/vnd.jupyter.widget-view+json": {
356+
"model_id": "",
357+
"version_major": 2,
358+
"version_minor": 0
359+
},
360+
"text/plain": [
361+
"modules.json: 0%| | 0.00/349 [00:00<?, ?B/s]"
362+
]
363+
},
364+
"metadata": {},
365+
"output_type": "display_data"
366+
},
367+
{
368+
"data": {
369+
"application/vnd.jupyter.widget-view+json": {
370+
"model_id": "4cb9b53338984b4ca3782660fd369ac5",
371+
"version_major": 2,
372+
"version_minor": 0
373+
},
374+
"text/plain": [
375+
"config_sentence_transformers.json: 0%| | 0.00/124 [00:00<?, ?B/s]"
376+
]
377+
},
378+
"metadata": {},
379+
"output_type": "display_data"
380+
},
381+
{
382+
"data": {
383+
"application/vnd.jupyter.widget-view+json": {
384+
"model_id": "a13d1f303c0b475da7cadfcd2519fbb7",
385+
"version_major": 2,
386+
"version_minor": 0
387+
},
388+
"text/plain": [
389+
"README.md: 0%| | 0.00/68.0k [00:00<?, ?B/s]"
390+
]
391+
},
392+
"metadata": {},
393+
"output_type": "display_data"
394+
},
395+
{
396+
"data": {
397+
"application/vnd.jupyter.widget-view+json": {
398+
"model_id": "f2c90530720a49e981bf4f93573966ad",
399+
"version_major": 2,
400+
"version_minor": 0
401+
},
402+
"text/plain": [
403+
"sentence_bert_config.json: 0%| | 0.00/52.0 [00:00<?, ?B/s]"
404+
]
405+
},
406+
"metadata": {},
407+
"output_type": "display_data"
408+
},
409+
{
410+
"data": {
411+
"application/vnd.jupyter.widget-view+json": {
412+
"model_id": "f70a76e14fc34714979c1721b7faf546",
413+
"version_major": 2,
414+
"version_minor": 0
415+
},
416+
"text/plain": [
417+
"config.json: 0%| | 0.00/719 [00:00<?, ?B/s]"
418+
]
419+
},
420+
"metadata": {},
421+
"output_type": "display_data"
422+
},
423+
{
424+
"data": {
425+
"application/vnd.jupyter.widget-view+json": {
426+
"model_id": "c472a492c4844bdfbdd8b21ddf159d47",
427+
"version_major": 2,
428+
"version_minor": 0
429+
},
430+
"text/plain": [
431+
"model.safetensors: 0%| | 0.00/133M [00:00<?, ?B/s]"
432+
]
433+
},
434+
"metadata": {},
435+
"output_type": "display_data"
436+
},
437+
{
438+
"data": {
439+
"application/vnd.jupyter.widget-view+json": {
440+
"model_id": "2d1b971f1430455e88c69a79e510d6cb",
441+
"version_major": 2,
442+
"version_minor": 0
443+
},
444+
"text/plain": [
445+
"tokenizer_config.json: 0%| | 0.00/1.24k [00:00<?, ?B/s]"
446+
]
447+
},
448+
"metadata": {},
449+
"output_type": "display_data"
450+
},
451+
{
452+
"data": {
453+
"application/vnd.jupyter.widget-view+json": {
454+
"model_id": "318728fd211d40c5b1f8c2202f67120a",
455+
"version_major": 2,
456+
"version_minor": 0
457+
},
458+
"text/plain": [
459+
"vocab.txt: 0%| | 0.00/232k [00:00<?, ?B/s]"
460+
]
461+
},
462+
"metadata": {},
463+
"output_type": "display_data"
464+
},
465+
{
466+
"data": {
467+
"application/vnd.jupyter.widget-view+json": {
468+
"model_id": "77c7c8d87fba49ce82365b931b506013",
469+
"version_major": 2,
470+
"version_minor": 0
471+
},
472+
"text/plain": [
473+
"tokenizer.json: 0%| | 0.00/711k [00:00<?, ?B/s]"
474+
]
475+
},
476+
"metadata": {},
477+
"output_type": "display_data"
478+
},
479+
{
480+
"data": {
481+
"application/vnd.jupyter.widget-view+json": {
482+
"model_id": "219f45c9280a4cd4b6bbc93aac5e7a98",
483+
"version_major": 2,
484+
"version_minor": 0
485+
},
486+
"text/plain": [
487+
"special_tokens_map.json: 0%| | 0.00/695 [00:00<?, ?B/s]"
488+
]
489+
},
490+
"metadata": {},
491+
"output_type": "display_data"
492+
},
493+
{
494+
"data": {
495+
"application/vnd.jupyter.widget-view+json": {
496+
"model_id": "3b612c8b15ad49f088535c1c70a35648",
497+
"version_major": 2,
498+
"version_minor": 0
499+
},
500+
"text/plain": [
501+
"config.json: 0%| | 0.00/190 [00:00<?, ?B/s]"
502+
]
503+
},
504+
"metadata": {},
505+
"output_type": "display_data"
506+
},
353507
{
354508
"name": "stdout",
355509
"output_type": "stream",
@@ -526,7 +680,6 @@
526680
" n_starting_documents=2,\n",
527681
" factor=2,\n",
528682
" max_iterations=4,\n",
529-
" strict_prompt=True, # needed for open source models, instructs LLM to give JSON output strictly\n",
530683
" ),\n",
531684
")"
532685
]

Diff for: python/pathway/xpacks/llm/document_store.py

+15-18
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,21 @@
3131
import llama_index.core.schema
3232

3333

34+
@pw.udf
35+
def _get_jmespath_filter(metadata_filter: str, filepath_globpattern: str) -> str | None:
36+
ret_parts = []
37+
if metadata_filter:
38+
metadata_filter = (
39+
metadata_filter.replace("'", r"\'").replace("`", "'").replace('"', "")
40+
)
41+
ret_parts.append(f"({metadata_filter})")
42+
if filepath_globpattern:
43+
ret_parts.append(f"globmatch('{filepath_globpattern}', path)")
44+
if ret_parts:
45+
return " && ".join(ret_parts)
46+
return None
47+
48+
3449
class DocumentStore:
3550
"""
3651
Builds a document indexing pipeline for processing documents and querying closest documents
@@ -360,24 +375,6 @@ def format_stats(counts, last_modified, last_indexed) -> pw.Json:
360375

361376
@staticmethod
362377
def merge_filters(queries: pw.Table):
363-
@pw.udf
364-
def _get_jmespath_filter(
365-
metadata_filter: str, filepath_globpattern: str
366-
) -> str | None:
367-
ret_parts = []
368-
if metadata_filter:
369-
metadata_filter = (
370-
metadata_filter.replace("'", r"\'")
371-
.replace("`", "'")
372-
.replace('"', "")
373-
)
374-
ret_parts.append(f"({metadata_filter})")
375-
if filepath_globpattern:
376-
ret_parts.append(f"globmatch('{filepath_globpattern}', path)")
377-
if ret_parts:
378-
return " && ".join(ret_parts)
379-
return None
380-
381378
queries = queries.without(
382379
*DocumentStore.FilterSchema.__columns__.keys()
383380
) + queries.select(

Diff for: python/pathway/xpacks/llm/prompts.py

+20-61
Original file line numberDiff line numberDiff line change
@@ -219,77 +219,36 @@ def prompt_qa(
219219
return prompt
220220

221221

222-
# prompt for `answer_with_geometric_rag_strategy`, it is the same as in the research project
223-
# docs` argument will be deprecated in favor of `context: str` argument
224-
# this will require the use of `BaseContextProcessor`
225222
@pw.udf
226223
def prompt_qa_geometric_rag(
224+
context: str,
227225
query: str,
228-
docs: list[pw.Json] | list[str],
229226
information_not_found_response="No information found.",
230227
additional_rules: str = "",
231-
strict_prompt: bool = False, # instruct LLM to return json for local models, improves performance
232228
):
233-
context_pieces = []
234229

235-
for i, doc in enumerate(docs, 1):
236-
if isinstance(doc, str):
237-
context_pieces.append(f"Source {i}: {doc}")
238-
else:
239-
context_pieces.append(f"Source {i}: {doc['text']}") # type: ignore
240-
context_str = "\n".join(context_pieces)
241-
242-
if strict_prompt:
243-
prompt = f"""
244-
Use the below articles to answer the subsequent question. If the answer cannot be found in the articles, write "{information_not_found_response}" Do not explain.
245-
ONLY RESPOND IN PARSABLE JSON WITH THE ONLY KEY `answer`.
246-
When referencing information from a source, cite the appropriate source(s) using their corresponding numbers. Every answer should include at least one source citation.
247-
Only cite a source when you are explicitly referencing it.
248-
For example:
249-
Given following sources and query
250-
Example 1: "Source 1: The sky is red in the evening and blue in the morning.\nSource 2: Water is wet when the sky is red.
251-
Query: When is water wet?
252-
Response: {{"answer": "When the sky is red [2], which occurs in the evening [1]."}}
253-
Example 2: "Source 1: LLM stands for Large language models.
254-
Query: Who is the current pope?
255-
Response: {{"answer": "{information_not_found_response}"}}
256-
""" # noqa
257-
else:
258-
prompt = f"""
259-
Use the below articles to answer the subsequent question. If the answer cannot be found in the articles, write "{information_not_found_response}" Do not answer in full sentences.
260-
When referencing information from a source, cite the appropriate source(s) using their corresponding numbers. Every answer should include at least one source citation.
261-
Only cite a source when you are explicitly referencing it. For example:
262-
"Source 1:
263-
The sky is red in the evening and blue in the morning.
264-
Source 2:
265-
Water is wet when the sky is red.\n
266-
Query: When is water wet?
267-
Answer: When the sky is red [2], which occurs in the evening [1]."
268-
""" # noqa
230+
prompt = f"""
231+
Use the below articles to answer the subsequent question. If the answer cannot be found in the articles, write "{information_not_found_response}" Do not explain.
232+
For example:
233+
Given following sources and query
234+
Example 1: "Source 1: The sky is red in the evening and blue in the morning.\nSource 2: Water is wet when the sky is red.
235+
Query: When is water wet?
236+
Answer: "When the sky is red [2], which occurs in the evening [1]."
237+
Example 2: "Source 1: LLM stands for Large language models.
238+
Query: Who is the current pope?
239+
Answer: {information_not_found_response}
240+
""" # noqa
269241

270242
prompt += additional_rules + " "
271243

272-
if strict_prompt: # further instruction is needed for smaller models
273-
prompt += (
274-
"\n------\n"
275-
f"{context_str}"
276-
f"Query: {query}\n"
277-
"ONLY RESPOND IN PARSABLE JSON WITH THE ONLY KEY `answer` containing your response. "
278-
)
279-
280-
response_str = "Response"
281-
else:
282-
prompt += (
283-
"Now it's your turn. "
284-
"\n------\n"
285-
f"{context_str}"
286-
"\n------\n"
287-
f"Query: {query}\n"
288-
)
289-
290-
response_str = "Answer"
291-
292-
prompt += f"{response_str}:"
244+
prompt += (
245+
"Now it's your turn. "
246+
"\n------\n"
247+
f"{context}"
248+
"\n------\n"
249+
f"Query: {query}\n"
250+
"Answer: "
251+
)
293252
return prompt
294253

295254

0 commit comments

Comments
 (0)