Skip to content

Commit f1f61ed

Browse files
committed
fix
1 parent a694865 commit f1f61ed

File tree

7 files changed

+175
-47
lines changed

7 files changed

+175
-47
lines changed

plugins/golang-filter/mcp-server/servers/rag/READMD.md

Lines changed: 106 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -23,40 +23,36 @@
2323

2424
### 配置结构
2525

26-
```yaml
27-
rag:
28-
# RAG系统基础配置
29-
splitter:
30-
type: "recursive" # 递归分块器 recursive 和 nosplitter
31-
chunk_size: 500
32-
chunk_overlap: 50
33-
top_k: 5 # 搜索返回的知识块数量
34-
threshold: 0.5 # 搜索阈值
35-
36-
llm:
37-
provider: "openai" # openai
38-
api_key: "your-llm-api-key"
39-
base_url: "https://api.openai.com/v1" # 可选
40-
model: "gpt-3.5-turbo" # LLM模型
41-
max_tokens: 2048 # 最大令牌数
42-
temperature: 0.5 # 温度参数
43-
44-
embedding:
45-
provider: "openai" # openai, dashscope
46-
api_key: "your-embedding-api-key"
47-
base_url: "https://api.openai.com/v1" # 可选
48-
model: "text-embedding-ada-002" # 嵌入模型
49-
50-
vectordb:
51-
provider: "milvus" # milvus
52-
host: "localhost"
53-
port: 19530
54-
database: "default"
55-
collection: "test_collection"
56-
username: "" # 可选
57-
password: "" # 可选
26+
| 名称 | 数据类型 | 填写要求 | 默认值 | 描述 |
27+
|----------------------------|----------|-----------|---------|--------|
28+
| **rag** | object | 必填 | - | RAG系统基础配置 |
29+
| rag.splitter.provider | string | 必填 | recursive | 分块器类型:recursive或nosplitter |
30+
| rag.splitter.chunk_size | integer | 可选 | 500 | 块大小 |
31+
| rag.splitter.chunk_overlap | integer | 可选 | 50 | 块重叠大小 |
32+
| rag.top_k | integer | 可选 | 10 | 搜索返回的知识块数量 |
33+
| rag.threshold | float | 可选 | 0.5 | 搜索阈值 |
34+
| **llm** | object | 可选 | - | LLM配置 |
35+
| llm.provider | string | 可选 | openai | LLM提供商 |
36+
| llm.api_key | string | 可选 | - | LLM API密钥 |
37+
| llm.base_url | string | 可选 | | LLM API基础URL |
38+
| llm.model | string | 可选 | gpt-4o | LLM模型名称 |
39+
| llm.max_tokens | integer | 可选 | 2048 | 最大令牌数 |
40+
| llm.temperature | float | 可选 | 0.5 | 温度参数 |
41+
| **embedding** | object | 必填 | - | 嵌入配置 |
42+
| embedding.provider | string | 必填 | dashscope | 嵌入提供商:openai或dashscope |
43+
| embedding.api_key | string | 必填 | - | 嵌入API密钥 |
44+
| embedding.base_url | string | 可选 | | 嵌入API基础URL |
45+
| embedding.model | string | 必填 | text-embedding-v4 | 嵌入模型名称 |
46+
| **vectordb** | object | 必填 | - | 向量数据库配置 |
47+
| vectordb.provider | string | 必填 | milvus | 向量数据库提供商 |
48+
| vectordb.host | string | 必填 | localhost | 数据库主机地址 |
49+
| vectordb.port | integer | 必填 | 19530 | 数据库端口 |
50+
| vectordb.database | string | 必填 | default | 数据库名称 |
51+
| vectordb.collection | string | 必填 | test_collection | 集合名称 |
52+
| vectordb.username | stri选ng | 可选 | - | 数据库用户名 |
53+
| vectordb.password | string | 可选 | - | 数据库密码 |
54+
5855

59-
```
6056
### higress-config 配置样例
6157

6258
```yaml
@@ -124,6 +120,83 @@ data:
124120
#### LLM
125121
- **OpenAI**
126122
123+
## 如何测试数据集的效果
124+
125+
测试数据集的效果分两步,第一步导入数据集语料,第二步测试Chat效果。
126+
127+
### 导入数据集语料
128+
129+
使用 `RAGClient.CreateChunkFromText` 工具导入数据集语料,比如数据集语料格式为 JSON,每个 JSON 对象包含 `body`、`title` 和 `url` 等字段。样例代码如下:
130+
131+
```golang
132+
func TestRAGClient_LoadChunks(t *testing.T) {
133+
t.Logf("TestRAGClient_LoadChunks")
134+
ragClient, err := getRAGClient()
135+
if err != nil {
136+
t.Errorf("getRAGClient() error = %v", err)
137+
return
138+
}
139+
// load json output/corpus.json and then call ragclient CreateChunkFromText to insert chunks
140+
file, err := os.Open("/dataset/corpus.json")
141+
if err != nil {
142+
t.Errorf("LoadData() error = %v", err)
143+
return
144+
}
145+
defer file.Close()
146+
decoder := json.NewDecoder(file)
147+
var data []struct {
148+
Body string `json:"body"`
149+
Title string `json:"title"`
150+
Url string `json:"url"`
151+
}
152+
if err := decoder.Decode(&data); err != nil {
153+
t.Errorf("LoadData() error = %v", err)
154+
return
155+
}
156+
157+
for _, item := range data {
158+
t.Logf("LoadData() url = %s", item.Url)
159+
t.Logf("LoadData() title = %s", item.Title)
160+
t.Logf("LoadData() len body = %d", len(item.Body))
161+
chunks, err := ragClient.CreateChunkFromText(item.Body, item.Title)
162+
if err != nil {
163+
t.Errorf("LoadData() error = %v", err)
164+
continue
165+
} else {
166+
t.Logf("LoadData() chunks len = %d", len(chunks))
167+
}
168+
}
169+
t.Logf("TestRAGClient_LoadChunks done")
170+
}
171+
```
172+
173+
### 测试Chat效果
174+
175+
使用 `RAGClient.Chat` 工具测试 Chat 效果。样例代码如下:
176+
177+
```golang
178+
func TestRAGClient_Chat(t *testing.T) {
179+
ragClient, err := getRAGClient()
180+
if err != nil {
181+
t.Errorf("getRAGClient() error = %v", err)
182+
return
183+
}
184+
query := "Which online betting platform provides a welcome bonus of up to $1000 in bonus bets for new customers' first losses, runs NBA betting promotions, and is anticipated to extend the same sign-up offer to new users in Vermont, as reported by both CBSSports.com and Sporting News?"
185+
resp, err := ragClient.Chat(query)
186+
if err != nil {
187+
t.Errorf("Chat() error = %v", err)
188+
return
189+
}
190+
if resp == "" {
191+
t.Errorf("Chat() resp = %s, want not empty", resp)
192+
return
193+
}
194+
t.Logf("Chat() resp = %s", resp)
195+
}
196+
```
197+
198+
199+
127200

128201
## Milvus 安装
129202

plugins/golang-filter/mcp-server/servers/rag/llm/openai.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212

1313
const (
1414
OPENAI_CHAT_ENDPOINT = "/chat/completions"
15-
OPENAI_DEFAULT_MODEL = "gpt-3.5-turbo"
15+
OPENAI_DEFAULT_MODEL = "gpt-4o"
1616
)
1717

1818
// openAI specific configuration captured after initialization.

plugins/golang-filter/mcp-server/servers/rag/llm/prompt.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"strings"
55
)
66

7-
const RAGPromptTemplate = `You are a professional knowledge Q&A assistant. Your task is to provide accurate, complete, and strictly relevant answers based on the user's question and retrieved context.
7+
const RAGPromptTemplate = `You are a professional knowledge Q&A assistant. Your task is to provide direct and concise answers based on the user's question and retrieved context.
88
99
Retrieved relevant context (may be empty, multiple segments separated by line breaks):
1010
{contexts}
@@ -13,9 +13,11 @@ User question:
1313
{query}
1414
1515
Requirements:
16-
1. If the context provides sufficient information, answer directly based on the context. You may use domain knowledge to supplement, but do not fabricate facts beyond the context.
17-
2. If the context is insufficient or unrelated to the question, respond with: "I am unable to answer this question."
18-
3. Your response must correctly answer the user's question and must not contain any irrelevant or unrelated content.`
16+
1. Provide ONLY the direct answer without any explanation, reasoning, or additional context.
17+
2. If the context provides sufficient information, output the answer in the most concise form possible.
18+
3. If the context is insufficient or unrelated to the question, respond with: "I am unable to answer this question."
19+
4. Do not include any phrases like "The answer is", "Based on the context", etc. Just output the answer directly.
20+
`
1921

2022
func BuildPrompt(query string, contexts []string, join string) string {
2123
rendered := strings.ReplaceAll(RAGPromptTemplate, "{query}", query)

plugins/golang-filter/mcp-server/servers/rag/rag_client.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,15 @@ func NewRAGClient(config *config.Config) (*RAGClient, error) {
4646
}
4747
ragclient.embeddingProvider = embeddingProvider
4848

49-
llmProvider, err := llm.NewLLMProvider(ragclient.config.LLM)
50-
if err != nil {
51-
return nil, fmt.Errorf("create llm provider failed, err: %w", err)
49+
if ragclient.config.LLM.Provider == "" {
50+
ragclient.llmProvider = nil
51+
} else {
52+
llmProvider, err := llm.NewLLMProvider(ragclient.config.LLM)
53+
if err != nil {
54+
return nil, fmt.Errorf("create llm provider failed, err: %w", err)
55+
}
56+
ragclient.llmProvider = llmProvider
5257
}
53-
ragclient.llmProvider = llmProvider
5458

5559
demoVector, err := embeddingProvider.GetEmbedding(context.Background(), "initialization")
5660
if err != nil {

plugins/golang-filter/mcp-server/servers/rag/rag_client_test.go

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package rag
22

33
import (
4+
"encoding/json"
5+
"os"
46
"testing"
57

68
"github.com/alibaba/higress/plugins/golang-filter/mcp-server/servers/rag/config"
@@ -137,7 +139,11 @@ func TestRAGClient_Chat(t *testing.T) {
137139
t.Errorf("getRAGClient() error = %v", err)
138140
return
139141
}
140-
query := "what is the competition about?"
142+
// query := "Who is the individual associated with the cryptocurrency industry facing a criminal trial on fraud and conspiracy charges, as reported by both The Verge and TechCrunch, and is accused by prosecutors of committing fraud for personal gain?"
143+
// query := "Which individual is implicated in both inflating the value of a Manhattan apartment to a figure not yet achieved in New York City's real estate history, according to 'Fortune', and is also accused of adjusting this apartment's valuation to compensate for a loss in another asset's worth, as reported by 'The Age'?"
144+
// query := "Who is the figure associated with generative AI technology whose departure from OpenAI was considered shocking according to Fortune, and is also the subject of a prevailing theory suggesting a lack of full truthfulness with the board as reported by TechCrunch?"
145+
// query := "Do the TechCrunch article on software companies and the Hacker News article on The Epoch Times both report an increase in revenue related to payment and subscription models, respectively?"
146+
query := "Which online betting platform provides a welcome bonus of up to $1000 in bonus bets for new customers' first losses, runs NBA betting promotions, and is anticipated to extend the same sign-up offer to new users in Vermont, as reported by both CBSSports.com and Sporting News?"
141147
resp, err := ragClient.Chat(query)
142148
if err != nil {
143149
t.Errorf("Chat() error = %v", err)
@@ -147,4 +153,45 @@ func TestRAGClient_Chat(t *testing.T) {
147153
t.Errorf("Chat() resp = %s, want not empty", resp)
148154
return
149155
}
156+
t.Logf("Chat() resp = %s", resp)
157+
}
158+
159+
func TestRAGClient_LoadChunks(t *testing.T) {
160+
t.Logf("TestRAGClient_LoadChunks")
161+
ragClient, err := getRAGClient()
162+
if err != nil {
163+
t.Errorf("getRAGClient() error = %v", err)
164+
return
165+
}
166+
// load json output/corpus.json and then call ragclient CreateChunkFromText to insert chunks
167+
file, err := os.Open("/dataset/corpus.json")
168+
if err != nil {
169+
t.Errorf("LoadData() error = %v", err)
170+
return
171+
}
172+
defer file.Close()
173+
decoder := json.NewDecoder(file)
174+
var data []struct {
175+
Body string `json:"body"`
176+
Title string `json:"title"`
177+
Url string `json:"url"`
178+
}
179+
if err := decoder.Decode(&data); err != nil {
180+
t.Errorf("LoadData() error = %v", err)
181+
return
182+
}
183+
184+
for _, item := range data {
185+
t.Logf("LoadData() url = %s", item.Url)
186+
t.Logf("LoadData() title = %s", item.Title)
187+
t.Logf("LoadData() len body = %d", len(item.Body))
188+
chunks, err := ragClient.CreateChunkFromText(item.Body, item.Title)
189+
if err != nil {
190+
t.Errorf("LoadData() error = %v", err)
191+
continue
192+
} else {
193+
t.Logf("LoadData() chunks len = %d", len(chunks))
194+
}
195+
}
196+
t.Logf("TestRAGClient_LoadChunks done")
150197
}

plugins/golang-filter/mcp-server/servers/rag/server.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func init() {
2828
TopK: 10,
2929
},
3030
LLM: config.LLMConfig{
31-
Provider: "openai",
31+
Provider: "",
3232
APIKey: "",
3333
BaseURL: "",
3434
Model: "gpt-4o",
@@ -103,8 +103,6 @@ func (c *RAGConfig) ParseConfig(config map[string]any) error {
103103
if llmConfig, ok := config["llm"].(map[string]any); ok {
104104
if provider, exists := llmConfig["provider"].(string); exists {
105105
c.config.LLM.Provider = provider
106-
} else {
107-
return errors.New("missing llm provider")
108106
}
109107
if apiKey, exists := llmConfig["api_key"].(string); exists {
110108
c.config.LLM.APIKey = apiKey
@@ -190,7 +188,7 @@ func (c *RAGConfig) NewServer(serverName string) (*common.MCPServer, error) {
190188

191189
// Intelligent Q&A Tool
192190
mcpServer.AddTool(
193-
mcp.NewToolWithRawSchema("chat", "Generate contextually relevant responses using RAG system with LLM integration", GetChatSchema()),
191+
mcp.NewToolWithRawSchema("chat", "Answer user questions by retrieving relevant knowledge from the database and generating responses using RAG-enhanced LLM", GetChatSchema()),
194192
HandleChat(ragClient),
195193
)
196194

plugins/golang-filter/mcp-server/servers/rag/tools.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ func HandleChat(ragClient *RAGClient) common.ToolHandlerFunc {
169169
if !ok {
170170
return nil, fmt.Errorf("invalid query argument")
171171
}
172+
// check llm provider
173+
if ragClient.llmProvider == nil {
174+
return nil, fmt.Errorf("llm provider is empty, please check the llm configuration")
175+
}
172176
// Generate response using RAGClient's LLM
173177
reply, err := ragClient.Chat(query)
174178
if err != nil {

0 commit comments

Comments
 (0)