egg_server/utils/llm/index.ts

119 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { PromptTemplate } from "@langchain/core/prompts"
import { z } from "zod"
import { adjustTimeRange, getTimeRange } from "../time"
import { getLangfuse, getModel } from "./base"
/**
* 解析timeParser用户输入
* 如果解析失败,则返回过去三天的时间范围
* @param userInput 用户输入
* @param requestId 请求ID
* @returns
*/
const timeParser = async (userInput: string, requestId: string) => {
const { langfuseHandler } = await getLangfuse(
"parseGroupAgentQuery",
requestId
)
const model = await getModel()
const structuredLlm = model.withStructuredOutput(
z.object({
s: z.string().describe("开始时间,格式为 YYYY-MM-DD HH:mm:ss"),
e: z.string().describe("结束时间,格式为 YYYY-MM-DD HH:mm:ss"),
}),
{
name: "timeParser",
}
)
const invokeParser = async () => {
try {
return await structuredLlm.invoke(
`
当前时间为:${new Date().toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" })}
请解析以下用户输入,提取出开始时间和结束时间,默认为过去三天
除非用户指定到了分钟,开始时间为当天的 00:00:00结束时间为当天的 23:59:59
请将解析结果严格按照以下格式返回:
\`\`\`ts
interface GroupAgent {
s: string // 开始时间,格式为 YYYY-MM-DD HH:mm:ss
e: string // 结束时间,格式为 YYYY-MM-DD HH:mm:ss
}
\`\`\`
用户输入:
\`\`\`
${userInput.replaceAll("`", " ")}
\`\`\`
`,
{
callbacks: [langfuseHandler],
}
)
} catch {
// 如果解析失败,则返回空字符串
return { s: "", e: "" }
}
}
const validateResult = (result: any) => {
const regex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/
return regex.test(result.s) && regex.test(result.e)
}
let result
let attempts = 0
do {
result = await invokeParser()
attempts++
} while (!validateResult(result) && attempts < 3)
// 如果解析失败,则返回过去三天的时间范围
if (!validateResult(result)) {
return getTimeRange("threeDays")
}
// 解析成功,调整时间范围
return adjustTimeRange(result.s, result.e)
}
/**
* 调用LLM模型
* @param promptName 提示Key
* @param variables 变量
* @param requestId 请求ID
* @param temperature 温度
* @returns
*/
const invoke = async (
promptName: string,
variables: Record<string, any>,
requestId: string,
temperature = 0
) => {
const { langfuse, langfuseHandler } = await getLangfuse("invoke", requestId)
const prompt = await langfuse.getPrompt(promptName)
const langchainTextPrompt = PromptTemplate.fromTemplate(
prompt.getLangchainPrompt()
).withConfig({
metadata: { langfusePrompt: prompt },
})
const chain = langchainTextPrompt.pipe(await getModel(temperature))
const { content } = await chain.invoke(variables, {
callbacks: [langfuseHandler],
})
return content
}
const llm = {
timeParser,
invoke,
}
export default llm