feat: 优化追问功能 - LLM智能生成 + 显示位置修复

- 修复 AuthLoader 组件中 router.push 在渲染期间调用的 React 警告
- 追问问题改为只在最新 AI 回复下方显示(修复多处显示问题)
- 新增 LLM 生成追问 API:POST /api/v1/apps/{id}/suggestions
- 前端调用 LLM API 生成智能追问,失败时降级到规则生成
- 登录页填入默认测试账号 kj-admin@govai.gov.cn
This commit is contained in:
selfrelease
2026-06-23 15:35:58 +08:00
parent 96b944ac8d
commit 8959456eb7
6 changed files with 211 additions and 21 deletions
+97
View File
@@ -1737,3 +1737,100 @@ func (h *LLMChatHandler) generateConversationName(appID, userID, convID, userMes
DO UPDATE SET name = EXCLUDED.name, updated_at = now()`,
appID, userID, convID, name)
}
// GenerateSuggestions 生成追问建议(由 LLM 智能生成)
func (h *LLMChatHandler) GenerateSuggestions(ctx context.Context, conversationID, appID string, messages []map[string]string) ([]string, error) {
if len(messages) == 0 {
return nil, nil
}
// 构建对话历史上下文
var historyBuilder strings.Builder
for i, msg := range messages {
role := "用户"
if msg["role"] == "assistant" {
role = "助手"
}
historyBuilder.WriteString(fmt.Sprintf("%d. %s%s\n", i+1, role, msg["content"]))
}
systemPrompt := `你是一个智能政务问答助手。请根据对话历史,生成4个追问问题,帮助用户深入了解相关内容。
要求:
1. 问题必须与对话内容紧密相关
2. 每个问题不超过20个字
3. 问题要有深度,引导用户进一步思考
4. 避免重复或过于宽泛的问题
5. 直接输出问题,用换行分隔,不要编号,不要解释`
suggestReq := &llm.ChatRequest{
Model: "",
Messages: []llm.Message{
{Role: "system", Content: systemPrompt},
{Role: "user", Content: "对话历史:\n" + historyBuilder.String()},
},
Temperature: 0.7,
MaxTokens: 200,
Stream: false,
}
// 获取激活的 provider
provider, defaultModel, err := h.getProviderWithModel(ctx)
if err != nil {
return nil, err
}
if defaultModel != "" {
suggestReq.Model = defaultModel
}
result, err := h.manager.Chat(ctx, provider, suggestReq)
if err != nil {
return nil, err
}
// 解析结果:按换行分割
suggestions := strings.Split(strings.TrimSpace(result.Content), "\n")
var validSuggestions []string
for _, s := range suggestions {
s = strings.TrimSpace(s)
// 过滤空行和过长的行
if len(s) > 0 && len([]rune(s)) <= 25 {
validSuggestions = append(validSuggestions, s)
}
}
// 最多返回4个
if len(validSuggestions) > 4 {
validSuggestions = validSuggestions[:4]
}
return validSuggestions, nil
}
// GetSuggestions HTTP handler:获取追问建议
func (h *LLMChatHandler) GetSuggestions(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
appID := chi.URLParam(r, "id")
if appID == "" {
response.Error(w, http.StatusBadRequest, 40001, "缺少应用ID")
return
}
var req struct {
ConversationID string `json:"conversation_id"`
Messages []map[string]string `json:"messages"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
response.Error(w, http.StatusBadRequest, 40002, "请求格式错误")
return
}
suggestions, err := h.GenerateSuggestions(ctx, req.ConversationID, appID, req.Messages)
if err != nil {
log.Warn().Err(err).Msg("generate suggestions failed")
response.Error(w, http.StatusInternalServerError, 50001, "生成追问失败")
return
}
response.JSON(w, http.StatusOK, suggestions)
}