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_id→plan_id→context_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.ymlsmart_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 | 消息列表,每条含 role 和 content |
[{ 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' }] |
写入门控策略:
- 必写:
tasks、decisions(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
- Plan:
RetrievalPlanner分析意图,生成RetrievalPlan(主查询 + 扩展查询),自动判断是否启用资源检索(enable_resource_retrieval: 'auto'时,关键词"查资料/引用/论文/文档/compare/对比/来源"触发) -
Retrieve:双路并行 —
- 记忆侧:
ExactRetriever(词重叠匹配,支持中英文分词)+RelationalRetriever(实体/引用关联) - 资源侧:通过 SmartRAG 适配器检索文档资源(仅当 planner 启用时)
- 记忆侧:
- Fuse:
Merger归一化 → 去重 → 词重叠加分重排 → 多样性约束(同文档 ≤ 3 条,同来源 ≤ 2 条)→ 预算裁剪(总条数 ≤evidence_max_items,snippet ≤max_snippet_chars)→ memory/resource 比例控制(默认 40/60) -
Compose:
ContextComposer按固定槽位装配:system_blocks → developer_blocks → working_summary → recent_turns → evidence → - 输出:
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_id → plan_id → context_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: 30、candidate_k: 200、enable_resource_retrieval: auto、query_expansion: { enabled: true, max_queries: 8 } |
| Composition(装配) | compose_context |
recent_turns_max: 8、evidence_max_items: 12、max_snippet_chars: 800、diversity: { 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,丢弃资源证据并在 warnings 和 explain.ignored_fields 中说明原因。
运行示例
example.rb
SmartBrain + SmartAgent + SmartPrompt + SmartRAG 联动示例(2 轮对话)。
bundle exec ruby example.rb
依赖的本地文件:
config/example_agent.ymlconfig/example_llm.ymlagents/brain_assistant.rbworkers/brain_assistant.rbtemplates/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 字段)