mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 17:38:10 +00:00
- 重写 extractor.go: 分句、17条 POS 模板、依存模板 + COO 链、ATT合并 - parser.go: 分句循环 + TransE 向量验证(h+r≈t) - fallback.go: jieba POS 降级解析器 - bridge.go: nlp.Triple ↔ memory.Triple 转换 - pipeline.go: extractKeyTriples 改用 NLP 提取器, 删除5条旧前缀规则 - distill.go: docToTriples 改用 NLP 提取器 - reorgGraph: 语义相似度增强检测, 保持纯 LLM 决断 - Provider 接口加 MaxContextTokens() + 模型窗口映射表 - tokenbudget.go: 中文 token 估算器 + budget 分配(80%利用率) - process.go/buildSystemPrompt: 按 token 预算截断 memory+timeline
225 lines
6.5 KiB
Go
225 lines
6.5 KiB
Go
package core
|
||
|
||
import (
|
||
"context"
|
||
"log"
|
||
"strings"
|
||
"sync"
|
||
"time"
|
||
|
||
agentAPI "gitcode.com/JianFeeeee/HomeAgent/internal/agent/api"
|
||
agentPkg "gitcode.com/JianFeeeee/HomeAgent/internal/agent"
|
||
agentIO "gitcode.com/JianFeeeee/HomeAgent/internal/agent/io"
|
||
"gitcode.com/JianFeeeee/HomeAgent/internal/events"
|
||
"gitcode.com/JianFeeeee/HomeAgent/internal/knowledge"
|
||
"gitcode.com/JianFeeeee/HomeAgent/internal/memory"
|
||
"gitcode.com/JianFeeeee/HomeAgent/internal/memory/document"
|
||
"gitcode.com/JianFeeeee/HomeAgent/internal/memory/social"
|
||
"gitcode.com/JianFeeeee/HomeAgent/internal/memory/text"
|
||
"gitcode.com/JianFeeeee/HomeAgent/internal/plugin"
|
||
"gitcode.com/JianFeeeee/HomeAgent/internal/skill"
|
||
"gitcode.com/JianFeeeee/HomeAgent/internal/tracker"
|
||
"gitcode.com/JianFeeeee/HomeAgent/pkg/types"
|
||
)
|
||
|
||
// ContextEvent 和 RelevanceContext 定义在 context.go
|
||
|
||
// Agent — 单 agent,不区分会话/实例
|
||
type Agent struct {
|
||
mu sync.Mutex
|
||
id types.AgentID
|
||
provider agentAPI.Provider
|
||
providerManager *agentAPI.ProviderManager
|
||
io *agentIO.IOManager
|
||
memory *memory.GraphDB
|
||
indexer *memory.Indexer
|
||
skills *skill.Manager
|
||
tracker *tracker.Tracker
|
||
context *RelevanceContext
|
||
systemPrompt string
|
||
ctx context.Context
|
||
cancel context.CancelFunc
|
||
|
||
// 文档记忆(第二层)
|
||
docStore *document.Store
|
||
|
||
// 知识库
|
||
knowledge *knowledge.Store
|
||
|
||
// 人物特质与关系网
|
||
social *social.SocialStore
|
||
|
||
// 文本记忆(原始对话日志)
|
||
textMem *text.Memory
|
||
|
||
// 人格设定
|
||
personality *agentPkg.Personality
|
||
|
||
// 插件注册表(用于 plgreload)
|
||
pluginReg *plugin.Registry
|
||
pluginDir string
|
||
|
||
// 定期心跳蒸馏
|
||
distillInterval time.Duration
|
||
|
||
// 上下文裁剪:活跃上下文最大条数,超出按相关性裁剪
|
||
maxContextSize int
|
||
|
||
// 当前请求的输出通道(mutex 保护,process() 内独占)
|
||
currentOutputChannel string
|
||
|
||
// 阶段管道:插件消息流编辑
|
||
stageHost *StageHost
|
||
eventBus *events.Bus
|
||
pluginHealth *pluginHealthTracker
|
||
|
||
// 自循环输入通道:核心内部任务(记忆消歧、系统维护),不经过 IO 层
|
||
selfInputCh chan string
|
||
|
||
// 子任务异步执行
|
||
childMu sync.Mutex
|
||
childNextID int64
|
||
childResults map[string]string
|
||
|
||
// 高优先级打断通道:interceptLoop 注入,process() 在工具循环轮次间非阻塞读取
|
||
interceptCh chan *agentIO.InputEvent
|
||
|
||
// 进行中的 LLM 请求取消函数,interceptLoop 可调用以在请求中打断
|
||
cancelLLM context.CancelFunc
|
||
llmMu sync.Mutex
|
||
|
||
// 模型思考模式(thinking/reasoning)
|
||
thinkingEnabled bool
|
||
|
||
// 启动时间
|
||
startTime time.Time
|
||
|
||
// 当前轮次的非文本媒体数据(图片/音频),供 describe_image 等工具访问
|
||
pendingMedia map[string]interface{}
|
||
|
||
// 非文本输入处理配置
|
||
inputCfg types.InputProcessingConfig
|
||
|
||
// noMergeMarkets 记录被标记"禁止合并"的实体对,key="entityA||entityB"(字典序),
|
||
// 每次 reorgGraph 扫描到对应实体对时计数减一,归零后自动移除。
|
||
noMergeMarkers map[string]int
|
||
noMergeMu sync.Mutex
|
||
|
||
// 词嵌入模型,用于实体语义相似度计算
|
||
embedder *memory.StaticEmbedder
|
||
}
|
||
|
||
type AgentConfig struct {
|
||
ID types.AgentID
|
||
SystemPrompt string
|
||
Provider agentAPI.Provider
|
||
ProviderManager *agentAPI.ProviderManager
|
||
IO *agentIO.IOManager
|
||
Memory *memory.GraphDB
|
||
Indexer *memory.Indexer
|
||
Skills *skill.Manager
|
||
Tracker *tracker.Tracker
|
||
|
||
DocStore *document.Store
|
||
Knowledge *knowledge.Store
|
||
SocialStore *social.SocialStore
|
||
TextMemory *text.Memory
|
||
Personality *agentPkg.Personality
|
||
PluginReg *plugin.Registry
|
||
PluginDir string
|
||
DistillInterval time.Duration
|
||
MaxContextSize int // 活跃上下文最大条数,超出按相关性裁剪
|
||
ContextSavePath string // 上下文持久化路径,空则不持久化
|
||
EmbeddingModelPath string // 预训练词嵌入模型路径(word2vec 文本格式),空则不使用
|
||
StageHost *StageHost
|
||
EventBus *events.Bus
|
||
ThinkingEnabled bool
|
||
|
||
InputProcessing types.InputProcessingConfig // 非文本输入处理配置
|
||
}
|
||
|
||
func New(cfg AgentConfig) *Agent {
|
||
ctx, cancel := context.WithCancel(context.Background())
|
||
if cfg.DistillInterval <= 0 {
|
||
cfg.DistillInterval = 30 * time.Minute
|
||
}
|
||
if cfg.MaxContextSize <= 0 {
|
||
cfg.MaxContextSize = 30
|
||
}
|
||
|
||
embedder := memory.NewStaticEmbedder(strings.Split(cfg.EmbeddingModelPath, ",")...)
|
||
if cfg.DocStore != nil {
|
||
cfg.DocStore.SetVectorizer(embedder)
|
||
cfg.DocStore.ReindexWithVectorizer(embedder)
|
||
}
|
||
|
||
rc := NewRelevanceContext(cfg.ContextSavePath, embedder)
|
||
if cfg.StageHost != nil {
|
||
rc.SetToolDefLookup(cfg.StageHost.ToolDef)
|
||
}
|
||
|
||
return &Agent{
|
||
id: cfg.ID,
|
||
startTime: time.Now(),
|
||
provider: cfg.Provider,
|
||
providerManager: cfg.ProviderManager,
|
||
io: cfg.IO,
|
||
memory: cfg.Memory,
|
||
indexer: cfg.Indexer,
|
||
skills: cfg.Skills,
|
||
tracker: cfg.Tracker,
|
||
context: rc,
|
||
systemPrompt: cfg.SystemPrompt,
|
||
ctx: ctx,
|
||
cancel: cancel,
|
||
docStore: cfg.DocStore,
|
||
knowledge: cfg.Knowledge,
|
||
social: cfg.SocialStore,
|
||
textMem: cfg.TextMemory,
|
||
personality: cfg.Personality,
|
||
pluginReg: cfg.PluginReg,
|
||
pluginDir: cfg.PluginDir,
|
||
distillInterval: cfg.DistillInterval,
|
||
maxContextSize: cfg.MaxContextSize,
|
||
stageHost: cfg.StageHost,
|
||
eventBus: cfg.EventBus,
|
||
selfInputCh: make(chan string, 64),
|
||
childResults: make(map[string]string),
|
||
interceptCh: make(chan *agentIO.InputEvent, 64),
|
||
pluginHealth: newPluginHealthTracker(),
|
||
thinkingEnabled: cfg.ThinkingEnabled,
|
||
inputCfg: cfg.InputProcessing,
|
||
embedder: embedder,
|
||
noMergeMarkers: make(map[string]int),
|
||
|
||
}
|
||
}
|
||
|
||
func (a *Agent) Start() {
|
||
go a.eventLoop()
|
||
go a.interceptLoop()
|
||
go a.distillLoop()
|
||
log.Printf("[agent] %s started, waiting for IO interrupts", a.id)
|
||
}
|
||
|
||
func (a *Agent) Stop() {
|
||
a.cancel()
|
||
}
|
||
|
||
func (a *Agent) ID() types.AgentID { return a.id }
|
||
|
||
// SelfInputChan 返回自循环输入通道(只读,供内部测试验证)
|
||
func (a *Agent) SelfInputChan() <-chan string {
|
||
return a.selfInputCh
|
||
}
|
||
|
||
// injectSelf 向自循环通道发送内部任务(记忆消歧、系统维护)
|
||
// 线程安全,不阻塞发送者(通道缓冲 64)
|
||
func (a *Agent) injectSelf(task string) {
|
||
select {
|
||
case a.selfInputCh <- task:
|
||
default:
|
||
log.Printf("[agent] self input channel full, dropping task: %s", truncateStr(task, 80))
|
||
}
|
||
}
|