Agent开发实战:四层框架模型与选型指南

发布时间:2026/9/7 4:15:51
Agent开发实战:四层框架模型与选型指南 做了8个月Agent开发中间有很长一段时间我是懵的。LangChain的文档翻了好几遍AutoGen的例子跑通了几个但真要我从零设计一个Agent应用脑子里还是乱成一团。直到有一天我把自己写的代码和主流框架的源码放在一起对比才突然意识到Agent开发的复杂度不在于某个API怎么调而在于这些能力被放在了不同的层级上。没看懂层级之前所有的教程、框架、热词都是散的看懂之后LangChain、LlamaIndex、CrewAI这些名字才有了各自的位置。这篇文章想把“框架层级”这件事讲透。不是概念层面的泛泛而谈而是结合我这8个月的实战路径从踩坑、选型、搭工作流到准备面试的全过程给后来的人一条能直接上手的认知地图。如果你正被各种Agent框架淹没或者刚入行不知道怎么规划学习路线这篇应该能帮你省下不少时间。1. 从“调API”到“写智能体”我的理解拐点1.1 最初踩的坑把框架当万能工具箱我接触Agent开发的第一周最先干的事就是把当时热门的框架全装了一遍。LangChain、LlamaIndex、AutoGen、CrewAI一个一个跑demo。跑通了之后信心爆棚觉得自己已经会Agent开发了。但真的接到第一个需求时——一个企业内部的知识库问答Agent——我连从哪个框架下手都不知道。我当时犯的最大错误是把框架当成一个“什么都能干”的工具箱。遇到需求就找一个看起来最接近的抽象类往里套套不进去就换一个框架。结果就是在LangChain里写了一半发现它的Tool调用封装太绕转去LlamaIndex又发现它主打的是RAG索引业务逻辑还是要自己在外面写。折腾了半个月项目进展几乎为零每天的有效产出就是跑通一个demo。后来我把几个框架的同类型代码并排打印出来看才看出门道。LangChain和LlamaIndex的代码量差别其实没那么大关键是它们把代码组织在了不同的层级上。LangChain的重心在编排和链式调用LlamaIndex的重心在检索和索引CrewAI的重心在角色分工和协作流程。如果我连自己要把代码写在哪个层级都不知道框架当然帮不了我。1.2 拐点从代码结构看层级真正让我想明白的是一段我自己写的、没用什么框架的Agent代码。那时候我试着用纯Python加OpenAI的函数调用接口写一个能查数据库、能发邮件的“小秘书”。代码拆成了四层最下面是对模型API的封装中间是工具的注册和调用逻辑再往上是任务规划和状态管理最外层才是循环执行的入口。写完之后我再回头看LangChain的AgentExecutor一下就通了。它干的事情就是把我的这套流程标准化模型对话循环、工具调用的触发与回传、中间状态的保存全部做成了统一的抽象。你说它复杂吗代码量确实大但层级是清晰的。之前觉得复杂是因为我拿着一个上层的抽象试图去理解所有下层的细节那当然会晕。如果你也在学Agent开发我的建议是不求快、不追新先把一次“模型—工具—模型”的完整循环用原生代码写一遍。这几十行代码带给你的理解比你刷十个框架demo都有用。这节课之后我给自己定了一个原则先画层级图再选框架。所有需求到我手上第一件事不是问用哪个框架而是问这个能力应该放在哪一层。2. 实践中总结的Agent框架四层模型我按自己实战中用到的能力把Agent框架拆成四个层级。这个分法不一定学术但特别实用因为每一层对应着一类你需要独立解决的问题。2.1 模型层是底座但别只盯模型最底层是模型层也就是LLM本身。这一层的核心能力是“对话理解与生成”但真正决定Agent上限的其实是大模型对结构化的支持最典型的就是Function Calling函数调用。我用四个月才彻底搞明白Agent和普通聊天机器人最本质的区别就落在这里。普通聊天机器人只需要生成文本而Agent需要让模型输出一个可执行的指令比如“调用search_news(query人工智能)”或者“调用send_email(toxxx, content...)”。模型要能在正常的对话里识别出这个意图并且按规定的JSON格式输出参数。哪个模型在这件事上做得稳哪个就更适合做Agent底座。我实测过几个主流模型的函数调用表现差异非常明显。有的模型在函数定义较多时会出现参数缺漏或格式错乱的情况有的模型在简单场景下表现很好一旦函数定义超过20个就开始“选择困难”。所以我在选型上有一个很实际的建议先把你的工具函数定义好再用真实数据对模型做一轮“函数调用压力测试”不要只看榜单分数。另外提醒一点上下文长度也是模型层的硬指标。Agent和模型一次交互往往要携带系统提示、工具定义、历史对话、工具返回结果这些加在一起很容易超过小窗口模型的限制。窗口不够大很多时候不是代码写得有问题而是模型层压根装不下。2.2 记忆与上下文管理最容易被忽视的层级很多初学Agent开发的人包括我前几个月都把注意力放在“怎么调工具”上很少认真考虑“Agent怎么记住之前干了什么”。但随着任务变长记忆问题会迅速成为瓶颈。这个层级我称之为“记忆与上下文管理层”。它的核心问题有三个短期记忆怎么存、长期记忆怎么存、上下文超了怎么处理。短期记忆最简单的方案是直接把对话历史塞给模型实现成本最低但会随着对话轮次增加快速膨胀。长期记忆则需要外部存储比如向量数据库加Embedding让Agent能检索到相关的历史信息。上下文超限是所有方案里最现实的痛点。我之前做一个数据分析Agent用户的会话经常长达几十轮中间还穿插着大段的工具返回结果。有几次直接把上下文窗口撑爆了程序直接报错。后来我采用了“滑动窗口关键信息提取”的策略会话历史只保留最近8轮更早的内容让模型做一次摘要并存储下来需要时再通过检索召回。这个方案运行稳定成本也大幅下降。记忆层级的设计会直接影响Agent的使用体验。如果做完一项任务后Agent对用户之前提过的偏好完全没印象用户就会觉得“这个Agent很蠢”。在2024年到2025年的开发趋势里记忆已经从加分项变成了必需项很多框架自带的Memory模块也开始分化出短期和长期两类。选框架时千万要看清这一层的实现方式别等上线了才发现它只支持缓存两三轮对话。2.3 规划与编排层Agent聪明与否的分水岭Agent和普通“调用工具的程序”最大的区别在于它能不能自己规划步骤。规划与编排层负责的就是这件事把一个大目标拆成若干小步骤决定步骤之间的依赖关系动态调整执行计划。最早的Agent实现里规划大多靠“人工写死”。例如我第一版个人任务管理Agent就是先用关键词匹配用户意图再走固定的流程。这样做的缺点是显而易见的用户的话稍有变化流程就乱了。后来我改成让大模型自己输出下一步动作再根据执行结果决定后续动作整个系统的灵活性才有了质的提升。框架层面的编排能力差异是巨大的。轻量的编排就是循环调用模型重一点的会引入Plan-Execute模式也就是“先规划再执行”再重一点的是ReAct模式模型在Reasoning推理和Acting行动之间循环。LangChain的AgentExecutor、LlamaIndex的AgentRunner、AutoGen的ConversableAgent本质上都是在做编排只是编排的粒度和控制方式不同。这一层还牵扯到“单Agent vs 多Agent”的选择。单Agent适合任务链路短、目标单一的场景多Agent适合一个大项目需要多个角色协作的场景。但我要泼一盆冷水很多项目的复杂度根本不需要上多Agent。我见过有人用一个三个Agent的团队去做一个简单的字段提取任务结果Agent之间互相传话的token开销比实际干活还多效果反而不如单Agent。多Agent是编排层的进阶选项不是必选项。2.4 工具与外部系统接入层能否落地的关键模型负责思考但真正动手干活的是工具。工具与外部系统接入层就是Agent的“手脚”它负责把Agent和外部世界连接起来查数据库、调接口、执行代码、操作文件、访问网页等。我在实践中的体会是这一层的核心难点不在怎么调用API而在工具的定义、注册和容错。先说定义模型的Function Calling效果很大程度取决于函数描述写得好不好。函数名、参数描述、示例值都直接影响模型的选择准确性。我的经验是函数描述里一定要写清楚“这个工具在什么情况下用、什么情况下不要用”这比参数描述更重要。容错是我踩坑最多的部分。工具返回的数据格式不固定、接口超时、第三方服务返回500都是家常便饭。如果你的工具层没有做兜底处理Agent的执行流程会直接卡死。我现在的做法是给每个工具包一层统一的返回格式再在调用层加try-except和超时控制同时要求模型在工具调用失败时能够自我修正。接入层的复杂度直接决定了框架的选型。如果你的Agent只需要调用两三个结构化API用轻量框架甚至原生代码就够了如果你的Agent要接几十个内部系统、处理各种非结构化的返回数据那就需要一个像LangChain这样有大量现成集成器的框架。我在选型时有一个简单粗暴的参考标准工具数量在5个以内用原生SDK5到20个考虑轻量Agent框架超过20个或者需要复杂的工具动态选择机制再上重框架。3. 热门框架怎么选LangChain、LlamaIndex、AutoGen、CrewAI实测对比经常有人问我“到底该学哪个框架”我的回答永远是先搞清楚你要解决什么问题再选框架。作为把主流框架都折腾过一遍的人我分享一下自己的横向对比和选型经验。3.1 按场景选框架先看需求再看名气LangChain是生态最丰富的文档里能找到几乎所有厂商的集成器。它对“链式调用”和“工具编排”的抽象非常成熟适合做复杂的业务逻辑编排比如多步骤的工具处理流程、带路由的问答系统等。但它的学习成本也是最高的因为抽象层级多很多概念需要花时间理解。我建议对Agent原理还没完全吃透的新手先别从LangChain入手否则容易被抽象概念淹没。LlamaIndex主打数据和RAG场景如果你的核心需求是“让Agent理解一大堆文档”它的索引、检索、重排序能力是做得很好的。但它本质上是一个偏检索的框架Agent的编排能力相对较弱。我做过一个合同审查Agent需求是先从数百份合同里捞相关的条款再让模型做分析用LlamaIndex做检索环节确实省事但后面的分析编排我还是回到了LangChain。AutoGen是微软开源的主打多Agent对话式协作内部Agent之间通过消息交换来协作完成任务。它在复杂任务分解、代码自动生成等方向表现不错。但代价是调试难度更高两个Agent来回对话几十轮出了问题很难定位是哪个Agent、哪条消息导致的。适合有一定经验的开发者研究。CrewAI主打角色扮演式协作可以用很直观的方式定义“分析师”“执行者”“审核者”等角色并设定角色之间的协作流程。上手快、表达清晰适合业务宣讲和多角色工作流的快速建模。但它的灵活性和对复杂控制流的支持不如LangChain。我的经验是用它做MVP演示非常好接近生产环境时要把协作逻辑摸透再决定。3.2 轻量与重量之间的取舍我在3.1提到按场景选择这里想单独说说轻量和重量之间的取舍因为这可能是最容易劝退新手的地方。我见过很多人一开始就上LangChain结果被抽象概念绕晕最后连一个完整功能都跑不出来。也见过有人坚持用原生代码结果随着需求变复杂代码里到处是判断分支维护成本指数级上升。目前Agent开发领域有一个明显的趋势原生SDK的能力越来越强。OpenAI、Anthropic以及国内多家模型厂商都提供了原生的Agent开发套件或函数调用能力很多简单的Agent用原生SDK完全能够实现。因此我自己的选择标准逐渐变为先评估团队对Agent原理的熟悉度再评估项目的工具数量和编排复杂度最后决定要不要引入重框架。如果你刚入行我强烈建议从原生方式开始。先实现一次“循环调用模型—解析工具调用结果—再调用模型”的最小闭环代码量大约50到100行。跑通之后再来对比LangChain做了哪些抽象这时候你看到的就不是一堆名词而是有明确意义的封装逻辑。3.3 我们项目里的真实选型过程去年年底我参与了一个企业内部的智能工单Agent项目需求是从用户的自然语言描述里提取工单信息、搜索历史工单、匹配处理方案并生成回复。当时团队内部发生了选型分歧一部分人认为直接用LangChain的Agent另一部分人认为工具就三个没必要引框架。最后我们采用的是折中方案核心循环用原生代码工具封装自己在内部实现框架只使用了LangChain里的PromptTemplate和输出解析组件。这样做的原因有两条。第一工具数量少且结构稳定Agent需要处理的流程相对固定上重框架带来的抽象成本大于收益第二团队当时对框架源码的理解还不够深入一旦出bug反而难排查。这个项目给我最大的启发是选型不是为了用框架而用框架而是为了降低代码的复杂度和维护成本。如果引入框架之后你的代码变得更难理解那这个引入就是不划算的。框架层级的价值在于提供“可编排的抽象”但抽象也有它的代价——调试时你得同时理解业务逻辑和框架的封装逻辑。4. 实战演示从零搭一个“个人任务管理Agent”工作流纸上谈兵聊了很多这一节我用一个完整的例子来串联。需求很简单做一个个人任务管理Agent让用户用自然语言添加任务、查询任务、标记完成并把任务清单存到本地JSON文件里。4.1 需求拆解与任务层级设计这类Agent最适合用来理解层级因为它的功能边界清晰工具不多但又覆盖了模型层、记忆层、规划层和工具层。拆完之后大概是这样的模型层负责理解用户意图输出结构化指令工具层提供三个函数——add_task、query_tasks、complete_task编排层读取模型输出执行对应函数返回结果给模型记忆层保存任务数据到本地文件实现长期存储在拆解需求的时候我习惯把每个功能点先标好层级而不是一上来就写代码。这一步能让你在设计数据结构时就从全局出发避免代码写到一半发现模型输出和工具参数对不上。4.2 选型思路这次我为什么不用重框架这个项目我特意选择不用LangChain等重框架原因有三。第一工具数量太少重框架的集成优势体现不出来第二业务逻辑简单涉及的判断分支有限原生的流程控制足够第三这个项目本身就是一个学习项目用原生代码能把层级关系看得更清楚也更方便你以后再去看框架源码。如果你只是要一个能用的任务管理工具用原生代码加模型SDK几十行就够了。如果你想把Agent开发学明白我建议你也在自己的学习项目里刻意避开重框架先体验一下“没有框架帮你兜底”是什么感觉。刻意练习的原理是如果你总是依赖框架帮你完成关键流程你永远不知道框架替你扛住了什么问题。只有亲手实现一次底层循环你才会理解为什么框架要这样抽象。4.3 核心实现与代码逻辑拆解下面是任务管理Agent的核心逻辑我用Python实现。主要分三块模型对话循环、工具定义、工具调用分发。import json import openai client openai.OpenAI() TOOLS [ { type: function, function: { name: add_task, description: 添加一个新任务。当用户明确表示要记录/新增任务时使用。, parameters: { type: object, properties: { content: { type: string, description: 任务内容 }, due_date: { type: string, description: 截止日期格式YYYY-MM-DD可选 } }, required: [content] } } }, { type: function, function: { name: query_tasks, description: 查询当前任务列表。当用户询问有哪些任务、任务进度时使用。, parameters: { type: object, properties: {} } } }, { type: function, function: { name: complete_task, description: 将指定任务标记为已完成。当用户表示任务完成时使用。, parameters: { type: object, properties: { task_id: { type: string, description: 任务ID } }, required: [task_id] } } } ] def add_task(content, due_dateNone): tasks load_tasks() task { id: str(len(tasks) 1), content: content, due_date: due_date, completed: False } tasks.append(task) save_tasks(tasks) return f已添加任务{content}ID为{task[id]} def query_tasks(): tasks load_tasks() return json.dumps(tasks, ensure_asciiFalse) def complete_task(task_id): tasks load_tasks() for task in tasks: if task[id] task_id: task[completed] True save_tasks(tasks) return f任务{task_id}已标记完成 return 未找到对应的任务ID def load_tasks(): try: with open(tasks.json, r, encodingutf-8) as f: return json.load(f) except FileNotFoundError: return [] def save_tasks(tasks): with open(tasks.json, w, encodingutf-8) as f: json.dump(tasks, f, ensure_asciiFalse, indent2)上面这3个工具完全对应“工具层”。关键点是函数描述要写得足够清楚比如add_task里面加了“当用户明确表示要记录/新增任务时使用”这能有效减少模型在意图不明时误调用工具的概率。complete_task也是同理加上了“当用户表示任务完成时使用”这样的触发条件描述。模型层的调度循环如下def run_agent(user_input): messages [{role: user, content: user_input}] while True: response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, toolsTOOLS, ) message response.choices[0].message messages.append(message) if message.tool_calls: for tool_call in message.tool_calls: fn_name tool_call.function.name args json.loads(tool_call.function.arguments) if fn_name add_task: result add_task(**args) elif fn_name query_tasks: result query_tasks() elif fn_name complete_task: result complete_task(**args) else: result f未知工具{fn_name} messages.append({ role: tool, tool_call_id: tool_call.id, content: result }) else: print(Agent回复, message.content) break if __name__ __main__: run_agent(帮我加一个任务周三之前写完项目总结)这段代码是“编排层”的核心逻辑循环判断模型是否发起了工具调用如果发起了就遍历所有工具调用并执行然后把结果作为tool角色的消息回传给模型如果没有工具调用说明回答已经生成循环结束。我刚开始写这个循环时经常漏掉一个关键点——messages里必须把模型的返回原样追加进去再把工具结果追加进去。如果漏了模型的那条带tool_calls的消息后续请求就会失去上下文模型会变得“很懵”。4.4 实际调试中的问题与优化点代码跑起来之后我遇到了几个比较典型的问题每个都和层级相关。第一个问题是函数描述不精准导致的误调用。有次用户问“下午有什么安排”查询任务列表是合理的但模型有时候会把这句话误判成新增任务。排查下来发现是add_task的描述太宽泛了。我把描述改成了“当用户说‘加一个/记住/新增/提醒我’等表示要录入新任务时才使用”误判率立刻下降。这件事让我意识到工具层定义不是写代码是在和模型的注意力机制打交道。第二个问题是并发处理。原本的执行逻辑是逐个执行tool_calls里的所有工具假设模型一次生成两个工具调用任务A和任务B会串行执行。对于任务管理场景足够用了但如果以后接入耗时的外部API就要考虑是否改成并行或异步执行。我的建议是在工具层设计时给每个工具预留一个“幂等性”的约定——同样的输入重复调用不会产生副作用这样未来改造成并行执行时才不会出问题。第三个问题是长期记忆。这个项目目前只把任务存到了JSON文件但Agent本身没有跨会话的记忆。也就是说下次启动对话Agent不记得之前的偏好。如果想要更智能的体验可以在工具层加一个“读取用户偏好”的工具在每次真正完成任务前先检索一下或者在系统提示词里把用户的历史偏好摘要注入进去。后一种做法实现简单但需要额外的存储和检索能力更适合接入向量数据库。5. Agent开发学习路线与面试经验给后来者的参考这个博客最初定位是分享技术经验但我发现读者里相当一部分是准备转行Agent开发、或者正在投Agent相关岗位的人。他们后台留言问得最多的两件事怎么学、怎么准备面试。这一节我就把这两件事一次说清楚。5.1 学习路线先底层、再框架、后业务如果你把Agent开发当成一个工种那它的学习曲线其实非常陡峭因为横跨的知识点太多了Prompt、模型API、函数调用、RAG、向量数据库、工作流编排、多Agent协作、工程评估。如果一开始就去追着新框架、新概念跑会很累。我的建议是按“底层能力—框架原理—业务落地”三个阶段推进。第一阶段是底层能力目标是把一次完整的“模型调工具”循环吃透内容包括OpenAI或其他模型提供商的ChatCompletion接口、Function Calling的机制、上下文构建方法以及一个简单的工具调用分发器。这个阶段不需要任何框架我上一节的任务管理Agent就是一个很好的练习项目。第二阶段是框架原理目标是从源码层面理解主流框架的核心抽象是来解决什么问题的。可以选LangChain和LlamaIndex各做一个小项目。LangChain项目可以做一个“带检索增强的问答Agent”LlamaIndex项目可以做一个“本地文档知识库”。做完之后再回头对比自己第一阶段写的原生代码框架的设计取舍一目了然。第三阶段是业务落地目标是把Agent投放到真实场景里并解决工程化问题。重点关注如何评估Agent的任务完成率、如何处理工具调用失败、如何设计人工兜底流程、如何控制token成本、如何做好日志追踪。越接近生产环境工程化能力和评测手段就越重要。关于学习资料我不推荐只看某一家框架的官方教程。做Agent开发真正的通用知识不是某个框架的用法而是对“模型能力边界”和“任务流程拆解”的理解。框架会变模型也会更新但这两项能力可以一直复用。5.2 Agent开发面试常考什么我整理的高频问题面试是检验水平和查缺补漏的好方式。我在面试中也面过不少候选人一个很深的体会是能讲清楚框架原理的人比会调框架的人稀缺得多。面试官虽然会问工具和API但更看重的是你在陌生问题上的拆解思路。我整理几个高频的面试方向每一个背后都有一串需要系统掌握的知识点请讲一下你做过的一个Agent项目为什么选择这个架构 这类问题考察的是项目决策能力重点说清楚你要解决什么问题为什么选这个模型、这个框架、这种记忆方案以及你对比过哪些替代方案。我在面试中遇到的候选人多半只讲功能很少讲“为什么”当你讲清楚之后会立刻和普通候选人拉开差距。如果你的Agent调用的工具超时或返回了错误数据你会怎么处理 这道题考察的是工程化兜底能力。回答思路包括给工具统一包装超时和错误码在编排层加入失败重试在返回给模型的内容中明确标注当前状态是错误在几次失败后切换到人工处理流程。其实考察点在于你有没有真的调试过Agent而不是只跑过demo。用户上下文超过了模型的窗口限制怎么办 考察记忆和上下文管理能力。核心回答要点是滑动窗口、关键信息摘要、外部向量检索、按需注入工具返回结果等。如果你能展开说明各种方案的取舍和适用场景面试官一般会认可你的实战深度。多Agent协作和单Agent相比优势在哪里劣势在哪里 这是现在很火的考点。可以从可维护性、可扩展性、调试难度、token开销、角色职责边界这几个方面展开。最重要的是要给出自己的判断准则比如“当任务责任边界清晰且需要并发处理时适合多Agent否则单Agent更好”。你怎么评估Agent的效果 这个问题问的人开始变多因为Agent评测确实是工程落地难点。你可以从任务成功率、工具调用准确率、回答相关性、用户反馈这几个维度设计评估集再结合人工标注和线上指标来评估。评估集不需要特别大但覆盖各种类型的场景很重要。5.3 关于Agent开发工程师这份工作搜“Agent开发工程师”这个岗位能看到不少机会但它和传统的后端开发、算法工程师又不太一样。和传统后端相比Agent开发更多是在跟“不确定的输出”打交道和算法工程师相比Agent开发又要做大量的工程落地和业务需求理解。从我做这8个月的感受来说Agent开发工程师更像是一个“翻译官”——把业务需求翻译成模型能理解的任务再把模型的行为翻译回业务结果。做好这份工作需要的不是背几个框架API而是不断积累“模型表现与业务预期之间的落差”处理经验。如果你正打算入行我的建议是先把一个真实的小项目完整走通记录下所有踩过的坑然后带着这个项目去面试。有完整项目经验的人在面试里的竞争力比看了一堆教程、但没有独立完成过任务的人强得多。项目不需要大你只要把一个很小的任务交给Agent完成并让它稳定跑上一个月就已经超过了大部分人。最后说点实在的看过层级之后的Agent开发和之前完全是两个世界。以前我被一种“什么都想用、什么都学不深”的焦虑推着走总觉得是不是因为自己不够努力现在我知道真正有效的努力是把力气花在正确的层级上。模型层和工具层下功夫能让Agent“能干活”记忆层和编排层下功夫能让Agent“干得聪明”工程化评测和生产级设计下功夫才能让Agent真正“靠得住”。如果你身处转型期或者正在写自己的第一个Agent我的体会是不用急着把所有热词都追一遍也不用在框架选择上反复犹豫。用最少的依赖跑通一个最小闭环然后把时间花在调试真实问题上半年之后你也会有自己的答案。