feat: add rag answerability gate types
This commit is contained in:
@@ -0,0 +1,78 @@
|
|||||||
|
package executor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"cs-agent/internal/ai/runtime/internal/impl/callbacks"
|
||||||
|
"cs-agent/internal/ai/runtime/internal/impl/factory"
|
||||||
|
"cs-agent/internal/ai/runtime/internal/impl/retrievers"
|
||||||
|
"cs-agent/internal/models"
|
||||||
|
|
||||||
|
"github.com/cloudwego/eino/components/model"
|
||||||
|
"github.com/cloudwego/eino/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
answerabilityNodeRetrieve = "retrieve_knowledge"
|
||||||
|
answerabilityNodeGrade = "grade_answerability"
|
||||||
|
answerabilityNodeAllow = "allow_agent"
|
||||||
|
answerabilityNodeFallback = "fallback"
|
||||||
|
|
||||||
|
answerabilityStatusSkipped = "skipped"
|
||||||
|
answerabilityStatusAnswerable = "answerable"
|
||||||
|
answerabilityStatusUnanswerable = "unanswerable"
|
||||||
|
)
|
||||||
|
|
||||||
|
type knowledgeContextRetriever interface {
|
||||||
|
KnowledgeBaseIDs() []int64
|
||||||
|
RetrieveContextByOptions(ctx context.Context, opts retrievers.KnowledgeRetrieveOptions, query string) (*retrievers.KnowledgeRetrieveResult, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type answerabilityRetrieverFactory func(aiAgent models.AIAgent) knowledgeContextRetriever
|
||||||
|
|
||||||
|
type answerabilityChatModelFactory func(ctx context.Context, aiConfig models.AIConfig) (model.BaseChatModel, error)
|
||||||
|
|
||||||
|
type KnowledgeAnswerabilityGate struct {
|
||||||
|
newRetriever answerabilityRetrieverFactory
|
||||||
|
newChatModel answerabilityChatModelFactory
|
||||||
|
now func() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type answerabilityGateInput struct {
|
||||||
|
Request RunInput
|
||||||
|
Summary *RunResult
|
||||||
|
Collector *callbacks.RuntimeTraceCollector
|
||||||
|
Messages []*schema.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
type answerabilityGateState struct {
|
||||||
|
Input answerabilityGateInput
|
||||||
|
KnowledgeIDs []int64
|
||||||
|
RetrieveResult *retrievers.KnowledgeRetrieveResult
|
||||||
|
Decision knowledgeGuardDecision
|
||||||
|
Grade answerabilityDecision
|
||||||
|
SkipGate bool
|
||||||
|
FallbackReply string
|
||||||
|
ErrorMessage string
|
||||||
|
}
|
||||||
|
|
||||||
|
type answerabilityDecision struct {
|
||||||
|
Answerable bool `json:"answerable"`
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
SupportingChunkIDs []string `json:"supportingChunkIds"`
|
||||||
|
MissingInfo []string `json:"missingInfo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewKnowledgeAnswerabilityGate() *KnowledgeAnswerabilityGate {
|
||||||
|
chatModelFactory := factory.NewChatModelFactory()
|
||||||
|
return &KnowledgeAnswerabilityGate{
|
||||||
|
newRetriever: func(aiAgent models.AIAgent) knowledgeContextRetriever {
|
||||||
|
return retrievers.NewKnowledgeRetriever(aiAgent)
|
||||||
|
},
|
||||||
|
newChatModel: func(ctx context.Context, aiConfig models.AIConfig) (model.BaseChatModel, error) {
|
||||||
|
return chatModelFactory.Build(ctx, aiConfig)
|
||||||
|
},
|
||||||
|
now: time.Now,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,6 +51,18 @@ func resolveKnowledgeFallbackReply(aiAgent models.AIAgent) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resolveKnowledgeHumanSupportFallback(aiAgent models.AIAgent) string {
|
||||||
|
base := strings.TrimSpace(resolveKnowledgeFallbackReply(aiAgent))
|
||||||
|
if base == "" {
|
||||||
|
base = "当前知识库暂无明确信息。"
|
||||||
|
}
|
||||||
|
suggestion := "建议你联系人工客服进一步确认。"
|
||||||
|
if strings.Contains(base, suggestion) {
|
||||||
|
return base
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(base + " " + suggestion)
|
||||||
|
}
|
||||||
|
|
||||||
func buildKnowledgeRuntimeInstruction(answerMode enums.KnowledgeAnswerMode, fallbackReply string) string {
|
func buildKnowledgeRuntimeInstruction(answerMode enums.KnowledgeAnswerMode, fallbackReply string) string {
|
||||||
fallbackReply = strings.TrimSpace(fallbackReply)
|
fallbackReply = strings.TrimSpace(fallbackReply)
|
||||||
if fallbackReply == "" {
|
if fallbackReply == "" {
|
||||||
|
|||||||
@@ -100,6 +100,29 @@ func TestBuildKnowledgeUnavailableDecisionSkipsWhenAgentHasNoKnowledge(t *testin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestResolveKnowledgeHumanSupportFallbackUsesAgentMessage(t *testing.T) {
|
||||||
|
agent := newKnowledgeGuardAgentFixture()
|
||||||
|
agent.FallbackMessage = "我暂时没有找到足够准确的信息。"
|
||||||
|
|
||||||
|
got := resolveKnowledgeHumanSupportFallback(agent)
|
||||||
|
|
||||||
|
want := "我暂时没有找到足够准确的信息。 建议你联系人工客服进一步确认。"
|
||||||
|
if got != want {
|
||||||
|
t.Fatalf("unexpected fallback: %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveKnowledgeHumanSupportFallbackUsesDefault(t *testing.T) {
|
||||||
|
agent := newKnowledgeGuardAgentFixture()
|
||||||
|
|
||||||
|
got := resolveKnowledgeHumanSupportFallback(agent)
|
||||||
|
|
||||||
|
want := "当前知识库暂无明确信息。 建议你联系人工客服进一步确认。"
|
||||||
|
if got != want {
|
||||||
|
t.Fatalf("unexpected fallback: %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func newKnowledgeGuardAgentFixture() models.AIAgent {
|
func newKnowledgeGuardAgentFixture() models.AIAgent {
|
||||||
return models.AIAgent{
|
return models.AIAgent{
|
||||||
FallbackMode: enums.AIAgentFallbackModeNoAnswer,
|
FallbackMode: enums.AIAgentFallbackModeNoAnswer,
|
||||||
|
|||||||
Reference in New Issue
Block a user