0.0
The project is in a healthy, maintained state
SmartBrain provides scoped agent memory, retrieval planning, evidence fusion, governance, and context assembly.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

>= 2.0
~> 1.11
~> 0.3.2
~> 13.0
~> 0.1.0
~> 3.13
~> 0.2.3

Runtime

~> 2.11
~> 3.16
~> 1.5
~> 5.87
~> 0.1
~> 7.2
~> 4.2
 Project Readme

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 字段)