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:
@@ -17,6 +17,11 @@ type PersonaConfig struct {
|
|||||||
ThinkingGuidelines ThinkingGuidelines `yaml:"thinking_guidelines"`
|
ThinkingGuidelines ThinkingGuidelines `yaml:"thinking_guidelines"`
|
||||||
MemoryGuidelines MemoryGuidelines `yaml:"memory_guidelines"`
|
MemoryGuidelines MemoryGuidelines `yaml:"memory_guidelines"`
|
||||||
ReflectionGuidelines ReflectionGuidelines `yaml:"reflection_guidelines"`
|
ReflectionGuidelines ReflectionGuidelines `yaml:"reflection_guidelines"`
|
||||||
|
|
||||||
|
// NarrativePersona is the full text of persona.md, injected verbatim
|
||||||
|
// into the system prompt as the narrative personality layer.
|
||||||
|
// Not parsed from YAML — loaded from persona.md alongside the YAML config.
|
||||||
|
NarrativePersona string `yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildSystemPrompt 构建系统Prompt (向后兼容,不含心情)
|
// BuildSystemPrompt 构建系统Prompt (向后兼容,不含心情)
|
||||||
@@ -43,8 +48,11 @@ func (pc *PersonaConfig) BuildSystemPromptWithMood(userName string, affectionLev
|
|||||||
## 你的身份
|
## 你的身份
|
||||||
%s
|
%s
|
||||||
|
|
||||||
|
## 你的叙事人格
|
||||||
|
%s
|
||||||
|
|
||||||
## 你的性格
|
## 你的性格
|
||||||
`, pc.Identity.TrueName, pc.Identity.Essence)
|
`, pc.Identity.TrueName, pc.Identity.Essence, pc.NarrativePersona)
|
||||||
|
|
||||||
for _, trait := range pc.Personality.CoreTraits {
|
for _, trait := range pc.Personality.CoreTraits {
|
||||||
prompt += fmt.Sprintf("- %s: %s\n", trait.Name, trait.Description)
|
prompt += fmt.Sprintf("- %s: %s\n", trait.Name, trait.Description)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package persona
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
@@ -54,6 +55,17 @@ func NewLoader(personaDir string) (*Loader, error) {
|
|||||||
return nil, fmt.Errorf("未找到任何人格配置文件")
|
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
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +94,12 @@ func (l *Loader) Reload(name string, path string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
l.mu.Lock()
|
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.configs[name] = &cfg
|
||||||
l.mu.Unlock()
|
l.mu.Unlock()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,253 @@
|
|||||||
|
# 12 — 下一阶段优化大纲
|
||||||
|
|
||||||
|
> **日期**:2026-06-22
|
||||||
|
> **来源**:对照 Cyrene 人格、记忆及功能拓展架构设计文档,逐项比对现状后梳理
|
||||||
|
> **状态**:大纲,待拆分为详细实施计划
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
1. [P0 — 自主思考分层](#1-p0--自主思考分层)
|
||||||
|
2. [P1 — LLM 可自主操作提醒与日程](#2-p1--llm-可自主操作提醒与日程)
|
||||||
|
3. [P2 — 对话后处理补全](#3-p2--对话后处理补全)
|
||||||
|
4. [P3 — 群聊并发(协会议话)](#4-p3--群聊并协会议话)
|
||||||
|
5. [P4 — 多平台前缀统一抽象](#5-p4--多平台前缀统一抽象)
|
||||||
|
6. [P5 — 工具子会话增强](#6-p5--工具子会话增强)
|
||||||
|
7. [实施顺序建议](#7-实施顺序建议)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. P0 — 自主思考分层
|
||||||
|
|
||||||
|
### 现状
|
||||||
|
|
||||||
|
所有后台思考(periodic / silence / post_chat / startup)共用同一个 LLM 模型和同一套 system prompt。高频短思考(如每分钟检查状态)和低频深度反思(如每 5 分钟整理记忆)没有区分,浪费 token。
|
||||||
|
|
||||||
|
### 目标
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────┐ 唤醒 ┌─────────────┐
|
||||||
|
│ 简单思考 │ ──────────────► │ 复杂思考 │
|
||||||
|
│ (下位模型) │ │ (思考模型) │
|
||||||
|
│ 高频/轻量 │ │ 低频/深度 │
|
||||||
|
│ 例: 每分钟 │ │ 例: 每5分钟 │
|
||||||
|
└──────┬───────┘ └──────┬───────┘
|
||||||
|
│ 可调用工具 │ 可调用工具
|
||||||
|
│ 可主动消息 │ 可主动消息
|
||||||
|
│ 可追加继续 │ 可追加继续
|
||||||
|
▼ ▼
|
||||||
|
共享 ProactiveGuard 频率控制
|
||||||
|
```
|
||||||
|
|
||||||
|
### 要点
|
||||||
|
|
||||||
|
- **模型配置**:简单思考用 fast/flash 模型(temperature 0.3),复杂思考用 thinking 模型(temperature 0.7)
|
||||||
|
- **周期**:简单思考 30-60s / 复杂思考 300s(可配置)
|
||||||
|
- **唤醒**:简单思考可判定"需要深思"→ 触发一次复杂思考
|
||||||
|
- **追加**:两种思考都允许 `continue` 信号追加(当前只有 post_chat 可追加)
|
||||||
|
- **后处理**:每次复杂思考结束后触发记忆整理
|
||||||
|
|
||||||
|
### 涉及文件
|
||||||
|
|
||||||
|
| 文件 | 改动 |
|
||||||
|
|------|------|
|
||||||
|
| `background/thinker.go` | Thinker 拆分为 SimpleThinker + DeepThinker 或增加双模式循环 |
|
||||||
|
| `config/loader.go` → `models.json` | 新增 `simple_think` / `deep_think` 路由 |
|
||||||
|
| `background/thinker.go` → `buildThinkingSystemPrompt` | 简单/复杂两套 prompt |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. P1 — LLM 可自主操作提醒与日程
|
||||||
|
|
||||||
|
### 现状
|
||||||
|
|
||||||
|
Gateway 有 Reminder CRUD API,但 LLM 无法调用——没有注册 `reminder_create` / `reminder_update` / `schedule_query` 工具。昔涟不能在思考中说"明天早上 8 点提醒开拓者开会",因为这句话无法转化为实际的定时提醒。
|
||||||
|
|
||||||
|
### 目标
|
||||||
|
|
||||||
|
在 AI-Core 的 ToolRegistry 中新增 3-4 个提醒/日程工具,LLM 可在对话中或自主思考中调用。
|
||||||
|
|
||||||
|
### 要点
|
||||||
|
|
||||||
|
- **工具列表**:
|
||||||
|
- `reminder_create(time, content, repeat?)` → 创建提醒
|
||||||
|
- `reminder_list()` → 列出当前用户的提醒
|
||||||
|
- `reminder_delete(id)` → 删除提醒
|
||||||
|
- `schedule_query(date)` → 查询某一天的日程
|
||||||
|
- **实现方式**:HTTP 调用 Gateway `/api/v1/reminders` API(已有后端 CRUD)
|
||||||
|
- **自主思考可调用**:加入 `AutonomousToolPolicy.AllowedTools` 白名单
|
||||||
|
- **防止阻塞**:配置 `THINK_SCHEDULE_WINDOW` 环境变量,在提醒时间窗口内确保简单思考被唤醒
|
||||||
|
|
||||||
|
### 涉及文件
|
||||||
|
|
||||||
|
| 文件 | 改动 |
|
||||||
|
|------|------|
|
||||||
|
| `ai-core/internal/tools/reminder_tool.go` | **新建** — 3-4 个 reminders 工具 |
|
||||||
|
| `ai-core/cmd/main.go` | 注册提醒工具到 ToolRegistry |
|
||||||
|
| `background/thinker.go` → `AutonomousToolPolicy` | 允许提醒工具在自主思考中调用 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. P2 — 对话后处理补全
|
||||||
|
|
||||||
|
### 3.1 自主思考后触发记忆整理
|
||||||
|
|
||||||
|
**现状**:记忆提取(`ExtractMemoriesOnly`)只在 `platform_silent` 和正常对话后触发。自主思考(periodic/silence/startup)结束后不触发。
|
||||||
|
|
||||||
|
**目标**:复杂思考结束后自动调用一次记忆整理。
|
||||||
|
|
||||||
|
**涉及文件**:`background/thinker.go` → `performThink` 的结尾逻辑
|
||||||
|
|
||||||
|
### 3.2 对话后思考可追加
|
||||||
|
|
||||||
|
**现状**:`post_chat` 思考支持追加(`allowContinuation` + `triggerReason == "post_chat"`),但 `periodic` / `silence` 不支持。
|
||||||
|
|
||||||
|
**目标**:所有思考类型都支持 `continue` 信号追加,通过 `MaxContinuationRounds` 限制防止死循环。
|
||||||
|
|
||||||
|
**涉及文件**:`background/thinker.go` → 思考循环的 `allowContinuation` 条件
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. P3 — 群聊并发(协会议话)
|
||||||
|
|
||||||
|
### 现状
|
||||||
|
|
||||||
|
一个 session 的消息处理是严格线性的。当多个 QQ 用户同时在群里 @ 昔涟时:
|
||||||
|
- 消息按到达顺序排队
|
||||||
|
- 每条的 LLM 合成延迟 3-4s
|
||||||
|
- 第 3 条消息要等前面 2 条处理完才开始回复(6-8s 延迟)
|
||||||
|
|
||||||
|
### 目标
|
||||||
|
|
||||||
|
```
|
||||||
|
主会话 (session_id=platform_qq_<groupID>)
|
||||||
|
│
|
||||||
|
├─ 消息A → 主会话处理 (LLM 合成中...)
|
||||||
|
│
|
||||||
|
├─ 消息B (主会话繁忙) → 协会议话 B (独立 LLM 合成)
|
||||||
|
│ └─ 完成 → 结果写入主会话上下文
|
||||||
|
│
|
||||||
|
└─ 消息C (主会话繁忙) → 协会议话 C (独立 LLM 合成)
|
||||||
|
└─ 完成 → 结果写入主会话上下文
|
||||||
|
```
|
||||||
|
|
||||||
|
### 要点
|
||||||
|
|
||||||
|
- **并发检测**:收到新消息时,检查主会话是否正在处理(`isProcessing` 标记)
|
||||||
|
- **协会议话**:独立 goroutine + 独立 LLM 调用,共享主会话的对话历史
|
||||||
|
- **结果合并**:协会议话完成后,回复通过 platform-bridge 发送,上下文摘要写回主会话
|
||||||
|
- **数量限制**:最多 3 个协会议话并行,超出则排队
|
||||||
|
- **身份一致性**:每个协会议话携带相同的 persona config + 群聊上下文
|
||||||
|
|
||||||
|
### 涉及文件
|
||||||
|
|
||||||
|
| 文件 | 改动 |
|
||||||
|
|------|------|
|
||||||
|
| `ai-core/orchestrator/orchestrator.go` | ProcessInput 增加并发检测 + 协会议话创建 |
|
||||||
|
| `ai-core/orchestrator/concurrent_handler.go` | **新建** — 协会议话管理器 |
|
||||||
|
| `platform-bridge/cmd/main.go` | 可能需要支持协会议话的回复路由 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. P4 — 多平台前缀统一抽象
|
||||||
|
|
||||||
|
### 现状
|
||||||
|
|
||||||
|
QQ 平台标识(`【QQ群聊:xxx】`、`【QQ私聊:xxx】`)硬编码在 `thinker.go` 的 `buildThinkingUserPrompt` 里,`extractProactiveMessage` 里的 `qqTargetRe` 也只匹配 QQ。如果要接入 Telegram / Discord / 企业微信,需要在多个位置添加硬编码。
|
||||||
|
|
||||||
|
### 目标
|
||||||
|
|
||||||
|
将"平台前缀"抽象为一个统一的 `PlatformRouteFormat` 接口,每个 adapter 注册时声明自己的格式。
|
||||||
|
|
||||||
|
### 要点
|
||||||
|
|
||||||
|
- `PlatformRouteFormat` 接口:
|
||||||
|
- `ProactiveMarker(chatType, channelID, atUserID string) string` — 主动消息标记格式
|
||||||
|
- `ChannelPrefix(channelID string) string` — 消息来源前缀(如 `【QQ群聊:xxx】`)
|
||||||
|
- 注册在 `PlatformAdapter` 接口扩展中
|
||||||
|
- thinker prompt 和 extractProactiveMessage 从 router 获取当前已注册的格式列表
|
||||||
|
- 后向兼容:QQ 当前行为不变
|
||||||
|
|
||||||
|
### 涉及文件
|
||||||
|
|
||||||
|
| 文件 | 改动 |
|
||||||
|
|------|------|
|
||||||
|
| `platform-bridge/bridge/adapter.go` | PlatformAdapter 接口扩展 |
|
||||||
|
| `platform-bridge/bridge/router.go` | GetRouteFormats() 方法 |
|
||||||
|
| `platform-bridge/handler/bridge_handler.go` | API 端点暴露格式信息 |
|
||||||
|
| `ai-core/background/thinker.go` | 从 bridge 获取格式替代硬编码 |
|
||||||
|
| `ai-core/cmd/main.go` | 启动时拉取格式配置 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. P5 — 工具子会话增强
|
||||||
|
|
||||||
|
### 6.1 子会话返回时间戳
|
||||||
|
|
||||||
|
**现状**:子会话结果(SubSessionResult)没有记录创建时间和结束时间。
|
||||||
|
|
||||||
|
**目标**:每个子会话结果增加 `CreatedAt` / `FinishedAt` 字段。
|
||||||
|
|
||||||
|
**涉及文件**:`model/sub_session.go` + 各 provider 的 `Execute()` 方法
|
||||||
|
|
||||||
|
### 6.2 工具调用不阻塞主会话
|
||||||
|
|
||||||
|
**现状**:`Synthesizer.ChatWithTools` 的 LLM 工具调用循环(最多 5 轮)在主 goroutine 中执行,长工具调用(如 `web_search` + `web_fetch` 链)会阻塞流式输出。
|
||||||
|
|
||||||
|
**目标**:工具调用结果通过 channel 异步返回,Synthesizer 先输出等待提示(如"让我查一下..."),收到结果后再继续流式生成。
|
||||||
|
|
||||||
|
**涉及文件**:`orchestrator/synthesizer.go` — `ChatWithTools` 的调用模型改为 publish/subscribe
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 实施顺序建议
|
||||||
|
|
||||||
|
```
|
||||||
|
Phase A (本节可做) ─────────────────────────────
|
||||||
|
P2.2 对话后思考可追加 ~10 行改动
|
||||||
|
P2.1 自主思考后触发记忆整理 ~5 行改动
|
||||||
|
P5.1 子会话返回时间戳 ~20 行改动
|
||||||
|
|
||||||
|
Phase B (需要跨服务协调) ───────────────────────
|
||||||
|
P1 LLM 可自主操作提醒与日程 新建 1 文件 + 注册工具
|
||||||
|
P0 自主思考分层 重构 thinker 核心循环
|
||||||
|
|
||||||
|
Phase C (架构级改动) ───────────────────────────
|
||||||
|
P4 多平台前缀统一抽象 跨 ai-core + platform-bridge
|
||||||
|
P3 群聊并发(协会议话) 跨 ai-core + platform-bridge
|
||||||
|
|
||||||
|
Phase D (后续优化) ─────────────────────────────
|
||||||
|
P5.2 工具调用不阻塞主会话 改造 synthesizer 调用模型
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 附:与架构设计文档的对照清单
|
||||||
|
|
||||||
|
| # | 设计要求 | 状态 | 对应章节 |
|
||||||
|
|---|---------|------|---------|
|
||||||
|
| 1 | 基础出人格库 | ✅ | — |
|
||||||
|
| 2 | 故事背景知识库 | ✅ | — |
|
||||||
|
| 3 | 多优先级自主增删改记忆 | ⚠️ 缺自主删改 | 待定 |
|
||||||
|
| 4 | 用户手动增删改知识库 | ✅ | — |
|
||||||
|
| 5 | IoT 功能调用知识库 | ✅ | — |
|
||||||
|
| 6 | 插件功能调用知识库 | ✅ | — |
|
||||||
|
| 7 | 定时任务模块 | ❌ | P1 |
|
||||||
|
| 8 | 定时任务自主增删改 | ❌ | P1 |
|
||||||
|
| 9 | 日程自主增删改 | ❌ | P1 |
|
||||||
|
| 10 | 简单思考(高频下位模型) | ❌ | P0 |
|
||||||
|
| 11 | 复杂思考(低频思考模型) | ⚠️ 有但未分层 | P0 |
|
||||||
|
| 12 | 简单思考可唤醒复杂思考 | ❌ | P0 |
|
||||||
|
| 13 | 两种思考均可追加 | ⚠️ 仅 post_chat | P2.2 |
|
||||||
|
| 14 | 两种思考均可调用工具 | ✅ | — |
|
||||||
|
| 15 | 主动通讯(客户端+平台) | ✅ | — |
|
||||||
|
| 16 | 思考后触发记忆整理 | ❌ | P2.1 |
|
||||||
|
| 17 | 回复一句一句发 | ✅ | — |
|
||||||
|
| 18 | 工具调用不阻塞主会话 | ⚠️ 部分阻塞 | P5.2 |
|
||||||
|
| 19 | 工具子会话返回时间戳 | ❌ | P5.1 |
|
||||||
|
| 20 | 群聊并发协会议话 | ❌ | P3 |
|
||||||
|
| 21 | 多平台消息前缀 | ⚠️ QQ 硬编码 | P4 |
|
||||||
|
| 22 | 多平台发送方式 | ✅ | — |
|
||||||
|
|
||||||
|
> 共 22 项设计要求:✅ 已完成 9 项,⚠️ 部分完成 5 项,❌ 未实现 8 项。
|
||||||
Reference in New Issue
Block a user