fix: 提示词链里的引导提问不算轮数,分类器固定结果、跳过过短输入

- 引导对话和 AI 对话存在同一个对话里,提示词链把它当成一轮“AI 对话”,显示“没有网页”。
  现在标成“引导”,淡化显示,不计入轮数,也不能选中(↑↓ 跳过)
- 分类器 temperature 设为 0:同一句提示词以前约两成会被打成不同层级
- 不到 4 个字的提问(“1”“,”等)不打层级,--force 重标时清掉旧标签

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-10-27 20:26:29 +08:00
1 parent bc9da688ba
commit 30630e8125
6 files changed
+73 -10

No files matched your search

+9 -1
View File
@@ -13,6 +13,8 @@ const CLASSIFY_SYSTEM_PROMPT = `你是一个教育评估专家。根据布鲁姆
只返回一个数字(1-6),不要解释。`
const MIN_PROMPT_CHARS = 4
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
async function callLlm(content: string): Promise<number | null> {
@@ -23,7 +25,8 @@ async function callLlm(content: string): Promise<number | null> {
{ role: "system", content: CLASSIFY_SYSTEM_PROMPT },
{ role: "user", content },
],
{ maxTokens: 10, timeoutMs: 30_000 },
// 同一句提示词要得到同一个层级
{ maxTokens: 10, temperature: 0, timeoutMs: 30_000 },
)
const match = /[1-6]/.exec(text)
if (!match) {
@@ -43,6 +46,11 @@ export async function classifyMessage(messageId: number): Promise<number | null>
{ id: messageId },
)
if (!msg) return null
// “1”“,”“可以”这类太短,判断不出层级;清掉以前打的标签(--force 重标时)
if ([...msg.content.trim()].length < MIN_PROMPT_CHARS) {
run(`UPDATE prompt_message SET prompt_level = NULL WHERE id = $id`, { id: messageId })
return null
}
const level = await callLlm(msg.content)
if (level !== null) {
run(`UPDATE prompt_message SET prompt_level = $level WHERE id = $id`, {
+4 -1
View File
@@ -63,6 +63,7 @@ interface CompletionOptions {
model?: string
stream: boolean
maxTokens?: number
temperature?: number
signal?: AbortSignal
timeoutMs?: number
}
@@ -82,6 +83,7 @@ function buildRequest(messages: ChatMessage[], opts: CompletionOptions) {
stream: opts.stream,
}
if (opts.maxTokens) body.max_tokens = opts.maxTokens
if (opts.temperature !== undefined) body.temperature = opts.temperature
const apiKey = ark ? config.arkApiKey : config.llmApiKey
if (!apiKey) throw new Error("未配置模型接口密钥")
const baseUrl = (ark ? config.arkBaseUrl : config.llmBaseUrl).replace(/\/$/, "")
@@ -203,12 +205,13 @@ export function streamGuidance(history: ChatMessage[], signal?: AbortSignal) {
export async function complete(
messages: ChatMessage[],
opts: { model?: string; maxTokens?: number; timeoutMs?: number } = {},
opts: { model?: string; maxTokens?: number; temperature?: number; timeoutMs?: number } = {},
): Promise<string> {
const res = await buildRequest(messages, {
model: opts.model ?? config.llmModel,
stream: false,
maxTokens: opts.maxTokens,
temperature: opts.temperature,
timeoutMs: opts.timeoutMs,
})
await ensureOk(res)
+13
View File
@@ -646,3 +646,16 @@ describe("课堂总结", () => {
expect(all.json.top_scored.map((t: any) => t.username)).toEqual(["weba2小李", "weba1小明"])
})
})
describe("提示词分类", () => {
test("太短的提问不打层级,以前打的也清掉", async () => {
const { classifyMessage } = await import("../src/services/classifier")
const { createConversation, insertMessage } = await import("../src/services/prompt")
const conv = createConversation(makeUser("stu"), makeTask("T"))
const id = insertMessage({ conversation_id: conv, role: "user", content: " 1 " })
run(`UPDATE prompt_message SET prompt_level = 6 WHERE id = $id`, { id })
expect(await classifyMessage(id)).toBeNull()
const row = get<{ prompt_level: number | null }>(`SELECT prompt_level FROM prompt_message WHERE id = $id`, { id })
expect(row!.prompt_level).toBeNull()
})
})