轻量Agent框架pentagi:从规划到工具调用的完整实践
你们有没有遇到过这种尴尬大模型的 API 单独调起来很爽可真想让它替你干活比如定时抓取信息、整理成表格、再自动归档到本地就发现要写一堆胶水代码。我琢磨这事挺久后来趁几个周末把平时常用的 Agent 逻辑收敛成了一个轻量框架代号就叫 pentagi。名字听着挺玄乎其实就是 Penta 加 GI五个核心模块加通用智能。这个项目解决的核心问题很简单在不上重型框架的前提下给大模型一个能规划、能调用工具、能记住长期信息的“身体”。它适合个人开发者拿来做自动化助手也适合小团队快速验证内部系统的自然语言入口更推荐给想真正搞清楚 Agent 内部流转逻辑的人。我写这篇不是给你念官方文档而是把我设计时的取舍、实现时踩的坑、实际用下来觉得关键的地方都摊开讲。你读完至少能知道 pentagi 是怎么运转的、怎么部署一个最小实例以及遇到“模型反复调用同一个工具”“召回内容看着对但时序是错的”这类问题时该怎么下手。1. pentagi 到底是个什么东西1.1 名字拆解Penta GI先说命名。Pentagi 不是拍脑袋起的Penta 指的是我设计里的五个能力模块Planner 负责把大任务拆成可执行步骤Executor 负责真正做事的动作Memory 存储和召回上下文Toolbox 统一管理外部工具Coordinator 负责在多个 Agent 之间协调。GI 则是 General Intelligence 的缩写强调这套东西面向的是通用任务不是单一场景的 Demo。这五个模块听起来和市面上各种 Agent 框架大同小异但 pentagi 的差异点在于它的 AbstractAgent 基类和工具协议都极简所有模块之间通过标准输入输出通信不搞复杂的链式绑定。你可以很轻松地把某个模块替换成自己的实现而不需要理解整套框架的设计哲学。另一个很实际的设计取向是“本地可跑优先”。我的目标环境不是 K8s 集群而是一台普通笔记本或一台低配服务器。所以 pentagi 对显存和内存的控制很保守默认不加载重模型模型调用全走 API 或者本地推理服务的标准接口。1.2 项目想解决的问题网上有很多 Agent 框架但我在用的时候一直有种割裂感有的框架把抽象层级铺得太厚文档里全是 Chain、Graph、Node 这种概念新人想改个细节得翻半天源码有的框架又太偏 Demo演示视频里很酷实际接第三方工具时发现格式协议完全是私有的。pentagi 想解决的第一个问题就是“编排层太重”。我理想中的状态是大模型负责思考和生成结构化动作指令框架负责执行和返回结果中间不要夹太多无关抽象。第二个问题是“工具接入太麻烦”很多框架要求你严格继承类、实现固定生命周期方法而我更希望一个注册函数就能把普通 Python 方法变成 Agent 可调用的工具。第三个问题是“记忆系统与任务状态割裂”很多 AI Agent 只有短期上下文任务一长就“失忆”而 pentagi 把短期上下文和长期知识分开管至少保证“现在在干什么”和“以前学过什么”两个维度不会被搞混。1.3 适合谁不适合谁这个项目不是通用银弹。适合的人我觉得有三类第一类是个人开发者想做一个能定时汇总信息、自动写周报、整理 RSS 或网页内容的私人助手第二类是小团队想把内部几个只有 HTTP 接口的系统串起来统一用一个自然语言入口对话第三类是 AI 应用学习者想看一个“麻雀虽小但五脏俱全”的 Agent 框架长什么样源码量不大一天能读完。不适合的场景也很明确如果你需要海量并发、分布式编排、复杂的状态机流转pentagi 不是对手请去用正经的工作流引擎。如果只是想在聊天界面里接一个上下文窗口pentagi 也偏重直接调 API 更省事。它解决的是“介于随手脚本和专业平台之间的那一段”。2. 核心架构与设计思路2.1 五边形能力模型我最初画架构图的时候随手画了一个五边形Pentagi 这个名字就是那时候定下来的。这五个模块并不是一层套一层的工作流更像大脑的不同功能区。Planner 模块的职责是把用户输入转成一个带有明确依赖关系的执行计划。它输出的格式我定义成一个 JSON 数组每个节点包含节点 ID、动作类型、输入参数、依赖哪些前置节点。这个格式是贯穿全项目的主线模型只负责产出这个 JSON后续的 Executor 或 Coordinator 都消费这个 JSON。Executor 是真正干苦力的模块。它拿到 Planner 生成的节点后逐个执行并把执行结果写回任务状态表。如果某个节点失败Executor 会把错误信息原样返回给 Planner 做重新规划而不是直接让整个任务崩掉。这里有个关键点Executor 本身不知道业务逻辑它只会根据节点里的 action 去 Toolbox 注册表里查对应的工具函数。Memory 模块我拆了两层。短期记忆就是当前任务里的上下文存对话历史和节点执行结果存在内存里任务结束就清理。长期记忆则放向量数据库存的是“跨任务有用的知识”比如用户偏好、历史结论、工具返回的关键数据摘要。长期记忆的召回会影响 Planner 的初始规划比如你之前告诉过系统“我不喜欢邮件里附带 Excel”下次规划生成时它就会避免选择发送 Excel 附件。Toolbox 是个注册表每个工具是一个普通 Python 函数它接收一个字典参数返回一个可序列化的结果。用装饰器即可注册。这个设计是我刻意做的目的就是让“接入一个工具”的成本降到最低。Coordinator 只在多 Agent 场景下才活跃。它管理多个独立 Agent 的消息总线防止几个 Agent 同时操作同一个文件或资源时打架。节点依赖关系、共享变量、锁都由这个模块负责。2.2 一次完整任务的流转用一个例子串起来看。假设用户说了这么一句“帮我整理一下最近三天技术社区里关于大模型推理优化的讨论输出 Markdown 摘要存到工作目录。”任务进来后先经过一个轻量预处理层它会判断这是个需要多步骤执行的复合任务于是把原始文本转给 Planner。Planner 收到请求后结合长期记忆里“用户输出摘要时习惯要标题带日期”的偏好输出一段计划 JSON首先是调用搜索工具抓取关键词相关内容然后是解析内容并生成摘要最后是写入文件。Executor 拿到计划后先检查步骤间的依赖关系确定第一步搜索无前置依赖于是从 Toolbox 注册表里找到 search_web 函数并执行。搜索工具返回一批 URL 列表Executor 把结果作为参数传入下一步的 extract_and_summarize 节点。这一步可能由另一个 Agent 或同一 Agent 的二次规划来完成。最终 write_markdown 节点把摘要写入指定目录。全流程状态在 Console 日志里能看到哪个节点成功、耗时多少、输出大小。整个过程看起来就像一条流水线但不确定性的地方在于 Planner 每次生成的计划可能数量不同、顺序不同、工具组合不同这是 Agent 与固定工作流的核心区别。2.3 与主流框架的取舍对比很多人会拿 pentagi 和 LangChain、AutoGen 做对比。说实话我写 pentagi 的初衷并不是做一个“替代品”而是想保留最少的必要抽象。LangChain 生态很全但它的抽象层级多一个简单的工具调用也会经过 model、prompt、parser、output 多个环节改动成本高。AutoGen 在多 Agent 聊天式协作上很有想象力但它的会话模型会让不熟悉状态机的开发者摸不着头脑。我给 pentagi 定的设计原则是四个字协议优先。全系统只有两个核心协议一个是 Planner 输出的计划 JSON一个是工具函数的输入输出格式。只要满足这两个协议什么模型都能接什么工具都能挂。这就让pentagi的核心代码非常窄交给新手看也不会有压迫感。当然这种设计也有代价它没有内置太多高级功能比如复杂的条件分支、人工介入审批、可视化编排等。如果你需要的是一台万能机器pentagi 会让你失望如果你只是想快速把“模型工具记忆”跑起来并且后续方便自己改那它很顺手。3. 从零跑通一个最小可用实例3.1 准备环境与依赖我建议用 Python 3.10 以上的版本主要是为了类型标注和 Pydantic 的兼容性。安装依赖很简单核心包就几个python -m venv .venv source .venv/bin/activate pip install pydantic pyyaml httpx openai faiss-cpu sqlalchemy如果跑本地向量检索faiss-cpu 就够用了几百兆的语料完全没压力。SQLAlchemy 是用来做长期记忆和任务状态的落库默认 sqlite零配置文件。模型端我这边测试比较多的有两类一类是 DeepSeek 开放平台、通义千问这类国内可以直接访问的 API只需配好 key另一类是本地 Ollama 起的模型比如 qwen2.5 7B性能弱一些但数据不出内网。pentagi 的模型调用层兼容 OpenAI 接口规范所以只要能转发这个协议的地址都能配进去。3.2 配置文件怎么写pentagi 把可调参数都集中在 settings.yaml我建议刚开始不要乱动太多先配这几个provider: type: openai_compatible base_url: https://api.deepseek.com/v1 api_key: sk-xxxx model: deepseek-chat memory: top_k: 5 embedding_model: BAAI/bge-m3 store_dir: ./data/memory_store toolbox: whitelist: [search_web, read_url, write_file] timeout_seconds: 60 agent: max_iterations: 8 temperature: 0.2 verbose: trueprovider 段决定大模型从哪来。embedding_model 用 bge-m3 是权衡过精度的英文中文都能覆盖而且是本地跑的可以离线用。toolbox.whitelist 这个配置很关键它控制了当前任务实例可以调用哪些工具防止规划器头脑发热去调用不相关的危险操作。verbose 打开后你能看到每个节点的输入输出摘要调试期建议开。3.3 写一个自定义工具并把任务跑通举一个实际例子写一个“读取网页并提取正文”的简单工具。在 pentagi 里你只需要写一个普通函数然后加注册注解即可from pentagi.tools import register_tool import httpx from bs4 import BeautifulSoup register_tool(nameread_url, description读取一个网页链接的正文文本) def read_url(url: str) - dict: resp httpx.get(url, timeout30, follow_redirectsTrue) resp.raise_for_status() soup BeautifulSoup(resp.text, html.parser) for tag in soup([script, style]): tag.decompose() text soup.get_text(separator\n, stripTrue) return {url: url, content_preview: text[:2000]}就是这么简单一个纯函数被注册成了 Agent 可以调用的工具。Toolbox 注册表会利用函数名和 docstring 生成一个 JSON Schema放进系统提示词里让 Planner 知道这个工具叫什么、有什么用、参数长什么样。主程序入口更简单from pentagi import Agent from pentagi.memory import LocalMemory from pentagi import tools # 导入工具模块触发注册 agent Agent( settings_pathsettings.yaml, memoryLocalMemory.from_settings(settings.yaml) ) result agent.run(读取 https://example.com/blog 的内容并总结成 3 条要点) print(result.output)跑起来后verbose 模式会打印类似这样的日志Planner 生成了计划Executor 调用了 read_url然后又让 Planner 做了一次总结最终把结果输出。如果你给的工具越多样Planner 能编排出的任务就越复杂。3.4 启动调试的小技巧调试 pentagi 的时候有几个小技巧非常实用。第一个是开 dry-run它只让 Planner 产出计划而不真正调用工具适合验证“模型是否写出了正确的工具调用参数”而不是真的去执行副作用。第二个是每次跑完任务后查看 sqlite 里的 task_runs 表里面记录了每个节点的输入输出 JSON这样你能回溯模型在哪一步跑偏了。第三个是我自己加进去的“重放”模式把上一次任务的所有 LLM 请求参数保存下来调 prompt 时可以反复重放同一请求方便对比修改效果而不用真的重复调用工具。调试阶段会遇到最多的问题不是“模型不会写代码”而是“工具返回的结果太脏”。比如网页提取里混进了一大段导航文本摘要质量直线下降。这种问题的解法不是简单改 prompt而是让工具在返回前就做好清洗。工具内部的清洗永远比模型后处理更可控。4. 关键参数与记忆系统调优4.1 模型选择的权衡很多人在模型选择上容易犯一个错误就是只盯着推理模型挑忽略了一个事实Agent 框架里模型的职责不仅仅是推理还要严格遵守输出格式。我实际横向对比过几个模型在 pentagi 这种强制 JSON 输出的场景里有些声称很聪明的模型反而更容易自由发挥导致 Planner 输出的 JSON 不合规格。我的建议是先看模型的函数调用稳定性再谈聪明程度。如果你主要跑中文任务可以优先考虑 DeepSeek 或通义千问如果跑英文也可以按自己的习惯选择。为了兼顾离线场景我也建议本地部署一个中等规模的模型专门做规划和摘要虽然速度慢一些但胜在稳定可控。4.2 影响输出质量的关键参数在 settings.yaml 里有几个参数对最终效果影响特别大。第一个是 temperature我把它理解成模型的“发散程度”。做计划拆解时我强烈建议调低到 0.1 到 0.3因为计划阶段需要确定性和可复现性不需要脑洞但如果你让 Agent 写营销文案或周报标题可以把温度调到 0.7效果会明显更自然。pentagi 的一个特点在于planning 和 writing 阶段使用的是两套 temperature 配置这是我在实际使用中觉得非常有用的设计。第二个是 max_iterations它限制一个任务最多执行多少个节点防止 Planner 陷入无限循环。我一般设 8 到 12如果超出这个次数还没有产出结果就该反思是工具设计问题还是计划拆解问题而不是提高上限硬冲。第三个是 tool timeout。每个工具都有自己的超时时间忽略这个参数会导致一个很恶心的场景某个外部接口卡住了整个任务一直挂着直到全局超时才发现。现在我把每个工具默认超时设为 60 秒子类可以自行覆盖。4.3 长期记忆该存什么、怎么召很多 Agent 框架的长期记忆形同虚设原因主要是存的东西太杂。你要明白向量检索不是万能的更不能把所有聊天记录全塞进去否则每次召回都会混入大量无关信息。我的经验是长期记忆只存三类内容一类是用户明确表达的偏好比如“报告喜欢 PDF 格式”“邮件要抄送给组长”第二类是工具执行的关键结论比如“上次搜索得到的竞品价格表里最低档是 199 元”第三类是重要实体的关系比如“用户名张三关联的项目编号 P2024-013”。这些内容每条在入库前都会经过一次信息压缩用大模型把原文提炼成一句话然后才做向量化存储。召回的时候要注意时间权重。我试过只看相似度排名结果经常把三个月前的一段结论当最新事实用后来给每条记忆加了 time_decay 系数相似度分数乘以 exp(-age/30)相当于给记忆加了一个 30 天半衰期分数会随时间自然衰减。这个策略在“信息时效性高”的任务里很有用但对“用户口味偏好”这种长期稳定的记忆不太合适所以我在记忆条目上又加了一个 category 字段time decay 只作用在 news、data 这类类别上。5. 常见问题与排查实录5.1 现象、原因、解法速查表我整理了一张速查表都是你在使用 pentagi 时大概率会遇到的问题对应排查思路都已经被我验证过常见现象可能原因排查与解法同一个工具被连续调用多次Planner 没有意识到该工具已执行过检查 Executor 是否把结果写回 task state为工具名增加“已完成”的上下文摘要模型总是输出不符合 JSON 规范的计划prompt 里格式说明不够刚性把 JSON schema 直接放进系统提示词开启 response_format json_object长期记忆召回的内容明显过时时间衰减权重太小或 category 没设对调大 time_decay 系数检查入库前是否做了信息压缩调用外部 HTTP 工具一直超时工具没有单独设置 timeout_seconds给每个工具单独设定超时时间不要只靠全局配置多 Agent 同时写一个文件内容相互覆盖没有走 Coordinator 的资源锁对文件输出类工具增加单例互斥或让 Coordinator 串行调度写入节点任务运行中途模型报 context length exceeded短期上下文里塞了太多历史节点输出开启上下文压缩每次写回前用 LLM 做一次摘要更新5.2 几个容易踩的坑第一个坑是把系统提示词写得像作文而不是约束。我一开始给 Planner 写了大段“你是一个聪明的规划助手擅长拆解用户需求”之类的描述结果模型特别喜欢在输出里附加解释文本而不是纯粹输出 JSON。后来我把 system prompt 精简成三句话你是规划器只输出 JSON 计划禁止输出任何解释。效果立竿见影。第二个坑是工具函数没有做输入校验。因为 Planner 工具调用的参数是 LLM 生成的不是人敲死在代码里的所以你无法保证它传进来的参数合法。比如 read_url 的 url 参数它可能传入一个列表而不是字符串如果没有在函数入口做类型检查Pydantic 的报错会直接炸穿整个执行链。我的习惯是每个工具函数入口都用 isinstance 或 Pydantic BaseModel 做一次强校验宁可抛出可读的中文错误信息也不要让底层异常裸奔出来。第三个坑是向量库里存入了太多原始聊天内容。我最初图省事把用户每条输入都存进长期记忆结果是每次检索都召回一堆“嗯”“好的”这种无意义内容。后来做了源码级过滤和压缩才把长期记忆的质量提上来。这个过程的教训就是长期记忆的价值在于“精”不在“全”它更像人的长期记忆只留少而关键的事而不是对话录音。5.3 关于工具协议设计的一点体会工具协议是 pentagi 的地基我把每个工具统一成“输入一个 dict输出一个 dict”这个看似简单粗暴的设计极大简化了所有模块的对接逻辑。建议你在自己的使用过程中也不要轻易打破这个协议哪怕某个工具很特殊也尽可能包装成这种纯函数形式。这样做有三个好处第一所有工具输出可以直接序列化写入任务状态表方便追溯第二模型在生成工具参数时更容易对齐 JSON 格式第三如果你想让某个 Agent 能力扩展只需要注册新函数其他部分完全不用动。以我自己最近加的一个“分析本地 CSV 并输出统计摘要”的工具为例从写函数到注册进 Agent 跑通一共不到 20 行代码。这种轻量扩展的感觉是 pentagi 最让我满意的地方。如果你也想在小项目里快速拥有一个能规划会调用工具的智能体可以试着用这个思路做一个最小实现实践一圈下来你对 Agent 内部机制的认知会比读十篇概念文章更扎实。