@thinking-models/mcp-server
Version:
A Model Context Protocol (MCP) server for thinking models
289 lines (288 loc) • 10.7 kB
JavaScript
/**
* 学习能力模块 - 实现思维模型系统的学习和改进能力
*/
import { log } from './utils.js';
import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
import { calculateQueryMatch } from './similarity_engine.js';
// 兼容ESM的__dirname
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
/**
* 用户反馈类型
*/
export var FeedbackType;
(function (FeedbackType) {
FeedbackType["HELPFUL"] = "helpful";
FeedbackType["NOT_HELPFUL"] = "not_helpful";
FeedbackType["INCORRECT"] = "incorrect";
FeedbackType["INSIGHTFUL"] = "insightful";
FeedbackType["CONFUSING"] = "confusing"; // 令人困惑的
})(FeedbackType || (FeedbackType = {}));
// 默认的系统状态
const defaultSystemState = {
userFeedbacks: [],
knowledgeGaps: [],
modelUsageStats: {},
lastUpdated: Date.now()
};
// 内存中的系统状态
let systemState = { ...defaultSystemState };
// 状态文件路径
const getStateFilePath = () => {
// 始终使用默认数据目录
const dataDir = path.resolve(__dirname, '..', 'data');
return path.resolve(dataDir, 'learning_state.json');
};
/**
* 加载学习系统状态
*/
export async function loadLearningSystemState() {
try {
// 确保目录存在
const stateDir = path.dirname(getStateFilePath());
try {
await fs.access(stateDir);
}
catch {
await fs.mkdir(stateDir, { recursive: true });
log('创建学习系统数据目录');
}
// 读取状态文件
const stateData = await fs.readFile(getStateFilePath(), 'utf-8');
systemState = JSON.parse(stateData);
log(`学习系统状态加载完成,包含 ${systemState.userFeedbacks.length} 条反馈和 ${systemState.knowledgeGaps.length} 个知识缺口`);
}
catch (error) {
log('加载学习系统状态失败,使用默认状态');
systemState = { ...defaultSystemState };
await saveLearningSystemState();
}
}
/**
* 保存学习系统状态
*/
export async function saveLearningSystemState() {
try {
systemState.lastUpdated = Date.now();
await fs.writeFile(getStateFilePath(), JSON.stringify(systemState, null, 2), 'utf-8');
log('学习系统状态已保存');
}
catch (error) {
log(`保存学习系统状态失败: ${error.message}`);
}
}
/**
* 记录用户反馈
*/
export function recordUserFeedback(modelIds, context, feedbackType, comment, applicationResult, suggestedImprovements) {
const timestamp = Date.now();
const feedbackId = `feedback_${timestamp}_${Math.floor(Math.random() * 10000)}`;
const feedback = {
feedbackId,
timestamp,
modelIds,
context,
feedbackType,
comment,
applicationResult,
suggestedImprovements
};
// 添加到内存状态
systemState.userFeedbacks.push(feedback);
// 更新模型使用统计
modelIds.forEach(modelId => {
if (!systemState.modelUsageStats[modelId]) {
systemState.modelUsageStats[modelId] = {
modelId,
usageCount: 0,
averageHelpfulness: 0,
positiveCount: 0,
negativeCount: 0,
commonContexts: []
};
}
const stats = systemState.modelUsageStats[modelId];
stats.usageCount++;
// 更新有用性数据
if (feedbackType === FeedbackType.HELPFUL || feedbackType === FeedbackType.INSIGHTFUL) {
stats.positiveCount++;
}
else if (feedbackType === FeedbackType.NOT_HELPFUL || feedbackType === FeedbackType.INCORRECT || feedbackType === FeedbackType.CONFUSING) {
stats.negativeCount++;
}
stats.averageHelpfulness = stats.positiveCount / (stats.positiveCount + stats.negativeCount) || 0;
// 保存上下文片段(仅保存前100个字符作为关键上下文)
if (context && context.length > 0) {
const contextSummary = context.substring(0, 100) + (context.length > 100 ? '...' : '');
if (!stats.commonContexts.includes(contextSummary)) {
stats.commonContexts = [...stats.commonContexts, contextSummary].slice(-5); // 保留最近的5个上下文
}
}
});
// 异步保存状态
saveLearningSystemState().catch(() => { }); // 忽略保存错误
return feedback;
}
/**
* 检测和记录知识缺口
*/
export function detectKnowledgeGap(query, matchedModels, matchThreshold = 0.5) {
// 检查是否匹配度都很低,表明可能存在知识缺口
const hasSignificantMatch = matchedModels.some(model => {
const { score } = calculateQueryMatch(model, query);
return score >= matchThreshold;
});
if (hasSignificantMatch) {
return null; // 有足够匹配度的模型,不是知识缺口
}
// 提取可能的标签
const keywords = query.toLowerCase().split(/\s+/)
.filter(word => word.length > 3) // 忽略短词
.slice(0, 5); // 最多取5个关键词
// 检查是否已有类似的知识缺口
let existingGap = systemState.knowledgeGaps.find(gap => {
// 简单检查:如果有超过50%的关键词匹配,认为是相似的知识缺口
const matchingKeywords = keywords.filter(keyword => gap.description.toLowerCase().includes(keyword) ||
gap.relatedQueries.some(q => q.toLowerCase().includes(keyword)));
return matchingKeywords.length >= Math.max(1, Math.floor(keywords.length * 0.5));
});
const timestamp = Date.now();
if (existingGap) {
// 更新现有知识缺口
existingGap.detectionCount++;
existingGap.updatedAt = timestamp;
if (!existingGap.relatedQueries.includes(query)) {
existingGap.relatedQueries.push(query);
}
// 异步保存状态
saveLearningSystemState().catch(() => { });
return existingGap;
}
else {
// 创建新的知识缺口
const gapId = `gap_${timestamp}_${Math.floor(Math.random() * 10000)}`;
const newGap = {
gapId,
description: query,
detectionCount: 1,
relatedQueries: [query],
possibleTags: keywords,
createdAt: timestamp,
updatedAt: timestamp
};
systemState.knowledgeGaps.push(newGap);
// 异步保存状态
saveLearningSystemState().catch(() => { });
return newGap;
}
}
/**
* 获取模型的使用统计
*/
export function getModelUsageStats(modelId) {
return systemState.modelUsageStats[modelId] || null;
}
/**
* 获取知识缺口列表
*/
export function getKnowledgeGaps(limit = 10) {
// 按检测次数降序排序
return [...systemState.knowledgeGaps]
.sort((a, b) => b.detectionCount - a.detectionCount)
.slice(0, limit);
}
/**
* 获取模型的反馈历史
*/
export function getModelFeedbackHistory(modelId) {
return systemState.userFeedbacks.filter(feedback => feedback.modelIds.includes(modelId));
}
/**
* 分析模型使用模式并生成洞察
*/
export function analyzeModelUsage() {
const allStats = Object.values(systemState.modelUsageStats);
// 按使用频率排序的模型
const mostUsedModels = [...allStats]
.sort((a, b) => b.usageCount - a.usageCount)
.slice(0, 5)
.map(stat => ({
modelId: stat.modelId,
usageCount: stat.usageCount
}));
// 按有效性排序的模型(有正面反馈且使用次数至少有3次)
const mostEffectiveModels = [...allStats]
.filter(stat => stat.usageCount >= 3)
.sort((a, b) => b.averageHelpfulness - a.averageHelpfulness)
.slice(0, 5)
.map(stat => ({
modelId: stat.modelId,
helpfulness: stat.averageHelpfulness,
usageCount: stat.usageCount
}));
// 按问题反馈排序的模型(可能需要改进的)
const problemModels = [...allStats]
.filter(stat => stat.usageCount >= 3 && stat.negativeCount > stat.positiveCount)
.sort((a, b) => (b.negativeCount / b.usageCount) - (a.negativeCount / a.usageCount))
.slice(0, 5)
.map(stat => ({
modelId: stat.modelId,
negativeRatio: stat.negativeCount / stat.usageCount,
negativeCount: stat.negativeCount,
usageCount: stat.usageCount
}));
return {
totalFeedbackCount: systemState.userFeedbacks.length,
activeModelsCount: allStats.length,
mostUsedModels,
mostEffectiveModels,
problemModels,
knowledgeGapsCount: systemState.knowledgeGaps.length
};
}
/**
* 基于学习的模型推荐调整
* 利用过去的使用统计来提高推荐质量
*/
export function adjustModelRecommendations(recommendedModels, context) {
// 如果没有足够的反馈数据,直接返回原始推荐
if (systemState.userFeedbacks.length < 5) {
return recommendedModels;
}
return recommendedModels.map(rec => {
const modelStats = systemState.modelUsageStats[rec.id];
let adjustedScore = rec.score;
let adjustmentReason = undefined;
if (modelStats) {
// 基于历史有效性调整分数
if (modelStats.usageCount >= 3) {
// 有效性增强
if (modelStats.averageHelpfulness > 0.7) {
adjustedScore *= 1.2; // 增加20%的分数
adjustmentReason = "历史反馈表现优秀";
}
// 有效性降低
else if (modelStats.averageHelpfulness < 0.3) {
adjustedScore *= 0.8; // 减少20%的分数
adjustmentReason = "历史反馈表现不佳";
}
}
// 检查上下文相似性
const hasRelevantContext = modelStats.commonContexts.some(ctx => context.includes(ctx.replace('...', '')) ||
ctx.replace('...', '').includes(context.substring(0, 50)));
if (hasRelevantContext) {
adjustedScore *= 1.1; // 增加10%的分数
adjustmentReason = adjustmentReason
? `${adjustmentReason},且在类似上下文中使用过`
: "在类似上下文中使用过";
}
}
return {
id: rec.id,
score: adjustedScore,
adjustment_reason: adjustmentReason
};
}).sort((a, b) => b.score - a.score);
}