feat: add governance and skill instruction providers, update instruction assembly logic
This commit is contained in:
@@ -21,11 +21,13 @@ import (
|
||||
)
|
||||
|
||||
type AgentFactory struct {
|
||||
chatModelFactory *ChatModelFactory
|
||||
toolFactory *ToolFactory
|
||||
instructionAssembler *InstructionAssembler
|
||||
projectInstructionProvider *ProjectInstructionProvider
|
||||
toolAppendixProvider *ToolAppendixProvider
|
||||
chatModelFactory *ChatModelFactory
|
||||
toolFactory *ToolFactory
|
||||
instructionAssembler *InstructionAssembler
|
||||
projectInstructionProvider *ProjectInstructionProvider
|
||||
governanceInstructionProvider *GovernanceInstructionProvider
|
||||
skillInstructionProvider *SkillInstructionProvider
|
||||
toolAppendixProvider *ToolAppendixProvider
|
||||
}
|
||||
|
||||
// BuildCustomerServiceAgentInput 定义客服 Agent 的装配输入。
|
||||
@@ -59,11 +61,13 @@ type BuildCustomerServiceAgentInput struct {
|
||||
|
||||
func NewAgentFactory() *AgentFactory {
|
||||
return &AgentFactory{
|
||||
chatModelFactory: NewChatModelFactory(),
|
||||
toolFactory: NewToolFactory(),
|
||||
instructionAssembler: NewInstructionAssembler(),
|
||||
projectInstructionProvider: NewProjectInstructionProvider(),
|
||||
toolAppendixProvider: NewToolAppendixProvider(),
|
||||
chatModelFactory: NewChatModelFactory(),
|
||||
toolFactory: NewToolFactory(),
|
||||
instructionAssembler: NewInstructionAssembler(),
|
||||
projectInstructionProvider: NewProjectInstructionProvider(),
|
||||
governanceInstructionProvider: NewGovernanceInstructionProvider(),
|
||||
skillInstructionProvider: NewSkillInstructionProvider(),
|
||||
toolAppendixProvider: NewToolAppendixProvider(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,45 +157,32 @@ func (f *AgentFactory) assembleAgentInstruction(aiAgent *models.AIAgent, selecte
|
||||
if aiAgent != nil {
|
||||
baseInstruction = strings.TrimSpace(aiAgent.SystemPrompt)
|
||||
}
|
||||
appendixParts := buildInstructionAppendices(selectedSkill, toolDefinitions, extraToolCodes)
|
||||
projectInstruction := ""
|
||||
governanceInstruction := ""
|
||||
skillInstruction := ""
|
||||
appendixParts := buildInstructionAppendices(toolDefinitions, extraToolCodes)
|
||||
if f != nil && f.projectInstructionProvider != nil {
|
||||
projectInstruction = f.projectInstructionProvider.Resolve()
|
||||
}
|
||||
if f != nil && f.governanceInstructionProvider != nil {
|
||||
governanceInstruction = f.governanceInstructionProvider.Resolve()
|
||||
}
|
||||
if f != nil && f.skillInstructionProvider != nil {
|
||||
skillInstruction = f.skillInstructionProvider.Resolve(selectedSkill)
|
||||
}
|
||||
assembler := NewInstructionAssembler()
|
||||
if f != nil && f.instructionAssembler != nil {
|
||||
assembler = f.instructionAssembler
|
||||
}
|
||||
return assembler.Assemble(InstructionAssemblerInput{
|
||||
AgentInstruction: baseInstruction,
|
||||
SkillInstruction: firstAppendixPart(appendixParts),
|
||||
ToolAppendices: remainingAppendixParts(appendixParts),
|
||||
ProjectInstruction: projectInstruction,
|
||||
AgentInstruction: baseInstruction,
|
||||
GovernanceInstruction: governanceInstruction,
|
||||
SkillInstruction: skillInstruction,
|
||||
ToolAppendices: appendixParts,
|
||||
ProjectInstruction: projectInstruction,
|
||||
})
|
||||
}
|
||||
|
||||
func firstAppendixPart(parts []string) string {
|
||||
if len(parts) == 0 {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(parts[0])
|
||||
}
|
||||
|
||||
func remainingAppendixParts(parts []string) []string {
|
||||
if len(parts) <= 1 {
|
||||
return nil
|
||||
}
|
||||
ret := make([]string, 0, len(parts)-1)
|
||||
for _, item := range parts[1:] {
|
||||
item = strings.TrimSpace(item)
|
||||
if item == "" {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, item)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func buildSelectedSkillActivationInstruction(skill *models.SkillDefinition) string {
|
||||
if skill == nil {
|
||||
return ""
|
||||
|
||||
@@ -2,15 +2,22 @@ package factory
|
||||
|
||||
import "strings"
|
||||
|
||||
const defaultGovernanceInstruction = `
|
||||
你正在一个有明确工程约束的客服系统中工作。
|
||||
执行时必须严格遵守当前注入的项目规则、Agent 规则和技能规则。
|
||||
如果存在工具白名单限制,只能调用当前允许的工具;信息不足时优先追问,不要伪造事实或跳过必要确认。
|
||||
`
|
||||
|
||||
type InstructionAssembler struct {
|
||||
governanceInstruction string
|
||||
}
|
||||
|
||||
type InstructionAssemblerInput struct {
|
||||
AgentInstruction string
|
||||
SkillInstruction string
|
||||
ToolAppendices []string
|
||||
ProjectInstruction string
|
||||
AgentInstruction string
|
||||
GovernanceInstruction string
|
||||
SkillInstruction string
|
||||
ToolAppendices []string
|
||||
ProjectInstruction string
|
||||
}
|
||||
|
||||
// InstructionAssemblySummary 描述 instruction 各组成部分的来源摘要。
|
||||
@@ -31,11 +38,7 @@ type InstructionAssemblyResult struct {
|
||||
|
||||
func NewInstructionAssembler() *InstructionAssembler {
|
||||
return &InstructionAssembler{
|
||||
governanceInstruction: strings.TrimSpace(`
|
||||
你正在一个有明确工程约束的客服系统中工作。
|
||||
执行时必须严格遵守当前注入的项目规则、Agent 规则和技能规则。
|
||||
如果存在工具白名单限制,只能调用当前允许的工具;信息不足时优先追问,不要伪造事实或跳过必要确认。
|
||||
`),
|
||||
governanceInstruction: strings.TrimSpace(defaultGovernanceInstruction),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,8 +59,12 @@ func (a *InstructionAssembler) Assemble(input InstructionAssemblerInput) Instruc
|
||||
summary.HasProjectRule = true
|
||||
summary.SectionTitles = append(summary.SectionTitles, "项目级规则")
|
||||
}
|
||||
if a != nil && strings.TrimSpace(a.governanceInstruction) != "" {
|
||||
parts = append(parts, buildInstructionSection("系统治理规则", a.governanceInstruction))
|
||||
governanceInstruction := strings.TrimSpace(input.GovernanceInstruction)
|
||||
if governanceInstruction == "" && a != nil {
|
||||
governanceInstruction = strings.TrimSpace(a.governanceInstruction)
|
||||
}
|
||||
if governanceInstruction != "" {
|
||||
parts = append(parts, buildInstructionSection("系统治理规则", governanceInstruction))
|
||||
summary.HasGovernanceRule = true
|
||||
summary.SectionTitles = append(summary.SectionTitles, "系统治理规则")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package factory
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInstructionAssemblerRespectsProvidedSources(t *testing.T) {
|
||||
result := NewInstructionAssembler().Assemble(InstructionAssemblerInput{
|
||||
ProjectInstruction: "project-rule",
|
||||
GovernanceInstruction: "governance-rule",
|
||||
AgentInstruction: "agent-rule",
|
||||
SkillInstruction: "skill-rule",
|
||||
ToolAppendices: []string{"tool-rule-1", "tool-rule-2"},
|
||||
})
|
||||
if !strings.Contains(result.Text, "项目级规则:\nproject-rule") {
|
||||
t.Fatalf("missing project instruction: %s", result.Text)
|
||||
}
|
||||
if !strings.Contains(result.Text, "系统治理规则:\ngovernance-rule") {
|
||||
t.Fatalf("missing governance instruction: %s", result.Text)
|
||||
}
|
||||
if !strings.Contains(result.Text, "当前技能上下文:\nskill-rule") {
|
||||
t.Fatalf("missing skill instruction: %s", result.Text)
|
||||
}
|
||||
if !strings.Contains(result.Text, "工具补充规则:\ntool-rule-1") {
|
||||
t.Fatalf("missing tool appendix: %s", result.Text)
|
||||
}
|
||||
if !result.Summary.HasProjectRule || !result.Summary.HasGovernanceRule || !result.Summary.HasAgentRule || !result.Summary.HasSkillRule || !result.Summary.HasToolRule {
|
||||
t.Fatalf("unexpected summary: %#v", result.Summary)
|
||||
}
|
||||
}
|
||||
@@ -67,11 +67,28 @@ func NewToolAppendixProvider() *ToolAppendixProvider {
|
||||
return &ToolAppendixProvider{}
|
||||
}
|
||||
|
||||
func (p *ToolAppendixProvider) Build(selectedSkill *models.SkillDefinition, toolDefinitions []einoadapter.MCPToolDefinition, extraToolCodes map[string]string) []string {
|
||||
appendixParts := make([]string, 0, 2)
|
||||
if skillInstruction := buildSelectedSkillActivationInstruction(selectedSkill); skillInstruction != "" {
|
||||
appendixParts = append(appendixParts, skillInstruction)
|
||||
}
|
||||
type GovernanceInstructionProvider struct{}
|
||||
|
||||
func NewGovernanceInstructionProvider() *GovernanceInstructionProvider {
|
||||
return &GovernanceInstructionProvider{}
|
||||
}
|
||||
|
||||
func (p *GovernanceInstructionProvider) Resolve() string {
|
||||
return strings.TrimSpace(defaultGovernanceInstruction)
|
||||
}
|
||||
|
||||
type SkillInstructionProvider struct{}
|
||||
|
||||
func NewSkillInstructionProvider() *SkillInstructionProvider {
|
||||
return &SkillInstructionProvider{}
|
||||
}
|
||||
|
||||
func (p *SkillInstructionProvider) Resolve(selectedSkill *models.SkillDefinition) string {
|
||||
return buildSelectedSkillActivationInstruction(selectedSkill)
|
||||
}
|
||||
|
||||
func (p *ToolAppendixProvider) Build(toolDefinitions []einoadapter.MCPToolDefinition, extraToolCodes map[string]string) []string {
|
||||
appendixParts := make([]string, 0, 1)
|
||||
toolCodes := make([]string, 0, len(toolDefinitions)+len(extraToolCodes))
|
||||
for _, item := range toolDefinitions {
|
||||
toolCodes = append(toolCodes, item.ToolCode)
|
||||
|
||||
@@ -56,6 +56,6 @@ func buildRuntimeTraceToolMetadata(
|
||||
return ret
|
||||
}
|
||||
|
||||
func buildInstructionAppendices(selectedSkill *models.SkillDefinition, toolDefinitions []einoadapter.MCPToolDefinition, extraToolCodes map[string]string) []string {
|
||||
return NewToolAppendixProvider().Build(selectedSkill, toolDefinitions, extraToolCodes)
|
||||
func buildInstructionAppendices(toolDefinitions []einoadapter.MCPToolDefinition, extraToolCodes map[string]string) []string {
|
||||
return NewToolAppendixProvider().Build(toolDefinitions, extraToolCodes)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user