feat: #70 ChatSession 新增 knowledgeItemIds 字段,限定 AI 检索范围
All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 46s
All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 46s
- Prisma schema: ChatSession 加 knowledgeItemIds Json? 字段 - createSession: 接受可选 knowledgeItemIds 参数 - loadContext: 支持 itemIds 过滤,传入时只检索指定知识点 - sendMessage/sendMessageStream: 读取 session.knowledgeItemIds 传入 loadContext Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
6d0cc9b6dc
commit
17f16cea67
@ -1001,6 +1001,7 @@ model ChatSession {
|
|||||||
userId String
|
userId String
|
||||||
knowledgeBaseId String
|
knowledgeBaseId String
|
||||||
title String @default("新对话") @db.VarChar(200)
|
title String @default("新对话") @db.VarChar(200)
|
||||||
|
knowledgeItemIds Json? @default("[]")
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
|||||||
@ -13,8 +13,8 @@ export class RagChatController {
|
|||||||
|
|
||||||
@Post('sessions')
|
@Post('sessions')
|
||||||
@ApiOperation({ summary: '创建对话' })
|
@ApiOperation({ summary: '创建对话' })
|
||||||
async createSession(@CurrentUser() user: UserPayload, @Body() dto: { knowledgeBaseId: string; title?: string }) {
|
async createSession(@CurrentUser() user: UserPayload, @Body() dto: { knowledgeBaseId: string; title?: string; knowledgeItemIds?: string[] }) {
|
||||||
return this.svc.createSession(String(user.id), dto.knowledgeBaseId, dto.title);
|
return this.svc.createSession(String(user.id), dto.knowledgeBaseId, dto.title, dto.knowledgeItemIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('sessions')
|
@Get('sessions')
|
||||||
|
|||||||
@ -17,9 +17,14 @@ export class RagChatService {
|
|||||||
@Optional() private readonly aiGateway?: AiGatewayService,
|
@Optional() private readonly aiGateway?: AiGatewayService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async createSession(userId: string, knowledgeBaseId: string, title?: string) {
|
async createSession(userId: string, knowledgeBaseId: string, title?: string, knowledgeItemIds?: string[]) {
|
||||||
return this.prisma.chatSession.create({
|
return this.prisma.chatSession.create({
|
||||||
data: { userId, knowledgeBaseId, title: title || '新对话' },
|
data: {
|
||||||
|
userId,
|
||||||
|
knowledgeBaseId,
|
||||||
|
title: title || '新对话',
|
||||||
|
knowledgeItemIds: knowledgeItemIds ?? [],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +60,8 @@ export class RagChatService {
|
|||||||
|
|
||||||
// Retrieve knowledge base context
|
// Retrieve knowledge base context
|
||||||
this.logger.log(`RAG: kbId=${session.knowledgeBaseId}, content preview: ${content.substring(0, 30)}`);
|
this.logger.log(`RAG: kbId=${session.knowledgeBaseId}, content preview: ${content.substring(0, 30)}`);
|
||||||
const context = await this.loadContext(session.knowledgeBaseId);
|
const itemIds = (session as any).knowledgeItemIds as string[] | undefined;
|
||||||
|
const context = await this.loadContext(session.knowledgeBaseId, itemIds?.length ? itemIds : undefined);
|
||||||
this.logger.log(`RAG context: isEmpty=${context.isEmpty}, textLen=${context.text.length}, citations=${context.citations.length}, aiGateway=${!!this.aiGateway}`);
|
this.logger.log(`RAG context: isEmpty=${context.isEmpty}, textLen=${context.text.length}, citations=${context.citations.length}, aiGateway=${!!this.aiGateway}`);
|
||||||
|
|
||||||
// Generate AI response
|
// Generate AI response
|
||||||
@ -141,7 +147,8 @@ export class RagChatService {
|
|||||||
// Also auto-title in sendMessage (this is the sync method)
|
// Also auto-title in sendMessage (this is the sync method)
|
||||||
|
|
||||||
// Load context
|
// Load context
|
||||||
const context = await this.loadContext(session.knowledgeBaseId);
|
const itemIds = (session as any).knowledgeItemIds as string[] | undefined;
|
||||||
|
const context = await this.loadContext(session.knowledgeBaseId, itemIds?.length ? itemIds : undefined);
|
||||||
if (!context.text) {
|
if (!context.text) {
|
||||||
yield { type: 'content', content: this.fallbackReply(true) };
|
yield { type: 'content', content: this.fallbackReply(true) };
|
||||||
} else {
|
} else {
|
||||||
@ -186,10 +193,14 @@ export class RagChatService {
|
|||||||
|
|
||||||
// ── Private ──
|
// ── Private ──
|
||||||
|
|
||||||
private async loadContext(kbId: string) {
|
private async loadContext(kbId: string, itemIds?: string[]) {
|
||||||
try {
|
try {
|
||||||
const items = await this.prisma.knowledgeItem.findMany({
|
const items = await this.prisma.knowledgeItem.findMany({
|
||||||
where: { knowledgeBaseId: kbId, deletedAt: null },
|
where: {
|
||||||
|
knowledgeBaseId: kbId,
|
||||||
|
deletedAt: null,
|
||||||
|
...(itemIds && itemIds.length > 0 ? { id: { in: itemIds } } : {}),
|
||||||
|
},
|
||||||
select: { id: true, title: true, content: true, summary: true },
|
select: { id: true, title: true, content: true, summary: true },
|
||||||
orderBy: { updatedAt: 'desc' },
|
orderBy: { updatedAt: 'desc' },
|
||||||
take: 30,
|
take: 30,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user