Enhance workflow routing and agent configuration management
- Introduce WorkflowLLMRouter for pre-response LLM routing, allowing agents to determine the appropriate function to call based on user input. - Implement UserTurnRoutingProcessor to manage user turns before reaching the LLM, ensuring proper routing and handling of user messages. - Refactor WorkflowBrain to integrate new routing logic and enhance agent stage configuration, including entry modes and resource management. - Update service factory to support dynamic LLM resource configuration based on workflow settings. - Add tests for new routing functionality and ensure proper handling of user messages in various scenarios.
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
"use client";
|
||||
|
||||
import { Settings2 } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import type { KnowledgeRetrievalConfig } from "@/lib/api";
|
||||
|
||||
export const DEFAULT_KNOWLEDGE_RETRIEVAL_CONFIG: KnowledgeRetrievalConfig = {
|
||||
mode: "automatic",
|
||||
topN: 5,
|
||||
scoreThreshold: 0,
|
||||
};
|
||||
|
||||
export function KnowledgeRetrievalConfigDialog({
|
||||
disabled,
|
||||
value,
|
||||
onChange,
|
||||
}: {
|
||||
disabled: boolean;
|
||||
value: KnowledgeRetrievalConfig;
|
||||
onChange: (config: KnowledgeRetrievalConfig) => void;
|
||||
}) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [draft, setDraft] = useState(value);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
function openDialog() {
|
||||
setDraft(value);
|
||||
setError(null);
|
||||
setOpen(true);
|
||||
}
|
||||
|
||||
function saveDraft() {
|
||||
if (draft.topN === 0 || draft.topN < -1 || !Number.isInteger(draft.topN)) {
|
||||
setError("Top N 必须为 -1 或大于 0 的整数");
|
||||
return;
|
||||
}
|
||||
if (draft.scoreThreshold < 0 || draft.scoreThreshold > 1) {
|
||||
setError("最低相关度必须在 0 到 1 之间");
|
||||
return;
|
||||
}
|
||||
onChange(draft);
|
||||
setOpen(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
disabled={disabled}
|
||||
onClick={openDialog}
|
||||
aria-label="打开知识库高级配置"
|
||||
title={
|
||||
disabled
|
||||
? "请先选择知识库"
|
||||
: `${value.mode === "automatic" ? "自动检索" : "模型主动检索"} · Top N ${value.topN === -1 ? "不限" : value.topN} · 最低相关度 ${value.scoreThreshold}`
|
||||
}
|
||||
className="flex h-5 w-5 items-center justify-center rounded-full text-muted-soft transition-colors hover:bg-surface-strong hover:text-foreground disabled:cursor-not-allowed disabled:opacity-40"
|
||||
>
|
||||
<Settings2 size={14} />
|
||||
</button>
|
||||
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogContent className="sm:max-w-lg">
|
||||
<DialogHeader>
|
||||
<DialogTitle>知识库高级配置</DialogTitle>
|
||||
<DialogDescription>
|
||||
设置检索触发方式、返回数量和相关度过滤条件。
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-5 py-2">
|
||||
<div className="space-y-2">
|
||||
<div className="text-sm font-medium text-foreground">检索方式</div>
|
||||
<Select
|
||||
value={draft.mode}
|
||||
onValueChange={(mode: "automatic" | "on_demand") =>
|
||||
setDraft({ ...draft, mode })
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="w-full border-hairline-strong bg-background">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="automatic">自动检索</SelectItem>
|
||||
<SelectItem value="on_demand">模型主动检索</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{draft.mode === "automatic"
|
||||
? "每轮用户提问后自动检索,响应行为更稳定。"
|
||||
: "由大模型判断是否调用知识库,依赖模型的工具调用能力。"}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<label className="block">
|
||||
<span className="mb-2 block text-sm font-medium text-foreground">
|
||||
最多返回片段数
|
||||
</span>
|
||||
<Input
|
||||
type="number"
|
||||
step="1"
|
||||
min="-1"
|
||||
value={draft.topN}
|
||||
onChange={(event) =>
|
||||
setDraft({ ...draft, topN: Number(event.target.value) })
|
||||
}
|
||||
/>
|
||||
<span className="mt-1.5 block text-xs text-muted-foreground">
|
||||
填写 -1 时保留所有达到阈值的结果。
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label className="block">
|
||||
<span className="mb-2 block text-sm font-medium text-foreground">
|
||||
最低相关度
|
||||
</span>
|
||||
<Input
|
||||
type="number"
|
||||
step="0.01"
|
||||
min="0"
|
||||
max="1"
|
||||
value={draft.scoreThreshold}
|
||||
onChange={(event) =>
|
||||
setDraft({
|
||||
...draft,
|
||||
scoreThreshold: Number(event.target.value),
|
||||
})
|
||||
}
|
||||
/>
|
||||
<span className="mt-1.5 block text-xs text-muted-foreground">
|
||||
仅保留相关度达到该值的片段,范围 0–1。
|
||||
</span>
|
||||
</label>
|
||||
|
||||
{error && <p className="text-sm text-destructive">{error}</p>}
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<Button type="button" variant="outline" onClick={() => setOpen(false)}>
|
||||
取消
|
||||
</Button>
|
||||
<Button type="button" onClick={saveDraft}>
|
||||
保存配置
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user