新闻详情

新闻详情

首页 / 资讯中心 / 详情

从零搭建个人智能体:agent框架、harness与记忆系统的踩坑复盘

发布时间:2026/10/2 19:08:54来源:尧图网络
从零搭建个人智能体:agent框架、harness与记忆系统的踩坑复盘
把 pi agent 从零搭起来整个过程跟拿到一套毛坯房差不多框架给你了墙是灰的地是水泥的水电管线全要自己埋。我前后折腾了小一个月踩过的坑比卫生间要贴的砖还密。这篇文章不是那种一步步照做的教程而是把我装修这套 agent 毛坯房时最痛的几个环节拎出来复盘给准备自己动手搭 agent 或正在被 agent 框架折磨的朋友做个参照。先说清楚它是什么pi agent 是我给自己做的一个本地优先的个人智能体项目代号 pipersonal intelligence能连工具、能调模型、能挂技能也能跑在低性能设备上。它能解决什么问题主要是把散落的日常任务——查资料、写周报、整理本地文件、定时提醒——统一收口到一个可以长期用、可以随时改的 agent 里。适合谁看想自己搞 agent 但不想直接用全家桶、愿意花时间理解底层的人如果你只想开箱即用这篇帮不了你太多。1. 项目定位与整体设计为什么偏要选“毛坯房”思路1.1 想象中的“精装交付”和现实差距最早我差点就走“精装房”路线找一个现成的 agent 平台注册账号、点点配置、填几个 API key看起来一天就能跑起来。但实际用下来发现槽点非常明显。平台把 agent 的基本结构定义得太死了我想加一个“把网页收藏整理成 Markdown 笔记”的技能结果工具链被平台锁死只能写它规定的插件格式调试起来等于在框架里做适配不是在写自己的东西。而且数据全在对方云端我本地文件它碰不到我想要的“本地优先”核心需求直接被砍掉。这时候才意识到所谓精装房其实是用自由度换便利。而做 agent 这种事自由度恰恰是最值钱的部分。你早晚要改它的思维链路、要替换模型、要接自己的工具这些在封闭平台里都是难题。于是决定回到毛坯房框架自己搭管线自己埋每一层都搞明白再往上盖。1.2 “毛坯房装修”在这个项目里的具体含义我给自己定的规矩是不依赖任何一站式 agent 套件只保留最基础的编程框架模型接入、工具调用、记忆管理、子任务拆分这些全部自己定义。这就像毛坯房只能提供墙体结构和基础水电点位其他全部自己设计。但不是什么都从零写。LLM 调用 SDK 可以复用现成的HTTP 服务用 FastAPI任务循环这段核心逻辑自己写。这样做的好处是每换一个模型、每加一个新工具都知道该动哪一根筋不担心被框架牵着走。缺点是前期成本明显更高而且你有大量机会犯低级错误——后文要写的各种坑基本都是这么来的。1.3 目标拆解与验收标准动工之前我把“装修验收标准”列了出来做成清单后面所有工作都对着这个清单检查核心对话链路用户输入 → 模型决策 → 工具调用 → 结果回填能在本地完整跑通。记忆可用短期对话记忆、长期偏好记忆分开存重启不丢。技能可扩展不用改主程序加一个新技能只需要新增一个文件。安全可控agent 能做的事有权限边界风险操作要二次确认。资源可承受在只有 4GB 内存的迷你主机上也能流畅运行。这套验收标准在后面帮了大忙。很多时候坑了很久不是因为技术难而是忘了最初要解决什么问题。2. 硬装阶段agent 框架、harness 与底层通道搭建2.1 框架与 harness 的区别别选错“施工队”刚开始接触 agent 开发时搜索词里总能看见两个词agent 框架和 agent harness。很多人混着用但实际施工时区别很大。我的理解是harness 是脚手架负责把模型输出、工具调用、任务循环这几块拼起来让你能看到整个执行过程框架则是带装修方案的一体化工装不仅拼起来还帮你定了房间怎么隔、开关装在哪。毛坯房逻辑下我选择先用最少依赖写 harness而不是一上来就上重型框架。原因有两个一是重型框架的抽象层级太高出了问题很难定位你都不知道是哪一层把消息吞了二是未来换模型、改协议时harness 的改动成本低得多。实际代码结构大体是这个样子核心循环非常朴素messages load_short_term_memory() while True: response llm_chat(messages, toolstool_schema) if response.finish_reason tool_calls: for call in response.tool_calls: result execute_tool(call.name, call.arguments) messages.append({role: tool, tool_call_id: call.id, content: result}) continue reply response.content save_short_term_memory(messages [{role: assistant, content: reply}]) break这套 harness 足够应付绝大多数单线程任务。真的遇到复杂场景再往里面加 subagent 和并发控制不会一开始就背上重担。2.2 两条主通道LLM 接入与工具注册agent 的硬装核心有两条通道一条是通往大模型的对话通道一条是工具调用的执行通道。这两条没埋好后续全是漏水。对话通道我做了三层设计统一接口层、模型适配层、错误重试层。统一接口层保证主程序不感知具体模型模型适配层负责厂商协议转换错误重试层是我在踩完坑后补的下面细说。工具注册通道则采用装饰器模式新增技能只需要暴露函数和参数 schemaagent_tool(namesave_note, description把指定内容保存为Markdown笔记) def save_note(path: str, content: str) - str: # 实际写入逻辑 return fsaved to {path}工具参数说明一定要写清楚LLM 很依赖参数描述来决定填什么值。描述含糊的后果就是调用时经常传错参数或者干脆不调用。2.3 高频翻车response stream was malformed 的三类现场我踩到一个特别经典的报错原话是pi error: the response stream was malformed and no response was produced. try again.第一次看到这行字我以为是大模型服务端出了问题后来连续复现才意识到问题几乎都出在我自己身上。归纳下来有三类第一类是流式响应解析太严格。有些厂商的流式输出中间会夹杂空行、注释、或者 SSE 事件里的额外字段我的解析逻辑一遇到非预期格式就直接抛出异常。处理方式是把解析器改成容错模式只提取自己关心的字段忽略其他内容而不是让解析器去“校验”整个流的合法性。第二类是超时设置太短。长任务下模型偶尔会在思考阶段停顿十几秒才输出第一个 token而我的客户端超时设成了 10 秒连接被掐断后自然拿不到完整响应。后面把所有超时全部调到 60 秒以上同时加了心跳问题明显减少。第三类是上游模型偶发故障属于不可控因素。这种场景唯一能做的是做好重试和降级。我用的重试参数是最多重试 3 次退避按 1.5 的指数递增最长等待不超过 10 秒。三张表总结如下异常来源典型特征对策客户端解析过严固定在某段格式特殊内容附近失败解析器改为容错模式连接超时设置过短固定等一段时间后失败调大超时增加心跳上游模型故障随机出现重试后可能成功指数退避重试最多 3 次2.4 并发问题agent 怎么扛并发新手最容易想错相关搜索里频繁出现“ai agent 怎么扛并发”这问题我也研究过。先说结论普通个人 agent 项目建议先别碰并发老老实实把单路请求跑稳再去想并发的事。为什么这么说agent 和普通 Web API 最大的区别在于它要维护对话状态相同用户的多轮请求往往共享同一段上下文。如果你无脑加并发同一上下文的多个任务同时写记忆会出现记忆错乱、上下文打架最后行为变得像精神分裂。我在早期实验中用线程池同时跑了两个任务结果一个任务把另一个任务的中间结果当成了自己的上下文背景回答彻底跑偏。真要扛并发得在“任务”这个层级做隔离而不是“请求”层级。每个独立任务分配独立的 session拥有独立的短期记忆和上下文完成后异步合并结果。同时还要做限流我用的是令牌桶单模型通道的消费速率被限制在每分钟 6 次调用实测对大多数日常场景完全够用。3. 水电改造记忆、上下文与 skill 系统设计3.1 记忆分层把长期记忆和短期记忆分开毛坯房的水电改造对应到 agent 项目就是记忆系统。很多人一开始只用一个 messages 数组跑几个小时后上下文越滚越长最后模型直接失忆——开头说的什么都没记住。我的方案是把记忆拆成三层短期记忆、长期记忆、工作记忆。短期记忆是当前对话窗口内的 messages保存到本地 SQLite重启对话时恢复。长期记忆是用户偏好和事实类信息以结构化键值对存储比如“用户喜欢简洁回复”“用户的工作时间 9:00-18:00”每次对话结束后由模型抽取关键信息写回。工作记忆是当前任务中的临时状态任务结束即清除。三层各自独立存储互相不污染。这样即使上下文窗口被截断长期记忆也不会丢。3.2 上下文窗口卫生别把记忆当垃圾桶上下文窗口是 agent 最贵的资源窗口卫生直接决定回答质量。我用了一个 8k 上下文的模型做测试一开始把所有历史消息一股脑塞进去到第 10 轮对话时模型开始答非所问。原因不是模型变笨了而是早期无关信息把关键指令淹没了。后来每次请求前做上下文修剪规则是把对话前 2k token 压缩成 300 token 的摘要。完整保留最近 3 轮对话原文。长期记忆里与当前任务无关的条目全部剔除。用户当前指令始终放在最前面确保模型注意力优先。压缩后的整体预算大约控制在模型上限的 80%比如模型支持 8k我就把所有内容控制在 6.5k 以内给工具返回结果留出冗余。3.3 skill 导入与版本管理从 pi web 导入 skill 踩过的坑相关搜索里频繁出现“pi web 导入 skill”这正好戳中我的痛处。skill 我理解成 agent 可复用的能力包一个 skill 包含一段系统提示词、若干工具定义和触发规则。最初我把 skill 写死在代码里每次改 skill 都要重启服务非常痛苦。后来才改成独立文件加载每个 skill 一个目录skills/ web_research/ SKILL.md tools.py requirements.txt note_organizer/ SKILL.md tools.pySKILL.md 里面写清楚这个 skill 的适用场景、触发条件和关键指令。加载器启动时扫描所有子目录注册对应的工具并在系统提示词里注入 skill 的摘要信息。版本管理也踩了坑。一开始我直接用pip install安装所有 skill 依赖结果两个 skill 出现依赖冲突启动报错。后面改成每个 skill 使用独立虚拟环境加 subprocess 隔离执行冲突问题直接消失。3.4 subagent 拆分什么时候该拆、什么时候不该拆agent 项目里流行用 subagent也就是主 agent 派生出若干个子 agent 分别处理子任务。但我实际用下来发现subagent 不是越多越好。适合拆的场景一个任务包含多个相互独立的调研方向比如“对比三款笔记软件的优缺点”可以拆成三个子 agent 分别调研再汇总。前提是子任务之间没有状态依赖。不适合拆的场景任务链路是严格的串行逻辑比如 A 的结果直接影响 B 的执行方式。这种拆了反而增加通信开销而且子 agent 之间只能通过结构化消息交换信息细节容易丢失。早期我一股脑把任务全拆成 subagent结果主 agent 光是等结果就等了十几分钟还因为某个子 agent 返回格式不规范导致汇总失败。后面我给自己定了一条规矩单任务执行时间超过 20 秒且子任务可完全独立时才允许拆。4. 软装与安防权限沙箱、部署形态与实际调试技巧4.1 给 agent 装防盗门权限边界与沙箱设计agent 能调工具就意味着它有“手”。这手能伸多长是装修时最需要想清楚的安防问题。我给 agent 的权限做了三层限制第一层文件系统隔离。agent 默认只能访问工作目录不能读系统目录更不能碰用户主目录里的敏感文件。读取文件前先做路径规范化防../../跳目录。第二层命令执行隔离。需要执行 shell 命令的技能全部跑在子进程里设置独立的用户账号和低权限组CPU、内存、磁盘配额全部限制。对外网络访问用白名单只有少数域名允许连接。第三层危险操作二次确认。删除文件、覆盖写入、发消息这类特定操作必须经过人工确认才能执行。实现方式是在工具返回结果里插入一个pending_approval标记主循环遇到这个标记就停下来等用户输入。这三层下来即便 agent 被恶意提示词诱导能造成的破坏也很有限。4.2 桌面版与服务化两种部署形态的取舍项目做到后期需要部署搜索里经常出现“oh my pi 桌面版”“pi desktop”“hermes agent 桌面版配置”说明很多人关心桌面形态。我的实践是服务化和桌面版都做但它们解决的是不同问题。服务化部署适合无人值守和远程调用agent 作为后台服务常驻通过 HTTP 接口与外部系统对接。桌面版则适合交互场景用户能直接看到思考过程、手动修改工具结果适合高频使用场景。我自己在 Windows 上配置桌面版时最大的坑是环境变量没对agent 服务读不到 API key 导致反复报认证失败。排查路径是先在终端里确认环境变量能正常输出再启动桌面客户端问题瞬间定位。4.3 场景联动树莓派、ROS2 与嵌入式设备的接入边界很多人的 agent 不只是跑在电脑上还要跟硬件联动。相关搜索里出现“raspberry pi 2040 oled 0.96”“docker 容器里的 ros2 humble micro-ros agent”说明这类需求相当普遍。我在树莓派上也部署过精简版 pi agent目的是把本地的温湿度传感器数据周期性汇报到 agent 记忆里。硬件接入方式并不复杂agent 不用直接操作 GPIO只需要暴露一个本地 HTTP 端口让树莓派上的采集脚本定时推送数据即可。OLED 屏幕则用来显示 agent 的运行状态比如当前任务、上下文占用百分比。昂ROS2 环境如果要接 agent更建议以 micro-ros agent 作为消息代理让 agent 通过 ROS2 话题收发信息而不是直接去改 ROS2 的主程序。这种联动场景的核心教训是agent 不要试图直接控制硬件而要做成消息的消费者和生产者的角色。否则硬件中断和任务循环混在一起出了问题无从查起。4.4 调试技巧从日志反推 agent 意图而不是猜agent 调试和传统程序调试完全不一样。传统程序报错有明确堆栈agent 的“错误”可能只是一个偏离预期的回答或一次多余的调用。这时候必须给 agent 的行动留痕。我在每轮循环里输出三段日志thought模型的思考片段、action调用的工具和参数、observation工具返回结果。只要这三个字段完整任何一个环节出问题都能快速定位。对比下来过去要花一下午猜“为什么这样回答”现在看三段日志最多十分钟就搞清楚基本就是工具返回格式不规范或者系统提示词某句话导致模型理解偏差。另外模型调用失败时不要急着发愁。我遇到“codex 无法发送消息显示更新 agent 沙盒”这类问题普遍解法是重启沙盒服务而不是反复重发消息。沙盒状态和上下文不一致时重发只会让错误继续滚雪球。5. 装修验收一整套实测清单与踩坑速查表5.1 实测验收清单我每次改版后都跑一遍项目改到后期我总结了一套验收清单每一版改动都要过一遍避免修了新 bug 又弄坏旧功能。单轮对话链路输入一条指令观察 thought、action、observation、reply 四个阶段是否完整。工具调用正确性让 agent 调用一个需要参数的工具检查参数是否按 schema 正确填写。记忆持久化执行一轮对话后重启服务确认短期记忆和长期记忆都已恢复。上下文修剪生效多轮长对话后打印实际请求 token 数确认不超过预算。权限拦截生效故意触发一个危险操作确认需要二次确认。并发隔离同时跑两个独立任务确认双方上下文无串扰。低资源可用性在 4GB 内存的机器上连续运行 24 小时确认无内存泄漏。5.2 高频故障速查表都是真金白银换来的现象根因解法response stream was malformed解析容错不够/超时太短/上游故障容错解析、调长超时、指数退避重试上下文越长回答越偏早期信息稀释指令窗口修剪、摘要压缩、关键指令前置工具调用参数瞎传工具描述或参数描述含糊重写工具定义例写明格式和单位两个 skill 依赖冲突共用全局依赖环境每个 skill 独立虚拟环境执行并发后行为分裂同一上下文被多任务同时写任务级隔离独立 session桌面版启动报认证失败环境变量未正确继承先在终端输出确认变量再启动5.3 给新手的装修顺序建议经历过这一遭以后我给后来者的核心建议是先按毛坯房的标准搭一个最小可用的 harness把单轮对话和工具调用跑通再考虑记忆、subagent、并发这些高级功能。顺序千万不能反。反了的典型下场是框架选得很豪华功能上了一堆结果连最基础的工具调用都没跑通排查问题时每一层都可能是嫌疑犯根本无从下手。我有个朋友就是这个情况最后把代码全部推倒重写只用我最开始的朴素循环反而两天就上线了。我个人的体会是做 agent 项目最大的坑往往不是技术难点本身而是“过早追求复杂”。毛坯房的好处就在这每一根管线你都见过施工过程。等哪天它漏水了你知道该拆哪块砖。这种底层的掌控感是用任何精装框架都换不来的。项目后续能扩展的方向也很多比如把语音输入接到 agent、给 agent 配一个自动写周报的 skill、或者把它做成局域网内多个设备共享的中枢。不过这些都是后话了先把毛坯房住稳比什么都强。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

AI Agent安全实战指南:从工具调用、MCP到权限控制,用TaoToken统一Key管住智能体边界 2026/10/2 20:38:35

AI Agent安全实战指南:从工具调用、MCP到权限控制,用TaoToken统一Key管住智能体边界

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
GPT-5.6 Sol Ultra 模式跑一周:4 个 Agent 并行实测与 TaoToken 统一 Key 接入 2026/10/2 20:38:29

GPT-5.6 Sol Ultra 模式跑一周:4 个 Agent 并行实测与 TaoToken 统一 Key 接入

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
AI Coding 零基础实战教程|第五部分:完整项目案例实操:用 TaoToken 统一 Key 跑通 Next.js + TypeScript + Prisma 全流程 2026/10/2 20:38:29

AI Coding 零基础实战教程|第五部分:完整项目案例实操:用 TaoToken 统一 Key 跑通 Next.js + TypeScript + Prisma 全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
真机无线测试实战:TaoToken 统一 Key 打通 Android APK 局域网调试链路 2026/10/2 20:38:29

真机无线测试实战:TaoToken 统一 Key 打通 Android APK 局域网调试链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Delphi中Chrome Chromium、Cef3学习笔记(五):把Cef3的缓存与Cookie路径改到TaoToken统一通道 2026/10/2 20:38:29

Delphi中Chrome Chromium、Cef3学习笔记(五):把Cef3的缓存与Cookie路径改到TaoToken统一通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
六类高频陷阱与规避方案:单元测试如何从“测实现”到“测行为” 2026/10/2 20:38:22

六类高频陷阱与规避方案:单元测试如何从“测实现”到“测行为”

说句实话,在一线写代码这么多年,我见过太多把单元测试当成绩效考核应付的项目了——测试覆盖率报表全线飘绿,一上线照样出故障;随便重构一个方法,测试文件立刻红成一片;到最后团队受不了,干脆把…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉