实用指南:开源智能体框架与 ElevenAgents
- 发布时间
- 最近更新
收听收听本文
在上一篇文章 将外部智能体集成到 ElevenLabs 语音编排 中,我们介绍了团队如何通过 Custom LLM 将现有的文本智能体编排接入 ElevenLabs。本指南将在此基础上说明,如何调整主流开源智能体框架,并将其部署在 Custom LLM 接口之后。这样可在成熟的智能体系统之上叠加语音能力,同时不影响状态管理、工具编排或应用特定控制。无论使用哪种框架,都遵循相同的 3 步流程:创建生成请求、提取最终文本响应,并将其重新格式化为兼容 OpenAI 的服务器发送事件(SSE)格式。ElevenLabs 同时支持 Chat Completions 和 Responses 格式。本指南涵盖 4 个广泛采用的框架,但这些模式同样适用于任何能生成兼容 OpenAI 流式输出的运行时。
.webp&w=3840&q=80)
通用设置
本节示例使用 Python 和 FastAPI,但任何能处理 HTTP POST 请求和流式 SSE 响应的技术栈都适用。当 ElevenLabs 的语音编排检测到对话轮次可能结束时,会向配置的 Custom LLM 端点发起生成请求。本节将介绍这一转换层的核心组件,即让语音编排与智能体框架使用同一种语言的桥接层或代理层。
客户选择不同框架,通常是因为熟悉该框架,或它能满足特定需求。例如,LlamaIndex 最初旨在简化检索增强生成(RAG)的搭建,而 CrewAI 则面向智能体时代的明确任务自动化。不同设计目标会产生不同响应结构,因此需要针对性处理。让 LLM 在生成时即时流式传输内容,而非等待完整轮次结束,至关重要:这让文本转语音(TTS)模型能更早开始生成语音,从而降低感知延迟。本文主要聚焦 4 个热门框架:LangGraph、Google ADK、CrewAI 和 LlamaIndex。
共享代码说明
每个框架都必须以兼容 OpenAI 的 SSE 数据块流式传输响应。我们先介绍一个供各示例共用的小型辅助函数,用于构建这些数据块。
基础准备就绪后,先来看 LangGraph。
LangGraph
LangGraph 将 智能体 建模为图:节点代表各个步骤,边定义节点之间的控制流。最简设置很直接:初始化聊天模型、定义智能体工具并创建智能体图运行时。
每次生成请求时,LangGraph Agent 都会接收完整对话历史,从而在内部维护所需状态。LangGraph 支持通过 Checkpoints 实现服务端持久化,但为保持实现简洁,本文不展开介绍。
处理完状态管理后,下一个 LangGraph 特有的决策点是流式模式。LangGraph 提供两种选项,分别适合不同场景:
- stream_mode="values" 提供图状态快照。实现更简单,但每次响应都会包含更完整的消息状态,会增加实时对话流程的延迟。
- stream_mode="messages" 流式输出模型逐步生成的消息块。它通常更适合实时语音交互,因为能缩短 ElevenLabs 编排层生成首段音频的时间。
更具体地说,智能体循环的 messages 实现包含 工具调用 更新等不应朗读的中间步骤。代理会过滤这些内容,仅将面向用户的响应文本传给 TTS 层。下面是一个启用工具的对话轮次示例。
[1] 模型决定调用工具(tool_calls=["get_price"])[2] 工具执行并返回数据(result="$24.99") [3] 模型使用结果生成响应(content="价格为 $24.99")
显然,SSE 流中只应转发第 3 步的数据块。实际操作中,流式循环中的两项检查可完成过滤:一项仅保留 langgraph_node == "model" 事件,另一项跳过空内容。两者结合,确保只有面向用户的助手文本以 SSE 形式转发至 ElevenLabs。结合这些概念,下面给出一个轻量级请求代理实现。
这样可确保只有面向用户的模型数据块会被转发至 ElevenLabs。由于 LangGraph 会通过状态流公开内部工具执行过程,过滤由代理明确控制。
接下来,我们深入了解 Google Agent Development Kit(ADK)的使用要点。
Google ADK
Google 的 ADK 通过几个核心原语抽象了运行时循环:Agent、Runner 和 SessionService。ADK 的 Runner 位于 HTTP 层和智能体定义之间,负责消息路由、工具编排、会话生命周期和事件流式传输。
初始化智能体、会话后端和 runner 后,代理会为每个传入请求查找或创建 ADK 会话。在 ADK 中,session_id 控制记忆持久化:跨轮次复用同一 session_id,会自动保留历史记录、工具调用和先前响应。由于对话标识由 ElevenLabs 上游维护,代理会明确处理这一映射。为生成请求传入正确标识符后,SDK 即可在内部处理先前上下文。我们在发起对话时,通过传入请求正文的 额外参数 传递该任意标识符。
准备好消息和会话后,即可调用 runner。执行期间,工具调用及其结果仍会作为 ADK 内部事件出现,但会被视为中间编排步骤,而非面向用户的输出。相比工具调用以用户可见文本出现的框架,这无需手动过滤。
以下处理程序是简化实现,内联包含会话查找以及获取或创建逻辑。
接下来看看 CrewAI,它的设计更以任务为中心。
CrewAI
CrewAI 的设计目标是围绕结构化任务(研究、撰写、总结)编排多智能体 workflow,而不是处理开放式对话循环。智能体由角色、目标和背景故事定义。执行则以 Task 对象为中心,每个对象都有明确描述和预期输出。
不同于 LangGraph 和 ADK 使用的智能体循环模型,CrewAI 通常会为每个请求构建 Task 和 Crew,以定义该对话轮次的工作单元。我们通过占位符将先前轮次注入下一个任务,从而保留对话上下文。每次请求都会使用持续累积的对话历史填充 {crew_chat_messages} 变量,并在执行时插入任务描述。为生成干净、可直接朗读的文本,我们还会明确过滤中间追踪模式(Thought、Action、Action Input、Observation),只输出最终答案文本。
以下处理程序整合了按请求构建任务、插入历史记录、Crew 级流式传输、追踪过滤和输出格式化。
接下来看看 LlamaIndex。它采用不同路径,聚焦原生事件驱动的流式模型。
LlamaIndex
与本文介绍的其他框架不同,LlamaIndex 专为将 LLM 连接到外部数据源(文档存储、索引、检索管道)而设计。其智能体层 FunctionAgent 建立在这一基础之上,用于检索结构化上下文并进行推理,而非开放式对话或任务执行。
为保持对话连续性,代理会将传入消息转换为 LlamaIndex 聊天消息,再将其拆分为最新用户轮次(user_msg)和先前轮次(chat_history)。每个 AgentStream 事件的 event.delta 字段都包含下一个文本片段,可直接映射为 OpenAI 风格的 delta.content 数据块。非空 delta 可原样转发,因此这是本指南中最直接的流式桥接方式。流中既包含编排事件(工具调用、结果),也包含语音事件(助手文本增量)。为保持语音输出干净,代理仅保留 AgentStream 事件并跳过空 delta。
[1] AgentStream(delta='') ← 已忽略[2] ToolCall ← 已忽略[3] ToolCallResult ← 已忽略[4] AgentStream(delta='它') ← 已转发 ✓[5] AgentStream(delta=' 的价格是')← 已转发 ✓[6] AgentStream(delta=' $49.99')← 已转发 ✓
这种分离方式可避免将中间工具机制读出来,同时保留低延迟的增量语音。下面可直接使用的处理程序整合了这些步骤。
与内置编排层更重的框架相比,LlamaIndex 对端到端对话运行时模式的约束较少。在生产部署中,通常需要自行实现会话处理、响应防护、工具编排和追踪。
总结
本指南中的每个框架都通过同一约定接入 ElevenLabs:接受 OpenAI 风格的 Completions 或 Responses 请求,并流式返回 SSE 数据块。这样,团队只需对现有智能体实现做少量改动,就能在其上叠加语音编排,保留已构建的能力,同时解锁实时 对话式 AI。这种模块化是 ElevenAgents 平台的核心理念。无论是扩展现有智能体,还是从一开始构建原生语音智能体,ElevenAgent 的语音编排都能适配实际需求。
如果你已在使用开源框架运行智能体,并希望启用语音功能,不妨试试这种方法,并告诉我们你的体验。
.webp&w=3840&q=80)
.webp&w=3840&q=80)
.webp&w=3840&q=80)
