@lobehub/chat 1.71.1 → 1.71.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/changelog/v1.json +9 -0
- package/package.json +1 -1
- package/src/const/settings/agent.ts +3 -4
- package/src/database/server/models/__tests__/chunk.test.ts +4 -4
- package/src/database/server/models/chunk.ts +2 -1
- package/src/libs/agent-runtime/anthropic/index.ts +10 -1
- package/src/libs/agent-runtime/google/index.ts +6 -3
- package/src/libs/agent-runtime/runtimeMap.ts +47 -48
- package/src/server/routers/lambda/agent.ts +10 -7
- package/src/server/routers/lambda/chunk.ts +65 -49
- package/src/store/chat/slices/aiChat/actions/rag.ts +18 -12
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,31 @@
|
|
2
2
|
|
3
3
|
# Changelog
|
4
4
|
|
5
|
+
### [Version 1.71.2](https://github.com/lobehub/lobe-chat/compare/v1.71.1...v1.71.2)
|
6
|
+
|
7
|
+
<sup>Released on **2025-03-15**</sup>
|
8
|
+
|
9
|
+
#### 🐛 Bug Fixes
|
10
|
+
|
11
|
+
- **misc**: Fix knowledge base issue.
|
12
|
+
|
13
|
+
<br/>
|
14
|
+
|
15
|
+
<details>
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
17
|
+
|
18
|
+
#### What's fixed
|
19
|
+
|
20
|
+
- **misc**: Fix knowledge base issue, closes [#6973](https://github.com/lobehub/lobe-chat/issues/6973) ([15f39ef](https://github.com/lobehub/lobe-chat/commit/15f39ef))
|
21
|
+
|
22
|
+
</details>
|
23
|
+
|
24
|
+
<div align="right">
|
25
|
+
|
26
|
+
[](#readme-top)
|
27
|
+
|
28
|
+
</div>
|
29
|
+
|
5
30
|
### [Version 1.71.1](https://github.com/lobehub/lobe-chat/compare/v1.71.0...v1.71.1)
|
6
31
|
|
7
32
|
<sup>Released on **2025-03-15**</sup>
|
package/changelog/v1.json
CHANGED
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@lobehub/chat",
|
3
|
-
"version": "1.71.
|
3
|
+
"version": "1.71.2",
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
5
5
|
"keywords": [
|
6
6
|
"framework",
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import { DEFAULT_AGENT_META } from '@/const/meta';
|
2
|
-
import { DEFAULT_MODEL } from '@/const/settings/llm';
|
3
|
-
import { ModelProvider } from '@/libs/agent-runtime';
|
2
|
+
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from '@/const/settings/llm';
|
4
3
|
import { LobeAgentChatConfig, LobeAgentConfig, LobeAgentTTSConfig } from '@/types/agent';
|
5
4
|
import { UserDefaultAgent } from '@/types/user/settings';
|
6
5
|
|
@@ -15,7 +14,7 @@ export const DEFAUTT_AGENT_TTS_CONFIG: LobeAgentTTSConfig = {
|
|
15
14
|
|
16
15
|
export const DEFAULT_AGENT_SEARCH_FC_MODEL = {
|
17
16
|
model: DEFAULT_MODEL,
|
18
|
-
provider:
|
17
|
+
provider: DEFAULT_PROVIDER,
|
19
18
|
};
|
20
19
|
|
21
20
|
export const DEFAULT_AGENT_CHAT_CONFIG: LobeAgentChatConfig = {
|
@@ -41,7 +40,7 @@ export const DEFAULT_AGENT_CONFIG: LobeAgentConfig = {
|
|
41
40
|
top_p: 1,
|
42
41
|
},
|
43
42
|
plugins: [],
|
44
|
-
provider:
|
43
|
+
provider: DEFAULT_PROVIDER,
|
45
44
|
systemRole: '',
|
46
45
|
tts: DEFAUTT_AGENT_TTS_CONFIG,
|
47
46
|
};
|
@@ -495,13 +495,13 @@ content in Table html is below:
|
|
495
495
|
});
|
496
496
|
|
497
497
|
// 测试结果限制
|
498
|
-
it('should limit results to
|
498
|
+
it('should limit results to 15 items', async () => {
|
499
499
|
const fileId = '1';
|
500
|
-
// Create
|
500
|
+
// Create 24 chunks
|
501
501
|
const chunkResult = await serverDB
|
502
502
|
.insert(chunks)
|
503
503
|
.values(
|
504
|
-
Array(
|
504
|
+
Array(24)
|
505
505
|
.fill(0)
|
506
506
|
.map((_, i) => ({ text: `Test Chunk ${i}`, userId })),
|
507
507
|
)
|
@@ -528,7 +528,7 @@ content in Table html is below:
|
|
528
528
|
query: 'test',
|
529
529
|
});
|
530
530
|
|
531
|
-
expect(result).toHaveLength(
|
531
|
+
expect(result).toHaveLength(15);
|
532
532
|
});
|
533
533
|
});
|
534
534
|
});
|
@@ -207,7 +207,8 @@ export class ChunkModel {
|
|
207
207
|
.leftJoin(files, eq(files.id, fileChunks.fileId))
|
208
208
|
.where(inArray(fileChunks.fileId, fileIds))
|
209
209
|
.orderBy((t) => desc(t.similarity))
|
210
|
-
|
210
|
+
// 先放宽到 15
|
211
|
+
.limit(15);
|
211
212
|
|
212
213
|
return result.map((item) => {
|
213
214
|
return {
|
@@ -38,6 +38,10 @@ export class LobeAnthropicAI implements LobeRuntimeAI {
|
|
38
38
|
apiKey?: string;
|
39
39
|
private id: string;
|
40
40
|
|
41
|
+
private isDebug() {
|
42
|
+
return process.env.DEBUG_ANTHROPIC_CHAT_COMPLETION === '1';
|
43
|
+
}
|
44
|
+
|
41
45
|
constructor({ apiKey, baseURL = DEFAULT_BASE_URL, id, ...res }: AnthropicAIParams = {}) {
|
42
46
|
if (!apiKey) throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidProviderAPIKey);
|
43
47
|
|
@@ -51,6 +55,11 @@ export class LobeAnthropicAI implements LobeRuntimeAI {
|
|
51
55
|
try {
|
52
56
|
const anthropicPayload = await this.buildAnthropicPayload(payload);
|
53
57
|
|
58
|
+
if (this.isDebug()) {
|
59
|
+
console.log('[requestPayload]');
|
60
|
+
console.log(JSON.stringify(anthropicPayload), '\n');
|
61
|
+
}
|
62
|
+
|
54
63
|
const response = await this.client.messages.create(
|
55
64
|
{ ...anthropicPayload, stream: true },
|
56
65
|
{
|
@@ -60,7 +69,7 @@ export class LobeAnthropicAI implements LobeRuntimeAI {
|
|
60
69
|
|
61
70
|
const [prod, debug] = response.tee();
|
62
71
|
|
63
|
-
if (
|
72
|
+
if (this.isDebug()) {
|
64
73
|
debugStream(debug.toReadableStream()).catch(console.error);
|
65
74
|
}
|
66
75
|
|
@@ -23,7 +23,6 @@ import {
|
|
23
23
|
OpenAIChatMessage,
|
24
24
|
UserMessageContentPart,
|
25
25
|
} from '../types';
|
26
|
-
import { ModelProvider } from '../types/type';
|
27
26
|
import { AgentRuntimeError } from '../utils/createError';
|
28
27
|
import { debugStream } from '../utils/debugStream';
|
29
28
|
import { StreamingResponse } from '../utils/response';
|
@@ -77,6 +76,7 @@ interface LobeGoogleAIParams {
|
|
77
76
|
apiKey?: string;
|
78
77
|
baseURL?: string;
|
79
78
|
client?: GoogleGenerativeAI | VertexAI;
|
79
|
+
id?: string;
|
80
80
|
isVertexAi?: boolean;
|
81
81
|
}
|
82
82
|
|
@@ -85,8 +85,9 @@ export class LobeGoogleAI implements LobeRuntimeAI {
|
|
85
85
|
private isVertexAi: boolean;
|
86
86
|
baseURL?: string;
|
87
87
|
apiKey?: string;
|
88
|
+
provider: string;
|
88
89
|
|
89
|
-
constructor({ apiKey, baseURL, client, isVertexAi }: LobeGoogleAIParams = {}) {
|
90
|
+
constructor({ apiKey, baseURL, client, isVertexAi, id }: LobeGoogleAIParams = {}) {
|
90
91
|
if (!apiKey) throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidProviderAPIKey);
|
91
92
|
|
92
93
|
this.client = new GoogleGenerativeAI(apiKey);
|
@@ -94,6 +95,8 @@ export class LobeGoogleAI implements LobeRuntimeAI {
|
|
94
95
|
this.client = client ? (client as GoogleGenerativeAI) : new GoogleGenerativeAI(apiKey);
|
95
96
|
this.baseURL = client ? undefined : baseURL || DEFAULT_BASE_URL;
|
96
97
|
this.isVertexAi = isVertexAi || false;
|
98
|
+
|
99
|
+
this.provider = id || (isVertexAi ? 'vertexai' : 'google');
|
97
100
|
}
|
98
101
|
|
99
102
|
async chat(rawPayload: ChatStreamPayload, options?: ChatCompetitionOptions) {
|
@@ -168,7 +171,7 @@ export class LobeGoogleAI implements LobeRuntimeAI {
|
|
168
171
|
console.log(err);
|
169
172
|
const { errorType, error } = this.parseErrorMessage(err.message);
|
170
173
|
|
171
|
-
throw AgentRuntimeError.chat({ error, errorType, provider:
|
174
|
+
throw AgentRuntimeError.chat({ error, errorType, provider: this.provider });
|
172
175
|
}
|
173
176
|
}
|
174
177
|
|
@@ -37,7 +37,6 @@ import { LobeStepfunAI } from './stepfun';
|
|
37
37
|
import { LobeTaichuAI } from './taichu';
|
38
38
|
import { LobeTencentCloudAI } from './tencentcloud';
|
39
39
|
import { LobeTogetherAI } from './togetherai';
|
40
|
-
import { ModelProvider } from './types';
|
41
40
|
import { LobeUpstageAI } from './upstage';
|
42
41
|
import { LobeVLLMAI } from './vllm';
|
43
42
|
import { LobeVolcengineAI } from './volcengine';
|
@@ -47,51 +46,51 @@ import { LobeZeroOneAI } from './zeroone';
|
|
47
46
|
import { LobeZhipuAI } from './zhipu';
|
48
47
|
|
49
48
|
export const providerRuntimeMap = {
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
49
|
+
ai21: LobeAi21AI,
|
50
|
+
ai360: LobeAi360AI,
|
51
|
+
anthropic: LobeAnthropicAI,
|
52
|
+
azure: LobeAzureOpenAI,
|
53
|
+
azureai: LobeAzureAI,
|
54
|
+
baichuan: LobeBaichuanAI,
|
55
|
+
bedrock: LobeBedrockAI,
|
56
|
+
cloudflare: LobeCloudflareAI,
|
57
|
+
deepseek: LobeDeepSeekAI,
|
58
|
+
doubao: LobeVolcengineAI,
|
59
|
+
fireworksai: LobeFireworksAI,
|
60
|
+
giteeai: LobeGiteeAI,
|
61
|
+
github: LobeGithubAI,
|
62
|
+
google: LobeGoogleAI,
|
63
|
+
groq: LobeGroq,
|
64
|
+
higress: LobeHigressAI,
|
65
|
+
huggingface: LobeHuggingFaceAI,
|
66
|
+
hunyuan: LobeHunyuanAI,
|
67
|
+
internlm: LobeInternLMAI,
|
68
|
+
jina: LobeJinaAI,
|
69
|
+
lmstudio: LobeLMStudioAI,
|
70
|
+
minimax: LobeMinimaxAI,
|
71
|
+
mistral: LobeMistralAI,
|
72
|
+
moonshot: LobeMoonshotAI,
|
73
|
+
novita: LobeNovitaAI,
|
74
|
+
nvidia: LobeNvidiaAI,
|
75
|
+
ollama: LobeOllamaAI,
|
76
|
+
openai: LobeOpenAI,
|
77
|
+
openrouter: LobeOpenRouterAI,
|
78
|
+
perplexity: LobePerplexityAI,
|
79
|
+
ppio: LobePPIOAI,
|
80
|
+
qwen: LobeQwenAI,
|
81
|
+
sambanova: LobeSambaNovaAI,
|
82
|
+
sensenova: LobeSenseNovaAI,
|
83
|
+
siliconcloud: LobeSiliconCloudAI,
|
84
|
+
spark: LobeSparkAI,
|
85
|
+
stepfun: LobeStepfunAI,
|
86
|
+
taichu: LobeTaichuAI,
|
87
|
+
tencentcloud: LobeTencentCloudAI,
|
88
|
+
togetherai: LobeTogetherAI,
|
89
|
+
upstage: LobeUpstageAI,
|
90
|
+
vllm: LobeVLLMAI,
|
91
|
+
volcengine: LobeVolcengineAI,
|
92
|
+
wenxin: LobeWenxinAI,
|
93
|
+
xai: LobeXAI,
|
94
|
+
zeroone: LobeZeroOneAI,
|
95
|
+
zhipu: LobeZhipuAI,
|
97
96
|
};
|
@@ -122,13 +122,16 @@ export const agentRouter = router({
|
|
122
122
|
const knowledge = await ctx.agentModel.getAgentAssignedKnowledge(input.agentId);
|
123
123
|
|
124
124
|
return [
|
125
|
-
...files
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
125
|
+
...files
|
126
|
+
// 过滤掉所有图片
|
127
|
+
.filter((file) => !file.fileType.startsWith('image'))
|
128
|
+
.map((file) => ({
|
129
|
+
enabled: knowledge.files.some((item) => item.id === file.id),
|
130
|
+
fileType: file.fileType,
|
131
|
+
id: file.id,
|
132
|
+
name: file.name,
|
133
|
+
type: KnowledgeType.File,
|
134
|
+
})),
|
132
135
|
...knowledgeBases.map((knowledgeBase) => ({
|
133
136
|
avatar: knowledgeBase.avatar,
|
134
137
|
description: knowledgeBase.description,
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { TRPCError } from '@trpc/server';
|
1
2
|
import { inArray } from 'drizzle-orm/expressions';
|
2
3
|
import { z } from 'zod';
|
3
4
|
|
@@ -126,60 +127,75 @@ export const chunkRouter = router({
|
|
126
127
|
semanticSearchForChat: chunkProcedure
|
127
128
|
.input(SemanticSearchSchema)
|
128
129
|
.mutation(async ({ ctx, input }) => {
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
//
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
embeddings
|
148
|
-
|
130
|
+
try {
|
131
|
+
const item = await ctx.messageModel.findMessageQueriesById(input.messageId);
|
132
|
+
const { model, provider } =
|
133
|
+
getServerDefaultFilesConfig().embeddingModel || DEFAULT_FILE_EMBEDDING_MODEL_ITEM;
|
134
|
+
let embedding: number[];
|
135
|
+
let ragQueryId: string;
|
136
|
+
|
137
|
+
// if there is no message rag or it's embeddings, then we need to create one
|
138
|
+
if (!item || !item.embeddings) {
|
139
|
+
// TODO: need to support customize
|
140
|
+
const agentRuntime = await initAgentRuntimeWithUserPayload(provider, ctx.jwtPayload);
|
141
|
+
|
142
|
+
// slice content to make sure in the context window limit
|
143
|
+
const query =
|
144
|
+
input.rewriteQuery.length > 8000
|
145
|
+
? input.rewriteQuery.slice(0, 8000)
|
146
|
+
: input.rewriteQuery;
|
147
|
+
|
148
|
+
const embeddings = await agentRuntime.embeddings({
|
149
|
+
dimensions: 1024,
|
150
|
+
input: query,
|
151
|
+
model,
|
152
|
+
});
|
153
|
+
|
154
|
+
embedding = embeddings![0];
|
155
|
+
const embeddingsId = await ctx.embeddingModel.create({
|
156
|
+
embeddings: embedding,
|
157
|
+
model,
|
158
|
+
});
|
159
|
+
|
160
|
+
const result = await ctx.messageModel.createMessageQuery({
|
161
|
+
embeddingsId,
|
162
|
+
messageId: input.messageId,
|
163
|
+
rewriteQuery: input.rewriteQuery,
|
164
|
+
userQuery: input.userQuery,
|
165
|
+
});
|
166
|
+
|
167
|
+
ragQueryId = result.id;
|
168
|
+
} else {
|
169
|
+
embedding = item.embeddings;
|
170
|
+
ragQueryId = item.id;
|
171
|
+
}
|
172
|
+
|
173
|
+
let finalFileIds = input.fileIds ?? [];
|
174
|
+
|
175
|
+
if (input.knowledgeIds && input.knowledgeIds.length > 0) {
|
176
|
+
const knowledgeFiles = await serverDB.query.knowledgeBaseFiles.findMany({
|
177
|
+
where: inArray(knowledgeBaseFiles.knowledgeBaseId, input.knowledgeIds),
|
178
|
+
});
|
179
|
+
|
180
|
+
finalFileIds = knowledgeFiles.map((f) => f.fileId).concat(finalFileIds);
|
181
|
+
}
|
182
|
+
|
183
|
+
const chunks = await ctx.chunkModel.semanticSearchForChat({
|
184
|
+
embedding,
|
185
|
+
fileIds: finalFileIds,
|
186
|
+
query: input.rewriteQuery,
|
149
187
|
});
|
150
188
|
|
151
|
-
|
152
|
-
embeddingsId,
|
153
|
-
messageId: input.messageId,
|
154
|
-
rewriteQuery: input.rewriteQuery,
|
155
|
-
userQuery: input.userQuery,
|
156
|
-
});
|
189
|
+
// TODO: need to rerank the chunks
|
157
190
|
|
158
|
-
ragQueryId
|
159
|
-
}
|
160
|
-
|
161
|
-
ragQueryId = item.id;
|
162
|
-
}
|
191
|
+
return { chunks, queryId: ragQueryId };
|
192
|
+
} catch (e) {
|
193
|
+
console.error(e);
|
163
194
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
if (input.knowledgeIds && input.knowledgeIds.length > 0) {
|
168
|
-
const knowledgeFiles = await serverDB.query.knowledgeBaseFiles.findMany({
|
169
|
-
where: inArray(knowledgeBaseFiles.knowledgeBaseId, input.knowledgeIds),
|
195
|
+
throw new TRPCError({
|
196
|
+
code: 'INTERNAL_SERVER_ERROR',
|
197
|
+
message: (e as any).errorType || JSON.stringify(e),
|
170
198
|
});
|
171
|
-
|
172
|
-
finalFileIds = knowledgeFiles.map((f) => f.fileId).concat(finalFileIds);
|
173
199
|
}
|
174
|
-
|
175
|
-
const chunks = await ctx.chunkModel.semanticSearchForChat({
|
176
|
-
embedding,
|
177
|
-
fileIds: finalFileIds,
|
178
|
-
query: input.rewriteQuery,
|
179
|
-
});
|
180
|
-
// TODO: need to rerank the chunks
|
181
|
-
console.timeEnd('semanticSearch');
|
182
|
-
|
183
|
-
return { chunks, queryId: ragQueryId };
|
184
200
|
}),
|
185
201
|
});
|
@@ -21,7 +21,7 @@ export interface ChatRAGAction {
|
|
21
21
|
id: string,
|
22
22
|
userQuery: string,
|
23
23
|
messages: string[],
|
24
|
-
) => Promise<{ chunks: ChatSemanticSearchChunk[]; queryId
|
24
|
+
) => Promise<{ chunks: ChatSemanticSearchChunk[]; queryId?: string; rewriteQuery?: string }>;
|
25
25
|
/**
|
26
26
|
* Rewrite user content to better RAG query
|
27
27
|
*/
|
@@ -74,17 +74,23 @@ export const chatRag: StateCreator<ChatStore, [['zustand/devtools', never]], [],
|
|
74
74
|
|
75
75
|
// 2. retrieve chunks from semantic search
|
76
76
|
const files = chatSelectors.currentUserFiles(get()).map((f) => f.id);
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
77
|
+
try {
|
78
|
+
const { chunks, queryId } = await ragService.semanticSearchForChat({
|
79
|
+
fileIds: knowledgeIds().fileIds.concat(files),
|
80
|
+
knowledgeIds: knowledgeIds().knowledgeBaseIds,
|
81
|
+
messageId: id,
|
82
|
+
rewriteQuery: rewriteQuery || userQuery,
|
83
|
+
userQuery,
|
84
|
+
});
|
85
|
+
|
86
|
+
get().internal_toggleMessageRAGLoading(false, id);
|
87
|
+
|
88
|
+
return { chunks, queryId, rewriteQuery };
|
89
|
+
} catch {
|
90
|
+
get().internal_toggleMessageRAGLoading(false, id);
|
91
|
+
|
92
|
+
return { chunks: [] };
|
93
|
+
}
|
88
94
|
},
|
89
95
|
internal_rewriteQuery: async (id, content, messages) => {
|
90
96
|
let rewriteQuery = content;
|