feat: 完整 Prompt 配置页 - 全部 6 个 prompt 可自定义

- panel.html: 6 个折叠式 textarea(提取/召回/进化/压缩/概要/反思)
- style.css: details/summary 折叠组样式
- panel.js: 全部 6 个 prompt 双向数据绑定
- index.js: 所有调用点传入 customPrompt
- extractor.js / retriever.js / evolution.js / compressor.js: 接受并使用自定义 prompt
- 留空时走内置默认 prompt,完全向后兼容
This commit is contained in:
Youzini-afk
2026-03-24 17:21:40 +08:00
parent 963e4f3b7b
commit 58304e7253
8 changed files with 106 additions and 18 deletions

View File

@@ -16,7 +16,7 @@ import { isDirectVectorConfig } from './vector-index.js';
* @param {boolean} [params.force=false] - 忽略阈值强制压缩
* @returns {Promise<{created: number, archived: number}>}
*/
export async function compressType({ graph, typeDef, embeddingConfig, force = false }) {
export async function compressType({ graph, typeDef, embeddingConfig, force = false, customPrompt }) {
const compression = typeDef.compression;
if (!compression || compression.mode !== 'hierarchical') {
return { created: 0, archived: 0 };
@@ -33,6 +33,7 @@ export async function compressType({ graph, typeDef, embeddingConfig, force = fa
level,
embeddingConfig,
force,
customPrompt,
});
totalCreated += result.created;
@@ -48,7 +49,7 @@ export async function compressType({ graph, typeDef, embeddingConfig, force = fa
/**
* 压缩特定层级的节点
*/
async function compressLevel({ graph, typeDef, level, embeddingConfig, force }) {
async function compressLevel({ graph, typeDef, level, embeddingConfig, force, customPrompt }) {
const compression = typeDef.compression;
// 获取该层级的活跃叶子节点
@@ -79,7 +80,7 @@ async function compressLevel({ graph, typeDef, level, embeddingConfig, force })
if (batch.length < 2) break; // 至少 2 个才压缩
// 调用 LLM 总结
const summaryResult = await summarizeBatch(batch, typeDef);
const summaryResult = await summarizeBatch(batch, typeDef, customPrompt);
if (!summaryResult) continue;
// 创建压缩节点
@@ -152,7 +153,7 @@ function migrateBatchEdges(graph, batch, compressedNode) {
/**
* 调用 LLM 总结一批节点
*/
async function summarizeBatch(nodes, typeDef) {
async function summarizeBatch(nodes, typeDef, customPrompt) {
const nodeDescriptions = nodes.map((n, i) => {
const fieldsStr = Object.entries(n.fields)
.filter(([_, v]) => v)
@@ -163,7 +164,7 @@ async function summarizeBatch(nodes, typeDef) {
const instruction = typeDef.compression.instruction || '将以下节点压缩总结为一条精炼记录。';
const systemPrompt = [
const systemPrompt = customPrompt || [
'你是一个记忆压缩器。将多个同类型节点总结为一条更高层级的压缩节点。',
instruction,
'',
@@ -190,13 +191,13 @@ async function summarizeBatch(nodes, typeDef) {
* @param {boolean} [force=false]
* @returns {Promise<{created: number, archived: number}>}
*/
export async function compressAll(graph, schema, embeddingConfig, force = false) {
export async function compressAll(graph, schema, embeddingConfig, force = false, customPrompt) {
let totalCreated = 0;
let totalArchived = 0;
for (const typeDef of schema) {
if (typeDef.compression?.mode === 'hierarchical') {
const result = await compressType({ graph, typeDef, embeddingConfig, force });
const result = await compressType({ graph, typeDef, embeddingConfig, force, customPrompt });
totalCreated += result.created;
totalArchived += result.archived;
}