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

258 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 来源徽章显示优化方案
## 问题描述
用户反馈:问答系统虽然在底部有"来源说明",但在正文对应位置没有显示显著的来源徽章,无法清晰看出每句话的具体出处。
## 当前实现状态
### 前端支持 ✅
`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. **多语言支持:** 如果有英文内容,标记格式保持一致