把 AutoGPT、MetaGPT、BabyAGI、SuperAGI、AgentGPT、Dify 和 Open Interpreter 这 7 个开源 Agent 项目的源码放在一起翻完,最明显的收获是:开源 Agent 之间的差距,很多时候不在模型选型,也不在 UI 美观度,而在系统提示词和指令遵循的工程细节里。系统提示词是 Agent 行为的源头,决定它“是什么、能做什么、不能做什么”;指令遵循是让提示词真正落地的执行系统,包括输出解析、工具调用约束、失败重试,甚至历史消息的组织方式。
如果你正准备做 Agent 开发,卡在模型总是不听话、格式总是乱、工具调用经常半路断掉,与其反复改提示词,不如先去看看成熟开源项目是怎么写的。这篇文章就当一份源码阅读笔记,讲清楚我看到的 7 个项目在系统提示词和指令遵循上的不同设计,也会给出可以直接抄走的实现思路。
1. 为什么要啃 Agent 源码里的系统提示词
1.1 行为差异大部分藏在提示词工程里
很多人有一个误解:Agent 能力强弱,主要取决于底层大模型。真正跑过项目之后会发现,在同一个模型上,不同 Agent 框架的行为可以天差地别。用同一个模型接 AutoGPT 和 MetaGPT,前者可能一直在“思考、计划、再做下一步”,后者却会在几个角色之间来回发消息、仿真出一个团队流程。这个差异不是模型突然变聪明了,而是两套系统提示词和流程逻辑完全不一样。
从源码角度看,系统提示词不是一句“你是一个有用的助手”那么简单。它是 Agent 的默认行为手册,包括了它看到的任务、可用的工具列表、输出格式要求、边界规则、历史摘要方式,甚至底层模型所不知道的运行时状态。读源码时你会发现,真正专业的项目通常不会把 system prompt 写死在某个 Python 字符串里,而是拆成模板、角色信息、工具说明和用户输入多个部分,再在运行时拼装出来。
1.2 只改提示词并不能解决所有问题
我在做 Agent 开发时踩过很典型的一个坑:发现模型不按预期格式输出,就一遍遍加长系统提示词。加了“你必须严格输出 JSON”之后,短时间内有效,过一会儿换个模型又失效,甚至同一个模型换个上下文长度也失效。
之后翻开源项目才意识到,系统提示词只是指令遵循的第一层。第二层是代码侧的硬约束,例如输出解析器、JSON Schema 校验、Function Calling 参数校验、重试机制。AutoGPT 这类早期项目甚至会把“你必须按以下 JSON 格式返回”写得很重,因为底层模型不保证遵循格式,源码就要靠解析和重试来兜底。所以当你系统提示词改到 3000 字还不行时,问题大概率不在提示词,而在于缺少一段可靠的解析与校验逻辑。
1.3 这份对比适合谁参考
这篇文章适合几类读者。一类是做 Agent 开发遇到瓶颈的人,想看看成熟项目的设计套路;另一类是刚接触 Agent、想从源码学习工程写法的人,可以避开很多弯路;还有一类是正在做系统提示词优化,想理解“提示词之外还有什么”的人。这 7 个项目风格差异很大,读代码时不需要全部精读,抓住系统提示词和指令遵循这条主线就够了。
2. 7 个开源 Agent 项目和源码入口定位
2.1 为什么选这 7 个开源项目
目前市面上叫 Agent 的开源项目非常多,有的偏个人助手,有的偏多角色协作,有的干脆是低代码平台内的一个模块。如果只看两三个,很容易把某一个项目的实现当成“唯一标准”。我选这 7 个,主要因为它们覆盖了 Agent 发展的几条典型路线。
AutoGPT 和 BabyAGI 属于早期单 Agent 自主执行路线;MetaGPT 把“软件公司”的 SOP 设计成多角色协作;SuperAGI 走向了偏企业级、可配置的 Agent 平台;AgentGPT 更强调浏览器端的产品交互;Dify 则把 Agent 嵌入到可编排的 LLMOps 流程里;Open Interpreter 走的是“模型生成代码、机器直接执行”这条路。放在一起看,你才看得出系统提示词在不同 Agent 架构里承担的角色完全不一样。
2.2 系统提示词在源码里通常什么位置
阅读这类源码第一件事不是找模型调用,而是先定位提示词构造逻辑。常见搜索方式是直接搜system_prompt、system_message、build_prompt、prompt_template这些关键词。AutoGPT 的实现比较典型,代码里会把指导原则、命令、资源、约束等都搜集起来,最后拼成一个偏长的 system prompt;MetaGPT 则把系统提示词分散到每个 Role 的profile、goal和constraints里;Dify 里能看到用户配置的 System Prompt 最终被注入到每次对话上下文中。
我个人看代码的经验是,不要只找字符串,还要找“这个 prompt 是在哪个函数里被拼出来的”。因为拼装现场决定了哪些信息会被动态插入。比如工具列表是每次调用都注入,还是一次性写死,这两者的指令遵循效果差别很大。
2.3 7 个项目定位和提示词形态快速一览
| 项目 | 定位 | 系统提示词形态 |
|---|---|---|
| AutoGPT | 单 Agent 自主完成多步任务 | 长时间运行时动态生成的长篇 system prompt,包含指令、资源、命令、边界 |
| BabyAGI | 任务规划与执行循环 | prompt 较简单,主要靠任务目标字符串驱动 |
| MetaGPT | 多角色协作 Agent | 每个角色有自己的 profile、goal、constraints,系统提示词是“岗位说明书” |
| SuperAGI | 可配置 Agent 平台 | 通过 Prompt Builder 把目标、工具、约束拼成模板,结构清晰 |
| AgentGPT | 网页端 Agent 产品 | 用户输入目标后前端动态生成 prompt,后端负责工具调用循环 |
| Dify | LLMOps 平台内的 Agent 节点 | 用户可自定义系统提示词,后端按编排流程注入变量和工具定义 |
| Open Interpreter | 自然语言驱动代码执行 | system prompt 很精简,主要靠代码块解析和安全限制控制行为 |
这张表只是给你一个大致坐标。看源码时如果找不到系统提示词,不如先看这个项目是不是平台型产品,因为平台型会更倾向于把提示词做成“用户可修改的配置”,而不是纯代码常量。这条设计差异会影响你后续改造项目的难度。
3. 系统提示词设计的三种路线
3.1 路线 A:把系统提示词写成“完整角色手册”
AutoGPT 和 BabyAGI 可以被看成第一代 Agent 代表。AutoGPT 的思路非常直接:把目标、资源、命令列表、安全注意事项全部写进系统提示词,让模型在每一步都“重新读一遍规则”。我记得典型版本里的 prompt 会比较长,因为它会列出一大堆命令名称和格式,还会要求在输出里包含“Thoughts/Reasoning/Plan/Criticism”这些字段。这种设计的出发点很好,想让模型在未知环境中自己决策、自己复盘。但副作用也很明显:上下文被大量固定规则占据,留给真实任务的 token 变少;提示词越长,模型越容易注意末尾部分,指令遵循反而打折。AutoGPT 的源码里还要依赖两个机制补救:一个是在输出解析时反复修正模型给出的 JSON,另一个是当模型没按格式返回时要求它重新生成。
BabyAGI 是另一个极端。它没有把 Agent 做成会自我对话的“人格”,而是把它当成一个任务队列执行循环。它的系统提示词更像一个动态变更的目标描述,核心是“当前任务是什么、上一个任务的结果是什么、下一步该创建什么任务”。源码里看到的字符串很朴素,没有大量人格化设定。BabyAGI 的指令遵循能力其实更多靠极简提示词来实现,因为任务明确、输出接口简单,模型不遵循的空间比较小。
两条路线对比下来你会发现:系统提示词越长不代表指令越有效。AutoGPT 在无人化长任务里更强,但它靠的是代码补足了大量错误容忍;BabyAGI 更轻量,但它不适合做复杂工具调用。如果你要自己写单 Agent,更建议采用 BabyAGI 的“界面窄化”思路,而不是无限堆提示词。
3.2 路线 B:系统提示词成为“岗位说明书”
MetaGPT 和 SuperAGI 把系统提示词的设计往前推了一步。MetaGPT 的源码会定义多个角色,比如产品经理、架构师、工程师,每个角色都有自己的名字、目标和约束。你去看Role类相关代码时会发现,一个 Agent 的 system prompt 不是一次性拼完,而是在不同工作流节点里只暴露和当前角色相关的部分。比如产品经理的 prompt 里会强调输出 PRD,架构师会强调输出接口设计,工程师会强调代码实现。这种做法的意义在于,让每个 Agent 的注意力集中在自己职责范围,而不是一个 Prompt 里包含整个项目的所有规则。多角色协作时,指令遵循的“指令”不再只来自系统提示词,还来自工作流中的消息结构。
SuperAGI 相比 MetaGPT 更偏重“可配置”。它的源码里有一个 Prompt Builder 的角色,负责把 Agent 名称、目标、执行指令、可用工具列表、约束规则、反馈历史等拼成一份最终 prompt。你可以把 Agent 的模板理解成一张表单,系统字段是模型能力,业务字段是目标与工具,每次执行任务时都会被重新渲染。这个设计很适合产品化,因为非技术人员也可以调整目标、增加约束,不需要直接改代码。但从源码里可以看到,可配置性提升带来的代价是抽象层变多,出问题时需要一层层追踪 prompt 是从哪个字段拼出来的。
3.3 路线 C:提示词变成“用户可编辑的配置”
AgentGPT、Dify 和 Open Interpreter 这三者的共同点,是它们都没有把系统提示词当不可变的算法,而更像是把它当成产品配置。AgentGPT 会让用户填写 Agent 名称和任务目标,前端再把任务和 Agent 的背景拼在一起。Dify 更典型,你在应用编排页里可以设置“系统提示词”,后端在每次对话时再注入用户问题、工具参数和历史消息。这种做法对有运营背景的人非常友好,等于把最关键的控制权交出来。
Open Interpreter 的路径不太一样。它没有试图用长篇大论的 system prompt 去规定模型每一步行为,而是把核心放在“模型生成代码,执行器执行代码”。所以它的系统提示词通常很短,强调的基本是当前环境、代码块规则和安全边界。在 Open Interpreter 源码里,对模型行为的限制更多来自代码执行层的安全机制,例如允许执行哪些命令、哪些操作需要通过用户确认。这其实给了一个很重要的启示:指令遵循不能完全指望模型,要尽量把高风险动作从“让模型自觉”变成“系统强制拦截”。
3.4 三种路线对应的选择建议
如果你做的是通用型个人助手,想要自驱完成长链路任务,参考 AutoGPT 和 AgentGPT 的长提示词设计,但一定要配套输出校验器。如果你做的是企业内部流程自动化,MetaGPT 的岗位说明书思路最值得学习,因为它能让不同 Agent 的上下文更干净,指令冲突更少。如果你要给非开发人员配置 Agent,Dify 和 SuperAGI 的模板化配置是可抄作业的范本。Open Interpreter 这种“少提示词、重执行器”的路线更适合代码执行、运维控制类 Agent,不建议在需求模糊的聊天场景里照搬。
4. 指令遵循不只是提示词:源码里的硬约束
4.1 输出格式解析器决定了模型的“自由空间”
把 7 个项目源码里的模型调用看一遍,会发现它们基本都要求模型返回结构化内容。AutoGPT 早期版本要求模型输出 JSON,里面要包含 Thoughts、Plan 和 Command。MetaGPT 则要求不同角色输出固定消息格式。如果没有输出格式解析器,模型发挥空间太大,后面工具根本没法接。源码里它未必只是一个函数,而可能是正则提取、JSON 解析、字段校验、类型转换的组合。
所谓指令遵循,在工程上首先是“输出能被可靠解析”。系统提示词写得再好,模型仍然可能多输出一句问候语,或者把 JSON 包在 markdown 代码块里。这时解析器就要负责把脏内容过滤掉。如果你自己在做 Agent,我建议先把解析器写好,哪怕一开始只支持一种输出格式,也比在长提示词里反复喊“不要输出废话”更有效。
4.2 Function Calling 与提示词格式的取舍
新一点的 Agent 框架会更倾向于使用 Function Calling 或 JSON Mode,而不是在系统提示词里手工写工具 JSON。原因是工具参数本身很复杂,如果完全靠模型从文字里理解,很容易出现参数拼错。Dify 这类平台在接不同模型时,会遇到“这个模型支持 function calling,那个不支持”的差异,所以源码里会保留两套执行路径。支持 Function Calling 的模型走结构化工具调用,不支持的就退回到 ReAct 式的文本解析。
这个取舍直接影响了系统提示词怎么写。走 Function Calling 时,系统提示词通常不需要把工具 Schema 转换成大段文字,模型会从调用接口里直接拿到工具定义;走文本解析时,则要在提示词里明确写出工具名和参数格式。源码里你会发现很多分支都围绕“模型能力”展开。所以不要在网上抄一套 prompt 就到处用,先确认你的模型走的是哪条执行路线。
4.3 失败重试与自我纠正机制
看了这些源码之后,我强烈建议不要把“重试”当成补救手段,而要把“重试路径”当成 Agent 的基础设施。AutoGPT 早期非常依赖“如果输出格式错了,告诉模型出错了,让它重新生成”。这种做法的好处是实现简单,但代价是可能形成死循环。SuperAGI 和 AgentGPT 在重试逻辑上会更克制,通常只重试有限次数,超过后就进入人工确认或结束执行。
另外一个很值得学的是“自我纠正”。AutoGPT 输出里专门有 Criticism 字段,让模型批评自己上一步的计划。MetaGPT 的角色在产出结果后也会进入评审流程。但源码里你会发现,自我纠正并不是单纯让模型“再想想”,而是把外部反馈重新拼进 prompt,例如测试结果、编译错误、评审意见。真正的指令遵循,是让 Agent 能接收外部反馈并按反馈修正,而不是在孤立的对话里来回改自己的话术。
4.4 越权与安全边界不放进 prompt
我读这些项目时有一个强烈体会:安全边界类的规则,如果只写在系统提示词里,迟早会失效。模型可能被后续用户消息覆盖,也可能因为上下文截断忘记早期安全规则。Open Interpreter 的做法是,把可执行命令的权限放在代码执行器里,用白名单机制控制;Dify 在工具节点上会配置鉴权信息,Agent 无法自由调用没有密钥的工具。AgentGPT 也会在建 Agent 时限制使用的工具范围。
这说明“指令遵循”分为两个层次:低层是模型遵循系统提示词里的要求;高层是系统在工具调用前做参数校验和权限判断。你在源码里会看到有的项目把工具参数校验放在模型请求之后、实际执行之前,这是一个很好的兜底逻辑。只依赖提示词让模型“不要调用危险工具”,基本等于没有限制。
5. 能直接抄走的 5 个源码级设计
5.1 系统提示词模板化,不写死字符串
第一个可以马上学的设计是模板化。把系统提示词从prompt = "你是..."改成模板,再用变量注入任务、工具、历史摘要。七项目里 Dify 和 SuperAGI 最接近这个思路。模板化不等于一定要用 Jinja2,简单情况下用 Python 的格式化字符串也可以,但一定要做到“系统规则、用户目标、工具列表”三个部分互不打扰。
下面是我常用的一个最小结构:
SYSTEM_PROMPT_TEMPLATE = """你是一个{role}。 任务目标: {objective} 可用工具: {tools} 输出要求: {output_format} """这样做的价值是,每次要换角色或换任务时不需要重写整个提示词,只需要替换变量。而且对不同模型做效果测试时,可以快速控制变量。真正调试时你还能把最终拼出来的 prompt 保存下来,方便排查问题。
5.2 任务指令与执行策略分开管理
看 MetaGPT 源码时很受启发的一点是,它把“角色定义”和“单次任务目标”分得很开。角色定义回答“我是谁、我擅长什么、边界是什么”,任务目标回答“这次要交付什么”。很多 Agent 不听话,是因为系统提示词里同时塞进了大量一次性任务要求,比如“今天去查天气然后帮我订餐厅”,把它写进系统提示词导致每次对话都带着这个历史任务。
正确做法是维护一个长期系统层,只放与身份、能力边界、通用规范相关的内容;再把短期任务层放到每轮用户消息或独立变量里。这样模型既不会忘记身份,也能灵活切换任务。长期层越稳定,指令遵循的干扰因素越少。短期层则按轮次更新,避免上下文被过期目标污染。
5.3 工具列表按轮次注入,不要一次塞满
在 AgentGPT 和函数调用型源码里,工具列表不一定全部塞进系统提示词,而是按照当前步骤能够使用的范围做筛选。例如一个 Agent 可能有 50 个工具,但当前子任务只需要其中 5 个,就把这 5 个注入。这种做法看似多做了过滤,实际收益很大:模型可选择范围变小,错误调用概率明显下降。
自己做 Agent 时也容易犯“把所有工具都告诉模型”的毛病,总怕它能力不够。结果模型开始疯狂调用不该用的工具。更好的做法是建立工具注册表,每个工具带 metadata 和适用条件,在拼装系统提示词前先用规则或模型判断当前阶段需要的工具子集。这个过程即使简单粗暴,也比全量展示好。
5.4 记录完整 prompt,而不是只记录答案
很多开源项目在调试面板里并不会展示完整 system prompt,但对开发者来说,没有完整 prompt 几乎没法定位问题。我自己踩过几次坑后发现,最好的习惯是在每次请求前把最终 prompt 存日志,尤其是系统提示词、工具 Schema、最近几轮消息都拆开存。一旦模型行为异常,打开日志看拼接结果,绝大多数问题都能立刻发现。
调试 Dify 这类低代码平台时你可能看不到底层 prompt 拼接细节,这时就要用代理日志或者在源码里打断点。好的 Agent 源码通常会在请求模型前留一个日志钩子,帮你把 prompt 打出来。如果你的项目还没有这个能力,建议补上,比任何提示词优化技巧都值钱。
5.5 先写校验器,再调提示词
最后一个建议来自多次失败经验:不要把提示词调优当成唯一手段,先写一个输出校验器,把模型返回结果的关键字段校验好。比如你需要模型返回 JSON,至少先检查它能不能被json.loads解析,字段存不存在,值类型对不对。校验不通过时,再把原始输出拼到重试消息中让模型修正,而不是默默丢弃。
四五个 Agent 项目的源码都有一个共同气质:提示词靠设计,校验靠代码。两者不应该互相取代。你的 Agent 越复杂,越需要把“不能出错”的逻辑从提示词迁移到代码边界里。比如要 Agent 调用搜索工具,可以在代码里规定必须传入关键词,如果模型漏了参数就直接重试,不要在系统提示词里大吼“你必须带关键词”。这样模型输入什么其实不那么重要,系统质量和稳定性明显更高。
6. 调试系统提示词时踩过的坑
6.1 遇到不遵循指令,先看冲突而不是字面密度
一个常见问题是 Agent 突然不遵循系统提示词。新手会大幅增加提示词,老手会先检查有没有“指令冲突”。源码里经常出现的情况是,系统提示词里说了“不要猜测”,但用户消息的若干个 few-shot 示例都在展示猜测行为,模型就会优先学 few-shot。或者某个工具返回的文本被拼进上下文后,携带了“忽略之前指令”的文字,直接把系统提示词带偏。
我在调试时总结出的排查顺序是:先查最近几轮消息里有没有和后端规则冲突的内容;再看工具返回结果有没有作为用户角色进入上下文;最后才是调整系统提示词措辞。这比单纯让 prompt 更严格要高效得多。
6.2 同一个 Prompt 在不同开源项目里表现不同
很多人会把一个项目里的系统提示词复制到另一个项目里,效果却不对。原因并非提示词质量突然下降,而是执行细节不同。MetaGPT 在多角色环境里会插入大量中间消息,角色的历史非常长,AutoGPT 的 Prompt 是独立生成的;Open Interpreter 则把大部分任务交给代码执行。把 AutoGPT 的长篇角色设定搬到 Open Interpreter 会非常浪费,甚至扰动代码生成。
正确做法是理解每个项目默认的“prompt 上下文结构”,再决定要抄什么。如果你想改善指令遵循,可以参考 SuperAGI 和 Dify 的模板化配置;如果你想抄输出解析,AutoGPT 的容错思路很好;如果你想抄多角色协作提示词,MetaGPT 是不二之选。不要只拿一段文本套所有架构。
6.3 一套稳定的调试循环
最后分享一套目前验证过的调试流程。先在源码里找到最终 prompt 的拼接函数,给它的返回值加日志。接着固定一批测试用例,保持同样的用户输入和历史上下文,避免模型随机性干扰判断。然后开始调系统提示词,每次只改一个变量,看它对输出格式和任务完成度的影响。系统提示词稳定以后,再去调工具 Schema 和参数校验规则。最后再测试边界输入,比如空工具返回、超长文本、恶意指令,确认安全限制是靠代码落地的。
我在实际使用中发现,把七成精力放在输出结构和校验上,比把七成精力放在写精美提示词更有用。系统提示词只要做到简洁、不含糊、不冲突,剩下的稳定性交给代码,Agent 的表现通常不会差。