refactor(instruction): remove governance instruction handling and update related tests
This commit is contained in:
Vendored
+13
-8
@@ -72,17 +72,22 @@ func buildSeedItems(aiConfigID int64, knowledgeIDs []int64, defaultTeamIDs strin
|
||||
now := time.Now()
|
||||
return []models.AIAgent{
|
||||
{
|
||||
Name: "测试AI客服",
|
||||
Description: "本地测试 AI 客服 Agent",
|
||||
Status: enums.StatusOk,
|
||||
AIConfigID: aiConfigID,
|
||||
ServiceMode: enums.IMConversationServiceModeAIFirst,
|
||||
SystemPrompt: "你是一个友好的客服助手,请用中文回答用户的问题。",
|
||||
WelcomeMessage: "您好,欢迎咨询!有什么可以帮助您的?",
|
||||
Name: "测试AI客服",
|
||||
Description: "本地测试 AI 客服 Agent",
|
||||
Status: enums.StatusOk,
|
||||
AIConfigID: aiConfigID,
|
||||
ServiceMode: enums.IMConversationServiceModeAIFirst,
|
||||
SystemPrompt: `你正在一个有明确工程约束的客服系统中工作。
|
||||
执行时必须严格遵守当前注入的 Agent 规则和技能规则。
|
||||
如果存在工具白名单限制,只能调用当前允许的工具;信息不足时优先追问,不要伪造事实或跳过必要确认。
|
||||
禁止承诺未经系统确认的处理时效、完成时间、回访时间或联系时间。
|
||||
禁止代表人工团队、技术团队、售后团队承诺后续动作,除非当前上下文已有明确的工具结果、人工确认或知识库事实支持。
|
||||
当用户只表示已发送资料、邮件、截图或附件时,只能确认已收到当前消息或建议等待人工确认,不能自行补充内部处理流程、SLA 或跟进安排。`,
|
||||
WelcomeMessage: "您好,有什么可以帮助您的?",
|
||||
ReplyTimeoutSeconds: 180,
|
||||
TeamIDs: defaultTeamIDs,
|
||||
HandoffMode: enums.AIAgentHandoffModeWaitPool,
|
||||
FallbackMessage: "我暂时没有找到足够准确的信息。你可以补充订单号、产品名或更具体的问题,我再继续帮你查。",
|
||||
FallbackMessage: "我暂时没有找到足够准确的信息。你可以补充具体的问题,我再继续帮你查。",
|
||||
KnowledgeIDs: utils.JoinInt64s(knowledgeIDs),
|
||||
SkillIDs: defaultSkillIDs,
|
||||
SortNo: 10,
|
||||
|
||||
@@ -5,18 +5,16 @@ import "strings"
|
||||
type Assembler struct{}
|
||||
|
||||
type AssemblerInput struct {
|
||||
AgentInstruction string
|
||||
GovernanceInstruction string
|
||||
SkillInstruction string
|
||||
ToolAppendices []string
|
||||
AgentInstruction string
|
||||
SkillInstruction string
|
||||
ToolAppendices []string
|
||||
}
|
||||
|
||||
type AssemblySummary struct {
|
||||
SectionTitles []string
|
||||
HasGovernanceRule bool
|
||||
HasAgentRule bool
|
||||
HasSkillRule bool
|
||||
HasToolRule bool
|
||||
SectionTitles []string
|
||||
HasAgentRule bool
|
||||
HasSkillRule bool
|
||||
HasToolRule bool
|
||||
}
|
||||
|
||||
type AssemblyResult struct {
|
||||
@@ -33,14 +31,8 @@ func (a *Assembler) Build(input AssemblerInput) string {
|
||||
}
|
||||
|
||||
func (a *Assembler) Assemble(input AssemblerInput) AssemblyResult {
|
||||
parts := make([]string, 0, 4)
|
||||
summary := AssemblySummary{SectionTitles: make([]string, 0, 4)}
|
||||
governanceInstruction := strings.TrimSpace(input.GovernanceInstruction)
|
||||
if governanceInstruction != "" {
|
||||
parts = append(parts, buildInstructionSection("系统治理规则", governanceInstruction))
|
||||
summary.HasGovernanceRule = true
|
||||
summary.SectionTitles = append(summary.SectionTitles, "系统治理规则")
|
||||
}
|
||||
parts := make([]string, 0, 3)
|
||||
summary := AssemblySummary{SectionTitles: make([]string, 0, 3)}
|
||||
if agentInstruction := strings.TrimSpace(input.AgentInstruction); agentInstruction != "" {
|
||||
parts = append(parts, buildInstructionSection("Agent 规则", agentInstruction))
|
||||
summary.HasAgentRule = true
|
||||
|
||||
@@ -7,13 +7,12 @@ import (
|
||||
|
||||
func TestAssemblerRespectsProvidedSources(t *testing.T) {
|
||||
result := NewAssembler().Assemble(AssemblerInput{
|
||||
GovernanceInstruction: "governance-rule",
|
||||
AgentInstruction: "agent-rule",
|
||||
SkillInstruction: "skill-rule",
|
||||
ToolAppendices: []string{"tool-rule-1", "tool-rule-2"},
|
||||
AgentInstruction: "agent-rule",
|
||||
SkillInstruction: "skill-rule",
|
||||
ToolAppendices: []string{"tool-rule-1", "tool-rule-2"},
|
||||
})
|
||||
if !strings.Contains(result.Text, "系统治理规则:\ngovernance-rule") {
|
||||
t.Fatalf("missing governance instruction: %s", result.Text)
|
||||
if !strings.Contains(result.Text, "Agent 规则:\nagent-rule") {
|
||||
t.Fatalf("missing agent instruction: %s", result.Text)
|
||||
}
|
||||
if !strings.Contains(result.Text, "当前技能上下文:\nskill-rule") {
|
||||
t.Fatalf("missing skill instruction: %s", result.Text)
|
||||
@@ -21,17 +20,17 @@ func TestAssemblerRespectsProvidedSources(t *testing.T) {
|
||||
if !strings.Contains(result.Text, "工具补充规则:\ntool-rule-1") {
|
||||
t.Fatalf("missing tool appendix: %s", result.Text)
|
||||
}
|
||||
if !result.Summary.HasGovernanceRule || !result.Summary.HasAgentRule || !result.Summary.HasSkillRule || !result.Summary.HasToolRule {
|
||||
if !result.Summary.HasAgentRule || !result.Summary.HasSkillRule || !result.Summary.HasToolRule {
|
||||
t.Fatalf("unexpected summary: %#v", result.Summary)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAssemblerDoesNotInjectGovernanceInstructionWhenInputIsEmpty(t *testing.T) {
|
||||
func TestAssemblerReturnsEmptyTextWhenInputIsEmpty(t *testing.T) {
|
||||
result := NewAssembler().Assemble(AssemblerInput{})
|
||||
if result.Text != "" {
|
||||
t.Fatalf("expected empty assembled text, got: %s", result.Text)
|
||||
}
|
||||
if result.Summary.HasGovernanceRule {
|
||||
t.Fatalf("expected no governance rule summary, got %#v", result.Summary)
|
||||
if len(result.Summary.SectionTitles) != 0 || result.Summary.HasAgentRule || result.Summary.HasSkillRule || result.Summary.HasToolRule {
|
||||
t.Fatalf("expected empty summary, got %#v", result.Summary)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,17 @@
|
||||
package instruction
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
runtimetooling "cs-agent/internal/ai/runtime/tooling"
|
||||
"cs-agent/internal/ai/runtime/tooling"
|
||||
"cs-agent/internal/models"
|
||||
"cs-agent/internal/pkg/toolx"
|
||||
)
|
||||
|
||||
const defaultGovernanceInstruction = `
|
||||
你正在一个有明确工程约束的客服系统中工作。
|
||||
执行时必须严格遵守当前注入的 Agent 规则和技能规则。
|
||||
如果存在工具白名单限制,只能调用当前允许的工具;信息不足时优先追问,不要伪造事实或跳过必要确认。
|
||||
禁止承诺未经系统确认的处理时效、完成时间、回访时间或联系时间。
|
||||
禁止代表人工团队、技术团队、售后团队承诺后续动作,除非当前上下文已有明确的工具结果、人工确认或知识库事实支持。
|
||||
当用户只表示已发送资料、邮件、截图或附件时,只能确认已收到当前消息或建议等待人工确认,不能自行补充内部处理流程、SLA 或跟进安排。
|
||||
`
|
||||
|
||||
type ToolAppendixProvider struct{}
|
||||
|
||||
func NewToolAppendixProvider() *ToolAppendixProvider {
|
||||
return &ToolAppendixProvider{}
|
||||
}
|
||||
|
||||
type GovernanceInstructionProvider struct{}
|
||||
|
||||
func NewGovernanceInstructionProvider() *GovernanceInstructionProvider {
|
||||
return &GovernanceInstructionProvider{}
|
||||
}
|
||||
|
||||
func (p *GovernanceInstructionProvider) Resolve() string {
|
||||
return strings.TrimSpace(defaultGovernanceInstruction)
|
||||
}
|
||||
|
||||
type SkillInstructionProvider struct{}
|
||||
|
||||
func NewSkillInstructionProvider() *SkillInstructionProvider {
|
||||
@@ -43,7 +22,7 @@ func (p *SkillInstructionProvider) Resolve(selectedSkill *models.SkillDefinition
|
||||
return BuildSelectedSkillActivationInstruction(selectedSkill)
|
||||
}
|
||||
|
||||
func (p *ToolAppendixProvider) Build(toolDefinitions []runtimetooling.MCPToolDefinition, extraToolCodes map[string]string) []string {
|
||||
func (p *ToolAppendixProvider) Build(toolDefinitions []tooling.MCPToolDefinition, extraToolCodes map[string]string) []string {
|
||||
appendixParts := make([]string, 0, 1)
|
||||
toolCodes := make([]string, 0, len(toolDefinitions)+len(extraToolCodes))
|
||||
for _, item := range toolDefinitions {
|
||||
|
||||
@@ -3,38 +3,45 @@ package instruction
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"cs-agent/internal/ai/runtime/tooling"
|
||||
runtimetooling "cs-agent/internal/ai/runtime/tooling"
|
||||
"cs-agent/internal/models"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
assembler *Assembler
|
||||
governanceInstructionProvider *GovernanceInstructionProvider
|
||||
skillInstructionProvider *SkillInstructionProvider
|
||||
toolAppendixProvider *ToolAppendixProvider
|
||||
assembler *Assembler
|
||||
skillInstructionProvider *SkillInstructionProvider
|
||||
toolAppendixProvider *ToolAppendixProvider
|
||||
}
|
||||
|
||||
func NewService() *Service {
|
||||
func NewService(
|
||||
assembler *Assembler,
|
||||
skillProvider *SkillInstructionProvider,
|
||||
toolProvider *ToolAppendixProvider,
|
||||
) *Service {
|
||||
if assembler == nil {
|
||||
assembler = NewAssembler()
|
||||
}
|
||||
if skillProvider == nil {
|
||||
skillProvider = NewSkillInstructionProvider()
|
||||
}
|
||||
if toolProvider == nil {
|
||||
toolProvider = NewToolAppendixProvider()
|
||||
}
|
||||
return &Service{
|
||||
assembler: NewAssembler(),
|
||||
governanceInstructionProvider: NewGovernanceInstructionProvider(),
|
||||
skillInstructionProvider: NewSkillInstructionProvider(),
|
||||
toolAppendixProvider: NewToolAppendixProvider(),
|
||||
assembler: assembler,
|
||||
skillInstructionProvider: skillProvider,
|
||||
toolAppendixProvider: toolProvider,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) Build(
|
||||
aiAgent models.AIAgent,
|
||||
selectedSkill *models.SkillDefinition,
|
||||
toolDefinitions []tooling.MCPToolDefinition,
|
||||
toolDefinitions []runtimetooling.MCPToolDefinition,
|
||||
extraToolCodes map[string]string,
|
||||
) AssemblyResult {
|
||||
governanceInstruction := ""
|
||||
skillInstruction := ""
|
||||
toolAppendices := make([]string, 0)
|
||||
if s != nil && s.governanceInstructionProvider != nil {
|
||||
governanceInstruction = s.governanceInstructionProvider.Resolve()
|
||||
}
|
||||
if s != nil && s.skillInstructionProvider != nil {
|
||||
skillInstruction = s.skillInstructionProvider.Resolve(selectedSkill)
|
||||
}
|
||||
@@ -46,9 +53,8 @@ func (s *Service) Build(
|
||||
assembler = s.assembler
|
||||
}
|
||||
return assembler.Assemble(AssemblerInput{
|
||||
AgentInstruction: strings.TrimSpace(aiAgent.SystemPrompt),
|
||||
GovernanceInstruction: governanceInstruction,
|
||||
SkillInstruction: skillInstruction,
|
||||
ToolAppendices: toolAppendices,
|
||||
AgentInstruction: strings.TrimSpace(aiAgent.SystemPrompt),
|
||||
SkillInstruction: skillInstruction,
|
||||
ToolAppendices: toolAppendices,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ func (c *RuntimeTraceCollector) SetInstructionSummary(summary InstructionTraceSu
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.Data.Instruction.SectionTitles = append([]string(nil), summary.SectionTitles...)
|
||||
c.Data.Instruction.HasGovernanceRule = summary.HasGovernanceRule
|
||||
c.Data.Instruction.HasAgentRule = summary.HasAgentRule
|
||||
c.Data.Instruction.HasSkillRule = summary.HasSkillRule
|
||||
c.Data.Instruction.HasToolRule = summary.HasToolRule
|
||||
|
||||
@@ -70,11 +70,10 @@ type RetrieverPolicyTraceItem struct {
|
||||
}
|
||||
|
||||
type InstructionTraceSummary struct {
|
||||
SectionTitles []string
|
||||
HasGovernanceRule bool
|
||||
HasAgentRule bool
|
||||
HasSkillRule bool
|
||||
HasToolRule bool
|
||||
SectionTitles []string
|
||||
HasAgentRule bool
|
||||
HasSkillRule bool
|
||||
HasToolRule bool
|
||||
}
|
||||
|
||||
type RuntimeTraceData struct {
|
||||
@@ -91,11 +90,10 @@ type RuntimeTraceData struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
} `json:"model"`
|
||||
Instruction struct {
|
||||
SectionTitles []string `json:"sectionTitles,omitempty"`
|
||||
HasGovernanceRule bool `json:"hasGovernanceRule,omitempty"`
|
||||
HasAgentRule bool `json:"hasAgentRule,omitempty"`
|
||||
HasSkillRule bool `json:"hasSkillRule,omitempty"`
|
||||
HasToolRule bool `json:"hasToolRule,omitempty"`
|
||||
SectionTitles []string `json:"sectionTitles,omitempty"`
|
||||
HasAgentRule bool `json:"hasAgentRule,omitempty"`
|
||||
HasSkillRule bool `json:"hasSkillRule,omitempty"`
|
||||
HasToolRule bool `json:"hasToolRule,omitempty"`
|
||||
} `json:"instruction"`
|
||||
Input struct {
|
||||
HistoryMessageCount int `json:"historyMessageCount,omitempty"`
|
||||
|
||||
@@ -56,7 +56,7 @@ func NewAgentFactory() *AgentFactory {
|
||||
return &AgentFactory{
|
||||
chatModelFactory: NewChatModelFactory(),
|
||||
toolFactory: NewToolFactory(),
|
||||
instructionService: instruction.NewService(),
|
||||
instructionService: instruction.NewService(nil, nil, nil),
|
||||
handlerService: NewAgentHandlerService(nil),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ func TestAgentHandlerServiceBuildWithCollectorOnly(t *testing.T) {
|
||||
handlers, err := service.Build(context.Background(), BuildAgentHandlersInput{
|
||||
Collector: collector,
|
||||
InstructionSummary: einocallbacks.InstructionTraceSummary{
|
||||
SectionTitles: []string{"系统治理规则"},
|
||||
HasGovernanceRule: true,
|
||||
SectionTitles: []string{"Agent 规则"},
|
||||
HasAgentRule: true,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -24,7 +24,7 @@ func TestAgentHandlerServiceBuildWithCollectorOnly(t *testing.T) {
|
||||
if len(handlers) != 1 {
|
||||
t.Fatalf("expected 1 handler, got %d", len(handlers))
|
||||
}
|
||||
if !collector.Data.Instruction.HasGovernanceRule {
|
||||
if !collector.Data.Instruction.HasAgentRule {
|
||||
t.Fatalf("instruction summary was not written to collector: %#v", collector.Data.Instruction)
|
||||
}
|
||||
if len(collector.Data.Instruction.SectionTitles) != 1 {
|
||||
|
||||
@@ -14,11 +14,10 @@ import (
|
||||
|
||||
func buildInstructionTraceSummary(summary runtimeinstruction.AssemblySummary) einocallbacks.InstructionTraceSummary {
|
||||
return einocallbacks.InstructionTraceSummary{
|
||||
SectionTitles: append([]string(nil), summary.SectionTitles...),
|
||||
HasGovernanceRule: summary.HasGovernanceRule,
|
||||
HasAgentRule: summary.HasAgentRule,
|
||||
HasSkillRule: summary.HasSkillRule,
|
||||
HasToolRule: summary.HasToolRule,
|
||||
SectionTitles: append([]string(nil), summary.SectionTitles...),
|
||||
HasAgentRule: summary.HasAgentRule,
|
||||
HasSkillRule: summary.HasSkillRule,
|
||||
HasToolRule: summary.HasToolRule,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,17 +8,16 @@ import (
|
||||
|
||||
func TestBuildInstructionTraceSummary(t *testing.T) {
|
||||
got := buildInstructionTraceSummary(runtimeinstruction.AssemblySummary{
|
||||
SectionTitles: []string{"系统治理规则", "当前技能上下文"},
|
||||
HasGovernanceRule: true,
|
||||
HasAgentRule: true,
|
||||
HasSkillRule: true,
|
||||
HasToolRule: false,
|
||||
SectionTitles: []string{"Agent 规则", "当前技能上下文"},
|
||||
HasAgentRule: true,
|
||||
HasSkillRule: true,
|
||||
HasToolRule: false,
|
||||
})
|
||||
|
||||
if len(got.SectionTitles) != 2 {
|
||||
t.Fatalf("unexpected section titles: %#v", got.SectionTitles)
|
||||
}
|
||||
if !got.HasGovernanceRule || !got.HasAgentRule || !got.HasSkillRule {
|
||||
if !got.HasAgentRule || !got.HasSkillRule {
|
||||
t.Fatalf("unexpected summary flags: %#v", got)
|
||||
}
|
||||
if got.HasToolRule {
|
||||
|
||||
Reference in New Issue
Block a user