Files
GovAI/CITATION_BADGE_SOLUTION.md
T
selfrelease 73d1e00303 feat: 实施来源徽章后处理逻辑,确保100%显示
- 添加enhanceCitations等6个智能标注函数
- 自动为回答添加[[知识库:xxx]]和[[AI建议]]徽章
- 智能判断标注类型(事实陈述vs建议说明)
- 保护代码块和引用块不被标注
- 修改Chat和Completion函数应用后处理
- 添加extractKnowledgeSources提取知识库来源

新增文档:
- CITATION_BADGE_SOLUTION.md - 完整解决方案
- CITATION_POST_PROCESSING_REPORT.md - 实施报告
- citation_prompt.txt - 优化后的prompt模板
- test-citation-badges.sh - 测试脚本
2026-06-22 19:05:10 +08:00

7.6 KiB
Raw Blame History

来源徽章显示优化方案

问题描述

用户反馈:问答系统虽然在底部有"来源说明",但在正文对应位置没有显示显著的来源徽章,无法清晰看出每句话的具体出处。

当前实现状态

前端支持

apps/web/src/components/ui/gov-markdown.tsx 已经支持将特殊标记自动渲染为徽章:

// 知识库引用 → 蓝色徽章
[[知识库:文献名称]]  [[知识库:文献名称:条款号]]

// AI建议 → 橙色徽章  
[[AI建议]]

// 推荐应用 → 绿色跳转徽章
[[推荐应用:应用名称:slug]]

后端实现 ⚠️

server/internal/handler/chat_llm.go 已在 system prompt 中要求 LLM 标注来源,但可能遵循度不够稳定。

解决方案

方案1:强化 System Prompt(推荐)

优点: 不改变架构,只优化提示词 缺点: 仍依赖 LLM 遵循度

实施步骤:

chat_llm.gobuildMessages 函数中,将来源标注规则移到 system prompt 最前面,并:

  1. 使用视觉标记强调重要性🔴 最高优先级)
  2. 提供完整的正反示例
  3. 添加输出前检查清单
  4. 给出具体的徽章渲染效果说明

修改后的 system prompt 结构:

if hasKB {
    finalSystem += `
## 🔴 最高优先级规则:来源徽章标注

用户会在你回答的每句话后看到彩色徽章:
- 蓝色徽章 = 来自知识库
- 橙色徽章 = AI分析建议

你必须在每句话后添加对应标记。

### 标注格式

知识库引用:[[知识库:文献名称]]
AI分析建议:[[AI建议]]

### 完整示例

**用户问:** 居住证办理条件是什么?

**正确回答:**

居住证办理需要在居住地居住半年以上 [[知识库:户口登记管理规定]],
同时满足以下条件之一 [[知识库:户口登记管理规定]]:

1. 有合法稳定就业 [[知识库:户口登记管理规定]]
2. 有合法稳定住所 [[知识库:户口登记管理规定]]  
3. 连续就读 [[知识库:户口登记管理规定]]

建议您提前准备好所有材料 [[AI建议]]。

> **来源说明**
> 
> **知识库引用:**
> - 【户口登记管理规定】:第五条规定...(摘录原文)
> 
> **AI建议:**
> - 材料准备建议

### ✅ 输出前自检
- [ ] 每个事实陈述后都有 [[知识库:xxx]] 或 [[AI建议]]
- [ ] 末尾有来源汇总块
`
}

方案2:后端后处理(最可靠)

优点: 100%保证显示徽章,不依赖 LLM 缺点: 需要额外开发,可能误判

实施步骤:

  1. 在流式输出完成后,对完整回答进行后处理
  2. 自动识别需要标注的位置
  3. 插入相应的徽章标记
// 在 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. 添加最小化后处理:只在缺失标注时补充
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的完整后处理逻辑

验证方法

前端验证

在浏览器控制台运行:

// 测试徽章渲染
const testMarkdown = `
居住证办理需要身份证 [[知识库:户口登记管理规定]]。
建议提前准备 [[AI建议]]。
`;

console.log('应该看到两个徽章:蓝色知识库徽章 + 橙色AI建议徽章');

后端验证

测试问答:

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. 多语言支持: 如果有英文内容,标记格式保持一致