ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

为什么劝你做 Agent 先手搓一遍:框架的抽象税,是生产环境最贵的隐性负债

为什么劝你做 Agent 先手搓一遍:框架的抽象税,是生产环境最贵的隐性负债 如果你问我现在做一个 Agent第一反应应该用什么我的答案可能和大多数人不一样——先别急着上 LangChain自己手写一遍。不是框架不好用而是很多人在真正吃过苦头之前压根没意识到框架到底替你做了什么又悄悄拿走了什么。这篇文章想聊的不是框架 vs 手搓谁更高级而是一个更现实的问题在什么阶段框架是朋友在什么阶段框架是债。一、框架的糖衣为什么它一开始如此诱人从零搭一个 Agent远不止调一次大模型这么简单。你需要定义工具 Schema让模型知道每个工具叫什么、参数怎么传要解析模型返回的 tool_calls判断该不该继续执行要在每一轮调用之间正确维护消息顺序不能丢也不能乱要处理工具失败、参数缺失、超时重试甚至还要把任务状态、日志、Token 成本存下来方便回放。这些事情每一个 Agent 项目都得做一遍而且大同小异。框架的价值就在这里——把大量重复样板封装好你直接用就行。拿 LangChain 来说一个tool装饰器就能注册工具AgentExecutor把整个 ReAct loop 收进去还内置了 tracing、callback、记忆管理。探索期它真的让人上瘾几十行代码搭起一个能跑的 Agent两周的工作压缩到两天。这种爽感是真实的没必要否认。二、痛点从什么时候开始出现框架的问题不是一开始就暴露的而是随着项目推进在不同阶段逐渐浮出来。第一个奇怪的 bug 出现之后感觉就变了。Agent 在某个特定场景下输出了错误的工具参数你开始排查。代码只有五十行但报错的 stack trace 有四十层往下追到了框架内部。你不知道问题出在你写的那五十行里还是框架某个版本的逻辑变化或者是 callback 触发时机的问题。你只能在 GitHub issue 里翻或者一层层啃框架源码。有个类比很贴切老式车出了问题打开引擎盖自己就能看到哪根管子漏油现代豪华车出了问题你打开引擎盖看到的是一堆你看不懂的电子设备只能去 4S 店让诊断仪扫。框架的抽象层太多排查问题需要穿透那些你没写、也不完全懂的层这是实实在在的认知负担。有篇反思写得更狠——LangChain 一度是AI 界的 jQuery火过一阵子然后成了负债。作者读了全部源码在凌晨两点排过由框架内部逻辑导致的线上事故最后得出一个结论现代 AI 工程需要的是更少的抽象而不是更多。另一篇《Why I Stopped Using LangChain》把这种代价称作抽象税——你用一段不透明的逻辑代码置换了原本清晰的 API 请求。版本升级踩坑是另一个阶段的痛苦。线上跑了好几个月某次依赖升级LangChain 改了接口代码直接报错。你要么回滚要么把代码改到兼容新版本可能涉及十几处修改。早期 LangChain 版本升级频率很高breaking change 是常态。有意思的是后来官方自己都把AgentExecutor废弃了推荐迁移到 LangGraph——这本身就印证了框架设计在不断变化而你把核心业务逻辑建立在一个变动频繁的第三方框架上稳定性就得看别人脸色。再到规模化阶段性能优化时你会撞见隐性开销。你开始关心 Agent 的调用延迟发现某步 LLM 调用本身很快但总耗时超预期。仔细 profile 之后才发现框架内部每次调用都在做你根本不需要的事序列化中间结果、触发一堆 callback、记录详细日志。这些逻辑是框架为了通用性设计的对你的场景没用但每次都在跑。有对比测试显示相同功能下 LangChain 的响应时间比直接调 API 平均高出 40% 到 60%。高流量下这些隐性开销累积起来就是真实的延迟增加和费用浪费。三、手搓的本质优势完全掌控说清楚框架的痛点之后手搓的价值就清楚了。它的核心优势说白了就是三个字——完全掌控。第一是链路透明、可观测性好。手搓的每一行代码你都知道在干什么可以在任意位置加日志、打断点、插入监控没有任何黑盒。线上出了故障靠日志复现是最快的方式链路越清晰定位根因越快。这在生产环境里是真实的时间和成本节省。有实践团队算过一笔账自定义管线前期的开发成本多花 2 到 4 周但整个项目生命周期里能省下 4 到 8 周——因为后期调试省下来的时间远大于前期搭建的投入。第二是精确裁剪、没有多余开销。你只写你确确实实需要的那部分逻辑不带任何通用性包袱。工具调用、对话历史维护、错误重试每一块都按你的具体场景实现没有为了兼容其他用法而存在的冗余代码。在性能敏感的场景里这意味着优化空间完全在你手里不用绕过框架的限制来做裁剪。第三是稳定可控、不受框架升级影响。你自己写的接口不会突然变没有来自外部的 breaking change。依赖只剩底层的 LLM SDK相对稳定生产环境可以长期运行不用担心某次例行升级把线上跑坏。其实这个观点不只是个人经验。Anthropic 在官方的 Agent 构建指南里也明确建议过不要一上来就用框架先用最少的抽象把核心逻辑跑通。他们的意思很接近——框架的抽象层会让你离底层更远一旦出了问题调试成本比你省下的开发时间还高。这和实际项目里的感受完全一致框架帮你快速搭起来的东西往往也是后期最难排查的东西。有个类比能很好地概括框架是租房装修好直接住方便但结构改不了房东随时可能调整政策手搓是自建建起来慢但所有结构都熟悉想改什么都能改住着踏实。框架给你省了搭建时间但你对这个房子的控制权始终有限。四、同一个需求框架写 vs 手搓写差别在哪光说理论还不够直观拿最常见的场景对比一下实现一个带工具调用的 Agent loop。用框架写大概是这么几行fromlangchain.agentsimportAgentExecutor,create_openai_tools_agent agentcreate_openai_tools_agent(llm,tools,prompt)executorAgentExecutor(agentagent,toolstools)resultexecutor.invoke({input:帮我查一下今天的天气})三四行就跑起来了确实简洁。但问题是当你想知道这次调用里 LLM 返回了什么、工具是怎么被选中的、消息列表是什么顺序的时候你得去读AgentExecutor的源码它内部的调用链可能有十几层。手搓同样的功能代码量多一些但每一步都在你眼前messages[{role:system,content:system_prompt}]messages.append({role:user,content:user_input})foriinrange(max_turns):# 手动控制最大轮次responseclient.chat.completions.create(modelgpt-4,messagesmessages,toolstool_schemas)msgresponse.choices[0].message messages.append(msg)# 把 LLM 响应加入对话历史ifnotmsg.tool_calls:# 没有工具调用LLM 认为任务完成breakfortcinmsg.tool_calls:# 有工具调用逐个执行并写回resultexecute_tool(tc.function.name,tc.function.arguments)messages.append({role:tool,tool_call_id:tc.id,content:result})logger.info(f工具{tc.function.name}返回:{result})# 随意加日志手搓版本里消息列表怎么拼的、工具怎么选的、循环什么时候退出每一个细节都摆在明面上。出了问题你看这二三十行代码就够了不用去翻框架源码。这就是完全掌控的具体含义——不是说框架不好而是当你需要理解和调试每一个环节时手搓版本给你的确定性是框架给不了的。这和《工程实践中为什么有时手搓Agent 而不直接用现成框架》的核心判断一致框架是黑盒难调试、依赖频繁变动、prompt 难以精细控制而手搓换来的是完全可控的 prompt 与控制流。手搓不是炫技是为了拿回控制权。五、什么时候用框架什么时候手搓这不是非此即彼的选择判断关键看项目所处的阶段以及你对控制权的需求。框架适合这些时机POC 阶段快速验证 idea目标是跑通而不是优化团队刚接触 Agent 开发用框架能少踩一些基础性的坑周边工具文档解析、向量检索依赖框架的生态而核心逻辑本身复杂度不高。这些场景里框架带来的速度优势是真实的值得用。低代码可视化框架Dify、Coze尤其适合非技术团队主导的快速验证和 MVP 场景。手搓的时机准备上生产、稳定性成为核心关切流量开始上来性能和成本变得敏感业务逻辑高度定制和框架的通用设计偏差很大改起来反而费劲团队需要高可观测性链路要能随时监控和回溯。选型原则其实很简单简单场景优先低代码提效复杂核心场景用代码级框架或自研来保障可控性。六、折中方案核心手写周边借用实践中最常见也最务实的是介于两者之间的折中核心逻辑手写周边工具性功能借用框架。控制边界的逻辑是这样的工具调用的循环、对话历史的管理、错误处理和重试、任务状态的维护这些是 Agent 的心脏直接决定系统行为必须百分百理解、百分百掌控所以手写。而 LangSmith 的 tracing、LlamaIndex 的文档解析、某个向量库的 Python 客户端这些是工具性的周边功能出了问题一眼就能看出来不会带来黑盒困境用外部工具节省时间完全值得。就像盖房子承重墙在哪、房间怎么布局你必须完全掌控但门锁、插座面板、水龙头完全可以买现成的不必自己从头制造每一个零件。真实项目往往走这样一条路先用框架快速跑通、验证方向遇到第一批线上问题之后把排查困难的关键部分替换为手写流量上来之后把性能敏感的核心逻辑全部手写最后框架只保留做得好的周边工具。这条路既享受了早期框架的速度又在生产阶段拿回了掌控权。有篇回国复盘写得很实在——“从狂热到理性”作者最初半年每天都用 LangChain 提交代码两年后技术栈里已经找不到它便利背后藏着过度抽象的性能损耗、黑箱化带来的调试困难以及最关键的当你想突破框架限制时的束手束脚。写在最后有一个判断信号可以参考如果你能清楚说出框架在某个地方替我做了什么、我用的这个方法内部发生了什么说明你理解它用起来有掌控感如果你只是调了一个方法但完全不知道里面发生了什么出了问题就是一个不透明的黑盒——这才是需要警惕的信号。所以手搓从来不是要去贬低框架更不是炫技。它是把决定系统行为的核心逻辑写清楚把该自己扛的控制权拿回来。框架不是问题不理解就依赖才是。这也是我想劝你先手搓一遍的根本原因真正写过一遍那个 while 循环你才理解框架替你打包了什么、又藏起了什么。等你真的理解了再回去用框架那时你才是它的主人而不是它的乘客。权拿回来。框架不是问题不理解就依赖才是。这也是我想劝你先手搓一遍的根本原因真正写过一遍那个 while 循环你才理解框架替你打包了什么、又藏起了什么。等你真的理解了再回去用框架那时你才是它的主人而不是它的乘客。
返回列表