// internal/rag/reranker.go
type Reranker interface {
Rerank(ctx context.Context, query string, candidates []Chunk) ([]Chunk, error)
}
// 简单实现:用LLM的cross-encoder或相似度重新打分
type LLMReranker struct {
llmClient LLMClient
}
func (r *LLMReranker) Rerank(ctx context.Context, query string, candidates []Chunk) ([]Chunk, error) {
// 对每个candidate计算与query的相关度
// 用一个轻量级模型(可以用embedding的cosine相似度)
// 重新排序,返回top 5
}
// RAG答案结构
type RAGAnswer struct {
Answer string `json:"answer"`
Citations []Citation `json:"citations"`
Confidence string `json:"confidence"`
}
type Citation struct {
Source string `json:"source"` // 文档来源
ChunkID string `json:"chunk_id"` // 具体chunk ID
Text string `json:"text,omitempty"` // 引用的原文
}
// 生成答案时强制加citation
func (r *RAGEngine) GenerateAnswerWithCitations(ctx context.Context, query string, topChunks []Chunk) (*RAGAnswer, error) {
// 组织prompt:
// "根据以下参考文档回答问题。必须在答案中使用[chunk_id]标记引用。"
response, err := r.llmClient.Generate(ctx, GenerateRequest{
Messages: []Message{
{Role: "system", Content: systemPrompt},
{Role: "user", Content: fmt.Sprintf("参考文档:\n%s\n\n问题:%s", formatChunks(topChunks), query)},
},
})
// 从response里解析出[chunk_id]标记
citations := extractCitations(response.Content)
return &RAGAnswer{
Answer: response.Content,
Citations: citations,
Confidence: evaluateConfidence(citations),
}, nil
}
func evaluateConfidence(citations []Citation) string {
if len(citations) == 0 {
return "low" // 没引用 → 低信心
}
if len(citations) >= 2 {
return "high" // 多来源 → 高信心
}
return "medium"
}