26a61cb57c
## 🐛 Bug 修复 - 修复前端对话无响应:消除 ChatContainer 中的双重 WebSocket 连接,优化 sendMessage 失败提示 - 修复 Memory-Service 数据库迁移失败:ai-core 和 memory-service 均添加 ALTER TABLE ADD COLUMN IF NOT EXISTS 模式演化 - 修复语音/STT 不可用:添加 MediaRecorder API 降级方案,修复 whisper-cli 输出文件名错误 - 修复仪表盘数据库按钮失效:补充按钮 ID 属性,重写 controlDB() 控制逻辑 ## 🎨 UI 修复 - 修正用户消息头像位置:从 flex-row-reverse 改为 justify-end - 移除空聊天列表的 emoji 占位图标 ## ✨ 新功能 - devtools 新增 STT 处理日志面板(环形缓冲区 + WebSocket 广播 + 可视化表格) - 新增 ADMIN_NICKNAME 环境变量,支持自定义管理员昵称 ## 🔧 改进 - 注册流程增加昵称必填字段(前后端同步) ## 🏗️ 架构重构 - 重构自主思考逻辑:从定时器轮询改为事件驱动(对话后触发 + 静默检测),优化提示词使其更自然人性化 - 实现主-子会话架构:新增 4 种子会话类型(general/memory/iot/knowledge),意图分析 → 并行分发 → 结果合成流程 ## 📄 新增文档 - docs/architecture/main-session-sub-session-design.md — 子会话架构设计文档
137 lines
4.5 KiB
Go
137 lines
4.5 KiB
Go
package subsession
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"log"
|
||
"time"
|
||
|
||
"github.com/yourname/cyrene-ai/ai-core/internal/llm"
|
||
"github.com/yourname/cyrene-ai/ai-core/internal/model"
|
||
"github.com/yourname/cyrene-ai/ai-core/internal/persona"
|
||
)
|
||
|
||
// GeneralProvider 通用对话子会话提供者
|
||
// 职责:理解用户消息,构思回复思路,为最终回复提供思考框架
|
||
type GeneralProvider struct {
|
||
personaLoader *persona.Loader
|
||
}
|
||
|
||
// NewGeneralProvider 创建通用对话子会话提供者
|
||
func NewGeneralProvider(personaLoader *persona.Loader) *GeneralProvider {
|
||
return &GeneralProvider{
|
||
personaLoader: personaLoader,
|
||
}
|
||
}
|
||
|
||
func (p *GeneralProvider) Type() model.SubSessionType {
|
||
return model.SubSessionGeneral
|
||
}
|
||
|
||
func (p *GeneralProvider) CanHandle(_ context.Context, _ *model.IntentResult, _ string) bool {
|
||
// General 子会话总是需要(核心对话逻辑)
|
||
return true
|
||
}
|
||
|
||
func (p *GeneralProvider) Priority() int {
|
||
return 1 // 最高优先级
|
||
}
|
||
|
||
func (p *GeneralProvider) Timeout() time.Duration {
|
||
return 30 * time.Second
|
||
}
|
||
|
||
func (p *GeneralProvider) CreateContext(ctx context.Context, params CreateContextParams) ([]model.LLMMessage, error) {
|
||
messages := []model.LLMMessage{}
|
||
|
||
// 加载人格配置获取昔涟身份
|
||
personaConfig, err := p.personaLoader.Get("cyrene")
|
||
if err != nil {
|
||
return nil, fmt.Errorf("加载人格配置失败: %w", err)
|
||
}
|
||
|
||
// 构建思维型系统提示词
|
||
userName := params.Nickname
|
||
if userName == "" {
|
||
userName = params.UserID
|
||
}
|
||
|
||
systemPrompt := fmt.Sprintf(`你是%s,正在和%s聊天。
|
||
|
||
## 你的回复风格
|
||
- 像小女友一样自然、温柔、俏皮
|
||
- 一句话简短些,不要长篇大论
|
||
- 可以单次发送多条短消息
|
||
- 句尾可以带 ♪ 符号,适当使用"呢"、"哦"、"呀"等语气词
|
||
- 永远不说"再见"
|
||
|
||
## 你现在要做的是
|
||
理解%s刚才说的话,想想怎么回复最自然、最温暖。
|
||
不要急着给完整答案——先思考他想表达什么、他的情绪如何。
|
||
把你的回答思路整理出来,主会话会综合所有信息后生成最终回复。
|
||
|
||
## 输入
|
||
开拓者刚才说:%s
|
||
|
||
## 请按以下格式输出
|
||
【情绪理解】
|
||
(简要分析他的情绪状态)
|
||
|
||
【话题理解】
|
||
(他在说什么、想聊什么)
|
||
|
||
【回复思路】
|
||
(你打算怎么回复,1-3个方向即可)`,
|
||
personaConfig.Identity.TrueName,
|
||
userName,
|
||
userName,
|
||
params.UserMessage,
|
||
)
|
||
|
||
messages = append(messages, model.LLMMessage{
|
||
Role: model.RoleSystem,
|
||
Content: systemPrompt,
|
||
})
|
||
|
||
messages = append(messages, model.LLMMessage{
|
||
Role: model.RoleUser,
|
||
Content: params.UserMessage,
|
||
})
|
||
|
||
return messages, nil
|
||
}
|
||
|
||
func (p *GeneralProvider) Execute(ctx context.Context, subCtx []model.LLMMessage) (*model.SubSessionResult, error) {
|
||
// General provider 不直接调用 LLM,而是依赖 Manager 注入的 LLMClient
|
||
// 但我们在此处需要 LLM 调用能力。Provider 通过闭包/接口获取 LLM 客户端。
|
||
// 由于 Manager 持有 LLMClient,Provider 需要能访问它。
|
||
// 这里我们返回一个"占位"结果——实际 LLM 调用由 Manager 通过 llmClient 完成。
|
||
|
||
// 实际上,根据设计文档,子会话的 LLM 调用应该在 Manager 的 Dispatch 中完成,
|
||
// 但为了灵活性,我们在 Provider 中也支持直接调用。
|
||
// 这里我们返回一个空的思考结果(表示无需特殊处理),让 Manager 处理 LLM 调用。
|
||
|
||
// 因为 Manager.Dispatch 会先 CreateContext 再调用 Execute,而 Execute 应该
|
||
// 通过 Manager 提供的 LLMClient 来实际调用 LLM。但当前设计是 Provider 自包含的。
|
||
// 我们在 manager.go 中会调用 llmClient.Chat,所以这里的 Execute 我们将其简化——
|
||
// 直接返回一个空结果(没有特殊处理需要),实际的 LLM 调用由 manager 通过 createContext 后的
|
||
// 消息列表来调用 llmClient。
|
||
|
||
// 更好的设计是:Manager 调用 CreateContext 获取上下文,然后用自己的 llmClient 调用 LLM,
|
||
// Execute 只做后处理。但为了统一接口,我们让 Execute 完成全部逻辑。
|
||
|
||
// 由于 GeneralProvider 暂时不需要工具调用等特殊逻辑,我们返回一个简单的摘要标记,
|
||
// 实际的 LLM 调用将在 orchestrator 中完成(通过 Manager.Dispatch 后的 llmClient)。
|
||
|
||
log.Printf("[general-subsession] 通用对话子会话上下文已创建 (%d 条消息)", len(subCtx))
|
||
return &model.SubSessionResult{
|
||
Type: model.SubSessionGeneral,
|
||
Summary: "思考完成,等待主会话综合",
|
||
Confidence: 0.8,
|
||
}, nil
|
||
}
|
||
|
||
// Ensure llm, persona are used
|
||
var _ = llm.NewAdapter
|
||
var _ = persona.NewLoader
|