Browse Source

chore: 优化回答生成

chore: 优化milvus配置
chore: 优化HTML模板
refactor: 优化参数传递
main
tanxing 3 days ago
parent
commit
7ae94654ef
  1. 55
      deepsearcher/agent/deep_search.py
  2. 6
      deepsearcher/config.yaml
  3. 4
      deepsearcher/llm/openai_llm.py
  4. 3
      deepsearcher/online_query.py
  5. 4
      deepsearcher/templates/html/index.html
  6. 4
      deepsearcher/templates/static/js/app.js
  7. 16
      docs/intro_docs/milvus_benchmark.md
  8. 8
      main.py
  9. 4
      test.py

55
deepsearcher/agent/deep_search.py

@ -38,9 +38,10 @@ SUB_QUERY_PROMPT = """
示例输出例子中的数量不是要求:
[
"什么是机器学习?",
"机器学习的使用目的是什么?",
"机器学习和深度学习的区别是什么?",
"机器学习的历史演进过程?"
"机器学习的使用目的",
"机器学习的常用算法",
"机器学习的历史演进过程",
"机器学习和深度学习的区别是什么?"
]
</EXAMPLE>
@ -51,16 +52,16 @@ SUB_QUERY_PROMPT = """
RERANK_PROMPT = """
根据当前的问题和获取到的文档片段文档片段包裹都在<reference></reference><chunk></chunk>标签中并有对应的id
请你对当前获取到的文档是否能帮助回答这个问题直接或间接全面或部分都可以给出一个快速判断
对于每一个文档片段你只应该返回"YES"或者"NO"需要注意顺序和数量
根据当前的问题和获取到的文档片段文档片段包裹都在<reference></reference><chunk></chunk>标签中并有对应的连续的id
请你对当前获取到的文档片段是否能帮助回答这个问题直接或间接全面或部分都可以但需要有实际有效内容给出一个快速判断
对于每一个文档片段你只应该返回"True"或者"False"需要注意顺序和数量
问题: {query}
检索到的文档片段:
{chunks}
例如假如给出4个chunks实际检索到的文档片段不一定是这么多返回4个"YES"或者"NO"注意这只是一个示例不代表实际判断: ["YES", "NO", "YES", "YES"]
例如假如给出4个chunks实际检索到的文档片段不一定是这么多返回4个"True"或者"False"注意这只是一个示例不代表实际判断: ["True", "False", "True", "True"]
使用的语言与问题相同
你需要返回的是 a python list of str without any addtional content:
"""
@ -68,7 +69,7 @@ RERANK_PROMPT = """
REFLECT_PROMPT = """
根据原问题和子问题以及获取到的文档片段请你决定是否要生成更多的问题这些问题将被用于后续的思考和搜索
你应该根据已经获得到的文档片段进行批评思考生成其他新的问题来保证原问题的回答的准确和全面
你应该根据已经获得到的文档片段进行批评思考生成其他新的问题来保证原问题的回答的准确和全面请你使用自顶向下和自底向上两种方向来思考如何生成新问题
如果已经获得的文档片段没能覆盖所有的子问题这意味着有关这些问题的文档无法被检索到你应该根据你自己的知识补充思考
需要保证每个新的问题都具体清晰不可分原子性并且不可以和之前的问题重复新的问题中不要包含"请你回答""请你总结""请你分析"等祈使类型词语
如果没有真的必要继续研究取决于你的判断返回一个空列表
@ -86,12 +87,13 @@ REFLECT_PROMPT = """
SUMMARY_PROMPT = """
你是一个内容分析专家请你根据提供的问题和检索到的信息生成详尽的有逻辑的长文回答
你是一个内容分析专家请你根据提供的问题和检索到的信息生成详细层次分明尽可能长的回答
如果检索到的信息不足以回答问题你应该使用你的知识来进行扩展补充
注意不要一个子问题一个子问题的回答而是应该仔细分析子问题之间的关系子问题和原问题之间的关系
同时你应该根据提供的信息生成文内引用和文末参考资料列表使用markdown脚注
如果检索到的信息不足以回答问题或者必须添加额外信息才能回答你应该使用你的知识来进行补充
这种情况下你自己提供的信息需要使用例如"your knowledge here[^0]"引用
如果你自己提供的信息需要使用"your knowledge here[^0]"引用
注意这里的"[^0]"的序号0是固定的表示你的知识文末引用使用"[^0]: AI 生成",
来自<chunk><reference>的引用序号从[^1]开始来源需要与前文<reference>中的href一致不需要对每个<chunk>分配一个引用而是相同<reference><chunk>共用一个引用
来自<chunk><reference>的引用序号从[^1]开始来源需要与前文<reference>中的"href"一致不需要对每个<chunk>分配一个引用而是相同<reference><chunk>共用一个引用
另外如果回答的内容文内引用需要引用多个<reference>请添加多个[^index]到句尾
如果多个片段是相同的来源或者一个片段可以回答多个问题文内引用可以引用多次但文末只引用一次来源即文末的引用列表中不能有重复
@ -110,9 +112,10 @@ SUMMARY_PROMPT = """
错误例子
[^0]: AI 生成
[^1]: files/docs/machine_learning.md
[^2]: files/docs/chap_001_003_models.md
[^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错误也这是重复引用
</EXAMPLE>
@ -275,14 +278,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
@ -291,9 +294,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)
@ -427,12 +430,16 @@ class DeepSearch(BaseAgent):
chunks = []
chunk_count = 0
for i, reference in enumerate(references):
formated = f"<reference id='{i + 1}' href='{reference}'>\n" + "".join(
formated = "".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(references[reference])
]
) + f"</reference id='{i + 1}'>\n"
)
print(formated)
chunks.append(formated)
chunk_count += len(references[reference])

6
deepsearcher/config.yaml

@ -2,7 +2,7 @@ provide_settings:
llm:
provider: "OpenAILLM"
config:
model: "Qwen/Qwen3-30B-A3B-Thinking-2507"
model: "Qwen/Qwen3-32B"
api_key: "sk-fpzwvagjkhwysjsozfybvtjzongatcwqdihdxzuijnfdrjzt"
base_url: "https://api.siliconflow.cn/v1"
@ -83,5 +83,5 @@ query_settings:
max_iter: 3
load_settings:
chunk_size: 1024
chunk_overlap: 512
chunk_size: 4096
chunk_overlap: 1024

4
deepsearcher/llm/openai_llm.py

@ -48,9 +48,9 @@ class OpenAILLM(BaseLLM):
model=self.model,
messages=messages,
stream=True,
temperature=0.6,
temperature=0.7,
top_p=0.8,
presence_penalty=1.2
presence_penalty=1.3
) as stream:
# stream到控制台测试
content = ""

3
deepsearcher/online_query.py

@ -3,7 +3,7 @@ from deepsearcher import configuration
from deepsearcher.vector_db.base import RetrievalResult
def query(original_query: str, max_iter: int | None = None) -> tuple[str, list[RetrievalResult]]:
def query(original_query: str, **kwargs) -> tuple[str, list[RetrievalResult]]:
"""
Query the knowledge base with a question and get an answer.
@ -20,6 +20,7 @@ def query(original_query: str, max_iter: int | None = None) -> tuple[str, list[R
- A list of retrieval results that were used to generate the answer
"""
default_searcher = configuration.default_searcher
max_iter = kwargs.get("max_iter", 3)
return default_searcher.query(original_query, max_iter=max_iter)

4
deepsearcher/templates/html/index.html

@ -10,7 +10,7 @@
<div class="container">
<header>
<h1>DeepSearcher 智能搜索系统</h1>
<p class="app-description">基于大型语言模型和向量数据库的企业知识管理系统,支持私有数据搜索和在线内容整合,提供准确答案和综合报告。</p>
<p class="app-description">基于大型语言模型和向量数据库的知识管理系统,支持私有数据搜索和在线内容整合,提供准确答案和综合报告。</p>
</header>
<main>
@ -54,7 +54,7 @@
<h2 class="card-title">智能查询</h2>
<div class="form-group">
<label for="queryText">请输入您的问题</label>
<textarea id="queryText" rows="3" placeholder="例如: 请生成一份关于人工智能发展趋势的报告"></textarea>
<textarea id="queryText" rows="3" placeholder="例如: 请生成一份关于Milvus向量数据库的详细报告"></textarea>
</div>
<div class="form-group">
<label for="maxIter">最大迭代次数 (1-10)</label>

4
deepsearcher/templates/static/js/app.js

@ -250,7 +250,7 @@ document.getElementById('loadFilesBtn').addEventListener('click', async function
const filePaths = filePathsInput.split(',').map(path => path.trim()).filter(path => path);
setButtonLoading(button, true);
showStatus('loadStatus', '正在加载文件...', 'loading');
showStatus('loadStatus', ' 正在加载文件...', 'loading');
hideResult();
hideProcessResult();
@ -330,7 +330,7 @@ document.getElementById('loadWebsiteBtn').addEventListener('click', async functi
const urls = urlsInput.split(',').map(url => url.trim()).filter(url => url);
setButtonLoading(button, true);
showStatus('webLoadStatus', '正在加载网站内容...', 'loading');
showStatus('webLoadStatus', ' 正在加载网站...', 'loading');
hideResult();
hideProcessResult();

16
docs/intro_docs/milvus_benchmark.md

File diff suppressed because one or more lines are too long

8
main.py

@ -141,7 +141,7 @@ def load_files(
batch_size=batch_size if batch_size is not None else 8,
force_rebuild=force_rebuild,
)
return {"message": "成功加载文档"}
return {"message": "成功加载"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@ -198,7 +198,7 @@ def load_website(
batch_size=batch_size if batch_size is not None else 8,
force_rebuild=force_rebuild,
)
return {"message": "成功加载网址"}
return {"message": "成功加载"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@ -234,7 +234,7 @@ def perform_query(
# 清空之前的消息
message_stream = get_message_stream()
message_stream.clear_messages()
result_text, _ = query(original_query, max_iter)
result_text, _ = query(original_query, max_iter=max_iter)
return {
"result": result_text,
@ -297,7 +297,7 @@ async def perform_query_stream(
def run_query():
try:
print(f"Starting query: {original_query} with max_iter: {max_iter}")
result_text, retrieval_results = query(original_query, max_iter)
result_text, retrieval_results = query(original_query, max_iter=max_iter)
print(f"Query completed with result length: {len(result_text) if result_text else 0}")
print(f"Retrieved {len(retrieval_results) if retrieval_results else 0} documents")
return result_text, None

4
test.py

@ -16,7 +16,7 @@ load_from_local_files(
paths_or_directory="docs",
collection_name="default",
collection_description="a general collection for all documents",
force_rebuild=True, batch_size=8
force_rebuild=True, batch_size=16
)
@ -25,4 +25,4 @@ load_from_local_files(
# load_from_website(urls=website_url)
# Query
result = query("Write a comprehensive report about Milvus.") # Your question here
result = query("Write a comprehensive report about Milvus.", max_iter=2) # Your question here

Loading…
Cancel
Save