Skip to content

Commit 3d89744

Browse files
authored
feat: set search system message as config (#612)
* feat: set search system message as config Signed-off-by: Bob Du <i@bobdu.cc> * docs: readme file add web search section Signed-off-by: Bob Du <i@bobdu.cc> --------- Signed-off-by: Bob Du <i@bobdu.cc>
1 parent 7f72f6c commit 3d89744

File tree

8 files changed

+222
-72
lines changed

8 files changed

+222
-72
lines changed

README.en.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ Some unique features have been added:
3232

3333
[] Implement SSO login through the auth proxy feature (need to integrate a third-party authentication reverse proxy, it can support login protocols such as LDAP/OIDC/SAML)
3434

35+
[] Web Search functionality (Real-time web search based on Tavily API)
36+
3537
> [!CAUTION]
3638
> This project is only published on GitHub, based on the MIT license, free and for open source learning usage. And there will be no any form of account selling, paid service, discussion group, discussion group and other behaviors. Beware of being deceived.
3739
@@ -72,6 +74,13 @@ Some unique features have been added:
7274
- [Manual packaging](#manual-packaging)
7375
- [Backend service](#backend-service-1)
7476
- [Frontend webpage](#frontend-webpage-1)
77+
- [Auth Proxy Mode](#auth-proxy-mode)
78+
- [Web Search Functionality](#web-search-functionality)
79+
- [Features](#features)
80+
- [Configuration](#configuration)
81+
- [Usage](#usage)
82+
- [Technical Implementation](#technical-implementation)
83+
- [Notes](#notes)
7584
- [Frequently Asked Questions](#frequently-asked-questions)
7685
- [Contributing](#contributing)
7786
- [Sponsorship](#sponsorship)
@@ -347,6 +356,92 @@ Recommended for current IdP to use LDAP protocol, using [authelia](https://www.a
347356

348357
Recommended for current IdP to use OIDC protocol, using [oauth2-proxy](https://oauth2-proxy.github.io/oauth2-proxy)
349358

359+
## Web Search Functionality
360+
361+
> [!TIP]
362+
> Web Search functionality is based on [Tavily API](https://tavily.com/) implementation, allowing ChatGPT to access the latest web information to answer questions.
363+
364+
### Features
365+
366+
- **Real-time Web Search**: Get the latest web information based on Tavily API
367+
- **Intelligent Query Extraction**: Automatically extract the most relevant search keywords from user questions
368+
- **Search Result Integration**: Seamlessly integrate search results into AI conversations
369+
- **Per-session Control**: Each conversation can independently enable or disable search functionality
370+
- **Search History**: Save search queries and results to database
371+
- **Configurable System Messages**: Support custom search-related system prompt messages
372+
373+
### Configuration
374+
375+
#### 1. Get Tavily API Key
376+
377+
1. Visit [Tavily Official Website](https://tavily.com/) to register an account
378+
2. Obtain API Key
379+
380+
#### 2. Administrator Configuration
381+
382+
1. Login to the system as an administrator
383+
2. Go to system settings page
384+
3. Find "Web Search Configuration" option
385+
4. Fill in the following configurations:
386+
- **Enable Status**: Turn on/off global search functionality
387+
- **API Key**: Enter Tavily API Key
388+
- **Search Query System Message**: Prompt template for extracting search keywords
389+
- **Search Result System Message**: Prompt template for processing search results
390+
391+
#### 3. System Message Templates
392+
393+
**Search Query Extraction Template** (for extracting search keywords from user questions):
394+
```
395+
You are a search query extraction assistant. Extract the most relevant search query from user's question and wrap it with <search_query></search_query> tags.
396+
Current time: {current_time}
397+
```
398+
399+
**Search Result Processing Template** (for processing conversations with search results):
400+
```
401+
You are a helpful assistant with access to real-time web search results. Use the provided search information to give accurate and up-to-date responses.
402+
Current time: {current_time}
403+
```
404+
405+
### Usage
406+
407+
#### User Operations
408+
409+
1. **Enable Search Functionality**:
410+
- In the conversation interface, find the search toggle button
411+
- Click to enable web search functionality for the current session
412+
413+
2. **Ask Questions for Real-time Information**:
414+
- After enabling search, directly ask ChatGPT questions that require real-time information
415+
- The system will automatically search for relevant information and integrate it into the response
416+
417+
3. **View Search History**:
418+
- Search queries and results are saved in the database
419+
- You can view specific search records through the database
420+
421+
#### Workflow
422+
423+
1. **User Question**: User asks a question in a search-enabled session
424+
2. **Query Extraction**: System uses AI to extract search keywords from the question
425+
3. **Web Search**: Call Tavily API for real-time search
426+
4. **Result Integration**: Provide search results as context to AI
427+
5. **Generate Response**: AI generates more accurate responses based on search results
428+
429+
### Technical Implementation
430+
431+
- **Search Engine**: Tavily API
432+
- **Query Extraction**: Use OpenAI API to intelligently extract keywords
433+
- **Result Format**: JSON format to store complete search results
434+
- **Data Storage**: MongoDB stores search queries and results
435+
- **Timeout Setting**: Search request timeout is 300 seconds
436+
437+
### Notes
438+
439+
- Web Search functionality requires additional Tavily API costs
440+
- Search functionality will increase response time
441+
- It is recommended to enable selectively based on actual needs
442+
- Administrators can control the global search functionality status
443+
- Each session can independently control whether to use search functionality
444+
350445
351446
## Contributing
352447

README.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232

3333
[] 通过 auth proxy 功能实现sso登录 (配合第三方身份验证反向代理 可实现支持 LDAP/OIDC/SAML 等协议登录)
3434

35+
[] Web Search 网络搜索功能 (基于 Tavily API 实现实时网络搜索)
36+
3537

3638
> [!CAUTION]
3739
> 声明:此项目只发布于 Github,基于 MIT 协议,免费且作为开源学习使用。并且不会有任何形式的卖号、付费服务、讨论群、讨论组等行为。谨防受骗。
@@ -74,6 +76,13 @@
7476
- [手动打包](#手动打包)
7577
- [后端服务](#后端服务-1)
7678
- [前端网页](#前端网页-1)
79+
- [Auth Proxy Mode](#auth-proxy-mode)
80+
- [Web Search 网络搜索功能](#web-search-网络搜索功能)
81+
- [功能特性](#功能特性)
82+
- [配置方式](#配置方式)
83+
- [使用方式](#使用方式)
84+
- [技术实现](#技术实现)
85+
- [注意事项](#注意事项)
7786
- [常见问题](#常见问题)
7887
- [参与贡献](#参与贡献)
7988
- [赞助](#赞助)
@@ -358,6 +367,92 @@ pnpm build
358367

359368
当前 Idp 使用 OIDC 协议的 可以选择使用 [oauth2-proxy](https://oauth2-proxy.github.io/oauth2-proxy)
360369

370+
## Web Search 网络搜索功能
371+
372+
> [!TIP]
373+
> Web Search 功能基于 [Tavily API](https://tavily.com/) 实现,可以让 ChatGPT 获取最新的网络信息来回答问题。
374+
375+
### 功能特性
376+
377+
- **实时网络搜索**: 基于 Tavily API 获取最新的网络信息
378+
- **智能查询提取**: 自动从用户问题中提取最相关的搜索关键词
379+
- **搜索结果整合**: 将搜索结果无缝整合到 AI 对话中
380+
- **按会话控制**: 每个对话可以独立开启或关闭搜索功能
381+
- **搜索历史记录**: 保存搜索查询和结果到数据库
382+
- **可配置系统消息**: 支持自定义搜索相关的系统提示消息
383+
384+
### 配置方式
385+
386+
#### 1. 获取 Tavily API Key
387+
388+
1. 访问 [Tavily 官网](https://tavily.com/) 注册账号
389+
2. 获取 API Key
390+
391+
#### 2. 管理员配置
392+
393+
1. 以管理员身份登录系统
394+
2. 进入系统设置页面
395+
3. 找到 "Web Search 配置" 选项
396+
4. 填写以下配置:
397+
- **启用状态**: 开启/关闭全局搜索功能
398+
- **API Key**: 填入 Tavily API Key
399+
- **搜索查询系统消息**: 用于提取搜索关键词的提示模板
400+
- **搜索结果系统消息**: 用于处理搜索结果的提示模板
401+
402+
#### 3. 系统消息模板
403+
404+
**搜索查询提取模板** (用于从用户问题中提取搜索关键词):
405+
```
406+
You are a search query extraction assistant. Extract the most relevant search query from user's question and wrap it with <search_query></search_query> tags.
407+
Current time: {current_time}
408+
```
409+
410+
**搜索结果处理模板** (用于处理包含搜索结果的对话):
411+
```
412+
You are a helpful assistant with access to real-time web search results. Use the provided search information to give accurate and up-to-date responses.
413+
Current time: {current_time}
414+
```
415+
416+
### 使用方式
417+
418+
#### 用户端操作
419+
420+
1. **开启搜索功能**:
421+
- 在对话界面中,找到搜索开关按钮
422+
- 点击开启当前会话的网络搜索功能
423+
424+
2. **提问获取实时信息**:
425+
- 开启搜索后,直接向 ChatGPT 提问需要实时信息的问题
426+
- 系统会自动搜索相关信息并整合到回答中
427+
428+
3. **查看搜索历史**:
429+
- 搜索查询和结果会保存在数据库中
430+
- 可以通过数据库查看具体的搜索记录
431+
432+
#### 工作流程
433+
434+
1. **用户提问**: 用户在开启搜索的会话中提问
435+
2. **查询提取**: 系统使用 AI 从问题中提取搜索关键词
436+
3. **网络搜索**: 调用 Tavily API 进行实时搜索
437+
4. **结果整合**: 将搜索结果作为上下文提供给 AI
438+
5. **生成回答**: AI 基于搜索结果生成更准确的回答
439+
440+
### 技术实现
441+
442+
- **搜索引擎**: Tavily API
443+
- **查询提取**: 使用 OpenAI API 智能提取关键词
444+
- **结果格式**: JSON 格式存储完整搜索结果
445+
- **数据存储**: MongoDB 存储搜索查询和结果
446+
- **超时设置**: 搜索请求超时时间为 300 秒
447+
448+
### 注意事项
449+
450+
- Web Search 功能需要额外的 Tavily API 费用
451+
- 搜索功能会增加响应时间
452+
- 建议根据实际需求选择性开启
453+
- 管理员可以控制全局搜索功能的开启状态
454+
- 每个会话可以独立控制是否使用搜索功能
455+
361456

362457
## 常见问题
363458
Q: 为什么 `Git` 提交总是报错?

service/src/chatgpt/index.ts

Lines changed: 4 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -17,74 +17,8 @@ import type { ChatMessage, RequestOptions } from './types'
1717

1818
dotenv.config()
1919

20-
function systemMessageWithSearchResult(currentTime: string): string {
21-
return `You are an intelligent assistant that needs to answer user questions based on search results.
22-
23-
**Search Results Format Description:**
24-
- Search results may contain irrelevant information, please filter and use accordingly
25-
26-
**Context Information:**
27-
- Current time: ${currentTime}
28-
29-
**Response Requirements:**
30-
31-
1. **Content Processing**
32-
- Screen and filter search results, selecting content most relevant to the question
33-
- Synthesize information from multiple web pages, avoiding repetitive citations from a single source
34-
- When using web page information, please indicate the source in your answer (post it back to the application in the form of a link) to facilitate users' verification of the information source
35-
36-
2. **Response Strategy**
37-
- **Listing questions**: Limit to within 10 key points, prioritize providing the most relevant and complete information
38-
- **Creative questions**: Make full use of search results to generate in-depth professional long-form answers
39-
- **Objective Q&A**: Brief answers may appropriately supplement 1-2 sentences of related information
40-
41-
3. **Format Requirements**
42-
- Respond using markdown (latex start with $).
43-
- Use structured, paragraph-based answer format
44-
- When answering in points, limit to within 5 points, merging related content
45-
- Ensure answers are aesthetically pleasing and highly readable
46-
47-
4. **Language Standards**
48-
- Keep answer language consistent with user's question language
49-
- Do not change language unless specifically requested by the user
50-
51-
**Notes:**
52-
- Not all search results are relevant, need to judge based on the question
53-
- For listing questions, inform users they can check search sources for complete information
54-
- Creative answers need to be multi-perspective, information-rich, and thoroughly discussed`
55-
}
56-
57-
function systemMessageGetSearchQuery(currentTime: string): string {
58-
return `You are an intelligent search assistant.
59-
Current time: ${currentTime}
60-
61-
Before formally answering user questions, you need to analyze the user's questions and conversation context to determine whether you need to obtain more information through internet search to provide accurate answers.
62-
63-
**Task Flow:**
64-
1. Carefully analyze the user's question content and previous conversation history
65-
2. Based on the current time, determine whether the question involves time-sensitive information. If it involves time-sensitive issues, please inform the specific date to be searched in the returned results instead of referring to pronouns such as today or yesterday
66-
3. Evaluate whether existing knowledge is sufficient to answer the question
67-
4. If search is needed, generate a precise search query
68-
5. If search is not needed, return empty result
69-
70-
**Output Format Requirements:**
71-
- If search is needed: return <search_query>example search query keywords</search_query>
72-
- If search is not needed: return <search_query></search_query>
73-
- Do not include any other explanations or answer content
74-
- Search query should be concise and clear, able to obtain the most relevant information
75-
76-
**Judgment Criteria:**
77-
- Time-sensitive information (such as latest news, stock prices, weather, real-time data, etc.): search needed
78-
- Latest policies, regulations, technological developments: may need search
79-
- Common sense questions, historical facts, basic knowledge: usually no search needed
80-
- Latest research or developments in professional fields: search recommended
81-
82-
**Notes:**
83-
- Search query should target the core needs of user questions
84-
- Consider the timeliness and accuracy requirements of information
85-
- Prioritize obtaining the latest and most authoritative information sources
86-
87-
Please strictly return results according to the above format.`
20+
function renderSystemMessage(template: string, currentTime: string): string {
21+
return template.replace(/{current_time}/g, currentTime)
8822
}
8923

9024
const ErrorCodeMessage: Record<string, string> = {
@@ -167,7 +101,7 @@ async function chatReplyProcess(options: RequestOptions) {
167101
let hasSearchResult = false
168102
const searchConfig = globalConfig.searchConfig
169103
if (searchConfig.enabled && searchConfig?.options?.apiKey && searchEnabled) {
170-
messages[0].content = systemMessageGetSearchQuery(dayjs().format('YYYY-MM-DD HH:mm:ss'))
104+
messages[0].content = renderSystemMessage(searchConfig.systemMessageGetSearchQuery, dayjs().format('YYYY-MM-DD HH:mm:ss'))
171105
const completion = await openai.chat.completions.create({
172106
model,
173107
messages,
@@ -201,7 +135,7 @@ search query: <search_query>${searchQuery}</search_query>
201135
search result: <search_result>${searchResult}</search_result>`,
202136
})
203137

204-
messages[0].content = systemMessageWithSearchResult(dayjs().format('YYYY-MM-DD HH:mm:ss'))
138+
messages[0].content = renderSystemMessage(searchConfig.systemMessageWithSearchResult, dayjs().format('YYYY-MM-DD HH:mm:ss'))
205139
hasSearchResult = true
206140
}
207141
}

service/src/storage/model.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ export class SearchConfig {
177177
public enabled: boolean
178178
public provider?: SearchServiceProvider
179179
public options?: SearchServiceOptions
180+
public systemMessageWithSearchResult?: string
181+
public systemMessageGetSearchQuery?: string
180182
}
181183

182184
export enum SearchServiceProvider {

src/components/common/Setting/Search.vue

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ async function fetchConfig() {
2424
loading.value = true
2525
const { data } = await fetchChatConfig<ConfigState>()
2626
if (!data.searchConfig)
27-
data.searchConfig = new SearchConfig(false, '', { apiKey: '' })
27+
data.searchConfig = new SearchConfig(false, '', { apiKey: '' }, '', '')
2828
if (!data.searchConfig.options)
2929
data.searchConfig.options = { apiKey: '' }
3030
config.value = data.searchConfig
@@ -107,6 +107,18 @@ onMounted(() => {
107107
/>
108108
</div>
109109
</div>
110+
<div v-if="config && config.enabled" class="flex items-center space-x-4">
111+
<span class="shrink-0 w-[100px]">{{ $t('setting.systemMessageWithSearchResult') }}</span>
112+
<div class="flex-1">
113+
<NInput v-model:value="config.systemMessageWithSearchResult" type="textarea" :autosize="{ minRows: 2 }" :placeholder="t('setting.systemMessageWithSearchResultPlaceholder')" />
114+
</div>
115+
</div>
116+
<div v-if="config && config.enabled" class="flex items-center space-x-4">
117+
<span class="shrink-0 w-[100px]">{{ $t('setting.systemMessageGetSearchQuery') }}</span>
118+
<div class="flex-1">
119+
<NInput v-model:value="config.systemMessageGetSearchQuery" type="textarea" :autosize="{ minRows: 2 }" :placeholder="t('setting.systemMessageGetSearchQueryPlaceholder')" />
120+
</div>
121+
</div>
110122
<div class="flex items-center space-x-4">
111123
<span class="shrink-0 w-[100px]" />
112124
<div class="flex flex-wrap items-center gap-4">

src/components/common/Setting/model.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,13 @@ export class SearchConfig {
192192
enabled: boolean
193193
provider: SearchServiceProvider
194194
options: SearchServiceOptions
195-
constructor(enabled: boolean, provider: SearchServiceProvider, options: SearchServiceOptions) {
195+
systemMessageWithSearchResult: string
196+
systemMessageGetSearchQuery: string
197+
constructor(enabled: boolean, provider: SearchServiceProvider, options: SearchServiceOptions, systemMessageWithSearchResult: string, systemMessageGetSearchQuery: string) {
196198
this.enabled = enabled
197199
this.provider = provider
198200
this.options = options
201+
this.systemMessageWithSearchResult = systemMessageWithSearchResult
202+
this.systemMessageGetSearchQuery = systemMessageGetSearchQuery
199203
}
200204
}

src/locales/en-US.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ export default {
167167
searchEnabled: 'Search Enabled',
168168
searchProvider: 'Search Provider',
169169
searchApiKey: 'Search API Key',
170+
systemMessageWithSearchResult: 'System message for conversations with search results',
171+
systemMessageGetSearchQuery: 'System message for getting search query',
172+
systemMessageWithSearchResultPlaceholder: 'System message template when with search results. Use {\'{current_time}\'} as placeholder for current time.',
173+
systemMessageGetSearchQueryPlaceholder: 'System message template for generating search query word. Use {\'{current_time}\'} as placeholder for current time. Require LLM to return the query word in <search_query>example search query</search_query> tags or return empty <search_query></search_query> tag if not need search.',
170174
searchTest: 'Test Search',
171175
accessTokenExpiredTime: 'Expired Time',
172176
userConfig: 'Users',

0 commit comments

Comments
 (0)