经过前五章对 AI Agent 核心概念、架构、执行逻辑、高级工具以及智能策略的深入探讨,我们已经打下了坚实的理论基础。现在,是时候将理论付诸实践,进入激动人心的框架实战环节了!理论是灯塔,而框架则是我们航向目标的船只。本章,我们将聚焦于当前 Python 生态中最主流、应用最广泛的两大 Agent 开发框架:LangChain 和 LlamaIndex。我们将学习如何利用这两个强大的框架,快速构建、配置和运行我们自己的 AI Agent,并通过具体的代码示例理解它们各自的设计哲学与核心优势。掌握它们,是你将 Agent 应用从想法变为现实的关键一步。
LangChain 以其灵活性、高度模块化和广泛的集成能力而闻名。它提供了一套丰富的组件和工具链,让开发者可以像搭积木一样自由地构建复杂的 LLM 应用,其中 Agent 是其核心功能之一。
核心 API 与概念详解:
在使用 LangChain 构建 Agent 时,你会经常遇到以下核心组件:
Tool
: 这是对 Agent 可用功能的抽象封装(对应第四章的工具概念)。你需要为 Agent 定义一系列工具,每个工具包含名称、描述(供 LLM 理解何时使用)、以及具体的执行函数。Memory
: 用于让 Agent 维持状态和记忆(对应第二章的记忆模块)。LangChain 提供了多种 Memory 类型,如 ConversationBufferMemory
等。PromptTemplate
/ChatPromptTemplate
: 用于精确控制发送给 LLM 的指令,指导 Agent 如何思考、使用工具和格式化输出。LLM
/ChatModel
: Agent 的核心大脑,如 OpenAI GPT-4, Anthropic Claude 等。AgentExecutor
: LangChain Agent 的核心执行器,负责驱动 Agent 的运行逻辑(例如执行第三章讨论的 ReAct 循环)。initialize_agent
: 快速初始化 AgentExecutor
的便捷函数(较旧的 API,现在更推荐使用 LCEL 或 create_react_agent
等方式)。Agent 类型概览:
LangChain 提供了一些预置的 Agent 类型,如 zero-shot-react-description
, conversational-react-description
等,方便快速启动。
定制 Agent 实践:
常见的定制包括修改 Prompt、添加自定义工具、自定义输出解析,以及集成图数据库工具(如将 Cypher 查询封装为 Tool)。
实战代码演练:构建一个简单的 LangChain ReAct Agent
目标/场景: 下面的代码将演示如何使用 LangChain 构建一个简单的 ReAct Agent。这个 Agent 会拥有一个计算数字平方的工具,并能调用它来回答问题。
前提条件:
pip install langchain langchain-openai
OPENAI_API_KEY
。关键代码示例:
import os
from langchain_openai import ChatOpenAI
from langchain.agents import tool, AgentExecutor, create_react_agent
from langchain_core.prompts import PromptTemplate # 或者 ChatPromptTemplate
from langchain import hub # 用于获取预置的 ReAct prompt
# --- 前提:设置 OpenAI API Key ---
# 确保你的 OpenAI API Key 已经设置在环境变量中
# os.environ["OPENAI_API_KEY"] = "sk-..."
# 如果没有设置,后续创建 LLM 时会报错
# --- 1. 定义工具 ---
@tool
def get_square(number: float) -> float:
"""当需要计算一个数字的平方时,使用此工具。输入一个数字,返回它的平方值。"""
print(f"\n*** 调用 get_square 工具,输入: {number} ***\n")
return number ** 2
tools = [get_square]
# --- 2. 选择 LLM ---
# 使用 OpenAI 的 GPT-3.5 Turbo 模型
# temperature=0 表示我们希望得到更确定性的输出
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# --- 3. 获取 ReAct Prompt 模板 ---
# 从 LangChain Hub 拉取一个预置的 ReAct prompt,它定义了 Agent 的思考和行动格式
# 这是 LangChain 推荐的方式之一,简化了 Prompt 工程
prompt = hub.pull("hwchase17/react")
# 你可以通过 print(prompt.template) 查看模板内容
# --- 4. 创建 Agent 核心逻辑 ---
# create_react_agent 函数将 LLM、工具列表和 Prompt 模板组合起来
# 它定义了 Agent 如何根据输入和工具描述来决定下一步行动
agent = create_react_agent(llm, tools, prompt)
# --- 5. 创建 Agent 执行器 ---
# AgentExecutor 负责实际运行 ReAct 循环:
# 调用 Agent 获取下一步行动 -> 执行行动(调用工具)-> 获取结果 -> 重复
# verbose=True 会打印出 Agent 的完整思考过程(Thought, Action, Observation)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, handle_parsing_errors=True)
# handle_parsing_errors=True 可以帮助处理 LLM 输出格式偶尔不规范的问题
# --- 6. 运行 Agent ---
print("\n--- 运行 Agent ---")
try:
response = agent_executor.invoke({
"input": "计算 5 的平方是多少?"
})
print("\n--- Agent 执行完毕 ---")
print("最终答案:")
print(response['output'])
except Exception as e:
print(f"Agent 执行出错: {e}")
# 思考:如果问 "法国的首都是哪里?" Agent 会怎么做?(它没有相关工具)
# 尝试运行: agent_executor.invoke({"input": "法国的首都是哪里?"})
代码解释:
get_square
工具,注意其 docstring 对 Agent 理解工具功能至关重要。gpt-3.5-turbo
作为 LLM。create_react_agent
创建了 Agent 的核心逻辑。AgentExecutor
来运行 Agent,并设置 verbose=True
以观察其内部思考过程。invoke
方法传入问题来运行 Agent。观察重点: 运行代码时,仔细观察 verbose=True
打印出的 Thought:
, Action:
, Observation:
序列。你会看到 Agent 如何分析问题,决定需要计算平方,选择 get_square
工具,指定输入参数,然后根据工具返回的 Observation
(计算结果)得出最终答案。尝试问一个它没有工具能回答的问题,观察它的反应。
LlamaIndex 最初以其在数据索引和检索增强生成 (RAG) 方面的强大能力而闻名。它的 Agent 构建思路也深受其数据处理核心的影响,呈现出以数据为中心的特色。
核心概念与设计哲学:
AgentRunner
/ ReActAgent
等: LlamaIndex 提供了类似 LangChain AgentExecutor
的执行器类。知识图谱集成(重点):
LlamaIndex 对知识图谱提供了优秀的原生支持:
KnowledgeGraphIndex
从文档中自动构建知识图谱(提取实体和关系)。实战代码演练:构建一个使用 KG 索引工具的 LlamaIndex Agent
目标/场景: 下面的代码将演示如何使用 LlamaIndex 构建一个简单的知识图谱索引,并将其作为工具提供给一个 ReAct Agent,用于回答基于图谱知识的问题。
前提条件:
pip install llama-index llama-index-llms-openai
OPENAI_API_KEY
。关键代码示例:
import os
from llama_index.core import SimpleDirectoryReader, KnowledgeGraphIndex, Settings
from llama_index.core.graph_stores import SimpleGraphStore # 使用内存中的简单图存储
from llama_index.core.storage.storage_context import StorageContext
from llama_index.llms.openai import OpenAI # 使用 OpenAI LLM
from llama_index.embeddings.openai import OpenAIEmbedding # 使用 OpenAI Embedding
from llama_index.core.agent import ReActAgent
from llama_index.core.tools import QueryEngineTool, ToolMetadata
# --- 前提:设置 OpenAI API Key ---
# os.environ["OPENAI_API_KEY"] = "sk-..."
# --- 1. 配置 LLM 和 Embedding ---
# LlamaIndex 使用 Settings 来全局配置 LLM 和 Embedding
Settings.llm = OpenAI(model="gpt-3.5-turbo")
Settings.embed_model = OpenAIEmbedding(model="text-embedding-ada-002")
# --- 2. 准备简单数据 ---
# 为了演示,我们创建一些简单的文本数据,LlamaIndex 将从中提取实体关系
# 实际应用中可以使用 SimpleDirectoryReader 读取文件
from llama_index.core import Document
documents = [
Document(text="张三是北京智科公司的软件工程师。"),
Document(text="李四是北京智科公司的项目经理,他认识张三。"),
Document(text="北京智科公司位于中关村软件园。")
]
print("\n--- 准备演示数据 ---")
for doc in documents:
print(doc.text)
# --- 3. 构建知识图谱索引 ---
# 使用内存存储 (SimpleGraphStore)
graph_store = SimpleGraphStore()
storage_context = StorageContext.from_defaults(graph_store=graph_store)
print("\n--- 开始构建知识图谱索引 (可能需要一点时间) ---")
# 从文档中构建 KG 索引,max_triplets_per_chunk 控制提取三元组的数量
# include_embeddings=True 允许后续进行混合查询(如果需要)
index = KnowledgeGraphIndex.from_documents(
documents,
max_triplets_per_chunk=5,
storage_context=storage_context,
include_embeddings=True,
)
print("--- 知识图谱索引构建完成 ---")
# --- 4. 创建 KG 查询引擎并封装为工具 ---
# 将 KG 索引转换为查询引擎
kg_query_engine = index.as_query_engine(
include_text=False, # 通常 KG 查询我们更关心结构化结果
response_mode="tree_summarize" # 可以尝试不同的响应模式
)
# 创建 QueryEngineTool,让 Agent 可以使用这个 KG 查询引擎
kg_tool = QueryEngineTool(
query_engine=kg_query_engine,
metadata=ToolMetadata(
name="knowledge_graph_query",
description=(
"当需要查询人物、组织、地点之间的关系或属性时使用。"
"例如,查询某人的职位、某公司位于何处、某人认识谁等。"
"输入应该是针对这些实体和关系的自然语言问题。"
)
)
)
tools = [kg_tool]
print("\n--- KG 查询工具已创建 ---")
print(f"工具名称: {kg_tool.metadata.name}")
print(f"工具描述: {kg_tool.metadata.description}")
# --- 5. 创建 LlamaIndex ReAct Agent ---
# 使用配置好的 LLM 和 KG 工具创建 Agent
agent = ReActAgent.from_tools(tools=tools, llm=Settings.llm, verbose=True)
print("\n--- LlamaIndex ReAct Agent 已创建 ---")
# --- 6. 运行 Agent ---
print("\n--- 运行 Agent 查询 KG ---")
try:
# 提问需要利用图谱关系的问题
response = agent.chat("李四在北京智科公司的职位是什么?他在公司认识谁?")
# 也可以尝试: agent.chat("北京智科公司在哪里?")
print("\n--- Agent 执行完毕 ---")
print("最终答案:")
print(str(response)) # Agent 的响应通常是 Response 对象,转为字符串打印
# 对比直接查询 KG 索引 (如果需要)
# direct_response = kg_query_engine.query("李四在北京智科公司的职位是什么?他在公司认识谁?")
# print("\n直接查询 KG 引擎结果:")
# print(str(direct_response))
except Exception as e:
print(f"Agent 执行出错: {e}")
代码解释:
Document
对象作为数据源。KnowledgeGraphIndex.from_documents
从这些文档中自动提取三元组,构建了一个内存中的知识图谱索引。QueryEngine
,它封装了查询图谱的能力。QueryEngineTool
将这个查询引擎包装成 Agent 可用的工具,并提供了清晰的描述。ReActAgent
,并将 KG 工具传递给它。agent.chat()
方法向 Agent 提问,问题需要利用我们构建的 KG 中的关系才能回答。观察重点: 运行代码时,注意观察 verbose=True
输出的 ReAct 过程。看看 Agent 是如何理解问题,判断需要使用 knowledge_graph_query
工具,构造内部查询(可能是自然语言,由 Query Engine 转译),获取 KG 返回的信息,并最终整合出答案的。可以尝试不同的问题,测试 Agent 利用 KG 工具的能力。思考 Agent 查询与直接查询 KG 引擎结果的异同。
LangChain 和 LlamaIndex 都是非常优秀的框架,各有千秋。选择哪个(或者如何结合使用)取决于你的具体需求:
对比维度:
选型建议:
总结
在本章中,我们通过具体的代码示例,动手实践了如何使用两大主流框架——LangChain 和 LlamaIndex 来构建 AI Agent。我们学习了它们的核心 API 与概念,体验了如何定义工具、配置 Agent 并观察其运行逻辑,特别是在 LlamaIndex 中实践了将知识图谱索引作为工具的强大功能。我们还比较了它们的设计哲学和选型考量。
掌握 LangChain 和 LlamaIndex 是 Agent 开发者的基本功。然而,Agent 的世界远不止于此。在下一章,我们将目光投向另外两个备受关注、各具特色的主流 Agent 框架:Microsoft 的 AutoGen 和 CrewAI,它们分别在多 Agent 协作和结构化流程定义方面展现出独特的魅力。让我们继续探索!