155 lines
5.7 KiB
TypeScript
155 lines
5.7 KiB
TypeScript
/**
|
||
* Prompt 模板集中管理。
|
||
* 修改提示词只动这个文件,方便版本对照与回滚。
|
||
*/
|
||
|
||
import type { ChatMessage } from "./client.js";
|
||
|
||
export interface FragmentInput {
|
||
content: string;
|
||
createdTime?: string;
|
||
}
|
||
|
||
/**
|
||
* 残片聚合为学习报告。
|
||
* 原则:报告是写给"未来复习的自己"的,保留具体知识点,剔除口语碎屑;
|
||
* 不虚构残片中不存在的内容。
|
||
*/
|
||
export function aggregateReportPrompt(
|
||
taskName: string,
|
||
fragments: FragmentInput[],
|
||
expectation?: string,
|
||
): ChatMessage[] {
|
||
const fragmentLines = fragments
|
||
.map((f, i) => `${i + 1}. ${f.content}${f.createdTime ? `(${f.createdTime})` : ""}`)
|
||
.join("\n");
|
||
|
||
const expectationBlock = expectation
|
||
? `\n本次学习开始前的预期目标:\n${expectation}\n`
|
||
: "";
|
||
|
||
return [
|
||
{
|
||
role: "system",
|
||
content: [
|
||
"你是一名学习记录整理助手。用户在一次学习会话中随手记录了若干学习残片,",
|
||
"请将它们整理为一份简洁的学习报告。要求:",
|
||
"1. 只基于残片内容,不虚构、不扩写残片中没有的知识;",
|
||
"2. 保留具体的知识点、概念、结论,去掉口语化的碎屑;",
|
||
"3. 按逻辑而非时间组织内容,相关的点合并;",
|
||
"4. 报告以要点形式呈现,控制在 300 字以内;",
|
||
"5. 如果提供了学习预期,在报告末尾用一句话说明本次学习与预期的差距(完成/部分完成/未涉及);",
|
||
"6. 直接输出报告正文,不要输出「报告如下」之类的引导语。",
|
||
].join(""),
|
||
},
|
||
{
|
||
role: "user",
|
||
content: `学习任务:${taskName}\n${expectationBlock}\n本次学习的残片记录:\n${fragmentLines}`,
|
||
},
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 从学习报告生成标准思维导图(预留,用于替代 Java 端 BuiltinMindMapGenerator)。
|
||
* 输出为缩进大纲文本,与后端 MindMapTreeTool.parseOutline 格式一致。
|
||
*/
|
||
export function generateMindMapPrompt(
|
||
taskName: string,
|
||
taskDescription: string,
|
||
reports: string[],
|
||
): ChatMessage[] {
|
||
return [
|
||
{
|
||
role: "system",
|
||
content: [
|
||
"你是一名知识结构整理助手。请阅读某个学习任务的全部学习报告,",
|
||
"将其中的知识点整理成一份思维导图大纲。要求:",
|
||
"1. 第一行是导图根标题(任务主题);",
|
||
"2. 之后每行一个节点,用两个空格的缩进表示层级;",
|
||
"3. 按知识的内在结构组织(概念→细分→要点),不按时间顺序;",
|
||
"4. 合并重复的知识点;",
|
||
"5. 只基于给定内容,不补充外部知识;",
|
||
"6. 直接输出大纲,不要任何解释。",
|
||
].join(""),
|
||
},
|
||
{
|
||
role: "user",
|
||
content: [
|
||
`学习任务:${taskName}`,
|
||
taskDescription ? `任务描述:${taskDescription}` : "",
|
||
"",
|
||
"学习报告:",
|
||
...reports.map((r, i) => `${i + 1}. ${r}`),
|
||
]
|
||
.filter(Boolean)
|
||
.join("\n"),
|
||
},
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 回忆对比:将用户凭记忆写的导图与标准导图语义对比。
|
||
*
|
||
* AI 只需输出平铺的匹配/遗漏/额外列表(不输出树结构,树标注由 Java 端完成)。
|
||
*
|
||
* 输出要求:严格 JSON,不要 markdown 代码块,格式如下:
|
||
* {
|
||
* "matches": [
|
||
* { "standardTitle": "A知识点", "recallTitle": "知识点A" }
|
||
* ],
|
||
* "missedTitles": ["在标准导图中但用户未回忆到的节点标题"],
|
||
* "extraNodes": [
|
||
* { "title": "用户额外回忆的知识点", "path": "所属路径" }
|
||
* ],
|
||
* "recallRatio": 1.0,
|
||
* "evaluation": "中文评价 2-5 句"
|
||
* }
|
||
*
|
||
* matches 中 standardTitle 必须与标准导图中的节点标题逐字一致。
|
||
* missedTitles 存放标准导图中有但用户完全没提到的节点标题。
|
||
* extraNodes 的 path 用 "根 > 父节点 > 当前节点" 格式。
|
||
*/
|
||
export function compareRecallPrompt(
|
||
taskName: string,
|
||
standardOutline: string,
|
||
recallOutline: string,
|
||
): ChatMessage[] {
|
||
return [
|
||
{
|
||
role: "system",
|
||
content: [
|
||
"你是一名学习评估专家。请对比两份思维导图大纲:",
|
||
"1. 标准导图(系统从学习报告中提炼的知识结构)",
|
||
"2. 用户导图(用户凭记忆回忆的知识结构)",
|
||
"",
|
||
"你的任务:",
|
||
"- 对标准导图的每个非根节点,判断用户在回忆中是否覆盖了它;",
|
||
"- 匹配应基于语义理解:同义表达算匹配(如\"锁升级\"≈\"锁膨胀\");",
|
||
"- 考虑层级上下文:节点在用户导图中的归属逻辑正确即可;",
|
||
"- 找出用户额外回忆的、标准导图中没有的知识点;",
|
||
"- 统计覆盖率 = 命中数 / (命中数 + 遗漏数);",
|
||
"- 用中文写一段评价(2-5 句话)。",
|
||
"",
|
||
"重要:你不需要输出标准导图的树结构。只需列出 matches(匹配对)、",
|
||
"missedTitles(遗漏的节点标题列表)、extraNodes(额外节点列表)。",
|
||
"matches 中的 standardTitle 必须与标准导图中的标题文字完全一致,不要改写。",
|
||
"输出必须是有效 JSON 对象,不要包含 ```json 之类的标记,直接输出 JSON。",
|
||
].join("\n"),
|
||
},
|
||
{
|
||
role: "user",
|
||
content: [
|
||
`学习任务:${taskName}`,
|
||
"",
|
||
"===== 标准导图(知识结构)=====",
|
||
standardOutline,
|
||
"",
|
||
"===== 用户回忆导图 =====",
|
||
recallOutline,
|
||
"",
|
||
"请输出 JSON(只包含 matches、missedTitles、extraNodes、recallRatio、evaluation 五个字段):",
|
||
].join("\n"),
|
||
},
|
||
];
|
||
}
|