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