1. 从一个真实的技术选型困境说起
去年下半年,我接手了一个 AI Data Agent 的项目。目标很明确:让业务人员用自然语言就能查询数据仓库、生成分析报告、自动做数据质量巡检。听起来是个典型的 LLM 应用,但真正动手时,第一个卡住我的不是模型选型,也不是 Prompt 调优,而是一个更底层的问题——这个 Agent 到底该怎么搭。
团队里有两派意见。一派主张用通用 Agent Runtime 加 Plugin 的方式,把能力拆成一个个插件,运行时负责调度和编排;另一派坚持用现成的 Agent Framework,比如 LangChain、AutoGen、CrewAI 这类,直接站在框架肩膀上快速迭代。两边都有道理,但谁也说服不了谁。我当时的判断是:这不是一个“哪个更好”的问题,而是一个“在什么阶段、什么场景下、什么团队配置下选哪个”的问题。
这篇文章就是那次选型过程的完整复盘。我会把两种路线的核心差异、适用边界、实操中的坑、以及我们最终怎么做的,全部摊开来讲。如果你正在做 AI Agent 相关的项目,尤其是数据类、工具调用密集型的 Agent,这篇内容应该能帮你少走至少两周的弯路。文章会涉及 Agent Runtime、Plugin、Agent Framework、AI Data Agent 这几个核心概念,也会聊到并发、记忆、安全这些绕不开的话题。不管你是刚接触 Agent 开发的新手,还是已经踩过几轮坑的老手,我都尽量把话说透。
先说结论:没有银弹,但有决策树。我们最后走的是混合路线,Runtime 做底座,Framework 做上层编排,Plugin 做能力扩展。具体怎么拆、为什么这么拆,下面慢慢说。
2. 先把概念理清楚:Runtime、Plugin、Framework 到底各管什么
在讨论选型之前,有必要把这三个词的定义对齐。我发现很多团队在争论时,其实说的是不同的东西,导致讨论完全跑偏。
2.1 Agent Runtime:Agent 的“操作系统”
Runtime 这个词在软件领域很常见,比如 Java Runtime、.NET Runtime、WebView2 Runtime。它的本质是提供一套运行环境,让上层应用能跑起来。放到 Agent 场景里,Agent Runtime 负责的是:
- 生命周期管理:Agent 怎么启动、怎么暂停、怎么销毁、怎么恢复状态
- 消息循环:接收输入、调用模型、处理工具调用、返回结果,这个循环怎么转
- 资源调度:并发请求怎么排队、超时怎么处理、重试怎么做
- 状态管理:对话历史、中间结果、执行上下文存在哪、怎么取
- 安全隔离:不同 Agent 之间怎么隔离、工具调用权限怎么控制
你可以把 Agent Runtime 理解成 Agent 的“操作系统”。它不关心你具体要做什么业务,只关心“怎么让 Agent 稳定、高效、安全地跑起来”。这跟 JVM 不关心你写的是电商还是社交,只关心字节码怎么执行,是一个道理。
2.2 Plugin:Agent 的“能力积木”
Plugin 解决的是能力扩展问题。一个 Agent 再聪明,如果只能聊天,价值也有限。它需要能查数据库、能调 API、能读文件、能发邮件。这些能力如果都写死在 Agent 核心代码里,那这个 Agent 就废了——改一个功能要动全身。
Plugin 的思路是:把每种能力封装成独立的、可插拔的模块。每个 Plugin 定义清楚的输入输出接口,Runtime 负责在合适的时机调用它。比如:
- 一个“SQL 查询”Plugin,输入是自然语言或 SQL,输出是查询结果
- 一个“图表生成”Plugin,输入是数据,输出是图片
- 一个“数据质量检查”Plugin,输入是表名,输出是检查报告
Plugin 的关键在于接口标准化。如果每个 Plugin 的调用方式都不一样,那 Runtime 就得写一堆适配代码,插件化就失去了意义。所以通常会用 JSON Schema 或者类似的方式来描述 Plugin 的入参和出参,让 Runtime 能统一处理。
2.3 Agent Framework:Agent 的“脚手架”
Framework 和 Runtime 的区别,很多人搞混。我的理解是:Framework 更偏向开发效率,Runtime 更偏向运行效率。
Agent Framework 通常提供一套完整的开发范式,包括:
- 抽象基类:比如
Agent、Tool、Memory、Chain这些概念 - 编排能力:多个 Agent 怎么协作、任务怎么分解、结果怎么汇总
- 内置组件:现成的工具库、记忆实现、模型适配器
- 开发工具:调试、追踪、可视化
LangChain、AutoGen、CrewAI 这些都是典型的 Agent Framework。它们的价值在于让你快速搭出一个能跑的 Agent,不用从零造轮子。但代价是抽象层多、黑盒多、定制困难。当你的业务逻辑复杂到一定程度,框架的抽象反而会成为束缚。
2.4 三者的关系:不是互斥,是层次
很多人把 Runtime、Plugin、Framework 当成三选一,这是误解。它们其实是不同层次的东西:
| 层次 | 关注点 | 典型代表 | 类比 |
|---|---|---|---|
| Framework | 开发效率、编排范式 | LangChain、AutoGen | 前端框架 React/Vue |
| Runtime | 运行效率、稳定性、安全 | 自研 Runtime、云厂商 Agent 服务 | 浏览器引擎、JVM |
| Plugin | 能力扩展、解耦 | 各种工具插件 | 浏览器扩展、IDE 插件 |
一个完整的 Agent 系统,通常是Runtime 做底座 + Plugin 做能力 + Framework 做编排。选型的核心不是“选哪个”,而是“哪些自己造、哪些用现成的、边界怎么划”。
3. 为什么 AI Data Agent 这个场景特别难选
不是所有 Agent 项目都面临这个选型困境。简单的客服机器人、文档问答,直接用 Framework 就搞定了。但 AI Data Agent 有几个特殊之处,让选型变得复杂。
3.1 工具调用密集,Plugin 质量决定上限
Data Agent 的核心工作是调工具:查元数据、写 SQL、执行查询、做数据校验、生成图表、发报告。一个完整的分析流程,可能涉及十几个工具调用。这意味着:
- Plugin 的数量多、类型杂
- Plugin 之间的依赖关系复杂(比如先查元数据才能写 SQL)
- Plugin 的稳定性直接决定 Agent 的可用性
如果 Plugin 层设计得不好,比如接口不统一、错误处理缺失、超时控制没有,那 Agent 就会频繁卡死或返回错误结果。这种情况下,Framework 内置的那几个工具根本不够用,你最终还是得自己写 Plugin,那 Framework 的价值就打了折扣。
3.2 数据安全要求高,Runtime 的隔离能力是刚需
Data Agent 要访问的是真实的数据仓库,里面有用户信息、交易记录、业务指标。这意味着:
- 不同用户的数据权限必须严格隔离
- SQL 注入、越权查询必须防住
- 敏感数据不能出现在日志或模型上下文里
这些需求,Framework 通常不提供。Framework 假设你是在一个可信环境里跑 Agent,安全是你自己的事。但 Runtime 不一样,Runtime 天生就要考虑隔离、权限、审计。所以在这个场景下,Runtime 的能力是刚需,不是锦上添花。
3.3 并发和成本压力大,Runtime 的调度能力关键
Data Agent 的用户可能是几十个业务人员同时在线,每个人都在跑查询。如果每个请求都独立起一个 Agent 实例,资源消耗会爆炸。如果共用一个实例,又会有状态污染问题。
这就需要 Runtime 提供并发调度、资源池化、状态隔离的能力。比如:
- 用连接池管理数据库连接
- 用队列控制并发查询数量
- 用会话隔离保证不同用户的状态不串
这些能力,Framework 基本不管。你如果用 Framework,就得自己在外面套一层调度逻辑,那还不如直接用 Runtime。
3.4 业务逻辑复杂,Framework 的抽象容易“漏”
Data Agent 的业务逻辑不是线性的“输入-处理-输出”,而是有分支、有循环、有回退的。比如:
- 用户问“上个月销售额为什么下降”,Agent 需要先查总体数据,再按维度拆解,再对比历史,最后生成结论
- 如果某个维度数据缺失,Agent 需要自动换一个维度
- 如果 SQL 执行失败,Agent 需要根据错误信息修正 SQL 再试
这种复杂的控制流,用 Framework 的 Chain 或 Graph 来表达,会非常别扭。你会在框架的抽象和业务的实际需求之间反复拉扯,最后写出一堆“框架适配代码”,而不是业务代码。
4. 两条路线的深度对比:从六个维度拆解
下面这张表是我当时做选型时整理的,从六个关键维度对比两种路线。注意,这里的“通用 Runtime + Plugin”指的是自研或选用偏底层的 Runtime,自己写 Plugin;“Agent Framework”指的是直接用 LangChain 这类成熟框架。
| 维度 | 通用 Runtime + Plugin | Agent Framework |
|---|---|---|
| 开发速度 | 慢,需要自己搭底座 | 快,开箱即用 |
| 定制能力 | 强,完全可控 | 弱,受框架抽象限制 |
| 运行稳定性 | 高,可针对性优化 | 中,依赖框架质量 |
| 安全隔离 | 强,可深度定制 | 弱,通常需额外开发 |
| 并发能力 | 强,可精细调度 | 中,框架层支持有限 |
| 团队要求 | 高,需要架构能力 | 低,会调 API 即可 |
| 长期维护 | 可控,但成本高 | 受框架版本影响大 |
| 适用阶段 | 中后期,业务稳定后 | 早期,快速验证 |
4.1 开发速度:Framework 赢在起跑线
用 LangChain 搭一个能查数据库的 Agent,熟练的话半天就能跑通。它内置了 SQLDatabaseToolkit、AgentExecutor、Memory 这些组件,你只需要配置一下模型和数据库连接,写几行 Prompt,就能得到一个能用的 Demo。
但用 Runtime + Plugin 的方式,你得先设计 Runtime 的接口、实现消息循环、定义 Plugin 协议、写调度逻辑,然后才能开始写第一个业务 Plugin。这个前期投入,保守估计两周起步。
所以如果你的目标是快速验证想法,Framework 是更理性的选择。先跑通,再优化。
4.2 定制能力:Runtime 赢在深水区
当业务逻辑复杂到一定程度,Framework 的抽象就会成为障碍。我举个实际例子。
我们的 Data Agent 需要支持“多轮追问”。用户问“上个月销售额多少”,Agent 返回结果后,用户可能接着问“那前个月呢”,这时候 Agent 需要理解“前个月”是相对于上一轮的时间范围,而不是当前时间。这个逻辑,用 Framework 的 Memory 组件来实现,非常别扭,因为 Memory 通常只存对话历史,不存业务上下文。
但用 Runtime + Plugin 的方式,我们可以在 Runtime 层维护一个“会话上下文”,里面存当前的时间范围、数据权限、已查询的表等信息。Plugin 在执行时,可以从上下文里读取这些信息。这个设计非常自然,因为 Runtime 本来就是管状态的。
4.3 运行稳定性:Runtime 的优势在细节
Framework 的稳定性问题,往往出在细节上。比如:
- 工具调用超时了怎么办?Framework 可能直接抛异常,整个 Agent 挂掉
- 模型返回了格式不对的 JSON 怎么办?Framework 可能解析失败,返回空结果
- 并发请求多了,Memory 会不会串?Framework 的 Memory 实现可能不是线程安全的
这些问题,在 Demo 阶段不会暴露,但一上生产就会集中爆发。而 Runtime 因为是你自己写的,你可以针对每个环节做防御性设计:超时重试、格式校验、状态隔离、降级策略。这些细节,才是生产级 Agent 和 Demo 级 Agent 的分水岭。
4.4 安全隔离:Runtime 是唯一选择
前面说过,Data Agent 的安全要求高。Framework 通常不提供细粒度的权限控制。你很难用 LangChain 实现“用户 A 只能查表 X,用户 B 只能查表 Y”这种逻辑。
但 Runtime 可以。你可以在 Runtime 层做权限校验:每次 Plugin 调用前,检查当前用户是否有权限执行这个操作。你还可以做 SQL 审计:记录所有执行的 SQL,便于事后追溯。这些能力,是 Data Agent 上生产的必要条件。
4.5 并发能力:Runtime 的调度是核心竞争力
并发问题在 Demo 阶段不明显,但用户一多就致命。我们当时压测发现,用 Framework 的方案,20 个并发请求就会导致响应时间从 2 秒飙升到 30 秒。原因是每个请求都独立创建 Agent 实例,数据库连接、模型调用都没有池化。
换成 Runtime + Plugin 后,我们在 Runtime 层做了几件事:
- 数据库连接池:复用连接,避免频繁创建销毁
- 模型调用队列:控制并发数,避免触发 API 限流
- 会话状态隔离:每个用户独立上下文,互不干扰
优化后,50 个并发请求的 P95 响应时间稳定在 5 秒以内。这个提升,是 Framework 方案很难达到的。
4.6 团队要求:Framework 对新手友好
这一点很现实。如果你的团队里没有人做过 Agent 架构,直接上 Runtime + Plugin 会非常痛苦。你需要有人懂消息循环、懂状态管理、懂并发调度、懂安全隔离。这些能力,不是看几篇文档就能获得的。
而 Framework 的好处是,它把复杂度封装了。一个会写 Python、会调 API 的工程师,看两天文档就能上手。这对于快速组建团队、快速出成果,非常重要。
5. 我们最终的方案:混合路线,分层解耦
经过两周的调研和一周的原型验证,我们最终没有选边站,而是走了一条混合路线。核心思路是:Runtime 做底座,Framework 做编排,Plugin 做能力。
5.1 整体架构分层
我们的架构分四层:
- Runtime 层:自研,负责生命周期、消息循环、并发调度、状态管理、安全隔离
- 编排层:用 Framework 的思路,但不用现成框架,自己实现了一个轻量的 Graph 编排器
- Plugin 层:自研,每个数据能力封装成独立 Plugin,统一接口协议
- 模型层:通过适配器对接多个模型,支持切换和降级
这个架构的关键在于边界清晰。Runtime 不关心业务逻辑,编排层不关心底层调度,Plugin 不关心编排流程。每层只做自己该做的事。
5.2 为什么不用现成 Framework 做编排
我们试过 LangChain 的 AgentExecutor 和 AutoGen 的 GroupChat,但都遇到了问题。LangChain 的 AgentExecutor 太死板,只支持固定的“思考-行动-观察”循环,我们的业务需要更灵活的控制流。AutoGen 的 GroupChat 又太重,多个 Agent 对话的开销太大,不适合工具调用密集的场景。
最后我们自己写了一个轻量编排器,核心是一个状态机。每个任务定义成一组状态和转移条件,编排器根据当前状态和 Plugin 返回结果,决定下一步走哪个状态。这个设计非常灵活,可以表达任意复杂的控制流,而且代码量不大,核心逻辑不到 500 行。
5.3 Plugin 协议的设计要点
Plugin 协议是我们花时间最多的地方。最终定下来的规范包括:
- 输入输出用 JSON Schema 描述:Runtime 可以自动校验参数,生成调用文档
- 每个 Plugin 必须声明权限要求:比如“需要查询表 X 的权限”,Runtime 在调用前校验
- 错误码标准化:区分“参数错误”“权限不足”“执行失败”“超时”等类型,便于编排层处理
- 支持流式输出:对于耗时长的 Plugin(如大数据量查询),支持分批返回结果
这套协议让 Plugin 的开发变得标准化。新人写 Plugin,只需要按照模板填业务逻辑,不用关心调度、权限、错误处理这些横切关注点。
5.4 实际效果和代价
这套方案上线后,效果符合预期:
- 并发能力:支持 100+ 并发,P95 响应时间 5 秒以内
- 稳定性:连续运行三个月,没有出现因 Agent 框架导致的故障
- 扩展性:新增一个数据源,只需要写一个 Plugin,平均半天完成
- 安全性:所有数据访问都有权限校验和审计日志
代价也很明显:
- 前期投入大:Runtime 和编排器开发花了约一个月
- 团队要求高:需要有人懂架构设计
- 维护成本:自研代码需要自己维护,没有社区支持
所以我的建议是:如果你的项目还在验证阶段,先用 Framework 快速跑通;如果已经确定要上生产,且业务逻辑复杂、安全要求高,那 Runtime + Plugin 的投入是值得的。
6. 实操中的坑和排查技巧
这一部分是我踩过的坑,以及怎么爬出来的。每一条都是真金白银换来的。
6.1 Plugin 超时导致 Agent 卡死
问题现象:某个 SQL 查询 Plugin 执行时间过长,整个 Agent 卡住,后续请求全部排队。
排查过程:一开始以为是数据库慢,查了慢查询日志发现 SQL 本身没问题。后来发现是 Plugin 没有设置超时,Runtime 一直在等它返回。
解决方法:在 Runtime 层给每个 Plugin 调用设置超时,超时后强制中断并返回错误。同时给 Plugin 加异步执行能力,耗时操作放到后台,Agent 先返回“正在处理”,完成后推送结果。
注意:超时时间不能一刀切。查询类 Plugin 可以设 30 秒,写入类 Plugin 设 10 秒,元数据类 Plugin 设 5 秒。要根据业务特点分别配置。
6.2 模型返回格式错误导致解析失败
问题现象:Agent 偶尔返回空结果,日志显示 JSON 解析失败。
排查过程:抓了模型原始输出,发现模型有时候会在 JSON 外面包一层 Markdown 代码块,有时候会多写一段解释文字。
解决方法:在 Runtime 层加一个“输出清洗”步骤,用正则提取 JSON 部分,再做解析。同时优化 Prompt,明确要求“只返回 JSON,不要任何其他内容”。双管齐下后,解析失败率从 5% 降到 0.1% 以下。
6.3 并发场景下会话状态串了
问题现象:用户 A 的查询结果出现在了用户 B 的对话里。
排查过程:查代码发现,Memory 组件用的是全局字典,key 是会话 ID,但会话 ID 生成逻辑有 bug,高并发下会重复。
解决方法:改用 UUID 加用户 ID 的组合作为会话 key,并且在 Runtime 层加锁,保证同一会话的请求串行处理。这个问题排查了整整两天,因为复现概率低,最后是靠日志里的会话 ID 对比才定位到。
6.4 常见问题速查表
| 问题 | 可能原因 | 排查方向 | 解决方案 |
|---|---|---|---|
| Agent 无响应 | Plugin 超时 | 查 Plugin 执行日志 | 加超时和异步 |
| 返回结果为空 | 模型输出格式错误 | 抓模型原始输出 | 加输出清洗 |
| 会话状态串 | 会话 ID 冲突 | 查会话 ID 生成逻辑 | 用 UUID + 加锁 |
| 并发性能差 | 资源未池化 | 查连接创建次数 | 加连接池和队列 |
| 权限校验失败 | Plugin 权限声明缺失 | 查 Plugin 配置 | 补权限声明 |
| 模型调用限流 | 并发数过高 | 查 API 调用频率 | 加队列和降级 |
6.5 几个独家避坑技巧
技巧一:Plugin 要幂等。同一个 Plugin 可能因为重试被调用多次,如果它有副作用(比如写数据),就会出问题。所以设计 Plugin 时,尽量让它幂等,或者加去重逻辑。
技巧二:日志要带 trace ID。Agent 的一次请求可能涉及多个 Plugin 调用、多次模型调用。如果没有统一的 trace ID,排查问题时会非常痛苦。我们在 Runtime 层生成 trace ID,贯穿整个调用链,日志里都带上,排查效率提升明显。
技巧三:模型调用要可降级。我们对接了两个模型,主模型挂了自动切备用。这个降级逻辑放在 Runtime 层,Plugin 不用关心。实测下来,模型 API 偶尔抖动时,用户几乎无感知。
技巧四:Prompt 要版本化。Prompt 改了之后,Agent 行为可能变化。我们把 Prompt 存在配置中心,每次修改都记录版本,出问题可以快速回滚。这个习惯帮我们避免了好几次线上事故。
7. 关于 Agent 记忆和并发的一些补充思考
这两个话题在选型时经常被忽略,但实际做起来非常关键。
7.1 Agent 记忆:不只是存对话历史
很多人以为 Agent 记忆就是存对话历史,其实远不止。Data Agent 的记忆至少分三层:
- 对话记忆:用户说了什么、Agent 回了什么,用于理解上下文
- 业务记忆:当前查询的时间范围、数据权限、已访问的表,用于保证逻辑一致
- 长期记忆:用户偏好、常用查询、历史报告,用于个性化服务
对话记忆用 Framework 的 Memory 组件就能搞定。但业务记忆和长期记忆,Framework 通常不管,需要自己在 Runtime 层实现。我们的做法是,在 Runtime 层维护一个“会话上下文”对象,Plugin 可以读写,编排器可以根据它做决策。
7.2 并发:不是加机器就能解决
Agent 的并发问题,不是简单加机器就能解决的。因为瓶颈往往不在计算资源,而在:
- 模型 API 限流:每个模型账号有 QPS 限制,加机器也没用
- 数据库连接数:数据库连接是稀缺资源,不能无限创建
- 状态一致性:并发操作同一会话,需要加锁保证顺序
所以并发优化的核心是调度,不是扩容。我们在 Runtime 层做了三级队列:模型调用队列、数据库查询队列、Plugin 执行队列。每个队列独立控制并发数,避免相互影响。这个设计让系统在高负载下依然稳定。
7.3 安全:Agent 场景的新挑战
Agent 的安全问题和传统应用不同。传统应用的安全主要是防外部攻击,Agent 的安全还要防模型被诱导。比如用户通过精心构造的 Prompt,让 Agent 执行越权操作。
我们的防御措施包括:
- 输入过滤:检测 Prompt 里的敏感指令,拦截可疑请求
- 权限校验:Plugin 调用前校验用户权限,不依赖模型判断
- 输出审计:记录所有 Agent 返回结果,便于事后追溯
- 最小权限:Plugin 只授予必要权限,避免“一个 Plugin 能查所有表”
这些措施不能保证 100% 安全,但能大幅降低风险。安全是个持续对抗的过程,没有一劳永逸的方案。
8. 给不同阶段团队的建议
最后,基于我的经验,给不同阶段的团队一些具体建议。
8.1 验证阶段:先用 Framework 跑通
如果你的项目还在验证想法,团队没有 Agent 架构经验,那就用 Framework。LangChain、AutoGen、CrewAI 都可以,选一个社区活跃、文档齐全的。目标是两周内跑通一个能用的 Demo,验证业务价值。
这个阶段不要纠结架构,不要追求完美。先让业务方看到效果,拿到反馈,再决定下一步。
8.2 成长阶段:Framework + 自研 Plugin
当 Demo 验证通过,开始有真实用户使用时,问题会逐渐暴露。这时候可以在 Framework 基础上,把关键能力抽成自研 Plugin。比如数据查询、权限校验、审计日志这些,Framework 内置的组件不够用,自己写更可控。
这个阶段的目标是在保持开发速度的同时,逐步替换掉不稳定的部分。不用一次性重写,可以一个模块一个模块地替换。
8.3 生产阶段:Runtime + Plugin + 轻量编排
当用户量上来,稳定性和安全性成为硬要求时,就该考虑自研 Runtime 了。这时候你对业务的理解已经足够深,知道哪些能力需要定制,哪些可以复用。
这个阶段的目标是构建一个稳定、安全、可扩展的 Agent 底座。投入会比较大,但长期收益也大。我们的经验是,Runtime 开发一个月,之后每个新 Plugin 的开发效率提升至少三倍。
8.4 一个简单的决策清单
如果你还在纠结,可以问自己这几个问题:
- 项目处于什么阶段?验证期选 Framework,生产期选 Runtime
- 团队有没有 Agent 架构经验?没有的话,先从 Framework 入手
- 安全要求高不高?高的话,Runtime 是必须的
- 业务逻辑复杂不复杂?复杂的话,Framework 的抽象会成为障碍
- 并发压力大不大?大的话,Runtime 的调度能力是关键
这五个问题,基本能帮你定位到合适的路线。
我在实际项目中的体会是,技术选型没有绝对的对错,只有适不适合。Framework 和 Runtime 不是对立关系,而是不同阶段的工具。关键是认清自己的阶段和需求,不要为了技术而技术,也不要为了省事而埋下隐患。Data Agent 这个场景,因为工具调用密集、安全要求高、并发压力大,最终大概率会走向 Runtime + Plugin 的路线。但这个过程可以循序渐进,不用一步到位。