
Agno 实战second_brain 测试日志解读——自建 MCP 记忆体如何验证、踩坑与修复【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno本篇围绕 Agno 仓库中cookbook/examples/second_brain/示例的测试日志 TEST_LOG.md 展开。日志记录了第二大脑记忆体在 REST、MCP、CLI 三条通道下的完整验证过程2026-07-25 针对gpt-5.6、分支feat/entity-memory-revamp实测8 轮 REST 交互、4 轮 MCP 交互、CLI 回归、冷启动时钟问题、一次身份覆盖的 FAIL 发现以及修复后的 4 轮复核。读完你可以掌握如何用一个 LearningMachine 把笔记 实体图 个人画像/记忆拼成可跨通道共享的记忆架构以及如何以数据库为 ground truth 逐轮验证 agent 的记忆行为。1. 被测对象一个把自己暴露为 MCP Server 的记忆体被测代码是 second_brain.py其文件头注释定义了示例的定位Memory You Own, Behind Your Own MCP Server——一个私有 agent记住你在构建什么并可作为 MCP server 供 Claude、ChatGPT、Claude Code 等宿主读写同一块大脑。存储分工在 second_brain.py 中一次成型db SqliteDb(db_filetmp/second_brain.db) notes FileSystem(db, namespacebrain) brain LearningMachine( dbdb, user_profileUserProfileConfig(modeLearningMode.AGENTIC), # private to each person user_memoryUserMemoryConfig(modeLearningMode.AGENTIC), # private to each person entity_memoryEntityMemoryConfig(namespaceglobal), # shared by the team )三类存储各司其职引自文件头注释NotesFileSystembrain命名空间承载内容本身——带推理过程的决策、进行中的文档、任何超过一行的东西Entitiesentity memoryglobal命名空间索引世界——人、项目、系统一行当前值 链接 指向笔记的 note pointerProfile / user memory按 user 隔离承载自我——你是谁、你偏好怎么工作。身份被钉死pinned在 agent 上second_brain.pyuser_idowner同时开启add_history_to_contextTrue和add_datetime_to_contextTrue。注释解释钉死的原因session 不会跨 MCP 传递未经认证的/mcp调用不携带任何用户所以个人大脑只命名一次所有者保证任何通道都落在同一个大脑上。服务化入口second_brain.pyagent_os AgentOS( dbdb, tracingTrue, mcpTrue, # /mcp 端点 agents[second_brain], ) app agent_os.get_app()运行后 REST 在http://localhost:7777MCP 在http://localhost:7777/mcp。日志开头还交代了测试前提2.8.4 之前的旧 storeenable_agentic_memory时代被搁置为tmp/second_brain_pre284.db.bak本次大脑在 learnings 表上从零开始。2. REST 通道实测8 轮交互每轮之间查库核对这是日志的核心章节TEST_LOG.mduvicorn 起在 7777 端口每轮通过POST /agents/second-brain/runs驱动且每轮都是新 session所有断言都在轮次之间打开tmp/second_brain.db直接核对。8 轮覆盖了写入、纠正、回忆、否定、归档、浏览、隐私分流七类行为轮次场景数据库中验证到的形态1捕获项目 决策harbor 选用 Postgres 而非 DynamoDB索引行写入实体database: Postgres, over DynamoDB - see note推理只存在于notes/harbor.md实体上挂properties.note notes/harbor.md指针postgres/dynamodb被创建为entity_typeunknown的最小目标——即先建链接、后补描述的设计形态2捕获人物Sarah Chen边落在两行上且带远端类型harbor:designs - sarah_chen, entity_type person即关系是双向落库的3纠正not blocked anymore, v0.1 shipped旧事实status: blocked on the auth review被退役superseded_by 新事实 id已在事实记录中验证并在笔记上追加一条带日期的更新4新 session 问为什么按笔记中推理的原始形状作答多行事务、团队熟悉 SQL、单表建模——note pointer 的往返链路成立5否定验证我们讨论过 Acme 合同吗回答No——我搜了实体目录和所有笔记里的 Acme 与 contract什么都没找到是一个有依据的否定6归档legacy-sync库中archived_at已置位、其余实体存活且后续索引轮次不再列出它7浏览完整索引从实体目录列出全部 4 个存活实体8隐私分流harbor 预算这事你知我知落进user_memoryuser_idowner明确没有进共享实体且大脑在回复中明说了这一点这些行为背后的工具面可以在源码中一一对应。LearningMachine的get_tools()文档machine.py列出了各存储贡献的工具user_profile →update_profileuser_memory →update_user_memoryentity_memory →remember_about、link_entities、search_entities、forget。轮次 3 的纠正即替换、永不累积superseded_by退役旧事实与轮次 2 的双向落边正是 entity_memory.py 中remember_about/link_entities/forget实现的语义轮次 1、4 的笔记读写则来自FileSystem的工具面——按 fs.py 的tools()文档默认七件套为read_file、write_file、append_file、replace_lines、list_files、search_content、move_file其中归档用move_file是被认可的退役流程与轮次 6 的归档行为吻合。日志同时如实记录了三条模型行为观察findings, not failures第 1 轮笔记模板出现字面行**Date recorded:** Not provided——无害但说明模型会把缺失日期说出来而不是省略后文第 5 节给出根因与修复Numbers before prose第 8 轮存为 user memory在后续回答中跨通道生效包括 MCP——偏好被记住并应用了本次运行 profile store 未被使用从未出现姓名形事实偏好落在 user_memory这正是它的正确归属。3. MCP 通道实测跨通道共享同一块大脑第二段验证TEST_LOG.md用进程内 fastmcp 客户端打/mcp共 4 轮Status: PASS客户端看到 8 个内建 AgentOS 工具每次run_agent调用都是新 session无 session 回声——这正是 MCP 的形态钉死的user_id带住了大脑harbor 现在什么状态——跨通道回忆出 REST 时代的状态v0.1 已发布、Postgres 胜过 DynamoDB从 MCP 侧发起一次写入Tom Alvarez / 负载测试带 note pointerload testing: Tom Alvarez will run the tests next week - see note第三个新 session 回忆出了这次 MCP 侧的写入MCP 上的为什么问题也按笔记中的推理作答。这段证明的关键不是 MCP 本身而是通道边界不隔离记忆REST 写入、MCP 读取、MCP 写入、再被新 session 读取全部落在同一个tmp/second_brain.db上。4. CLI 验证test.py 的最小可复现闭环TEST_LOG.md 第三节对应 test.py不起服务器直接跑同一个 agent验证两个不共享任何东西的 session靠大脑本身完成传递。# test.py 核心流程 second_brain.print_response( I am building quill, a Postgres-backed job queue in Rust. I picked advisory locks over SELECT FOR UPDATE SKIP LOCKED because our workers are long-lived. I want terse answers, no bullet lists., session_idCAPTURE_SESSION, streamTrue, ) second_brain.print_response( What did I decide about locking in quill, and why?, session_idRECALL_SESSION, streamTrue, ) for meta in notes.list(): print(f {meta.path} ({meta.size_bytes} bytes)\n) print(notes.read(meta.path))日志验证结果捕获 session 为 quill 建档advisory locks 而非SELECT FOR UPDATE SKIP LOCKED推理写在notes/quill.md全新的回忆 session 简洁且正确地回答advisory locks … because Quills workers are long-lived共享大脑清单同时显示notes/harbor.md含带日期的更新与notes/quill.md。两个 session id 用uuid4()生成从机制上排除了 session 回声的可能。5. 冷启动时钟问题add_datetime_to_context 的实证日志 2026-07-26 的第一条记录TEST_LOG.md解释了一个此前观察的根因**Date recorded:** Not provided行出现是因为agent 没有时钟。指令要求带日期的笔记但在任何实体事实渲染出 (as of …) 日期之前prompt 里没有任何东西可供落款——前两次运行甚至产出了## Date not provided - architecture这样的标题。开启 second_brain.py 中的add_datetime_to_contextTrue注释解释得直白一个不能给笔记落日期的大脑分不清七月的真话和三月的后全新库 一轮对话we picked Postgres over Dynamo for the radar ingest queue即产出notes/radar-ingest-queue.md标题为## 2026-07-26 - Postgres over Dynamo——第一轮就带日期无需从库里任何实体借日期。这是对单点配置效果的最小化对照实验值得在自建记忆体时借鉴。6. 日志中唯一的 FAIL钉死的 user_id 会被 MCP 宿主覆盖这是整份日志最有价值的发现TEST_LOG.md对真实/mcpapp 进程内实测run_agent对外声明了一个可选的user_id参数宿主传入的值会覆盖Agent(user_idowner)。一次带user_idclaude-desktop的调用把 session 和用户记忆都写到了claude-desktop名下而不是owner。实体是 global 的所以仍然共享但 profile 和用户记忆按宿主分叉。未认证的/mcp恰恰是宿主模型会随意填这个字段的地方。这一条同时得到 second_brain.py 文件头注释的印证——作者把measured rather than assumed实测而非假设写成了部署注意事项个人大脑的世界半边global 实体不受影响始终共享自我半边profile、user memory按宿主 user_id 分叉等于给不同宿主各开了一个影子大脑官方给出的缓解措施如果客户端会主动填user_id就在/mcp前加认证JWT 的 subject 同时压过宿主传值与 agent 钉值。从 machine.py 的_warn_if_user_id_missing可以看到框架对无 user_id一侧的对应处理per-user store 在无 user_id 的运行中整体失活profile/memory 不暴露工具且每机只告警一次。日志发现的这条 FAIL 是它的镜像——问题不在没有身份而在身份被别家填了。做 MCP 化的个人记忆体时这一条应视为部署红线。7. 修复后的 4 轮复核forget 的退役语义闭环日志最后一节TEST_LOG.md记录审查修复后的 4 轮复核全新库、gpt-5.6以表格形式给出预期—实际轮次预期实际一条消息里给决策 人物 系统写带日期笔记、实体带指针建档、双向链接write_file notes/quill.md## 2026-07-26 - Concurrency control decision、remember_about(Quill, facts[concurrency control: Postgres advisory locks... - see note])、两次link_entitiesPriya has moved off Quill旧关系退役、新关系记录forget(Priya Raman, runs - Quill)在两行上删除了边随后link_entities(Priya, works_on, Billing rewrite)Quill 行只剩backed_by - postgresqlBetween us: the Nimbus renewal is shaky私有记忆、不建共享实体仅update_user_memory(...)库里不存在 Nimbus 实体Quill 什么状态为什么选 advisory locks读笔记并从笔记回答search_entities→read_file(notes/quill.md)→ 按推理作答并主动说明没有记录接任负责人日志特别点出退役轮是修复的关键修复前的代码对同样的调用要么匹配不到可操作对象、要么匹配到两个候选并打印得一模一样。另有一条模型行为备注第 2 轮用write_file整体重写了笔记而非replace_lines——被允许且笔记仍然正确。8. 如何复现环境准备与运行方式见 cookbook/examples/README.md# 仓库根目录 ./scripts/demo_setup.sh source .venvs/demo/bin/activate export OPENAI_API_KEY... cd cookbook/examples/second_brain # 命令行驱动捕获 跨 session 回忆 python test.py # 或起服务AgentOS 在 http://localhost:7777MCP 在 http://localhost:7777/mcp python second_brain.py示例文件夹遵循统一约定example.py构建 agent 并起服务test.py用命令行跑同一个 agent。数据落在tmp/second_brain.dbSQLite笔记以brain命名空间存于同一库——这也是日志能做每轮之间查库核对这种验证方式的前提。9. 这份日志作为验证方法论的可借鉴之处回看全文TEST_LOG 的价值不仅在结论更在做法可直接迁移到任何记忆/学习类 agent 的验证数据库即 ground truth不依赖对话表象每一轮断言都落到库里的具体字段superseded_by、archived_at、properties.note、双行边把agent 说它记住了变成记录确实以预期形态存在每轮新 sessionREST 与 MCP 全部在新 session 中发问从机制上排除 session 上下文回声对回忆的冒充跨通道矩阵REST 写 → MCP 读、MCP 写 → 新 session 读验证的是存储层而非接口层否定与隐私也要测搜不到要有有依据的否定私事必须不落到共享实体并自我声明——这两类负向行为往往是记忆系统最容易悄悄做错的FAIL 也进日志user_id被 MCP 宿主覆盖的发现没有粉饰而是转写进示例文件头注释成为部署说明的一部分。配套源码入口汇总示例本体 second_brain.py 与 test.py学习机器编排 libs/agno/agno/learn/machine.py实体记忆四工具实现 libs/agno/agno/learn/stores/entity_memory.py文件系统工具面 libs/agno/agno/fs/fs.py。【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考