"use client"; import { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; import { ResponsiveLayout } from "@/components/layout"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { fetchPrompts, updatePrompt, type PromptItem } from "@/features/agent/services/promptsApi"; import { toast } from "@/hooks/useToast"; function getPlaceholderHint(key: string): string { switch (key) { case "rag_prompt": case "rag_prompt_with_web_optional": return "占位符:{{rag_context}} 为知识库检索内容,{{user_message}} 为用户问题。"; case "no_kb_prompt": return "占位符:{{user_message}} 为用户问题。"; case "web_search_result_prompt": return "占位符:{{web_context}} 为联网搜索结果,{{user_message}} 为用户问题。(当前流程未使用此模板)"; case "no_source_reply": case "ai_fail_reply": return "无占位符,内容将作为完整回复语直接展示给用户。"; default: return "请勿删除占位符,保存后由系统替换为实际内容。"; } } /** 各提示词的使用场景说明(展示在卡片中) */ function getUsageScenario(key: string): string { switch (key) { case "rag_prompt": return "有知识库检索结果,且本回合未勾选「联网搜索」时,用此模板拼成 prompt 发给模型。"; case "rag_prompt_with_web_optional": return "有知识库检索结果且本回合勾选「联网搜索」时,用此模板并传入联网工具,由模型决定是否调用联网。"; case "no_kb_prompt": return "没有知识库检索结果且本回合未走联网时,用此模板让模型仅凭自身知识回答。"; case "web_search_result_prompt": return "预留:若将来有「先联网搜再拼成一段 prompt」的流程,会使用此模板。当前未使用。"; case "no_source_reply": return "既未命中知识库、也未使用大模型或联网时(如用户关闭了所有数据源),直接向用户展示这句话。"; case "ai_fail_reply": return "调用 AI 接口失败(超时、报错等)时,向用户展示这句话。"; default: return ""; } } function getTextareaMinHeight(key: string): string { return key === "no_source_reply" || key === "ai_fail_reply" ? "min-h-[80px]" : "min-h-[200px]"; } export default function PromptsPage({ embedded = false }: { embedded?: boolean }) { const router = useRouter(); const [userId, setUserId] = useState(null); const [prompts, setPrompts] = useState([]); const [loading, setLoading] = useState(true); const [savingKey, setSavingKey] = useState(null); const [error, setError] = useState(""); useEffect(() => { const storedUserId = localStorage.getItem("agent_user_id"); if (!storedUserId) { router.push("/"); return; } setUserId(Number.parseInt(storedUserId, 10)); }, [router]); const loadPrompts = async () => { if (!userId) return; try { setLoading(true); setError(""); const data = await fetchPrompts(userId); setPrompts(data); } catch (e) { console.error("加载提示词失败:", e); setError((e as Error).message || "加载提示词失败"); } finally { setLoading(false); } }; useEffect(() => { if (userId) loadPrompts(); }, [userId]); const handleSave = async (key: string, content: string) => { if (!userId) return; setSavingKey(key); try { await updatePrompt(userId, key, content); toast.success("保存成功,将立即生效。"); await loadPrompts(); } catch (e) { toast.error((e as Error).message || "保存失败"); } finally { setSavingKey(null); } }; const handleContentChange = (key: string, content: string) => { setPrompts((prev) => prev.map((p) => (p.key === key ? { ...p, content } : p)) ); }; if (!userId) return null; const headerContent = (

提示词

配置系统中使用的提示词模板,用于 RAG、联网等场景。仅管理员可修改。占位符说明见下方各卡片。
{!embedded && ( )}
); const mainContent = (
{error && (
{error}
)} {loading ? (
加载中...
) : ( prompts.map((item) => ( {item.name} {getUsageScenario(item.key) && (

使用场景: {getUsageScenario(item.key)}

)}

{getPlaceholderHint(item.key)}