SmartBrain

SmartBrain(v0.2.0)是一个面向 Agent 的记忆运行时(Memory Runtime)与上下文编排器(Context Composer)

在多轮 Agent 对话中,SmartBrain 解决的核心问题是:如何高效地记录、检索、融合记忆,并装配出"最小充分"的上下文发给 LLM。

核心职责

  • commit_turn:记录事件真相并沉淀结构化长期记忆(写链路)
  • compose_context:在每轮请求前生成最小充分上下文(读 + 装配链路)
  • 联动 SmartRAG:对话记忆由 SmartBrain 管理(EventStore / MemoryStore),资源检索由 SmartRAG 提供(适配层)

架构边界

SmartBrain 把 Agent 的可用信息分为两类,分工明确:

类别 管理者 内容 特点
对话记忆 (Conversation Memory) SmartBrain 原始事件(turn/messages/tool_calls/refs)、结构化记忆(profile/preferences/tasks/decisions/entities/events)、滚动摘要(working_summary) 强时序、更新频繁、有写入门控与冲突管理
资源记忆 (Resource Memory) SmartRAG 文档/网页/代码仓库等长期资源 相对静态、内容大、需要高质量检索

SmartRAG 是 SmartBrain 的"资源知识库后端"。SmartBrain 不复制 SmartRAG 的索引能力,只通过契约适配层调用它。

当前进展

当前仓库已实现并打通:

  • commit_turn / compose_context 主链路
  • Retention / Consolidation / Retrieval / Composition 四类策略
  • 检索器:exact(关键词匹配) + relational(实体/引用关联)
  • 融合层:去重、词重叠加分重排、多样性约束、预算截断、memory/resource 比例控制
  • SmartRAG 适配器:NullClient(默认空)/ HttpClient(HTTP 远程)/ DirectClient(进程内直接调用)
  • 契约与可观测:request_idplan_idcontext_id 全链路追踪
  • RSpec 测试(单元 + 集成 + PostgreSQL 回归)

安装

bundle install

如遇本地权限或 shared gem 污染:

bundle config set --local path 'vendor/bundle'
bundle config set --local disable_shared_gems 'true'

核心 API

SmartBrain 提供以下核心工作流 API:

SmartBrain.configure(config_path: nil, smart_rag_client: nil, clock: -> { Time.now.utc })

初始化运行时并注入 SmartRAG 客户端(可选)。

  • config_path:策略配置文件路径,默认 config/brain.yml
  • smart_rag_client:SmartRAG 适配器实例,默认 NullClient(资源证据为空)
  • clock:时间源函数,默认 Time.now.utc

SmartBrain.commit_turn(session_id:, turn_events:, domain_id: nil, scope_context: nil)

写入事件、抽取记忆、冲突处理、摘要更新。返回 CommitResult

turn_events 支持的事件类型:

字段 类型 说明 示例
messages Array 消息列表,每条含 rolecontent [{ role: 'user', content: '...' }]
decisions Array 决策/选择/承诺 [{ key: 'decision:pg:pool_size', decision: '...' }]
tasks Array 任务,含状态流转 [{ key: 'task:brain:mvp', status: 'doing' }]
goals Array 长期目标 [{ key: 'goal:learn:ruby', goal: '...' }]
entities Array 重要实体 [{ key: 'entity:lang:ruby', name: 'Ruby', canonical: 'ruby', kind: 'language', remember: true }]
preferences Array 偏好,需 confirmed: true 才写入长期记忆 [{ key: 'pref:writing:tone', value: '...', confirmed: true }]
events Array 里程碑/异常等高价值事件
refs Array 文件/URL/产物引用
retractions Array 撤回旧记忆 [{ type: 'decisions', key: 'decision:old:topic' }]

写入门控策略:

  • 必写tasksdecisions(confidence: 0.9)
  • 条件写goals(需显示声明)、preferences(需 confirmed: true)、entities(需出现频率 ≥ 2 或含 URL/路径等结构信号)
  • 不写入:闲聊、未确认推测

冲突处理:

  • 覆盖型(preferences/goals/tasks):新值写入,旧值 → status=superseded
  • 多版本并存(decisions/events):保留历史
  • 撤回(retracted):旧条目 → status=retracted

返回值:

{
  ok: true,
  commit_id: "uuid",
  session_id: "...",
  turn_id: "uuid",
  memory_written: { count: 3, items: [...], conflicts: [...] },
  summary: { triggered: true, trigger_reason: "turn_threshold", text: "..." },
  explain: { retention: [...], conflicts: [...], summary: {...} }
}

SmartBrain.compose_context(session_id:, user_message:, agent_state: {}, domain_id: nil, scope_context: nil)

生成 ContextPackage,内部执行 5 阶段流水线:

Plan  Retrieve(双路并行)→ Fuse  Compose  ContextPackage
  1. PlanRetrievalPlanner 分析意图,生成 RetrievalPlan(主查询 + 扩展查询),自动判断是否启用资源检索(enable_resource_retrieval: 'auto' 时,关键词"查资料/引用/论文/文档/compare/对比/来源"触发)
  2. Retrieve:双路并行 —
    • 记忆侧:ExactRetriever(词重叠匹配,支持中英文分词)+ RelationalRetriever(实体/引用关联)
    • 资源侧:通过 SmartRAG 适配器检索文档资源(仅当 planner 启用时)
  3. FuseMerger 归一化 → 去重 → 词重叠加分重排 → 多样性约束(同文档 ≤ 3 条,同来源 ≤ 2 条)→ 预算裁剪(总条数 ≤ evidence_max_items,snippet ≤ max_snippet_chars)→ memory/resource 比例控制(默认 40/60)
  4. ComposeContextComposer 按固定槽位装配:
    system_blocks  developer_blocks  working_summary 
    recent_turns  evidence  user_message
    
  5. 输出ContextPackage(经过契约校验)

多 Scope 记忆

0.2.0 支持在同一 domain 内联合读取 global/project/expert/task 记忆,并将长期记忆写入明确授权的 scope:

scope_context = {
  read: [
    { type: 'global', id: 'default' },
    { type: 'project', id: 'project-001' },
    { type: 'task', id: 'task-030' }
  ],
  write: [
    { type: 'project', id: 'project-001' },
    { type: 'task', id: 'task-030' }
  ],
  default_write: { type: 'task', id: 'task-030' }
}

SmartBrain.commit_turn(
  domain_id: 'tenant-a', session_id: 'conversation-1', scope_context: scope_context,
  turn_events: { decisions: [{ key: 'decision:db', decision: 'use PostgreSQL' }] }
)

write 必须是 read 的子集,default_write 必须包含在 write 中。单条结构化记忆可以用 scope_ref 覆盖默认写 scope,但目标仍须在 write 中。提供 scope_context 时必须同时提供 domain_id;两者都省略时继续使用隔离的 legacy/session:<session_id>,兼容 0.1.x 调用。

返回值(ContextPackage):

{
  version: '0.1',
  context_id: "uuid",               # 本次装配唯一 ID
  session_id: "...",
  working_summary: "...",           # 滚动摘要文本
  recent_turns: [...],              # 最近 N 轮对话
  evidence: [                       # 融合后的证据列表
    {
      id: "...",
      source: 'memory' | 'resource',
      source_uri: "...",
      title: "...",
      snippet: "...",
      mode: 'exact' | 'relational' | 'hybrid',
      score: 0.85,
      ref: { memory_item_id: "..." }
    }
  ],
  user_message: { role: 'user', content: "..." },
  constraints: {
    token_budget: { limit: 8000, used_estimate: 1200 },
    diversity: { by_document: 3, by_source: 2 },
    truncation: { snippets_max_chars: 800, recent_turns_max: 8 }
  },
  debug: {
    trace: { request_id: "uuid", plan_id: "uuid", context_id: "uuid" },
    planner: { purpose: "qa", queries: ["..."] },
    why_selected: ["item-1 score=0.85 source=memory"],
    ignored: [],
    dropped: [{ id: "...", reason: "diversity" }]
  }
}

SmartBrain.diagnostics

返回 compose/commit 观测日志与指标快照:

{
  compose_logs: [...],
  commit_logs: [...],
  metrics: {
    compose_p95_ms: 45.2,
    memory_resource_ratio: "3/2",
    token_over_budget_rate: 0.0
  }
}

全链路追踪:每个请求有 request_idplan_idcontext_id 三连 ID,贯穿 Plan → Retrieve → Fuse → Compose 全流程。

策略配置

SmartBrain 的四类策略通过 config/brain.yml 配置:

策略类别 生效点 关键参数
Retention(写入门控) commit_turn entity_gate: { window_turns: 20, freq_threshold: 2 }confidence: { user_asserted: 0.8, tool_derived: 0.9, inferred: 0.6 }summarize_after_turns: 12
Retrieval(检索) compose_context top_k: 30candidate_k: 200enable_resource_retrieval: autoquery_expansion: { enabled: true, max_queries: 8 }
Composition(装配) compose_context recent_turns_max: 8evidence_max_items: 12max_snippet_chars: 800diversity: { by_document: 3, by_source_uri: 2 }memory_resource_ratio: "40/60"
Observability(可观测) 全局 trace: true

项目结构

lib/smart_brain.rb                          # Ruby 入口 API
lib/smart_brain/version.rb                  # 版本号
lib/smart_brain/configuration.rb            # YAML 配置加载
lib/smart_brain/runtime.rb                  # 主运行时编排(commit_turn / compose_context)
lib/smart_brain/contracts/                  # 契约校验
  retrieval_plan.rb                         #   RetrievalPlan 校验
  evidence_pack.rb                          #   EvidencePack 校验
  context_package.rb                        #   ContextPackage 校验
lib/smart_brain/event_store/
  in_memory.rb                              # 事件存储(当前内存实现,含 entity_frequencies 统计)
lib/smart_brain/memory_store/
  in_memory.rb                              # 记忆存储(当前内存实现,含 upsert 冲突管理)
lib/smart_brain/memory_extractor/
  extractor.rb                              # 从事件中抽取结构化记忆(写入门控)
lib/smart_brain/consolidator/
  working_summary.rb                        # 滚动摘要维护(turn_threshold / token_pressure / stage_event 触发)
lib/smart_brain/retrieval_planner/
  planner.rb                                # 生成 RetrievalPlan(query expansion + 资源检索启停判断 + filter hints)
lib/smart_brain/retrievers/
  exact_retriever.rb                        # 词重叠关键词匹配(支持中英文)
  relational_retriever.rb                   # 实体/引用关联检索
  memory_retriever.rb                       # 记忆检索门面(exact + relational 合并)
lib/smart_brain/fusion/
  merger.rb                                 # 多源融合(归一化 → 去重 → 词重叠加分重排 → 多样性 → 预算截断)
lib/smart_brain/context_composer/
  composer.rb                               # 固定槽位上下文装配 + token 估算
lib/smart_brain/adapters/smart_rag/
  null_client.rb                            # 默认空适配器(资源证据为空)
  http_client.rb                            # HTTP 远程调用适配器(支持超时降级)
  direct_client.rb                          # 进程内直接调用适配器
lib/smart_brain/observability/
  tracker.rb                                # 日志与指标(P95 / memory_resource_ratio / token_over_budget_rate)
config/
  example_llm.yml                           # LLM 配置示例(ollama + silicon_flow)
docs/
  smartbrain_design.md                      # 总体设计文档
  policies.md                               # 策略规范文档
  memory_types.md                           # 记忆类型规范(9 种 type + key 规则)
  context_package.md                        # ContextPackage 协议
  retrieval_plan.md                         # RetrievalPlan 协议
  evidence_pack.md                          # EvidencePack 协议
spec/
  spec_helper.rb
  commit_turn_spec.rb                       # commit_turn 单元测试
  compose_context_spec.rb                   # compose_context 单元测试
  fusion_merger_spec.rb                     # 融合层测试
  integration_smart_rag_adapter_spec.rb     # SmartRAG 适配器集成测试
  observability_metrics_spec.rb             # 可观测性测试
  planner_policy_spec.rb                    # 检索计划策略测试
  regression_context_spec.rb                # 回归测试
example.rb                                  # 简单示例
conversation_demo.rb                        # 完整多轮对话演示(SmartBrain + SmartRAG + SmartAgent)

快速开始

仅 SmartBrain(不依赖外部服务)

require_relative 'lib/smart_brain'

SmartBrain.configure

SmartBrain.commit_turn(
  session_id: 'demo',
  turn_events: {
    messages: [
      { role: 'user', content: '请记住:默认数据库是 Postgres。' },
      { role: 'assistant', content: '已记录。' }
    ],
    decisions: [
      { key: 'decision:smartbrain:storage', decision: 'Use Postgres by default' }
    ]
  }
)

context = SmartBrain.compose_context(
  session_id: 'demo',
  user_message: '继续并总结关键结论'
)

puts context[:context_id]
puts context.dig(:debug, :trace, :request_id)
puts context.dig(:debug, :trace, :plan_id)

多轮对话循环(与 SmartAgent + SmartRAG 联动)

require 'smart_brain'
require 'smart_agent'
require 'smart_rag'
require_relative 'lib/smart_brain/adapters/smart_rag/direct_client'

# 1. 初始化 SmartRAG
rag = SmartRAG::SmartRAG.new(database: {...}, llm: {...})
client = SmartBrain::Adapters::SmartRag::DirectClient.new(rag: rag)

# 2. 初始化 SmartBrain
SmartBrain.configure(smart_rag_client: client)

# 3. 初始化 SmartAgent
engine = SmartAgent::Engine.new('./config/example_agent.yml')
agent = engine.build_agent(:brain_assistant)

# 4. 多轮对话循环
session_id = "demo-session"
user_message = "Ruby 类名应该用什么命名风格?"

# 4a. 获取上下文(内部可能调用 SmartRAG 检索文档资源)
context = SmartBrain.compose_context(
  session_id: session_id,
  user_message: user_message,
  agent_state: { turn: 1 }
)

# 4b. 调用 Agent(LLM)生成回复
response = agent.please(context.to_json)

# 4c. 提交本轮(沉淀记忆)
commit = SmartBrain.commit_turn(
  session_id: session_id,
  turn_events: {
    messages: [
      { role: 'user', content: user_message },
      { role: 'assistant', content: response.to_s }
    ],
    decisions: [
      { key: 'decision:ruby:class_naming', decision: '使用 CamelCase' }
    ],
    entities: [
      { key: 'entity:lang:ruby', name: 'Ruby', canonical: 'ruby', kind: 'language', remember: true }
    ]
  }
)

# 5. 查看诊断信息
pp SmartBrain.diagnostics

SmartRAG 集成方式

1) NullClient(默认)

不配置 smart_rag_client 时,资源证据为空,仅使用记忆侧证据。适合纯对话记忆场景。

SmartBrain.configure  # 无需额外配置

2) HttpClient(HTTP 远程)

通过自定义 transport lambda 调用远端 SmartRAG 服务,支持超时降级。

transport = lambda do |plan, timeout_seconds:|
  {
    plan_id: 'p1',
    supports_language_filter: true,
    evidences: []
  }
end

scope_mapper = lambda do |domain_id:, scopes:|
  { filters: { topic_ids: scopes.map { |scope| "#{domain_id}:#{scope[:type]}:#{scope[:id]}" } } }
end
client = SmartBrain::Adapters::SmartRag::HttpClient.new(
  transport: transport, timeout_seconds: 2, scope_mapper: scope_mapper
)
SmartBrain.configure(smart_rag_client: client)

3) DirectClient(进程内直接调用)

直接依赖 smart_rag gem,进程内调用。需要配置 PostgreSQL 连接和 LLM。

require 'smart_rag'
require_relative 'lib/smart_brain/adapters/smart_rag/direct_client'

rag_config = SmartRAG::Config.load(ENV.fetch('SMARTRAG_CONFIG_PATH'))
rag = SmartRAG::SmartRAG.new(rag_config)
scope_mapper = lambda do |domain_id:, scopes:|
  { filters: { topic_ids: scopes.map { |scope| "#{domain_id}:#{scope[:type]}:#{scope[:id]}" } } }
end
client = SmartBrain::Adapters::SmartRag::DirectClient.new(rag: rag, scope_mapper: scope_mapper)

SmartBrain.configure(smart_rag_client: client)

Mapper 返回的 filters 会作为 scope_filters 发送给 SmartRAG。业务 scope 存在时,后端必须返回 scope_filter_applied: true;mapper 缺失、映射失败或后端未确认时,adapter 默认 fail closed,丢弃资源证据并在 warningsexplain.ignored_fields 中说明原因。

运行示例

example.rb

SmartBrain + SmartAgent + SmartPrompt + SmartRAG 联动示例(2 轮对话)。

bundle exec ruby example.rb

依赖的本地文件:

  • config/example_agent.yml
  • config/example_llm.yml
  • agents/brain_assistant.rb
  • workers/brain_assistant.rb
  • templates/brain_assistant.erb

conversation_demo.rb

完整多轮对话演示(5 轮),包含 SmartRAG 文档存储、检索、SmartAgent LLM 调用和 SmartBrain 记忆沉淀全流程。

bundle exec ruby conversation_demo.rb

测试

bundle exec rspec

测试覆盖 commit/compose、存储、治理、KG、协议适配、多 scope 隔离以及 PostgreSQL 迁移和持久化。

常见问题

1) cannot load such file -- sequel/extensions/pgvector

当前示例已在 example.rb 做兼容处理(Sequel.extension 'pgvector' + 去除 database.extensions 连接参数)。

2) Config file not found: config/llm_config.yml

example.rb 已将 SmartRAG 里 EmbeddingService 的 config_path 注入为 ./config/example_llm.yml

3) ruby-lsp: not found

gem install --user-install ruby-lsp debug

并将用户 gem bin 加入 PATH

路线图

  • 将 EventStore/MemoryStore 从内存实现切换到 Postgres 持久化实现
  • 接入真实 reranker / embedding 模型(当前为规则分 + 词重叠加分)
  • 完善 SmartRAG ingest 与跨会话评估工具
  • 扩展 SemanticRetriever(依赖 pgvector/embedding)
  • 支持 memory_chunks 表(FTS 索引 + 可选 embedding 字段)