feat: 人格文档双层架构 — persona.md全量注入system prompt + RAG黑名单过滤

- PersonaConfig 新增 NarrativePersona 字段,在 system prompt 的「你的身份」和「你的性格」之间插入「## 你的叙事人格」
- Loader.NewLoader 自动读取同目录 persona.md 注入所有 config;Reload 同步热更新
- RAG IngestDirectory 跳过 persona.md 和 _index.md,避免重复检索浪费token
- 新增 docs/dev-plan/12-next-phase-optimization.md 下一阶段优化大纲

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-22 20:25:45 +08:00
parent 6ef9e082a6
commit dbd89f39ab
3 changed files with 280 additions and 1 deletions
@@ -3,6 +3,7 @@ package persona
import (
"fmt"
"os"
"path/filepath"
"sync"
"gopkg.in/yaml.v3"
@@ -54,6 +55,17 @@ func NewLoader(personaDir string) (*Loader, error) {
return nil, fmt.Errorf("未找到任何人格配置文件")
}
// Load narrative persona from persona.md (same directory as YAML configs).
// This is the full-text personality narrative injected verbatim into the system prompt.
personaMDPath := filepath.Join(personaDir, "persona.md")
if data, err := os.ReadFile(personaMDPath); err == nil {
// Attach to every loaded persona config.
narrative := string(data)
for _, cfg := range l.configs {
cfg.NarrativePersona = narrative
}
}
return l, nil
}
@@ -82,6 +94,12 @@ func (l *Loader) Reload(name string, path string) error {
}
l.mu.Lock()
// Re-read persona.md to keep narrative persona in sync.
personaDir := filepath.Dir(path)
personaMDPath := filepath.Join(personaDir, "persona.md")
if data, err := os.ReadFile(personaMDPath); err == nil {
cfg.NarrativePersona = string(data)
}
l.configs[name] = &cfg
l.mu.Unlock()