|
|
@ -23,9 +23,11 @@ COLLECTION_ROUTE_PROMPT = """ |
|
|
|
|
|
|
|
SUB_QUERY_PROMPT = """ |
|
|
|
为了能够全面的回答这个问题,请你尝试把原本的问题拆分或扩展为几个子问题 |
|
|
|
不可以太多,但是也不可以太少,请根据问题复杂程度来决定子问题的数量 |
|
|
|
请你使用自顶向下和自底向上两种方向来思考如何拆分问题 |
|
|
|
子问题的数量不可以太多,但是也不可以太少,应当保证问题的回答全面性,请根据问题复杂程度来决定子问题的数量 |
|
|
|
如果原问题本身非常简单,没有必要进行拆分,则保留输出原问题本身 |
|
|
|
需要保证每个子问题都具体、清晰、不可分(原子性),最终返回一个字符串列表 |
|
|
|
需要保证每个子问题都具体、清晰、不可分(原子性,即不可以再包含更细分的子问题),子问题中不要包含"请你回答"、"请你总结"、"请你分析"等祈使类型词语 |
|
|
|
你需要最终返回一个字符串列表 |
|
|
|
|
|
|
|
原问题: {original_query} |
|
|
|
|
|
|
@ -36,9 +38,10 @@ SUB_QUERY_PROMPT = """ |
|
|
|
示例输出(例子中的数量不是要求): |
|
|
|
[ |
|
|
|
"什么是机器学习?", |
|
|
|
"机器学习的使用目的是什么?", |
|
|
|
"机器学习和深度学习的区别是什么?", |
|
|
|
"机器学习的历史演进过程?" |
|
|
|
"机器学习的使用目的", |
|
|
|
"机器学习的常用算法", |
|
|
|
"机器学习的历史演进过程", |
|
|
|
"机器学习和深度学习的区别是什么?" |
|
|
|
] |
|
|
|
|
|
|
|
</EXAMPLE> |
|
|
@ -49,26 +52,27 @@ SUB_QUERY_PROMPT = """ |
|
|
|
|
|
|
|
|
|
|
|
RERANK_PROMPT = """ |
|
|
|
根据当前的问题和获取到的文档片段 |
|
|
|
请你对当前获取到的文档是否能帮助回答这个问题(直接或间接,全面或部分,都可以)给出一个快速判断 |
|
|
|
对于每一个文档片段,你只应该返回"YES"或者"NO"(需要注意顺序和数量) |
|
|
|
根据当前的问题和获取到的文档片段(文档片段包裹都在<reference></reference>和<chunk></chunk>标签中并有对应的连续的id) |
|
|
|
请你对当前获取到的文档片段是否能帮助回答这个问题(直接或间接、全面或部分,都可以,但需要有实际有效内容)给出一个快速判断 |
|
|
|
对于每一个文档片段,你只应该返回"True"或者"False"(需要注意顺序和数量) |
|
|
|
|
|
|
|
问题: {query} |
|
|
|
|
|
|
|
检索到的文档片段: |
|
|
|
{chunks} |
|
|
|
|
|
|
|
例如,给定4个chunks(实际检索到的文档片段不一定是4个),返回: ["YES", "NO", "YES", "YES"] |
|
|
|
例如,假如给出4个chunks(实际检索到的文档片段不一定是这么多),返回4个"True"或者"False"(注意这只是一个示例,不代表实际判断): ["True", "False", "True", "True"] |
|
|
|
使用的语言与问题相同 |
|
|
|
你需要返回的是 a python list of str without any addtional content: |
|
|
|
你需要返回的是 a python list of str(bool) without any addtional content: |
|
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
REFLECT_PROMPT = """ |
|
|
|
根据原问题和子问题,以及获取到的文档片段,请你决定是否要生成更多的问题。 |
|
|
|
如果已经获得的文档片段没能覆盖所有的子问题,这意味着这些文档无法被检索到。 |
|
|
|
你可以尝试生成相似但些许不同的问题来尝试重新检索,但是也可以根据获得到的文档片段进行批评思考,生成新的问题来保证原问题的回答的准确和全面 |
|
|
|
如果没有真的必要继续研究(取决于你的判断),返回一个空列表 |
|
|
|
根据原问题和子问题,以及获取到的文档片段,请你决定是否要生成更多的问题,这些问题将被用于后续的思考和搜索。 |
|
|
|
你应该根据已经获得到的文档片段进行批评思考,生成其他新的问题来保证原问题的回答的准确和全面,请你使用自顶向下和自底向上两种方向来思考如何生成新问题。 |
|
|
|
如果已经获得的文档片段没能覆盖所有的子问题,这意味着有关这些问题的文档无法被检索到,你应该根据你自己的知识补充思考。 |
|
|
|
需要保证每个新的问题都具体、清晰、不可分(原子性)并且不可以和之前的问题重复,新的问题中不要包含"请你回答"、"请你总结"、"请你分析"等祈使类型词语 |
|
|
|
如果没有真的必要继续研究(取决于你的判断),返回一个空列表。 |
|
|
|
|
|
|
|
原问题: {original_query} |
|
|
|
|
|
|
@ -83,23 +87,19 @@ REFLECT_PROMPT = """ |
|
|
|
|
|
|
|
|
|
|
|
SUMMARY_PROMPT = """ |
|
|
|
你是一个内容分析专家,请你根据提供的问题和检索到的信息生成详尽的长文回答。 |
|
|
|
如果检索到的信息不足以回答问题或者必须添加额外信息才能能回答,你应该使用你的知识来进行补充, |
|
|
|
这种情况下,你自己提供的信息需要使用例如"your knowledge here[^0]"引用,注意,这里的"[^0]"的序号0是固定的,表示你的知识,下文当中有文末引用的例子 |
|
|
|
同时,你应该根据提供的信息生成文内引用和文末参考资料列表,来自文档切片的reference引用从[^1]开始 |
|
|
|
如果多个片段是相同的来源或者一个片段可以回答多个问题,文内引用可以引用多次,但文末只引用一次来源,即文末的引用列表中不能有重复的来源。 |
|
|
|
你是一个内容分析专家 |
|
|
|
请你综合已经提出的问题和检索到的信息,以原问题为中心,生成详细准确、层次分明、尽可能长的回答。 |
|
|
|
如果检索到的信息不足以回答问题,你应该使用你的知识来进行扩展补充。 |
|
|
|
注意,不要逐个回答问题,而是应该综合所有问题和信息,生成一个完整的回答。 |
|
|
|
同时,你应该根据提供的信息生成文内引用"[^index]"(markdown文内引用)。 |
|
|
|
如果你自己提供的信息需要使用"[^0]"引用,即你提供的信息使用固定index=0。 |
|
|
|
来自<chunk><reference>的引用序号从[^index]从index=1开始,来源需要与前文<reference>中的"href"一致 |
|
|
|
不需要对每个<chunk>分配一个引用,而是相同<reference>的<chunk>共用一个引用。 |
|
|
|
另外,如果回答的内容文内引用需要引用多个<reference>,请添加多个[^index]到句尾。 |
|
|
|
|
|
|
|
例子: |
|
|
|
<EXAMPLE> |
|
|
|
|
|
|
|
文内引用示例(使用markdown脚注): |
|
|
|
"XGBoost是非常强大的集成学习模型[^2]" |
|
|
|
(必须使用 "[^index]",这里的index是对应的<reference>的id) |
|
|
|
|
|
|
|
|
|
|
|
文末引用示例 (需要与前文reference的href一致,不需要对每个chunk分配一个引用,而是每一个referecen共用一个引用): |
|
|
|
[^0]: AI Generated |
|
|
|
[^2]: files/docs/chap_001_003_models.md |
|
|
|
"XGBoost是非常强大的集成学习模型。[^1]但是XGBoost的缺点是计算复杂度高,需要大量的计算资源。[^0]" |
|
|
|
|
|
|
|
</EXAMPLE> |
|
|
|
|
|
|
@ -241,7 +241,7 @@ class DeepSearch(BaseAgent): |
|
|
|
continue |
|
|
|
|
|
|
|
# Format all chunks for batch processing |
|
|
|
chunks = self._format_chunks(retrieved_results) |
|
|
|
chunks, _ = self._format_chunks(retrieved_results) |
|
|
|
|
|
|
|
# Batch process all chunks with a single LLM call |
|
|
|
content = self.llm.chat( |
|
|
@ -262,14 +262,14 @@ class DeepSearch(BaseAgent): |
|
|
|
relevance_list = self.llm.literal_eval(content) |
|
|
|
if not isinstance(relevance_list, list): |
|
|
|
raise ValueError("Response is not a list") |
|
|
|
except (ValueError, SyntaxError): |
|
|
|
except Exception as _: |
|
|
|
# Fallback: if parsing fails, treat all chunks as relevant |
|
|
|
log.color_print(f"Warning: Failed to parse relevance response. Treating all chunks as relevant. Response was: {content}") |
|
|
|
relevance_list = ["YES"] * len(retrieved_results) |
|
|
|
relevance_list = ["True"] * len(retrieved_results) |
|
|
|
|
|
|
|
# Ensure we have enough relevance judgments for all chunks |
|
|
|
while len(relevance_list) < len(retrieved_results): |
|
|
|
relevance_list.append("YES") # Default to relevant if no judgment provided |
|
|
|
relevance_list.append("True") # Default to relevant if no judgment provided |
|
|
|
|
|
|
|
# Filter relevant chunks based on LLM response |
|
|
|
accepted_chunk_num = 0 |
|
|
@ -278,9 +278,9 @@ class DeepSearch(BaseAgent): |
|
|
|
# Check if we have a relevance judgment for this chunk |
|
|
|
is_relevant = ( |
|
|
|
i < len(relevance_list) and |
|
|
|
"YES" in relevance_list[i].upper() and |
|
|
|
"NO" not in relevance_list[i].upper()) if i < len(relevance_list |
|
|
|
) else True |
|
|
|
"True" in relevance_list[i] and |
|
|
|
"False" not in relevance_list[i] |
|
|
|
) if i < len(relevance_list) else True |
|
|
|
|
|
|
|
if is_relevant: |
|
|
|
all_retrieved_results.append(retrieved_result) |
|
|
@ -296,7 +296,7 @@ class DeepSearch(BaseAgent): |
|
|
|
def _generate_more_sub_queries( |
|
|
|
self, original_query: str, all_sub_queries: list[str], all_retrieved_results: list[RetrievalResult] |
|
|
|
) -> list[str]: |
|
|
|
chunks = self._format_chunks(all_retrieved_results) |
|
|
|
chunks, _ = self._format_chunks(all_retrieved_results) |
|
|
|
reflect_prompt = REFLECT_PROMPT.format( |
|
|
|
original_query=original_query, |
|
|
|
all_sub_queries=all_sub_queries, |
|
|
@ -394,7 +394,7 @@ class DeepSearch(BaseAgent): |
|
|
|
if not all_retrieved_results or len(all_retrieved_results) == 0: |
|
|
|
send_info(f"'{original_query}'没能找到更多信息!") |
|
|
|
return "", [] |
|
|
|
chunks = self._format_chunks(all_retrieved_results) |
|
|
|
chunks, refs = self._format_chunks(all_retrieved_results) |
|
|
|
send_info(f"正在总结 {len(all_retrieved_results)} 个查找到的文档片段") |
|
|
|
summary_prompt = SUMMARY_PROMPT.format( |
|
|
|
original_query=original_query, |
|
|
@ -402,25 +402,33 @@ class DeepSearch(BaseAgent): |
|
|
|
chunks=chunks |
|
|
|
) |
|
|
|
response = self.llm.chat([{"role": "user", "content": summary_prompt}]) |
|
|
|
final_answer = self.llm.remove_think(response) |
|
|
|
send_answer(final_answer) |
|
|
|
return self.llm.remove_think(response), all_retrieved_results |
|
|
|
response = self.llm.remove_think(response) + refs |
|
|
|
send_answer(response) |
|
|
|
return response, all_retrieved_results |
|
|
|
|
|
|
|
def _format_chunks(self, retrieved_results: list[RetrievalResult]): |
|
|
|
def _format_chunks(self, retrieved_results: list[RetrievalResult]) -> tuple[str, str]: |
|
|
|
# 以referecen为key,把chunk放到字典中 |
|
|
|
references = defaultdict(list) |
|
|
|
ref_dict = defaultdict(list) |
|
|
|
for result in retrieved_results: |
|
|
|
references[result.reference].append(result.text) |
|
|
|
chunks = [] |
|
|
|
ref_dict[result.reference].append(result.text) |
|
|
|
formated_chunks = [] |
|
|
|
formated_refs = ["\n\n[^0]: AI 生成\n"] |
|
|
|
chunk_count = 0 |
|
|
|
for i, reference in enumerate(references): |
|
|
|
formated = f"<reference id='{i + 1}' href='{reference}'>\n" + "".join( |
|
|
|
for i, reference in enumerate(ref_dict): |
|
|
|
formated_chunk = "".join( |
|
|
|
[ |
|
|
|
f"<chunk id='{j + 1 + chunk_count}'>\n{chunk}\n</chunk id='{j + 1 + chunk_count}'>\n" |
|
|
|
for j, chunk in enumerate(references[reference]) |
|
|
|
( |
|
|
|
f"<reference id='{i + 1}' href='{reference}'>" + |
|
|
|
f"<chunk id='{j + 1 + chunk_count}'>\n{chunk}\n</chunk id='{j + 1 + chunk_count}'>" + |
|
|
|
f"</reference id='{i + 1}'>\n" |
|
|
|
) |
|
|
|
for j, chunk in enumerate(ref_dict[reference]) |
|
|
|
] |
|
|
|
) + f"</reference id='{i + 1}'>\n" |
|
|
|
print(formated) |
|
|
|
chunks.append(formated) |
|
|
|
chunk_count += len(references[reference]) |
|
|
|
return "".join(chunks) |
|
|
|
) |
|
|
|
print(formated_chunk) |
|
|
|
formated_chunks.append(formated_chunk) |
|
|
|
chunk_count += len(ref_dict[reference]) |
|
|
|
formated_refs.append(f"[^{i + 1}]: " + str(reference) + "\n") |
|
|
|
formated_chunks = "".join(formated_chunks) |
|
|
|
formated_refs = "".join(formated_refs) |
|
|
|
return formated_chunks, formated_refs |
|
|
|