# 来源徽章显示优化方案 ## 问题描述 用户反馈:问答系统虽然在底部有"来源说明",但在正文对应位置没有显示显著的来源徽章,无法清晰看出每句话的具体出处。 ## 当前实现状态 ### 前端支持 ✅ `apps/web/src/components/ui/gov-markdown.tsx` 已经支持将特殊标记自动渲染为徽章: ```typescript // 知识库引用 → 蓝色徽章 [[知识库:文献名称]] 或 [[知识库:文献名称:条款号]] // AI建议 → 橙色徽章 [[AI建议]] // 推荐应用 → 绿色跳转徽章 [[推荐应用:应用名称:slug]] ``` ### 后端实现 ⚠️ `server/internal/handler/chat_llm.go` 已在 system prompt 中要求 LLM 标注来源,但可能遵循度不够稳定。 ## 解决方案 ### 方案1:强化 System Prompt(推荐) **优点:** 不改变架构,只优化提示词 **缺点:** 仍依赖 LLM 遵循度 **实施步骤:** 在 `chat_llm.go` 的 `buildMessages` 函数中,将来源标注规则移到 system prompt 最前面,并: 1. **使用视觉标记强调重要性**(🔴 最高优先级) 2. **提供完整的正反示例** 3. **添加输出前检查清单** 4. **给出具体的徽章渲染效果说明** 修改后的 system prompt 结构: ```go if hasKB { finalSystem += ` ## 🔴 最高优先级规则:来源徽章标注 用户会在你回答的每句话后看到彩色徽章: - 蓝色徽章 = 来自知识库 - 橙色徽章 = AI分析建议 你必须在每句话后添加对应标记。 ### 标注格式 知识库引用:[[知识库:文献名称]] AI分析建议:[[AI建议]] ### 完整示例 **用户问:** 居住证办理条件是什么? **正确回答:** 居住证办理需要在居住地居住半年以上 [[知识库:户口登记管理规定]], 同时满足以下条件之一 [[知识库:户口登记管理规定]]: 1. 有合法稳定就业 [[知识库:户口登记管理规定]] 2. 有合法稳定住所 [[知识库:户口登记管理规定]] 3. 连续就读 [[知识库:户口登记管理规定]] 建议您提前准备好所有材料 [[AI建议]]。 > **来源说明** > > **知识库引用:** > - 【户口登记管理规定】:第五条规定...(摘录原文) > > **AI建议:** > - 材料准备建议 ### ✅ 输出前自检 - [ ] 每个事实陈述后都有 [[知识库:xxx]] 或 [[AI建议]] - [ ] 末尾有来源汇总块 ` } ``` ### 方案2:后端后处理(最可靠) **优点:** 100%保证显示徽章,不依赖 LLM **缺点:** 需要额外开发,可能误判 **实施步骤:** 1. 在流式输出完成后,对完整回答进行后处理 2. 自动识别需要标注的位置 3. 插入相应的徽章标记 ```go // 在 Chat 函数的流式输出完成后添加 func (h *LLMChatHandler) enhanceCitations(response string, hasKnowledge bool, kbSources []string) string { if !hasKnowledge || response == "" { return response } // 如果已经有标注,不再处理 if strings.Contains(response, "[[知识库:") || strings.Contains(response, "[[AI建议]]") { return response } // 策略:在每个自然段落末尾添加来源标注 lines := strings.Split(response, "\n") var enhanced []string for _, line := range lines { trimmed := strings.TrimSpace(line) // 跳过空行、标题行、列表项 if trimmed == "" || strings.HasPrefix(trimmed, "#") || strings.HasPrefix(trimmed, "-") || strings.HasPrefix(trimmed, "*") { enhanced = append(enhanced, line) continue } // 在陈述句末尾添加标注(简化判断:中英文句号、问号、感叹号) if strings.HasSuffix(trimmed, "。") || strings.HasSuffix(trimmed, ".") || strings.HasSuffix(trimmed, "!") || strings.HasSuffix(trimmed, "!") { // 如果有知识库来源,标注知识库 if len(kbSources) > 0 { line = strings.TrimRight(line, " \t") + " [[知识库:" + kbSources[0] + "]]" } else { line = strings.TrimRight(line, " \t") + " [[AI建议]]" } } enhanced = append(enhanced, line) } return strings.Join(enhanced, "\n") } ``` ### 方案3:混合方案(平衡) 1. 继续优化 system prompt(方案1) 2. 添加最小化后处理:只在缺失标注时补充 ```go func (h *LLMChatHandler) ensureBasicCitations(response string, hasKnowledge bool) string { // 检查是否完全没有标注 hasKBCitation := strings.Contains(response, "[[知识库:") hasAICitation := strings.Contains(response, "[[AI建议]]") if !hasKBCitation && !hasAICitation { // 只在末尾添加统一说明 if hasKnowledge { response += "\n\n> 💡 以上内容来自知识库检索和AI分析。" } else { response += "\n\n> 💡 以上内容为AI建议 [[AI建议]]。" } } return response } ``` ## 推荐实施顺序 1. **第一步:** 实施方案1(优化 system prompt) - 立即生效,无副作用 - 预期改善率:70-80% 2. **第二步:** 测试效果,观察 LLM 遵循度 - 收集实际问答样本 - 统计徽章标注率 3. **第三步:** 如遵循度仍不理想,实施方案3(混合方案) - 保底机制,确保用户体验 4. **可选:** 如需100%保证,实施方案2的完整后处理逻辑 ## 验证方法 ### 前端验证 在浏览器控制台运行: ```javascript // 测试徽章渲染 const testMarkdown = ` 居住证办理需要身份证 [[知识库:户口登记管理规定]]。 建议提前准备 [[AI建议]]。 `; console.log('应该看到两个徽章:蓝色知识库徽章 + 橙色AI建议徽章'); ``` ### 后端验证 测试问答: ```bash curl -X POST http://localhost:8080/api/v1/apps/{app_id}/chat/llm \ -H "Content-Type: application/json" \ -H "Authorization: Bearer {token}" \ -d '{ "message": "居住证办理条件是什么?" }' ``` 检查返回的 `answer` 字段是否包含 `[[知识库:xxx]]` 和 `[[AI建议]]` 标记。 ## 示例效果对比 ### 优化前 ❌ ``` 居住证办理条件包括在居住地居住半年以上,同时需满足有合法稳定就业、 合法稳定住所或连续就读其中之一。 > 来源说明 > - 知识库引用:户口登记管理规定 > - AI建议:流程说明 ``` 用户看到:纯文本,无法直观区分来源 ### 优化后 ✅ ``` 居住证办理条件包括在居住地居住半年以上 [[知识库:户口登记管理规定]], 同时需满足有合法稳定就业、合法稳定住所或连续就读其中之一 [[知识库:户口登记管理规定]]。 建议提前准备好所有材料 [[AI建议]]。 > **来源说明** > > **知识库引用:** > - 【户口登记管理规定】:第五条规定... > > **AI建议:** > - 材料准备建议 ``` 用户看到: - "居住证办理条件..." 后有 **🔵 户口登记管理规定** 蓝色徽章 - "建议提前准备..." 后有 **🟠 AI建议** 橙色徽章 ## 实施代码位置 - **后端 System Prompt:** `server/internal/handler/chat_llm.go` 第447-502行 - **前端徽章渲染:** `apps/web/src/components/ui/gov-markdown.tsx` 第71-91行 - **后处理函数(如需):** 在 `chat_llm.go` 新增 `enhanceCitations` 函数 ## 注意事项 1. **不要过度标注:** 不是每个标点符号都需要徽章,重点是事实陈述和观点 2. **保持可读性:** 徽章应该辅助理解,而不是干扰阅读 3. **兼容历史数据:** 旧对话记录可能没有徽章,前端需要优雅降级 4. **多语言支持:** 如果有英文内容,标记格式保持一致