feat(iit): Phase 1.5 AI对话能力集成 - 复用通用能力层LLMFactory

新增功能
- SessionMemory: 会话记忆管理器(存储最近3轮对话)
- ChatService: AI对话服务(复用LLMFactory,支持DeepSeek-V3)
- WechatCallbackController: 集成AI对话 + '正在查询'即时反馈

 技术亮点
- 复用通用能力层LLMFactory(零配置,单例模式)
- 上下文记忆(SessionMemory,Node.js内存,自动清理过期会话)
- 即时反馈(立即回复'正在查询,请稍候...',规避5秒超时)
- 极简MVP(<300行代码,1天完成)

 文档更新
- Phase1.5开发计划文档(反映通用能力层复用优势)

 完成度
- Phase 1.5核心功能:100%
- 预估工作量:2-3天  实际:1天(LLM调用层已完善)

Scope: iit-manager
This commit is contained in:
2026-01-03 16:42:46 +08:00
parent 6a567f028f
commit 4794640f5d
5 changed files with 3563 additions and 25 deletions

View File

@@ -0,0 +1,169 @@
/**
* SessionMemory - 会话记忆管理器(内存版)
*
* 功能:
* - 存储用户最近3轮对话
* - 提供上下文查询
* - 自动清理过期会话1小时
*
* 设计原则:
* - Node.js内存存储MVP阶段无需数据库
* - 单例模式(全局共享)
* - 轻量级(<100行代码
*/
import { logger } from '../../../common/logging/index.js';
/**
* 对话消息
*/
export interface ConversationMessage {
role: 'user' | 'assistant';
content: string;
timestamp: Date;
}
/**
* 对话历史
*/
export interface ConversationHistory {
userId: string;
messages: ConversationMessage[];
createdAt: Date;
updatedAt: Date;
}
/**
* 会话记忆管理器
*/
export class SessionMemory {
// 内存存储:{ userId: ConversationHistory }
private sessions: Map<string, ConversationHistory> = new Map();
private readonly MAX_HISTORY = 3; // 只保留最近3轮6条消息
private readonly SESSION_TIMEOUT = 3600000; // 1小时毫秒
/**
* 添加对话记录
*/
addMessage(userId: string, role: 'user' | 'assistant', content: string): void {
if (!this.sessions.has(userId)) {
this.sessions.set(userId, {
userId,
messages: [],
createdAt: new Date(),
updatedAt: new Date(),
});
logger.debug('[SessionMemory] 创建新会话', { userId });
}
const session = this.sessions.get(userId)!;
session.messages.push({
role,
content,
timestamp: new Date(),
});
// 只保留最近3轮6条消息3个user + 3个assistant
if (session.messages.length > this.MAX_HISTORY * 2) {
const removed = session.messages.length - this.MAX_HISTORY * 2;
session.messages = session.messages.slice(-this.MAX_HISTORY * 2);
logger.debug('[SessionMemory] 清理历史消息', { userId, removedCount: removed });
}
session.updatedAt = new Date();
logger.debug('[SessionMemory] 添加消息', {
userId,
role,
messageLength: content.length,
totalMessages: session.messages.length,
});
}
/**
* 获取用户对话历史最近N轮
*/
getHistory(userId: string, maxTurns: number = 3): ConversationMessage[] {
const session = this.sessions.get(userId);
if (!session) {
return [];
}
// 返回最近N轮2N条消息
const maxMessages = maxTurns * 2;
return session.messages.length > maxMessages
? session.messages.slice(-maxMessages)
: session.messages;
}
/**
* 获取用户上下文格式化为字符串用于LLM Prompt
*/
getContext(userId: string): string {
const history = this.getHistory(userId, 2); // 只取最近2轮
if (history.length === 0) {
return '';
}
return history
.map((m) => `${m.role === 'user' ? 'PI' : 'Assistant'}: ${m.content}`)
.join('\n');
}
/**
* 清除用户会话
*/
clearSession(userId: string): void {
const existed = this.sessions.delete(userId);
if (existed) {
logger.info('[SessionMemory] 清除会话', { userId });
}
}
/**
* 清理过期会话超过1小时未使用
*/
cleanupExpiredSessions(): void {
const now = Date.now();
let cleanedCount = 0;
for (const [userId, session] of this.sessions.entries()) {
if (now - session.updatedAt.getTime() > this.SESSION_TIMEOUT) {
this.sessions.delete(userId);
cleanedCount++;
}
}
if (cleanedCount > 0) {
logger.info('[SessionMemory] 清理过期会话', { cleanedCount });
}
}
/**
* 获取统计信息(用于监控)
*/
getStats() {
return {
totalSessions: this.sessions.size,
sessions: Array.from(this.sessions.entries()).map(([userId, session]) => ({
userId,
messageCount: session.messages.length,
createdAt: session.createdAt,
updatedAt: session.updatedAt,
})),
};
}
}
// 全局单例
export const sessionMemory = new SessionMemory();
// 定时清理过期会话(每小时)
setInterval(() => {
sessionMemory.cleanupExpiredSessions();
}, 3600000);
logger.info('[SessionMemory] 会话记忆管理器已启动', {
maxHistory: 3,
timeout: '1小时',
});