From f063a2d72f5e36f39994eb1446e95309bd5a14d3 Mon Sep 17 00:00:00 2001 From: tanxing Date: Fri, 15 Aug 2025 10:55:45 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E7=9A=84=E9=9D=9E=E6=B5=81=E5=BC=8F=E6=B6=88=E6=81=AF=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=20refactor:=20=E8=B0=83=E6=95=B4=E5=8F=82=E8=80=83?= =?UTF-8?q?=E6=96=87=E7=8C=AE=E7=9A=84=E7=94=9F=E6=88=90=E6=96=B9=E6=B3=95?= =?UTF-8?q?=20=20=20=20=20=E7=8E=B0=E5=9C=A8=E6=98=AF=E7=94=9F=E6=88=90?= =?UTF-8?q?=E5=9B=BA=E5=AE=9A=E7=9A=84=E5=8F=82=E8=80=83=E6=96=87=E7=8C=AE?= =?UTF-8?q?=E8=A1=A8=EF=BC=8C=E8=80=8C=E4=B8=8D=E6=98=AFAI=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=94=9F=E6=88=90=20chore:=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E8=AF=8D=E5=92=8CLLM=E9=85=8D=E7=BD=AE=20cho?= =?UTF-8?q?re:=20=E8=B0=83=E6=95=B4=E5=89=8D=E7=AB=AF=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deepsearcher/agent/deep_search.py | 72 +++++++++++-------------- deepsearcher/config.yaml | 2 +- deepsearcher/llm/openai_llm.py | 6 +-- deepsearcher/templates/html/index.html | 20 +++---- deepsearcher/templates/static/js/app.js | 2 +- main.py | 41 -------------- test.py | 2 +- 7 files changed, 46 insertions(+), 99 deletions(-) diff --git a/deepsearcher/agent/deep_search.py b/deepsearcher/agent/deep_search.py index 0e35e77..860c225 100644 --- a/deepsearcher/agent/deep_search.py +++ b/deepsearcher/agent/deep_search.py @@ -63,7 +63,7 @@ RERANK_PROMPT = """ 例如,假如给出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: """ @@ -87,35 +87,19 @@ REFLECT_PROMPT = """ SUMMARY_PROMPT = """ -你是一个内容分析专家,请你根据提供的问题和检索到的信息,生成详细、层次分明、尽可能长的回答。 +你是一个内容分析专家 +请你综合已经提出的问题和检索到的信息,以原问题为中心,生成详细准确、层次分明、尽可能长的回答。 如果检索到的信息不足以回答问题,你应该使用你的知识来进行扩展补充。 -注意,不要一个子问题一个子问题的回答,而是应该仔细分析子问题之间的关系、子问题和原问题之间的关系。 -同时,你应该根据提供的信息生成文内引用和文末参考资料列表,使用markdown脚注。 -如果你自己提供的信息需要使用"your knowledge here[^0]"引用。 -注意,这里的"[^0]"的序号0是固定的,表示你的知识,文末引用使用"[^0]: AI 生成", -来自的引用序号从[^1]开始,来源需要与前文中的"href"一致,不需要对每个分配一个引用,而是相同共用一个引用 +注意,不要逐个回答问题,而是应该综合所有问题和信息,生成一个完整的回答。 +同时,你应该根据提供的信息生成文内引用"[^index]"(markdown文内引用)。 +如果你自己提供的信息需要使用"[^0]"引用,即你提供的信息使用固定index=0。 +来自的引用序号从[^index]从index=1开始,来源需要与前文中的"href"一致 +不需要对每个分配一个引用,而是相同共用一个引用。 另外,如果回答的内容文内引用需要引用多个,请添加多个[^index]到句尾。 -如果多个片段是相同的来源或者一个片段可以回答多个问题,文内引用可以引用多次,但文末只引用一次来源,即文末的引用列表中不能有重复。 -例子: -文内引用示例: -"XGBoost是非常强大的集成学习模型[^2]" - - -文末引用示例: -正确例子: -[^0]: AI 生成 -[^1]: files/docs/machine_learning.md -[^2]: files/docs/chap_001_003_models.md - -错误例子: -[^0]: AI 生成 -[^1]: files/docs/chap_001_003_models.md -[^2]: files/docs/machine_learning.md -[^3]: files/docs/chap_001_003_models.md(错误,这是重复引用) -[^5]: files/docs/machine_learning.md(错误,也这是重复引用) +"XGBoost是非常强大的集成学习模型。[^1]但是XGBoost的缺点是计算复杂度高,需要大量的计算资源。[^0]" @@ -257,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( @@ -312,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, @@ -410,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, @@ -418,29 +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 = "".join( + for i, reference in enumerate(ref_dict): + formated_chunk = "".join( [ ( f"" + f"\n{chunk}\n" + f"\n" ) - for j, chunk in enumerate(references[reference]) + for j, chunk in enumerate(ref_dict[reference]) ] ) - 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 diff --git a/deepsearcher/config.yaml b/deepsearcher/config.yaml index e560153..5b59538 100644 --- a/deepsearcher/config.yaml +++ b/deepsearcher/config.yaml @@ -83,5 +83,5 @@ query_settings: max_iter: 3 load_settings: - chunk_size: 4096 + chunk_size: 2048 chunk_overlap: 1024 diff --git a/deepsearcher/llm/openai_llm.py b/deepsearcher/llm/openai_llm.py index e5edf6d..eacf374 100644 --- a/deepsearcher/llm/openai_llm.py +++ b/deepsearcher/llm/openai_llm.py @@ -48,9 +48,9 @@ class OpenAILLM(BaseLLM): model=self.model, messages=messages, stream=True, - temperature=0.7, - top_p=0.8, - presence_penalty=1.3 + temperature=0.8, + top_p=0.9, + presence_penalty=1.4 ) as stream: # stream到控制台测试 content = "" diff --git a/deepsearcher/templates/html/index.html b/deepsearcher/templates/html/index.html index c716062..fa53db4 100644 --- a/deepsearcher/templates/html/index.html +++ b/deepsearcher/templates/html/index.html @@ -9,7 +9,7 @@
-

DeepSearcher 智能搜索系统

+

DeepSearcher 智能深度搜索系统

基于大型语言模型和向量数据库的知识管理系统,支持私有数据搜索和在线内容整合,提供准确答案和综合报告。

@@ -21,12 +21,12 @@
- - + +
- - + +
@@ -39,12 +39,12 @@
- - + +
- - + +
@@ -79,7 +79,7 @@ diff --git a/deepsearcher/templates/static/js/app.js b/deepsearcher/templates/static/js/app.js index 8a750cb..2feb279 100644 --- a/deepsearcher/templates/static/js/app.js +++ b/deepsearcher/templates/static/js/app.js @@ -199,7 +199,7 @@ function handleStreamMessage(data) { // 处理answer类型,显示查询结果 console.log('Processing answer message:', message.content.substring(0, 100) + '...'); // 将结果内容显示在结果区域 - if (message.content && message.content !== "==== FINAL ANSWER====") { + if (message.content) { document.getElementById('resultText').textContent = message.content; showResult(); } diff --git a/main.py b/main.py index a1a76b0..4b34478 100644 --- a/main.py +++ b/main.py @@ -203,47 +203,6 @@ def load_website( raise HTTPException(status_code=500, detail=str(e)) -@app.get("/query/") -def perform_query( - original_query: str = Query( - ..., - description="Your question here.", - examples=["Write a report about Milvus."], - ), - max_iter: int = Query( - 3, - description="The maximum number of iterations for reflection.", - ge=1, - examples=[3], - ), -): - """ - Perform a query against the loaded data. - - Args: - original_query (str): The user's question or query. - max_iter (int, optional): Maximum number of iterations for reflection. Defaults to 3. - - Returns: - dict: A dictionary containing the query result and token consumption. - - Raises: - HTTPException: If the query fails. - """ - try: - # 清空之前的消息 - message_stream = get_message_stream() - message_stream.clear_messages() - result_text, _ = query(original_query, max_iter=max_iter) - - return { - "result": result_text, - "messages": message_stream.get_messages_as_dicts() - } - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) - - @app.get("/query-stream/") async def perform_query_stream( original_query: str = Query( diff --git a/test.py b/test.py index 72f45d0..29cff4e 100644 --- a/test.py +++ b/test.py @@ -25,4 +25,4 @@ load_from_local_files( # load_from_website(urls=website_url) # Query -result = query("Write a comprehensive report about Milvus.", max_iter=2) # Your question here +result = query("Write a comprehensive report about Milvus.", max_iter=1) # Your question here