119 lines
3.1 KiB
TypeScript
119 lines
3.1 KiB
TypeScript
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
|