AI Agent 框架设计与选型:LangChain、LlamaIndex、Qwen-Agent、AutoGen 深度对比与实战
前言
大模型(LLM)本身只会"说话",要让它真正"干活"——查数据、调接口、读文档、写代码,就需要 Agent 框架来搭桥。目前主流的 AI Agent 框架有:
- LangChain:全能型框架,管道式编排与丰富生态
- LlamaIndex:数据驱动的 RAG 专家
- Qwen-Agent:轻量级全能选手,工具调用与代码解释器
- AutoGen:多智能体协作框架
本文先拆解"编写一个 AI Agent 框架需要解决的四大核心问题",再逐一分析四大框架的实现方式与适用场景,最后通过一个"多文件智能问答 Agent"实战案例,演示同一个需求在三个框架下的不同实现,帮助大家建立清晰的选型思路。
一、AI Agent 的四大核心问题
如果让我们自己从零编写一个 AI Agent 框架,需要解决哪些核心问题?可以类比人体结构:
| 核心问题 | 类比 | 职责 |
|---|---|---|
| LLM 适配层 | 大脑 | 抹平不同模型的 API 差异,统一调用接口 |
| 工具注册与调度 | 双手 | 让 LLM 能调用 Python 函数、外部 API |
| Context 管理 | 记忆 | 管理对话历史与私有知识,防止 Token 爆炸 |
| 控制流编排 | 中枢 | 拆解复杂任务,组织执行流程 |
下面逐一展开。
1. 大脑的适配层:LLM 统一接口与 Prompt 管理
不同厂商的模型(OpenAI、DeepSeek、Qwen)API 格式各不相同,框架的第一件事就是通过 Model Adapter(适配器模式) 抹平这些差异。
三大框架的模型接入方式对比:
# ========== LangChain (v0.3) ==========
from langchain_community.chat_models import ChatTongyi
llm = ChatTongyi(
model_name="deepseek-v3",
dashscope_api_key=api_key
)
# ========== Qwen-Agent ==========
llm_cfg = {
'model': 'deepseek-v3',
'model_server': 'https://dashscope.aliyuncs.com/compatible-mode/v1',
'api_key': os.getenv('DASHSCOPE_API_KEY'),
'generate_cfg': {'top_p': 0.8}
}
# ========== LlamaIndex ==========
from llama_index.llms.dashscope import DashScope
llm = DashScope(
model="deepseek-v3",
api_key=api_key,
temperature=0.7,
)
| 框架 | LLM 封装方式 | 特点 |
|---|---|---|
| LangChain | ChatTongyi / ChatOpenAI 类 |
丰富的模型适配器,统一接口 |
| Qwen-Agent | llm_cfg 字典配置 |
配置式,支持多种 model_server |
| LlamaIndex | DashScope / OpenAI 类 |
与 Settings 全局配置结合 |
框架层相当于做了一个中间层,把统一的指令(如 invoke("你好"))翻译成特定模型的 API 调用。LLM 统一接口的作用:
- 统一调用方式
- 统一参数配置(如
temperature) - 统一输出格式(统一转为 Message 对象)
Prompt Engineering 工程化:System Message 的动态注入,将人设与上下文解耦。
# LangChain 的 PromptTemplate
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant."),
MessagesPlaceholder(variable_name="history"),
("human", "{input}")
])
# Qwen-Agent 的 system_message
system_instruction = '''你是一个乐于助人的AI助手。
在收到用户的请求后,你应该:
- 首先绘制一幅图像,得到图像的url,
- 然后运行代码下载该图像。
你总是用中文回复用户。'''
核心思想是:人设(角色定义)与任务流程(上下文指令)分离,便于复用和维护。
2. 双手的标准化:工具注册与调度(Tool Registry)
LLM 只能输出文本,怎么让它去执行 Python 函数?答案是:框架将函数的元信息转成 JSON Schema 喂给 LLM,LLM 决定调用哪个工具并生成参数,框架负责真正执行。
各框架提供了不同的工具注册方式:
| 模式 | 框架 | 特点 |
|---|---|---|
@tool 装饰器 |
LangChain | 最简洁,docstring 自动解析 |
@register_tool + 类 |
Qwen-Agent | 显式参数定义,结构清晰 |
FunctionTool 封装 |
LlamaIndex | 强类型约束,适合复杂工具 |
LangChain:@tool 装饰器
from langchain_core.tools import tool
@tool
def ping_tool(target: str) -> str:
"""检查本机到指定主机名或IP地址的网络连通性。
参数:
target: 目标主机名或IP地址
返回:
模拟的ping结果
"""
if "unreachable" in target:
return f"Ping {target} 失败"
return f"Ping {target} 成功"
@tool 的优势:自动从 docstring 解析工具描述和参数说明;支持类型注解,LLM 自动理解参数类型;一行装饰器,零配置即可使用。
Qwen-Agent:@register_tool
from qwen_agent.tools.base import BaseTool, register_tool
@register_tool('my_image_gen')
class MyImageGen(BaseTool):
description = 'AI 绘画服务,输入文本描述,返回图像 URL'
parameters = [{
'name': 'prompt',
'type': 'string',
'description': '期望的图像内容的详细描述',
'required': True
}]
def call(self, params: str, **kwargs) -> str:
prompt = json5.loads(params)['prompt']
return json5.dumps({'image_url': f'https://...'})
LlamaIndex:FunctionTool
from llama_index.core.tools import FunctionTool
def retrieve_documents(query: str) -> str:
"""从文档中检索相关信息"""
response = query_engine.query(query)
return str(response)
retrieve_tool = FunctionTool.from_defaults(fn=retrieve_documents)
小结:框架会将 Python 函数的 name、docstring(功能描述)和 type hints(参数类型)转换成 JSON Schema 喂给 LLM。LangChain 的 @tool 最符合 Python 原生直觉;Qwen-Agent 的 @register_tool 使用显式定义,强约束,适合复杂参数。
3. 记忆的存储:Context 管理机制
LLM 是无状态的,它记不住你说过什么,且 Context Window(上下文窗口)是昂贵的资源——Context 管理本质上是有限注意力的管理。
记忆系统分两层:
1)短期记忆(Window)
- 对话历史截断
- 滑动窗口策略
- 避免 Token 爆炸
2)长期记忆(RAG)
- VectorStoreIndex 向量索引
- 文档分块与 Embedding
- 相似度检索
LangChain 短期记忆(RunnableWithMessageHistory):
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
# 会话存储
store = {}
def get_session_history(session_id: str):
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
# 创建带记忆的对话链
conversation = RunnableWithMessageHistory(
chain,
get_session_history,
input_messages_key="input",
history_messages_key="history"
)
# 使用时指定 session_id
config = {"configurable": {"session_id": "user_123"}}
output = conversation.invoke({"input": "Hi!"}, config=config)
要点:session_id 机制支持多用户并发会话;MessagesPlaceholder 自动注入历史到 Prompt。
Qwen-Agent 短期记忆(messages 列表):
messages = [] # 对话历史
messages.append({'role': 'user', 'content': query})
for response in bot.run(messages=messages):
pass
messages.extend(response) # 追加响应
LlamaIndex 长期记忆(VectorStoreIndex):
index = VectorStoreIndex.from_documents(documents)
# 持久化
index.storage_context.persist(persist_dir="./storage")
| 框架 | 短期记忆 | 长期记忆 |
|---|---|---|
| LangChain | RunnableWithMessageHistory + session_id | 需集成 VectorStore |
| Qwen-Agent | messages 列表手动管理 | files 参数加载文档 |
| LlamaIndex | Agent chat() 内置 | 专业级 VectorStoreIndex |
小结:短期记忆方面,Session ID 是多用户并发的基础,滑动窗口策略只保留最近 N 轮,防止 Token 爆炸;长期记忆则是 RAG 的范畴,利用向量数据库进行相关性检索,而非按时间顺序回忆。
4. 中枢的编排:控制流设计(Orchestration)
复杂的任务不能靠 LLM 一口气说完,需要拆解步骤。常见的编排模式:
| 模式 | 说明 | 适用场景 |
|---|---|---|
| 管道模式(Pipeline) | LangChain 的 prompt | llm | parser 链式调用 |
线性处理流程 |
| 循环模式(Loop) | ReAct 循环:思考 → 行动 → 观察 | Agent 完成任务 |
| 单人模式 | 经典单 Agent | 单一任务 |
| 多人模式(DAG) | 接力赛:明确的执行顺序 | 流程化任务(如投资决策) |
| 多人模式(Chat) | 圆桌会议:自由讨论 | 开放式协作 |
LangChain 管道式编排(LCEL)
LCEL(LangChain Expression Language)使用 | 管道符连接组件:
from langchain_core.prompts import PromptTemplate
prompt = PromptTemplate(
input_variables=["product"],
template="What is a good name for a company that makes {product}?",
)
# 使用管道符组合
chain = prompt | llm
# invoke 调用
result = chain.invoke({"product": "colorful socks"})
LCEL 特点:
- 管道符:直观的链式调用,类似 Unix 管道
- invoke():统一的调用接口
- 支持流式输出、批处理、异步调用
- 管道模式:Prompt => LLM => Parser
ReAct 循环(Agent 模式)
from langchain.agents import create_agent
# 定义工具
tools = [ping_tool, dns_tool, calculator]
# 创建 Agent (LangChain 1.x 新写法)
agent = create_agent(llm, tools)
# 使用 messages 格式调用
result = agent.invoke({"messages": [("user", "检查 www.example.com 的连通性")]})
print(result["messages"][-1].content)
ReAct 的执行循环:Thought(思考)=> Action(行动)=> Observation(观察)=> Thought(思考)=> …,直到任务完成。
小结:
- Chain(链式):输入确定、输出确定,像工厂流水线(Pipeline)
- Loop(循环):即 ReAct 模式(思考-行动-观察-思考),像一个不断试错的实验员,直到任务完成
- DAG(有向无环图):像多人接力赛,有明确的前后依赖关系
二、LangChain:全能型 LLM 应用框架
定位:全能型 LLM 应用框架,丰富的生态和组件,适合各种复杂场景。
GitHub:github.com/langchain-ai/langchain
核心特性:LCEL 管道语法
LCEL 是 LangChain 1.x 的核心创新,使用 | 管道符连接组件。LangChain 采用组件化方式,核心优势是把 Prompt、Model、Memory、Retriever 都做成了标准积木(Runnable)。
from langchain_core.prompts import PromptTemplate
from langchain_community.llms import Tongyi
# 加载模型
llm = Tongyi(model_name="qwen-turbo", dashscope_api_key=api_key)
# 创建 Prompt Template
prompt = PromptTemplate(
input_variables=["product"],
template="What is a good name for a company that makes {product}?",
)
# 管道语法组合
chain = prompt | llm
# invoke 调用
result = chain.invoke({"product": "colorful socks"})
print(result)
工具注册:@tool 装饰器
LangChain 的 @tool 装饰器是最简洁的工具注册方式,自动从 docstring 解析工具描述:
from langchain_core.tools import tool
@tool
def ping_tool(target: str) -> str:
"""检查本机到指定主机名或IP地址的网络连通性。
参数:
target: 目标主机名或IP地址
返回:
模拟的ping结果
"""
if "unreachable" in target:
return f"Ping {target} 失败:请求超时。"
return f"Ping {target} 成功:延迟 20ms。"
@tool
def dns_tool(hostname: str) -> str:
"""解析给定的主机名,获取其对应的IP地址。
参数:
hostname: 要解析的主机名
返回:
模拟的DNS解析结果
"""
if hostname == "www.example.com":
return f"DNS 解析 {hostname} 成功:IP 地址是 93.184.216.34"
return f"DNS 解析 {hostname} 失败:找不到主机。"
创建 Agent
from langchain.agents import create_agent
from langchain_community.chat_models import ChatTongyi
# 加载模型(使用 ChatModel 以支持 tool calling)
llm = ChatTongyi(model_name="deepseek-v3", dashscope_api_key=api_key)
# 定义工具列表
tools = [ping_tool, dns_tool, calculator]
# 创建 Agent (LangChain 1.x 新写法)
agent = create_agent(llm, tools)
# 使用 messages 格式调用
result = agent.invoke({
"messages": [("user", "我无法访问 www.example.com,帮我诊断一下")]
})
# 获取最终回复
print(result["messages"][-1].content)
带记忆的对话链
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
# 创建带历史记录的 prompt
prompt = ChatPromptTemplate.from_messages([
("system", "You are a helpful assistant."),
MessagesPlaceholder(variable_name="history"),
("human", "{input}")
])
# 创建 chain
chain = prompt | llm
# 会话存储
store = {}
def get_session_history(session_id: str):
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
# 创建带记忆的对话链
conversation = RunnableWithMessageHistory(
chain,
get_session_history,
input_messages_key="input",
history_messages_key="history"
)
# 使用时指定 session_id
config = {"configurable": {"session_id": "user_123"}}
output = conversation.invoke({"input": "Hi there!"}, config=config)
print(output.content)
LangChain 小结
核心优势:
- 生态丰富:支持 100+ 模型、50+ 向量数据库、大量预置工具
- LCEL 管道语法:直观的链式调用,支持流式/批处理/异步
@tool装饰器:最简洁的工具注册方式- 完善的记忆管理:session_id 机制支持多用户并发
适用场景:
| 场景 | 说明 |
|---|---|
| 工具调用型 Agent | 网络诊断、数据查询、API 调用等需要多工具协作的场景 |
| 多轮对话系统 | 客服机器人、智能助手等需要记忆上下文的场景 |
| 复杂流程编排 | 使用 LCEL 构建多步骤处理流程 |
| 快速原型开发 | 丰富的组件库,快速搭建 POC |
三、LlamaIndex:数据驱动的 RAG 专家
定位:为 LLM 装上私有数据的最强接口。如果不涉及复杂的多人协作,只是想基于文档问答,它是首选。
GitHub:github.com/run-llama/llama_index
核心概念:Index 优先
Index-First 哲学:不同于 LangChain 关注流程,LlamaIndex 关注数据结构。它认为 LLM 应用的核心瓶颈在于如何让 LLM 索引私有数据。
加载文档并创建索引:
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
# 读取文档目录
reader = SimpleDirectoryReader('./docs')
documents = reader.load_data()
print(f"加载了 {len(documents)} 个文档")
# 创建向量索引
index = VectorStoreIndex.from_documents(documents)
# 持久化索引(避免重复创建)
index.storage_context.persist(persist_dir="./storage")
从存储加载索引:
from llama_index.core import StorageContext, load_index_from_storage
# 检查索引是否已存在
persist_dir = "./storage"
if os.path.exists(persist_dir):
# 从存储中加载索引(快速启动)
storage_context = StorageContext.from_defaults(persist_dir=persist_dir)
index = load_index_from_storage(storage_context)
print("从存储加载索引成功")
else:
# 创建新索引
index = VectorStoreIndex.from_documents(documents)
ReAct Agent 与工具集成
将 retrieve_tool 作为一个函数插拔到 Agent 上:
from llama_index.core.agent import ReActAgent
from llama_index.core.tools import FunctionTool
# 创建查询引擎
query_engine = index.as_query_engine(similarity_top_k=5)
# 定义检索工具
def retrieve_documents(query: str) -> str:
"""从文档中检索相关信息"""
response = query_engine.query(query)
return str(response)
# 封装为 FunctionTool
retrieve_tool = FunctionTool.from_defaults(fn=retrieve_documents)
# 创建 ReAct Agent
agent = ReActAgent.from_tools(
tools=[retrieve_tool],
llm=llm,
verbose=True, # 显示思考过程
system_prompt="你是一个乐于助人的AI助手,可以从文档中检索信息",
)
完整 RAG 问答流程
from llama_index.llms.dashscope import DashScope
from llama_index.embeddings.dashscope import DashScopeEmbedding
from llama_index.core import Settings
# 配置 LLM 和 Embedding
llm = DashScope(model="deepseek-v3", api_key=api_key)
embed_model = DashScopeEmbedding(model_name="text-embedding-v2", api_key=api_key)
Settings.llm = llm
Settings.embed_model = embed_model
# 加载/创建索引
index = load_documents_and_create_index('./docs')
# 创建 Agent 和检索器
agent, retriever = create_agent(index, llm)
# 查询
query = "介绍下雇主责任险"
# 先展示召回的文档内容
retrieved_nodes = retriever.retrieve(query)
for i, node in enumerate(retrieved_nodes):
print(f"文档片段 {i+1}: {node.text[:200]}...")
print(f"相似度分数: {node.score}")
# 使用 Agent 回答
response = agent.chat(query)
print(response)
LlamaIndex 小结
核心优势:
- 一站式文档处理:加载、分块、向量化、索引、检索
- 索引持久化:避免重复创建,快速启动
- 多种检索策略:向量检索、关键词检索、混合检索
- 与 Agent 无缝集成:FunctionTool 封装查询引擎
适用场景:
| 场景 | 说明 |
|---|---|
| 企业知识库 | 内部文档、FAQ、操作手册的智能问答 |
| 合同审查助手 | 基于合同文档的条款检索与解读 |
| 学术论文分析 | 论文摘要、引用关系、知识图谱构建 |
| 客服机器人 | 产品手册、服务政策的实时检索回答 |
四、Qwen-Agent:轻量级的全能选手
定位:阿里生态亲儿子,对 Tool Use 和 Code Interpreter 支持好;轻量、灵活,适合快速构建工具调用型 Agent。
GitHub:github.com/QwenLM/Qwen-Agent
核心概念
指令跟随优化:Qwen-Agent 是专门为 Qwen 模型(及其强大的 Tool Calling 能力)定制的。它不如 LangChain 抽象,但跑得快。
Code Interpreter(沙箱):这是它的杀手锏。不同于其他框架只调用外部 API,Qwen-Agent 内置了代码执行沙箱,允许 LLM 自己写 Python 代码来画图、做数据分析,自我修正错误。
适合什么场景? 想要快速搭建工具调用型或数据分析型 Agent,且不想处理复杂抽象层的开发者。利用 Qwen-Agent 的长文本优势是强项。
装饰器模式注册工具
import json5
import urllib.parse
from qwen_agent.tools.base import BaseTool, register_tool
@register_tool('my_image_gen')
class MyImageGen(BaseTool):
# description 告诉 LLM 这个工具的功能
description = 'AI 绘画服务,输入文本描述,返回图像 URL'
# parameters 定义输入参数
parameters = [{
'name': 'prompt',
'type': 'string',
'description': '期望的图像内容的详细描述',
'required': True
}]
def call(self, params: str, **kwargs) -> str:
# params 是 LLM 生成的 JSON 字符串
prompt = json5.loads(params)['prompt']
prompt = urllib.parse.quote(prompt)
return json5.dumps({
'image_url': f'https://image.pollinations.ai/prompt/{prompt}'
}, ensure_ascii=False)
装饰器模式优势:
@register_tool('name')一行代码完成注册description自动生成工具描述供 LLM 理解parameters定义参数约束,LLM 自动解析
Code Interpreter:沙箱代码执行
Qwen-Agent 内置 code_interpreter 工具,可以在沙箱环境中执行 Python 代码:
# 配置工具列表
tools = ['my_image_gen', 'code_interpreter']
# code_interpreter 是框架自带工具,可以:
# - 下载文件 (requests.get)
# - 处理图像 (PIL)
# - 数据分析 (pandas)
# - 绘图展示 (matplotlib)
system_instruction = '''你是一个乐于助人的AI助手。
在收到用户的请求后,你应该:
- 首先绘制一幅图像,得到图像的url,
- 然后运行代码 requests.get 以下载该图像,
- 最后从给定的文档中选择一个图像操作进行图像处理。
用 plt.show() 展示图像。'''
Code Interpreter 能力:
| 能力 | 说明 |
|---|---|
| 代码生成 | LLM 自动生成 Python 代码 |
| 沙箱执行 | 安全隔离环境运行代码 |
| 结果获取 | 捕获输出、图像、文件 |
| 错误修复 | 执行失败时自动修正重试 |
文件处理与多文档支持
import os
from qwen_agent.agents import Assistant
# 获取文件夹下所有文件
file_dir = os.path.join('./', 'docs')
files = []
if os.path.exists(file_dir):
for file in os.listdir(file_dir):
file_path = os.path.join(file_dir, file)
if os.path.isfile(file_path):
files.append(file_path)
print('files=', files)
# 创建 Assistant,传入文件列表
bot = Assistant(
llm=llm_cfg,
system_message=system_instruction,
function_list=tools,
files=files # 文档文件列表
)
流式输出对话
# 对话历史
messages = []
# 用户查询
query = "介绍下雇主责任险"
messages.append({'role': 'user', 'content': query})
# 流式输出
current_index = 0
for response in bot.run(messages=messages):
# 获取增量内容
current_response = response[0]['content'][current_index:]
current_index = len(response[0]['content'])
print(current_response, end='')
# 添加到对话历史,支持多轮对话
messages.extend(response)
Qwen-Agent 小结
适用场景:
| 场景 | 说明 |
|---|---|
| 数据分析 | 需要运行代码、绘图、生成报表 |
| 复杂工具调用链 | 多个工具协同完成任务 |
| 图像处理 | 生成、编辑、分析图像 |
| 文档问答 | 结合 Qwen 模型的长 Context 优势 |
五、四大框架对比与选型建议
框架对比总表
| 维度 | LangChain | Qwen-Agent | LlamaIndex | AutoGen |
|---|---|---|---|---|
| 核心定位 | 全能型框架 | 轻量工具调用 | RAG 数据接口 | 多 Agent 协作 |
| 工具注册 | @tool 装饰器 |
@register_tool 装饰器 |
FunctionTool 类 |
@register 装饰器 |
| RAG 支持 | 需集成 VectorStore | 基础文件读取 | 专业级向量索引 | 需自行集成 |
| 多 Agent | LangGraph 支持 | 基础支持 | 需自行编排 | 原生 GroupChat |
| 代码执行 | 需集成 | 内置 code_interpreter | 需集成 | UserProxyAgent |
| 记忆管理 | RunnableWithMessageHistory | messages 列表 | Agent chat() | GroupChat 自动 |
| 学习曲线 | 中等 | 简单 | 中等 | 中等 |
| 生态完整度 | 最丰富 | 阿里生态 | RAG 社区 | 微软生态 |
从业务场景出发的选型建议
- 选 LangChain:如果你要开发通用的 AI 应用,需要灵活控制流程,或者需要切换多种模型。
- 选 LlamaIndex:如果你主要做 RAG(企业知识库),手里有一堆 PDF/Word/Excel 要处理。
- 选 Qwen-Agent:如果你主要用 Qwen 模型,需要做数据分析(Code Interpreter)或处理超长文档(1M Context)。
- 选 AutoGen:如果任务太复杂,一个人(Agent)干不完,需要团队(多角色)讨论/协作才能出结果。
六、实战案例:多文件智能问答 Agent
需求:搭建一个保险产品智能问答 Agent,帮助用户快速了解各类保险产品的详细信息。已加载多个保险产品文档,包括:雇主责任险、平安商业综合责任保险、企业团体综合意外险、财产一切险、施工保、装修保等。用户通过自然语言提问,系统从文档中检索相关信息并给出回答。
技术方案:RAG(检索增强生成)
RAG 的核心流程:用户问题 → 向量检索 → 召回相关文档 → LLM 生成回答
为什么需要 RAG?
- LLM 没有私有数据的知识
- 避免模型幻觉(编造信息)
- 回答可追溯到具体文档来源
下面分别用三个框架实现同一个需求。
6.1 LangChain 实现
特点:LCEL 管道语法、丰富生态(多种文档加载器、向量数据库)、灵活组合。
LLM 配置:
from langchain_community.chat_models import ChatTongyi
llm = ChatTongyi(
model_name="deepseek-v3",
dashscope_api_key=DASHSCOPE_API_KEY
)
文档加载与索引:
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain_community.vectorstores import FAISS
# 加载目录下所有 txt 文件
loader = DirectoryLoader(
file_dir,
glob="/*.txt",
loader_cls=TextLoader,
loader_kwargs={"encoding": "utf-8"}
)
documents = loader.load()
# 创建向量索引
vector_store = FAISS.from_documents(chunks, embeddings)
问答链(LCEL 语法):
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
qa_prompt = ChatPromptTemplate.from_messages([
("system", "根据上下文回答问题...\n{context}"),
("human", "{question}")
])
# 管道语法
qa_chain = qa_prompt | llm | StrOutputParser()
# 调用
response = qa_chain.invoke({"context": context, "question": query})
完整代码见 langchain-agent-multi-files.py。
6.2 LlamaIndex 实现
特点:Index 优先(专注于数据索引和检索)、一站式 RAG(文档加载、分块、索引、检索一体化)、内置 ReAct Agent。
LLM 和 Embedding 配置:
from llama_index.llms.dashscope import DashScope
from llama_index.embeddings.dashscope import DashScopeEmbedding
from llama_index.core import Settings
llm = DashScope(model="deepseek-v3", api_key=api_key)
embed_model = DashScopeEmbedding(model_name="text-embedding-v2", api_key=api_key)
# 全局设置
Settings.llm = llm
Settings.embed_model = embed_model
文档加载与索引:
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
# 一行代码加载整个目录
reader = SimpleDirectoryReader(file_dir)
documents = reader.load_data()
# 创建向量索引
index = VectorStoreIndex.from_documents(documents)
# 持久化
index.storage_context.persist(persist_dir="./storage")
创建 Agent:
from llama_index.core.agent import ReActAgent
from llama_index.core.tools import FunctionTool
# 创建检索工具
def retrieve_documents(query: str) -> str:
response = query_engine.query(query)
return str(response)
retrieve_tool = FunctionTool.from_defaults(fn=retrieve_documents)
# 创建 ReAct Agent
agent = ReActAgent.from_tools(
tools=[retrieve_tool],
llm=llm,
verbose=True
)
# 对话
response = agent.chat(query)
完整代码见 llamaindex-agent-multi-files.py。
6.3 Qwen-Agent 实现
特点:开箱即用、内置 WebUI(一行代码启动 Web 界面)、内置 Code Interpreter、files 参数直接传入文件列表。
LLM 配置:
llm_cfg = {
'model': 'deepseek-v3',
'model_server': 'https://dashscope.aliyuncs.com/compatible-mode/v1',
'api_key': os.getenv('DASHSCOPE_API_KEY'),
'generate_cfg': {'top_p': 0.8}
}
自定义工具(@register_tool):
from qwen_agent.tools.base import BaseTool, register_tool
@register_tool('my_image_gen')
class MyImageGen(BaseTool):
description = 'AI 绘画服务'
parameters = [{
'name': 'prompt',
'type': 'string',
'description': '图像描述',
'required': True
}]
def call(self, params: str, **kwargs) -> str:
prompt = json5.loads(params)['prompt']
return json5.dumps({'image_url': f'https://...'})
创建 Assistant(files 参数直接传入文档):
from qwen_agent.agents import Assistant
# 获取文档文件列表
files = get_doc_files()
# 创建 Assistant
bot = Assistant(
llm=llm_cfg,
system_message=system_instruction,
function_list=['my_image_gen', 'code_interpreter'],
files=files # 直接传入文件列表
)
启动 WebUI:
from qwen_agent.gui import WebUI
WebUI(bot, chatbot_config=chatbot_config).run()
完整代码见 qwen-agent-multi-files.py。
6.4 三种实现对比
| 维度 | LangChain | LlamaIndex | Qwen-Agent |
|---|---|---|---|
| 定位 | 全能型框架 | RAG 专家 | 轻量级 Agent |
| 文档加载 | DirectoryLoader | SimpleDirectoryReader | files 参数 |
| 向量存储 | FAISS/Chroma 等 | VectorStoreIndex | 内置 |
| 问答方式 | LCEL 管道 | ReActAgent | bot.run() |
| 索引持久化 | save_local() | persist() | 无 |
| Web UI | 需集成 Gradio | 需集成 | 内置 WebUI |
| 代码执行 | 需集成 | 需集成 | 内置 code_interpreter |
动手练习:基于你的业务场景,搭建一个多文件智能问答 Agent(例如针对保险知识进行问答),可以任选 LangChain / LlamaIndex / Qwen-Agent 其中之一实现。
七、AutoGen:多智能体框架
AutoGen 是微软开源的多智能体对话框架,用于构建多个 AI Agent 协作完成复杂任务。它的核心理念是让 Agent 之间通过自然语言对话来协作,而非硬编码的函数调用。
GitHub:github.com/microsoft/autogen,也可以使用 Agent Framework(github.com/microsoft/agent-framework)。
注意:2025 年 10 月起,微软将 AutoGen 置为维护模式——仅修漏洞,不再新增功能;所有新特性都做到 Agent Framework 上。官方文档明确把 Agent Framework 称为下一代 Semantic Kernel 与 AutoGen,鼓励新项目直接迁移。
Agent 定义
Agent 是 AutoGen 的基本单元,每个 Agent 具备以下属性:
| 属性 | 说明 |
|---|---|
| name | Agent 的名称标识,在对话中用于区分发言者 |
| system_message | 角色设定/提示词,定义 Agent 的职责和行为方式 |
| llm_config | LLM 配置,包括模型、API Key、温度等参数 |
| tools | 可调用的外部工具函数,扩展 Agent 能力 |
投资委员会项目中的 Analyst Agent:
from autogen import ConversableAgent
agent = ConversableAgent(
name="AnalystAgent", # 名称标识
system_message="""你是投资委员会的分析师 … """,
llm_config={ # LLM 配置
"config_list": [{
"model": "gemini-2.5-flash",
"api_key": "your_api_key",
"api_type": "google"
}]
},
human_input_mode="NEVER", # 不需要人工输入
)
常用 Agent 类型:
| 类型 | 用途 | 特点 |
|---|---|---|
| ConversableAgent | 基础对话 Agent | 最灵活,可完全自定义 |
| AssistantAgent | 助手 Agent | 默认由 LLM 驱动,适合生成内容 |
| UserProxyAgent | 用户代理 | 可执行代码、调用工具、请求人工输入 |
项目中使用 ConversableAgent 创建了 4 个角色,区别在于是否注册工具函数:
# data_agent - 带工具的 Agent
agent = ConversableAgent(name="DataAgent", ...)
@agent.register_for_llm(description="获取股票的行情、估值、财务等综合数据")
@agent.register_for_execution()
def fetch_stock_data(query: str) -> str:
return get_stock_data(query)
# analyst_agent - 不带工具的 Agent
agent = ConversableAgent(name="AnalystAgent", ...)
# 无需注册工具,只靠 system_message 引导 LLM 输出分析结论
GroupChat(群聊)
GroupChat 是将多个 Agent 放在同一个对话中协作的容器:
from autogen import GroupChat, GroupChatManager
# 创建群聊,设定发言顺序
group_chat = GroupChat(
agents=[
data_agent, # 1. 数据员先获取数据
analyst_agent, # 2. 分析师进行分析
risk_agent, # 3. 风控官评估风险
trader_agent # 4. 交易员给出建议
],
messages=[],
max_round=8, # 4个Agent各发言1-2次
speaker_selection_method="round_robin", # 按顺序轮流发言
)
# 创建群聊管理器
manager = GroupChatManager(
groupchat=group_chat,
llm_config=data_agent.llm_config,
)
# 发起对话
result = data_agent.initiate_chat(
manager,
message="用户查询: 分析一下宁德时代能不能买",
)
对话流程:
- 用户发起查询
- GroupChatManager 根据策略选择第一个发言的 Agent
- 被选中的 Agent 生成回复(可能调用工具)
- 回复加入对话历史,所有 Agent 可见
- GroupChatManager 选择下一个发言者
- 重复 3-5,直到达到 max_round 或满足终止条件
发言者选择策略:
| 策略 | 说明 | 适用场景 |
|---|---|---|
| round_robin | 按 agents 列表顺序轮流发言 | 流程明确的任务(如:数据→分析→风控→决策) |
| random | 随机选择下一个发言者 | 头脑风暴、创意讨论 |
| auto | 由 LLM 判断谁最适合回答当前问题 | 开放式讨论、问答场景 |
| 自定义函数 | 完全控制选择逻辑 | 复杂业务流程、条件分支 |
经验法则:如果任务有明确的执行顺序,用 round_robin;如果需要灵活讨论,用 auto。投资委员会使用 round_robin,正是因为投资决策有固定流程:先获取数据 → 再分析 → 再风控 → 最后决策。
八、场景化选型总结
| 场景 | 推荐框架 | 理由 |
|---|---|---|
| 场景 1:企业知识库问答 | LlamaIndex | 专业的文档处理能力;多种检索策略(向量、关键词、混合);索引持久化,支持增量更新 |
| 场景 2:快速 Demo / POC | Qwen-Agent | 配置最简单;内置 WebUI,无需前端开发;开箱即用的工具(code_interpreter) |
| 场景 3:复杂业务流程 | LangChain | LCEL 支持灵活的流程编排;丰富的组件生态;可与其他框架组合使用 |
| 场景 4:多人协作 | AutoGen | 多智能体协同对话;支持角色自定义与任务分工;内置群聊管理与执行控制 |
结语
Agent 框架没有银弹,核心是理解每个框架的设计哲学:LangChain 胜在生态与流程编排,LlamaIndex 专注数据索引与 RAG,Qwen-Agent 轻量且自带代码沙箱,AutoGen 则把多智能体协作做到极致。建议先用 Qwen-Agent 快速验证想法跑通 POC,再根据业务复杂度(知识库量级、流程复杂度、协作角色数)决定是否引入 LlamaIndex、LangChain 或 AutoGen。框架是工具,业务场景才是选型的第一性原理。

浙公网安备 33010602011771号