新增网页检索,需要配置TAVILY_API_KEY

This commit is contained in:
Wenjie Zhang 2025-02-24 14:58:35 +08:00
parent d0b177a6cf
commit 04d7ddb741
6 changed files with 134 additions and 13 deletions

View File

@ -55,7 +55,7 @@ class Config(SimpleConfig):
self.add_item("enable_knowledge_base", default=False, des="是否开启知识库")
self.add_item("enable_knowledge_graph", default=False, des="是否开启知识图谱")
self.add_item("enable_search_engine", default=False, des="是否开启搜索引擎")
self.add_item("enable_web_search", default=False, des="是否开启网页搜索")
self.add_item("enable_web_search", default=False, des="是否开启网页搜索(需配置 TAVILY_API_KEY")
# 模型配置
## 注意这里是模型名,而不是具体的模型路径,默认使用 HuggingFace 的路径
## 如果需要自定义本地模型路径,则在 src/.env 中配置 MODEL_DIR

View File

@ -30,6 +30,7 @@ class Retriever:
return refs
def construct_query(self, query, refs, meta):
logger.debug(f"{refs=}")
if not refs or len(refs) == 0:
return query
@ -52,7 +53,7 @@ class Retriever:
# 解析网络搜索的结果
web_res = refs.get("web_search", {}).get("results", [])
if web_res:
web_text = "\n".join(f"{r['title']}: {r['snippet']}" for r in web_res)
web_text = "\n".join(f"{r['title']}: {r['content']}" for r in web_res)
external_parts.extend(["网络搜索信息:", web_text])
# 构造查询
@ -131,7 +132,7 @@ class Retriever:
return {"results": [], "message": "Web search is disabled"}
try:
search_results = self.web_searcher.search(query)
search_results = self.web_searcher.search(query, max_results=5)
except Exception as e:
logger.error(f"Web search error: {str(e)}")
return {"results": [], "message": "Web search error"}

View File

@ -76,6 +76,7 @@ MODEL_NAMES:
- Qwen/Qwen2.5-7B-Instruct
- deepseek-ai/DeepSeek-R1
- deepseek-ai/DeepSeek-V3
- deepseek-ai/DeepSeek-R1-Distill-Qwen-7B
EMBED_MODEL_INFO:
local/BAAI/bge-m3:

View File

@ -78,10 +78,7 @@
<div class="flex-center" @click="meta.use_graph = !meta.use_graph" v-if="configStore.config.enable_knowledge_base && meta.enable_retrieval">
图数据库 <div @click.stop><a-switch v-model:checked="meta.use_graph" /></div>
</div>
<div class="flex-center" @click="meta.use_web = !meta.use_web" v-if="configStore.config.enable_search_engine && meta.enable_retrieval">
搜索引擎Bing <div @click.stop><a-switch v-model:checked="meta.use_web" /></div>
</div>
<div class="flex-center" @click="meta.enable_web_search = !meta.enable_web_search" v-if="configStore.config.enable_search_engine && meta.enable_retrieval">
<div class="flex-center" @click="meta.enable_web_search = !meta.enable_web_search" v-if="configStore.config.enable_web_search && meta.enable_retrieval">
网页搜索 <div @click.stop><a-switch v-model:checked="meta.enable_web_search" /></div>
</div>
<!-- <div class="flex-center" v-if="configStore.config.enable_knowledge_base && meta.enable_retrieval">

View File

@ -12,6 +12,13 @@
>
<GlobalOutlined /> 关系图
</span>
<span
class="item btn"
@click="showWebResult(msg)"
v-if="msg.refs.web_search"
>
<GlobalOutlined /> 网页搜索 {{ msg.refs.web_search.results.length }}
</span>
<span class="filetag item btn"
v-for="(results, filename) in msg.groupedResults"
:key="filename"
@ -21,7 +28,7 @@
<a-drawer
v-model:open="openDetail[filename]"
:title="filename"
width="800"
width="700"
:contentWrapperStyle="{ maxWidth: '100%'}"
placement="right"
class="retrieval-detail"
@ -60,6 +67,35 @@
>
<GraphContainer :graphData="subGraphData" />
</a-modal>
<a-drawer
v-model:open="webResultVisible"
title="网页搜索结果"
width="700"
:contentWrapperStyle="{ maxWidth: '100%'}"
placement="right"
class="web-result-detail"
rootClassName="root"
>
<div class="results-list">
<div v-for="result in webResults" :key="result.url" class="result-item">
<div class="result-meta">
<div class="score-info">
<span>
<strong>相关度</strong>
<a-progress :percent="getPercent(result.score)"/>
</span>
</div>
<div class="result-url">
<a :href="result.url" target="_blank">{{ result.url }}</a>
</div>
</div>
<div class="result-content">
<h3 class="result-title">{{ result.title }}</h3>
<div class="result-text">{{ result.content }}</div>
</div>
</div>
</div>
</a-drawer>
</div>
</template>
@ -143,6 +179,20 @@ const closeSubGraph = () => {
subGraphVisible.value = false
}
//
const webResultVisible = ref(false)
const webResults = ref(null)
//
const showWebResult = (msg) => {
if (msg.refs.web_search) {
webResults.value = msg.refs.web_search.results
webResultVisible.value = true
} else {
console.error('无法获取网页搜索结果')
}
}
const hasSubGraphData = (msg) => {
return msg.refs &&
msg.refs.graph_base &&
@ -275,4 +325,76 @@ const getPercent = (value) => {
margin-bottom: 12px;
}
}
.web-result-detail {
.results-list {
.result-item {
border-bottom: 1px solid #f0f0f0;
padding: 16px 0;
&:last-child {
border-bottom: none;
}
}
.result-meta {
margin-bottom: 12px;
.score-info {
display: flex;
flex-wrap: wrap;
gap: 2rem;
margin-bottom: 8px;
span {
display: flex;
align-items: center;
strong {
margin-right: 8px;
white-space: nowrap;
color: #666;
}
.ant-progress {
width: 170px;
margin-bottom: 0;
margin-inline: 10px;
.ant-progress-bg {
background-color: #666;
}
}
}
}
.result-url {
font-size: 12px;
color: #1677FF;
margin-bottom: 8px;
word-break: break-all;
}
}
.result-content {
.result-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 8px;
color: #333;
}
.result-text {
font-size: 14px;
line-height: 1.6;
white-space: pre-wrap;
word-break: break-word;
background-color: #f9f9f9;
padding: 12px;
border-radius: 4px;
border: 1px solid #e8e8e8;
}
}
}
}
</style>

View File

@ -64,13 +64,13 @@
@change="handleChange('enable_knowledge_graph', !configStore.config.enable_knowledge_graph)"
/>
</div>
<!-- <div class="card">
<span class="label">{{ items?.enable_search_engine.des }}</span>
<div class="card">
<span class="label">{{ items?.enable_web_search.des }}</span>
<a-switch
:checked="configStore.config.enable_search_engine"
@change="handleChange('enable_search_engine', !configStore.config.enable_search_engine)"
:checked="configStore.config.enable_web_search"
@change="handleChange('enable_web_search', !configStore.config.enable_web_search)"
/>
</div> -->
</div>
<div class="card">
<span class="label">{{ items?.enable_reranker.des }}</span>
<a-switch