首页 / 资讯中心 / 文章详情

Phoenix 多框架 Agent 对比实战:用同一数据分析 Agent 跑通纯代码、LangGraph 与 LlamaIndex Workflows

Phoenix 多框架 Agent 对比实战:用同一数据分析 Agent 跑通纯代码、LangGraph 与 LlamaIndex Workflows ★ FEATURED ARTICLE
可观测性AI 评测LLMOpsAI 应用人工智能【免费下载链接】phoenixAI Observability Evaluation项目地址https://gitcode.com/gh_mirrors/phoenix13/phoenix点击查看免费下载本篇文章以 Phoenix 开源仓库中的 examples/agent_framework_comparison 示例项目为蓝本讲解如何在 PhoenixAI Observability Evaluation 平台之上用完全相同的业务能力路由、SQL 查询、数据分析、工具调用分别实现五种风格的 Agent纯代码无框架、LangGraph、LlamaIndex Workflows、AutoGen 多智能体与 CrewAI 多智能体。读完本文你将掌握多框架 Agent 的统一可观测性接入方法、基于 Phoenix Trace 数据构建本地 SQLite 检索库的流程以及各框架在路由 → 工具调用 → 回环执行这一核心范式上的实现差异。一、项目概览同一个 Agent五种框架实现该项目要解决的问题非常明确同一种数据分析 Agent 的灵魂提示词、工具、数据库保持不变只替换其骨架Agent 编排框架从而让开发者能够直观对比不同框架在实现同一任务时的代码结构、编排方式与可观测性表现。项目中定义的五种实现分别位于仓库的以下目录框架目录入口文件说明纯代码无框架code_based_agentmain.py手写路由循环 OpenAI Function CallingLangGraphlanggraphmain.py基于StateGraphToolNode的状态机编排LlamaIndex Workflowsli_workflowmain.py基于Workflowstep装饰器的事件驱动编排AutoGen 多智能体autogen_multi_agentmain.py基于GroupChatGroupChatManager的多 Agent 对话CrewAI 多智能体crewai_multi_agentmain.py基于CrewAgentTask的角色协作编排这个 Agent 的职责是数据助手它能根据用户的问题通过工具调用生成并执行 SQL 查询从本地 SQLite 数据库取数或对已有数据做趋势分析最终汇总结果回复用户。五种实现共享同一套提示词模板与工具定义这是理解本项目设计意图的关键。二、前置条件你需要准备什么根据 README.md运行本项目前需要满足两项前置条件一个包含 traces 的 Phoenix 项目因为该 Agent 被设计为对着一个 Phoenix 项目说话——它要从 Phoenix 中下载既有 traces 作为数据源。如果你还没有 Phoenix 项目可以先用仓库 tutorials/quickstarts/python_quickstart.ipynb 中的 tracing quickstart 生成一批 traces。一个 OpenAI API KeyAgent 的底层模型使用 OpenAI示例中统一为gpt-4o五种实现均依赖它完成路由决策、SQL 生成与数据分析。三、环境变量与依赖安装3.1 四个环境变量启动前需要设置以下环境变量对应 README.md 中的 Setup 部分export OPENAI_API_KEYyour-openai-key export PHOENIX_API_KEY export PHOENIX_CLIENT_HEADERSapi_key export PHOENIX_COLLECTOR_ENDPOINT各变量的作用可以从源码中得到印证OPENAI_API_KEYOpenAI 客户端认证凭证在 code_based_agent/router.py 中通过client OpenAI()隐式读取AutoGen 实现则显式读取os.environ[OPENAI_API_KEY]见 autogen_multi_agent/router.py。PHOENIX_COLLECTOR_ENDPOINTPhoenix OTLP collector 端点必填项。在 utils/instrument.py 中instrument()函数会先检查该变量是否设置未设置则直接抛出ValueError并提示Please set it before running the agent。PHOENIX_API_KEY与PHOENIX_CLIENT_HEADERS仅当连接Phoenix 云端实例时才需要用于鉴权连接本地 Phoenix 时可不设置。README 明确说明这两者是 cloud 场景的鉴权要求。3.2 安装依赖按 requirements.txt 安装依赖pip install -r examples/agent_framework_comparison/requirements.txt该文件按功能分三组基础运行时openai、gradio、python-dotenv、arize-phoenix、各框架 SDKlanggraph/langchain、llama_index、autogen、crewai、以及 OpenInference 插桩包openinference-instrumentation-openai、-langchain、-llama-index、-crewai、-litellm。后者正是实现多框架统一可观测性的关键依赖。四、数据准备把 Phoenix traces 下载到本地 SQLiteAgent 查询的数据来自 Phoenix 项目中的 traces因此第一步是用脚本把它们拉到本地 SQLite 数据库python examples/agent_framework_comparison/db/download_traces_from_px.py这个脚本db/download_traces_from_px.py非常简洁通过phoenix.client.Client()调用spans.get_spans_dataframe()取出全部 spans 的 DataFrame再交给save_df_to_db落库。落库逻辑在 db/database.py 中实现需要注意两个细节SQLite 不支持嵌套类型save_df_to_db先递归地把np.ndarray转成 list、把 dict/list 序列化为 JSON 字符串最后统一转成str再写入traces表if_existsreplace重复执行会重建表。数据库固定写入examples/agent_framework_comparison/db/example_traces.db表名为traces。仓库中已附带一份示例库db/example_traces.db你可以直接复用。database.py还提供了三个被各框架工具复用的函数run_query(sql_query)执行 SQLSELECT 返回全部结果其他语句返回受影响行数出错时返回An error occurred: ...字符串该返回格式被 SQL 工具的重试逻辑依赖。get_schema()通过PRAGMA table_info(traces)读取表结构供 SQL 生成器提示词使用。get_table()返回表名traces。五、运行 Agent五种实现各有其入口每个实现都有独立的main.py运行方式统一为直接执行脚本例如python examples/agent_framework_comparison/code_based_agent/main.py python examples/agent_framework_comparison/langgraph/main.py python examples/agent_framework_comparison/li_workflow/main.py python examples/agent_framework_comparison/autogen_multi_agent/main.py python examples/agent_framework_comparison/crewai_multi_agent/main.py每个main.py的结构高度一致调用instrument(...)完成插桩然后启动一个 Gradio Chat 界面。以纯代码版本为例code_based_agent/main.pyif __name__ __main__: instrument(project_nameagent-demo, frameworkFramework.CODE_BASED) launch_app()project_name是本次运行在 Phoenix 中归属的项目名五种实现各自使用不同的名字agent-demo、langgraph-agent-demo、li-workflow、autogen-multi-agent、crewai-multi-agent便于在 Phoenix UI 中区分。六、公共骨架五个 Agent 共享的代码资产README 的 Background on the code 一节点明了五种实现之外的公共组件它们正是同一个 Agent的物质基础公共组件路径职责插桩工具utils/instrument.py按框架选择对应的 OpenInference Instrumentor数据库访问db/database.py连接本地 SQLite执行查询、暴露 schema提示词模板prompt_templates/路由、SQL 生成、数据分析三类提示词技能Skillsskills/纯代码与 LlamaIndex 版本的工具实现与注册表6.1 插桩层多框架统一可观测性的核心utils/instrument.py 是理解为什么一个示例要同时依赖五套 SDK的钥匙。它定义了一个Framework枚举LLAMA_INDEX/LANGGRAPH/CODE_BASED/CREWAI/AUTOGEN并通过phoenix.otel.register(project_name...)注册 tracer provider再按框架选择 Instrumentorif framework Framework.LLAMA_INDEX: LlamaIndexInstrumentor().instrument(tracer_providertracer_provider) elif framework Framework.LANGGRAPH: LangChainInstrumentor().instrument(tracer_providertracer_provider) elif framework Framework.CREWAI: LiteLLMInstrumentor().instrument(tracer_providertracer_provider) elif framework Framework.AUTOGEN: OpenAIInstrumentor().instrument(tracer_providertracer_provider) else: OpenAIInstrumentor().instrument(tracer_providertracer_provider)从这段代码可以推断两个事实LangGraph 版本走的是LangChain Instrumentor因为 LangGraph 构建在 LangChain 的langchain_core之上CrewAI 版本依赖LiteLLM InstrumentorCrewAI 内部经 LiteLLM 调用模型AutoGen 与纯代码版本都通过OpenAI Instrumentor捕获 OpenAI SDK 调用。除了框架级自动插桩各工具函数还手动创建 OpenTelemetry span 并写入 OpenInference 语义属性SpanAttributes.INPUT_VALUE、OUTPUT_VALUE、OPENINFERENCE_SPAN_KIND、TOOL_NAME、TOOL_PARAMETERS等从而把路由调用工具执行等自定义环节也纳入 trace。例如纯代码版本的 router.py 中每次 router 调用都会开启一个OPENINFERENCE_SPAN_KIND CHAIN的 span并记录输入与 MIME 类型。6.2 Skills 层与框架解耦的工具抽象纯代码与 LlamaIndex 版本不直接在各 router 中散落工具代码而是通过SkillMap抽象skills/skill_map.py统一管理。SkillMap的 docstring 说明了设计意图将 skills 与 agents/routers 分离便于轻松新增 skill 并在不同 agent 与 router 中复用。其结构是每个 Skill基类见 skills/skill.py暴露三个方法——get_function_name()工具名、get_function_dict()OpenAI function calling 格式的工具描述 JSON、get_function_callable()可执行函数。SkillMap在初始化时把三个AnalyzeData()、GenerateSQLQuery()实例注册进字典并提供get_function_callable_by_name(name)按名取可调用函数路由工具调用时用get_combined_function_description_for_openai()汇总全部工具的 JSON 描述拼给client.chat.completions.create(tools...)时用get_function_description_by_name(name)取单个工具描述LlamaIndex 构建ToolMetadata时用。两个内置 Skillskills/generate_sql_query.py工具名generate_and_run_sql_query。它从提示词模板读取表名与 schema调用gpt-4o生成 SQL经_sanitize_query剥掉 markdown 反引号后执行run_query若执行结果以An error occurred开头且with_retriesTrue则把失败信息拼回 prompt 重试最多 2 次。工具描述中明确要求模型prompt 永远不应是 SQL 查询本身。skills/analyze_data.py工具名data_analyzer。按数据与原始 prompt 的模板调用模型产出洞察调用过程同样被记录为CHAINspan并用using_prompt_template标注提示词模板与版本。README 特别指出LangGraph 版本不使用公共skills/目录而是在自己的目录内用tool装饰器重写了data_analyzer与generate_and_run_sql_query见 langgraph/analyze_data.py 与 langgraph/generate_sql_query.py原因是 LangGraph 依赖 LangChain 的 tool 协议需要略有不同的 skill 结构。七、三种单 Agent 实现的编排逻辑对比7.1 纯代码手写路由循环纯代码版把Agent还原为最朴素的形式一个带记忆的 while 循环。核心在 code_based_agent/router.py若消息列表中没有 system 消息则插入路由提示词 prompt_templates/router_template.py要求模型要么调用工具要么输出文本若调用工具必须把原始 prompt 原样放进参数。携带SkillMap汇总的工具描述调用gpt-4otoolsskill_map.get_combined_function_description_for_openai()。若返回tool_calls把工具结果以{role: tool, content: ..., tool_call_id: ...}追加进消息历史然后递归调用自身return router(messages, new_context)并把当前 context 通过TraceContextTextMapPropagator注入保持 trace 上下文连续。若无工具调用则返回最终文本。代码对失败处理也很稳健工具名查不到时返回Error: Unknown function call模型无输出时返回空字符串。跨线程/跨调用的上下文传播依赖 OTel 的TraceContextTextMapPropagator().inject/extract这正是无框架实现里手工对齐的部分——其他框架把这件事封装进了各自的执行器。7.2 LangGraph状态图 条件边LangGraph 版把同一流程表述为一张图langgraph/router.pyworkflow StateGraph(MessagesState) tool_node ToolNode(tools) workflow.add_node(agent, call_model) workflow.add_node(tools, tool_node) workflow.add_edge(START, agent) workflow.add_conditional_edges(agent, should_continue) # 有 tool_calls 走 tools否则 END workflow.add_edge(tools, agent)两个节点agent调用绑定工具的ChatOpenAI与toolsToolNode自动分发执行加上一个条件边should_continue决定继续调工具还是结束即形成标准的 ReAct 环。此外工具通过model.bind_tools(tools)注册给模型使用MemorySaver()作为 checkpointer并固定thread_id42保留多轮对话状态run_agent每次调用都会重建并invoke图输入为HumanMessage(query)加SystemMessage(SYSTEM_PROMPT)。LangGraph 的工具即图节点设计使其天然拥有了可重复、可回放、可 checkpooint 的执行语义这是与纯代码递归路由最显著的差异。7.3 LlamaIndex Workflows事件驱动的 stepLlamaIndex 版把流程拆成三个step装饰的事件处理器li_workflow/router.pyprepare_agent(StartEvent) - RouterInputEvent把用户输入写入ChatMemoryBuffer取回历史后触发路由router(RouterInputEvent) - ToolCallEvent | StopEvent调用llm.achat_with_tools有工具调用则返回ToolCallEvent否则StopEvent(result...)结束tool_call_handler(ToolCallEvent) - RouterInputEvent遍历ToolSelection把每个工具结果作为roletool的ChatMessage写回 memory再回到路由 step——形成事件循环。几个值得注意的实现细节AgentFlow构造时把SkillMap里的每个 skill 包装成FunctionTool含ToolMetadata的名称与描述LlamaIndex 的ToolSelection.tool_kwargs把参数放在input键下代码将其重命名为prompt以匹配 skill 的参数约定arguments[prompt] arguments.pop(input)默认timeout300整个 workflow 异步执行Gradio 接口也相应声明为async defli_workflow/main.py。八、两种多智能体实现的协作模型8.1 AutoGenGroupChat 群聊协商autogen_multi_agent/router.py 定义了 5 个角色Calculator、Data_Analyzer、SQL_Querysystem message 内嵌SQL_SYSTEM_PROMPT.format(SCHEMA..., TABLE...)、Manager在路由提示词基础上追加了收集并聚合结果、完成后以 TERMINATE 结尾、趋势类任务先用 SQL Agent 取数的协作规则与User_Proxyhuman_input_modeNEVERmax_consecutive_auto_reply10并配置 Docker 代码执行环境。工具通过register_function注册如calculator注册给Calculatorrun_sql_query注册给SQL_Query然后全部 Agent 加入GroupChat(max_round15)由GroupChatManager协调群聊。终止条件由User_Proxy的is_termination_msg判定消息中是否含TERMINATE。最终结果取result.chat_history[-1][content]。与单 Agent 版本的关键差异路由与工具分派不再由一段 router 代码显式控制而是交给 LLM 在群聊中自行协商可观测性则体现在外层agents_callspan 上记录LLM_TOOLS属性。8.2 CrewAI角色 任务 流程crewai_multi_agent/router.py 用Agent(role..., goal..., backstory..., tools...)声明Calculator、Data Analyzer、SQL Query三个角色allow_delegationFalse外加一个可委派的Managerallow_delegationTrue。工具是基于crewai_tools.BaseTool的自定义类crewai_multi_agent/calculator.py 与 crewai_multi_agent/sql_query.py通过 Pydanticargs_schema声明参数。协作由Crew(agents[...], tasks[user_query_task], processProcess.sequential, manager_agentmanager_agent)组织Process.sequential表示按顺序执行任务manager agent 负责把用户 query 拆解、委托并汇总。CrewAI 版还针对除零给出了显式错误返回Error: Division by zero.。九、从源码看五种实现的共性规律对照全部main.py/router.py可以提炼出本示例想展示的设计规律统一可观测性优先无论框架如何全部实现都先经instrument()注册 tracer provider再手动/自动打 span 与 OpenInference 语义属性。插桩的选择LangChain / OpenAI / LlamaIndex / LiteLLM由框架决定集中在 utils/instrument.py 一个文件里属于典型的框架适配器模式。提示词与工具复用router_template.py、sql_generator_template.py、data_analysis_template.py三个模板被所有实现共享SQL 工具、数据分析工具的语义在各实现间保持一致只是包装方式不同SkillMap/tool/BaseTool/register_function。同一 Agent 语义的等价表达纯代码的递归 router、LangGraph 的条件边循环、LlamaIndex 的事件回环、AutoGen 的群聊协商、CrewAI 的顺序任务经理委派在语义上都等价于LLM 判断 → 工具执行 → 结果回填 → 再次判断只是各自用不同的抽象承载了状态与循环。SQL 失败自愈多个实现纯代码 skill、LangGraph tool、CrewAI SQLQueryTool都内置了剥反引号 出错重试逻辑说明 SQL 生成类 Agent 的容错设计是此类应用的关键环节。十、延伸trace 归档与示例数据仓库还提供了一个辅助脚本 utils/save_agent_traces.py它通过Client().spans.get_spans_dataframe(project_name...)把指定项目的 agent traces 以 Parquet 格式归档到examples/agent_framework_comparison/utils/saved_traces/目录。README 提到该脚本主要用于为每个 agent 创建示例 trace 集多数用户可能用不到但它展示了 Phoenix Python Client 的两个典型能力spans.get_spans_dataframe()拉取 spans、download_traces_from_px.py与它配合即可完成Phoenix → 本地数据资产的流水线。结语agent_framework_comparison示例的价值不在于介绍某个特定框架而在于提供了一张对照表在 Phoenix 统一可观测性的底座上同一 Agent 从零手写、状态图、事件驱动、群聊协商、角色协作五种编排风格逐一铺开各自的代码结构、循环控制与工具接入方式一目了然。对正在选型 Agent 框架的团队而言这是一个可以直接在本仓库中逐文件研读、按 requirements.txt 复现并接入 Phoenix 观察对比的现成实验场。赞分享可观测性AI 评测LLMOpsAI 应用人工智能【免费下载链接】phoenixAI Observability Evaluation项目地址https://gitcode.com/gh_mirrors/phoenix13/phoenix点击查看免费下载相关推荐Agno AgentOS 多框架集成实战用一套运行时同时服务 Agno、Claude Code、LangGraph 与 DSPy AgentAgno AgentOS 多框架集成实战用一套运行时同时服务 Agno、Claude Code、LangGraph 与 DSPy Agent 本指南基于 Ag人工智能大模型AI AgentAgent 框架多智能体工具调用RAGAgent 工作流Agent 记忆gpt-computer-assistantUpsonic基准测试实战三步跑通 Direct 与 Agent 的开销对比分析gpt computer assistantUpsonic基准测试实战三步跑通 Direct 与 Agent 的开销对比分析 本文以 benchmarks人工智能大模型AI AgentAgent 框架自主智能体工具调用RAGAgent 记忆Agent 编排PocketFlow 全解析100 行代码的 LLM 框架核心抽象、主流框架对比与 Agent 实战路线图PocketFlow 全解析100 行代码的 LLM 框架核心抽象、主流框架对比与 Agent 实战路线图 本文导读 本文以 PocketFlow 官方 R人工智能大模型AI Agent工作流自动化RAG创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站