我最近在尝试构建一个基于DeepAgents框架的多Agents代码审查工具。这个工具的目的是去审查一个陌生的代码仓库,为我梳理出代码架构和其中的安全风险。我本人在Agent开发方面算是经验极少,这算是我的第一个Agent项目。所以,在开发过程中会遇到很多的问题,也带来很多的经验感悟,这对于同样是新手的读者来说是很有用的,所以我打算记录和分享出来。同时我自己个人的代码水平也很差,这个项目的几乎所有代码都是使用AI写的,所以这对代码基础差的读者也有不少参考价值。
框架、架构与模型
从开发流程来看,当你有了一个 Agent 开发的想法,并将需求比较完整地写下来之后,下一步就是确定主要的技术路线,也就是选择什么框架、采用什么架构。
框架
现如今可用于 Agent 开发的框架已经不少了,例如 LangChain、LangGraph 等。但对我来说,DeepAgents 最大的吸引力在于,它原生支持 skill 和 subAgent。相较于前两者,这个较新的框架大致有这样几个特点:其一,Agent 可以借助 todo 工具动态组织运行图,而不需要开发者手动定义完整流程,编程负担更小;其二,它同时支持工具与 skill,这一点比较符合我对 Agent 开发演进方向的理解;其三,它原生支持子 Agent 和多 Agent 协作,挂载和组织方式也相对简单。总体来说,这是一个比较新、能力较强、同时又相对易上手的框架,对我这种基础还不够扎实的新手开发者而言,确实更友好一些。

不过,新框架的优势往往也伴随着新框架的问题。DeepAgents 大约是在 2025 年下半年左右发布的,目前在视频平台上仍然缺少比较成熟、系统的教学内容。同时,很多编程 AI 的知识库主要还是停留在 2024 年,对这类新框架的覆盖并不充分。于是这时如果还想单纯依赖 vibecoding,风险就会明显上升:你看不懂代码,AI 也未必真正懂这套框架,你更不知道它到底做了什么,整个项目很容易变成一个黑箱。
在这个项目的前期探索阶段,我就因为这个问题反复推倒重来过好几轮。最后我才意识到,对于这种较新的框架,最稳妥的做法还是先老老实实阅读文档,再根据文档认真设计系统,而不是一上来就让 AI 自由发挥。好在现在不少框架都支持通过 MCP 服务器挂载到编程 AI 上,让 AI 先获得对应框架的开发知识。于是到了后期,每当我要新开一个编程 AI 会话时,我几乎都会先给出一段固定指令:“请使用 MCP 工具阅读 DeepAgents 相关文档,了解开发规范;然后阅读设计文件,理解项目设计与需求;最后概览项目文件,了解当前开发进度。”至少这样做之后,AI 不再是在“盲写”,而是在一个相对明确的知识和约束条件下协助开发。
架构
至于架构设计,它其实与框架本身也存在一定关联。所谓架构设计,本质上就是职责分配与通信协作机制的设计。因此你首先要看,所选框架是否已经在这些方面做出了明确规定。
但在 DeepAgents 中,框架本身主要定义的是 Agent 的加载方式、记忆管理、几个系统工具以及运行后端,并没有显式规定各个 Agent 应该承担什么职责,也没有替你定义好多 Agent 之间的通信与协作机制。换句话说,这部分工作最终还是要由开发者自己来设计。因此,职责如何拆分、模块之间如何通信、协作过程如何组织,都会变成架构设计中的核心问题。

这时还会出现一个更基础的问题:为什么一定要做职责分配和多模块通信?这真的是必要的吗?我觉得这是一个必须认真思考的问题,而不是不加判断地把系统越堆越复杂,仿佛“大”就一定更好。
从 LLM 本身的特点来看,过长的上下文会让系统提示词和用户需求的注意力逐渐稀释,最终导致运行稳定性下降,效果也随之变差。因此,当你面对的是复杂任务时,一个重要思路不是一股脑把所有信息都塞给同一个 Agent,而是尽可能把问题拆分成若干个上下文相对独立、对全局上下文不那么敏感的子问题,并通过适当的上下文隔离来提高处理质量。也正因为如此,仔细思考需求本身、思考你真正要解决的问题是什么,就显得格外重要。
对我所面对的代码审查任务来说,这种拆分几乎是天然需要的。因为我真正关心的,往往只是整个仓库中的一部分代码;而在这部分代码里,真正存在风险的内容通常又只是更小的一部分。但与此同时,安全审查又非常看重查全率,不能因为过度聚焦而漏掉关键风险。所以,我最终需要的是一种分工明确的多 Agent 结构:有的 Agent 负责全局理解和架构梳理,有的 Agent 负责盯紧敏感点和风险链路,有的 Agent 负责做交叉验证,最后再由汇总代理生成较完整的审查报告。
但一旦架构变复杂,通信与协作的重要性就会迅速凸显出来。理论上,Agent 之间当然可以通过输入与返回值来相互传递任务和要求,告诉对方“该做什么”“做到什么程度”。可这种通信方式在实际开发中会带来几个明显问题。
第一个是偏移问题。当一个流程运行时间变长、链路变多之后,Agent 的记忆和目标很容易发生混乱,最终导致总结阶段出现遗漏,或者结论逐渐偏离初衷。
第二个是可观测性问题。如果中间过程完全靠返回值在 Agent 之间隐式流动,那么即便你可以借助 LangSmith 一类工具做链路追踪,这种协作过程对开发者和最终用户来说依然不够直观,也不够让人安心。
第三个是结构化问题。有些中间产物本身就是有独立价值的,例如仓库架构梳理结果、模块关系总结、风险点清单等。这些内容不仅要传递给下一个 Agent,还可能需要被其他程序进一步消费、展示或存储。如果中间产物缺乏结构化设计,后续处理就会变得很困难。
因此,Agent 之间如何分配任务、如何感知彼此做了什么和没做什么、如何沉淀出高质量且结构化的中间产物,其实是架构设计中的关键问题之一。这个问题会直接影响系统是否可调试、可扩展、可复用。至于这部分具体该怎么做,我会在后面的工具和 skill 部分继续展开。
模型
模型选择不应该等到你把系统开发到一半,发现 Agent 总是产出低质量报告、总是在重复错误调用工具,你自己已经开始“红温”和抓耳挠腮的时候,才被动拿出来考虑。这个问题应该在项目一开始就认真想清楚。
根据我的经验,一个 Agent 运行得是否稳定,输出的报告是否高质量,是否真正符合系统提示词和任务需求,其影响因素中最关键的一项,很多时候并不是提示词写得够不够花,也不只是上下文有没有被污染,而是你到底用了什么模型。换句话说,如果你希望自己拥有更好的开发、调试和使用体验,那么优先选择更合适、更高质量的模型,往往比后期疯狂修 prompt 更有效。当然,这里面依然需要结合成本做权衡。
一个适合 Agent 场景的模型,通常至少要具备几种能力:较稳定的记忆保持能力、较主动的任务执行倾向、较可靠的工具调用能力,以及在复杂约束下维持行为一致性的能力。凡是这些能力同时比较强的模型,通常也更适合被用于那些高度依赖 Agent 能力的热门应用场景,也一定适合被用在最火的Agent应用——OpenClaw中。那么,我们就可以看看“龙虾”社区中什么模型最受欢迎。

例如,在https://pinchbench.com中,就可以看到一些关于在OpenClaw中模型使用情况的统计信息。我认为,最值得关注的是平均成功率这一指标,因为它在某种程度上反映了一个模型能否较普遍地遵守规范、理解需求并成功完成任务,也就是我们最关心的稳定性问题。基于这类排行榜,再结合成本,就可以对模型做出相对务实的选择。
而如果由于成本、可用性或其他限制,不得不使用排名靠后的模型,那么一开始就要对它的能力边界有足够清醒的预期。此时,更合理的做法不是幻想通过“神奇 prompt”把它变成强模型,而是根据它的特点调整系统设计:对工具使用施加更强约束,对 skill 加载和输出格式设置更明确的规则,或者干脆只让它承担那些更简单、更局部、更容易验证的职责。这样做虽然保守,但往往更稳定,也更符合工程实践。
工具和skill设计
工具和 Skill 本质上是外部增强模型能力的辅助组件。虽然模型本身仅凭最基础的文件读写能力就能完成许多任务,但效果常常参差不齐。作为开发者,重要的是在需要的领域减少模型的能力缺失和表现的不确定性,通过合理的工具和 Skill 来提升模型的表现,拓展或约束其“解空间”。
显然,调控模型解空间是一门“艺术”。过于“权威”的工具可能会削弱模型的主动性,导致它满足最低要求就结束任务;而过于简陋的工具可能误导模型,使其偏离重点,达不到预期效果。在 Skill 设计中,如果过度强调结构化输出,可能会让模型专注于格式要求并不断修改,反而降低了其灵活性;但如果对格式要求过于宽松,则可能导致模型“随心所欲”,甚至偷懒,未能完成任务。因此,工具和 Skill 之间,以及它们与模型之间的权衡,如何在确定性和不确定性之间找到平衡,是设计和开发过程中的一个关键问题。
通信中间件设计
你真的需要结构化的 Agent 通信中间件吗?
我承认,在传统程序设计中,模块之间的通信中间件通常需要定义为固定的数据结构,然后通过 JSON 等格式进行序列化和存储。然而,对于 Agent 来说,这种格式化要求可能过于严格,增删改查十分困难,这样的结构化通信往往会对稳定性造成挑战。
在我的早期设计中,我使用了一整套称为“工件”的通信中间件体系。这个体系要求每个 Agent 输出和维护固定格式的 JSON 文件,包括版本、状态、载荷等内容,其他 Agent 则通过这些“工件”了解彼此的任务成果。与此同时,我还为工件设计了注册和跟踪工具,以确保工件在流程中存在、合规并保持最新版本。理论上,这是一个理想的结构化通信框架,但实际运行中,我却频繁遇到工件注册失败、Agent 不断返工消耗 token、产出结果逐渐恶化的问题。虽然这大部分源于模型能力不足,但也反映出:这种重量级且高度结构化的通信设计对模型有很高的一致性要求,可能会占用大量的注意力,抢占了任务本身完成的时间。
因此,在后期,我将中间件简化,只对必要的报告采用 JSON 格式,而其他内容则使用模型更熟悉的 Markdown(MD)格式。这就像 OpenClaw 的工作区设计一样,我让 Agent 将这些文档作为自己记忆和凝练经验的“家”。
最初,我完全放弃了格式要求,仅在提示词中要求 Agent 尽量完整地描述它们完成的工作。然而,经过实际测试,我发现这种做法让 Agent 略显“懒惰”。它开始有意无意地减少输出内容,或者将内容高度凝练,常常缺乏具体的出处或完整的描述。因此,我最终在这些非结构化文档中加入了适当的结构化约束,例如对风险描述需要提供行号、函数名、风险描述、代码摘要等细节。这使得在优秀的 LLM 模型支持下,Agent 输出的报告变得更为完整和高质量。
所以,在通信中间件的设计上,结构化与非结构化的平衡至关重要。这个平衡需要根据模型能力、对一致性的需求以及问题的复杂度等因素进行调整。对于需要程序渲染的内容,结构化是必要的;而对于需要频繁维护、修改的内容,则不必过于强求结构化。当然,目前我还未深入了解最先进的通信中间件方案,可能与数据库结合的方案会更为高效。
工具设计
关于工具设计,我的实践相对较少,但还是可以分享一些经验。若工具是业务的核心内容,Agent 的作用仅仅是自动化地驱动工具,那么我们应以工具为主。在这种情况下,提示词设计和参数输出约束尤为重要,必须确保 Agent 完全信任工具的产出,而不对其结果进行“臆测”。如果工具面临复杂且未知的环境,表现出不稳定性,我们就需要在提示词中明确指出,要求 Agent 对工具结果进行筛选、权衡和补充,否则 Agent 会局限于工具的能力范围,难以超越其边界。
工具的数量也是一个关键因素。核心工具的数量应尽量少而精,调用次数也应设计得适当。因为核心工具往往处理的是重要内容,如果工具过多或者调用过频,会分散注意力,可能导致一致性问题。而过于简单的工具应该尽量少用,最好将其封装在 Skill 中,因为工具的系统提示通常比 Skill 的提示要多,过多的简单工具会消耗模型的认知能力,减少其主动性和一致性。
总结来说,工具设计的经验是:分清主次,少而精。
Skill设计
Skill 是模型的任务相关外部知识库和行为规范,它在很大程度上决定了任务完成的稳定性和质量。因此,Skill 的编写不能随心所欲,必须遵循一定的设计方法论。
Skill 大致可以分为几类:任务控制类(用于教会 Agent 当前任务的执行方法)、知识补充类(用于补充原有 LLM 未涵盖的知识,例如绘制流程图)、业务规范类(用于告知 LLM 该业务的规范和标准)。这些类别的区别在于 Skill 的基本要素不同,因此设计要点也有所差异。
根据我的实践经验,一个任务控制类的 Skill 通常包括以下基本要素:
- 任务描述和背景信息。
- 各个任务阶段和流程拆分。
- 各个流程的具体工作过程(包括前后顺序、注意事项),以及前置和后置条件。
- 任务过程中需要交付的内容、格式要求和可用资源(如工具、文档等)。
- 限制和约束,即不允许做的事项。
- 异常处理和重试流程,例如在工具出错或任务流程中断时的应对方案。
- 自检清单,列出容易出错或难以完成的事项,以引起注意。
相比之下,知识补充类 Skill 通常没有涉及具体的工作流程和异常处理,而是提供补充知识,且最好包含一些示例(如 few-shot);而业务规范类 Skill 则侧重于明确的标准、清单、分级等内容。
在实际应用中,这些 Skill 类型往往是相互交织的。一个 Skill 中既可能包含知识补充,又有流程控制。因此,尽管分类有其意义,但更重要的是确保 Skill 要素的完整性。
另外,需要避免的是,Skill 过于庞大,无论是知识内容还是流程。如果 Skill 过于庞大,就违背了 Skill 设计的初衷——减少模型上下文消耗。庞大的 Skill 会带来稳定性和一致性问题。更好的做法是:如果是流程类 Skill,可以将其拆分为多个子 Agent 和 Skill;如果是知识补充类,那么建议不使用 Skill,而是通过 MCP 或 RAG 来进行分级知识加载。
VibeCoding与开发
开发 Agent 与开发一般项目既有相似之处,也有显著的不同。
相似之处在于,无论是设计还是开发,都需要进行模块拆分和职责分配,并且都要经过模块开发、单元测试和集成测试。然而,具体的开发方法和技巧,特别是在 VibeCoding 的时代,给开发过程带来了不同的挑战。
VibeCoding是个好东西,也是个危险的东西:它能够给开发者能力之外的收获,也会带来开发者能力之外的问题。因此,最理想的做法是先拓展自己的能力边界,然后再使用 VibeCoding 提升效率。但是,现在的节奏似乎不允许慢条斯理地学习,我们总是在赶鸭子上架。所以,结合我的实践经验,使用 VibeCoding 开发时有几个关键点:
- 先明确需求和技术路线:需求通常随着讨论的深入而逐渐明确,因此需要不断细化和标准化,才能为后续设计打好基础。技术路线(包括选择框架、技术和解决方案)通常超出了开发者现有的能力边界。在这种情况下,不要急于动手开发,而应与 AI 或有经验的开发者进行深度讨论和交流,关注技术的先进性、业务适配性和学习成本。有时,在发散式的讨论后,往往能发现一些之前未曾注意到的合适技术。
- 设计要尽可能详细:按照软件工程的角度,软件设计分为概要设计(指模块拆分、主要技术、通信和职责分配)和详细设计(模块内算法、流程、异常处理等)。编程AI最擅长的,就是一切设计均以完毕,只需要生成符合要求的代码。而由于上下文限制,它往往在模块间通信、接口匹配等等跨组件逻辑上出现问题。所以,不能指望通过一两句话就能够让它理解开发者的意思,设计做得越详细,效率和可控性越高。
- 善用版本管理工具并设置约束要求:为了确保编程 AI 在开发过程中保持稳定,必须明确它所需执行的任务,确保它理解当前修改需求、实现进度和开发方法。这一切都要使用设计文档、进度文档、框架技术文档、限制提示词等进行约束和限制。如果没有合理的约束,哪怕是最强大的编程 AI 也容易出现“幻觉”或做出不理智的操作。同时,在每次操作之前,应使用 Git 进行版本控制,以便在发生意外修改时能够轻松恢复。
- 新手不要害怕“炸掉”工程:作为新手,了解项目复杂度和编程 AI 的能力边界,并掌握项目的基本知识是一个逐步积累的过程。在这个过程中,可能会“搞炸”几个工程,这是正常现象。最重要的是,记录好文档和设计,代码本身在 VibeCoding 过程中并不值钱。积累的经验和经过修改的设计才是最宝贵的。如果是在生产环境中,那就另当别论了。
而在Agent具体的开发过程中,我也总结了一些个人经验。
首先,在模块集成方面,对于需要复杂流程的多 Agent 应用,虽然我们可能已经编写好了各个 Agent 的提示词,但为了确保开发的稳定性,我们需要将各个模块进行集成。这会影响整体流程的完整性,因此往往需要修改提示词。我的做法是在每个 Agent 的系统提示词中加入【开发时运行约定】,以规范当前开发阶段 Agent 需要执行的任务。同时,在集成测试阶段,我会说明当前的开发阶段和测试任务,从而集中管理修改,避免对其他提示词产生影响。一旦集成完成,便可以快速切换到新的工作流程。

接下来是状态观察问题。Agent 开发不像传统后端开发那样有现成的测试工具,Agent 的行为需要通过输出进行观察。这时,一定要使用像 LangSmith 这样的追踪工具。在每次运行之后,务必对每个步骤进行细致观察,不要偷懒。通过观察,你可以发现一些潜在的问题,如工具调用异常、流程问题和行为偏向等,这为调整提示词、 Skill 和工具提供了宝贵的依据。甚至有时候,某些看似小的或者正常的返回信息,可能会暴露出严重的问题。
总结
在开发基于 DeepAgents 框架的多 Agent 系统时,尽管面临诸多挑战,但我也获得了很多宝贵的经验。无论是框架、架构、模型设计,还是工具和 Skill 的使用,都需要在理论与实践之间找到平衡,既要充分发挥技术的优势,也要避免过度依赖工具而忽视了基础能力的培养。
VibeCoding 为开发者提供了巨大的效率提升,但它也带来了不小的挑战。在开发过程中,合理的需求分析、详细的设计、有效的版本控制、适当的工具和 Skill 使用,都是确保项目顺利进行的关键因素。尤其对于新手来说,理解项目的复杂性和编程 AI 的能力边界,勇于试错并从中积累经验,才是最重要的成长过程。
最终,开发 Agent 系统并不是单纯的技术堆砌,而是一个持续学习与调整的过程。从一开始的框架选择到后期的工具整合,每一步都需要认真思考与细致执行。随着开发经验的不断积累,我们将能够更加熟练地掌握这些工具和方法,构建出更加稳定、有效的多 Agent 系统。
无论是对于初学者,还是已经有一定经验的开发者,这些经验和思考都能为他们在开发类似项目时提供一定的参考和启发。希望这篇博客能够为大家在 Agent 开发的道路上提供一些有用的思路和实用的技巧。
当然,我作为初学者,同样也有很多理解不到位、认识错误的地方,希望大家能够积极讨论,共同进步。

2258

被折叠的 条评论
为什么被折叠?



