1. 入门教程(使用OpenAI) #
本教程将展示如何开始使用LlamaIndex构建智能代理。我们将从一个基础示例入手,随后演示如何添加RAG(检索增强生成)功能。
2. 设置您的OpenAI API密钥 #
LlamaIndex 使用 OpenAI 的 gpt-3.5-turbo 作为默认模型。确保通过将API密钥设置为环境变量,使其对您的代码可用:
# 在MacOS/Linux系统中设置OpenAI API密钥环境变量
# 请将XXXXX替换为您的实际API密钥
export OPENAI_API_KEY=XXXXX
# 在Windows系统中设置OpenAI API密钥环境变量
# 请将XXXXX替换为您的实际API密钥
set OPENAI_API_KEY=XXXXX💡 提示: 如果您使用的是OpenAI兼容的API,您可以使用
OpenAILikeLLM class。您可以在类似OpenAI的LLM集成与OpenAI类嵌入集成中找到更多信息。
3. 基础代理示例 #
让我们从一个简单的示例开始,使用一个能通过调用工具执行基本乘法的agent。创建一个名为 starter.py 的文件:
# 导入异步编程所需的模块
import asyncio
# 从llama_index.core.agent.workflow模块导入FunctionAgent类,用于创建基于函数的智能代理
from llama_index.core.agent.workflow import FunctionAgent
# 从llama_index.llms.openai模块导入OpenAI类,用于集成OpenAI语言模型
from llama_index.llms.openai import OpenAI
# 定义一个简单的计算器工具函数,接收两个浮点数参数,返回它们的乘积
def multiply(a: float, b: float) -> float:
"""用于计算两个数字的乘积。"""
return a * b
# 创建一个带有计算器工具的智能代理
# tools参数指定代理可用的工具列表,这里只包含multiply函数
# llm参数指定使用的语言模型,这里为OpenAI的gpt-4o-mini
# system_prompt参数定义代理的系统提示,描述其行为
agent = FunctionAgent(
tools=[multiply],
llm=OpenAI(model="gpt-4o-mini"),
system_prompt="你是一名乐于助人的助手,可以计算两个数字的乘积。",
)
# 定义主异步函数
async def main():
# 运行代理,向其提出一个中文数学问题
response = await agent.run("请帮我计算7乘以8等于多少?")
# 打印代理的回答
print(str(response))
# 程序入口点
# 如果直接运行此脚本,则执行main函数
if __name__ == "__main__":
asyncio.run(main())
这将输出类似以下内容:7乘以8等于56。
3.1 发生了什么? #
- 代理收到了一个问题:
What is 1234 * 4567? - 在底层实现中,这个问题连同工具的架构(名称、文档字符串及参数)被传递给了LLM
- 代理选择了
multiply工具并将参数写入该工具 - 代理从工具接收到结果,并将其插入到最终响应中
💡 提示: 如你所见,我们正在使用
asyncPython函数。许多LLM和模型支持异步调用,建议使用异步代码来提升应用程序性能。想深入了解异步代码和Python,我们推荐阅读关于异步与Python的简短章节。
4. 添加聊天历史记录 #
AgentWorkflow 还能够记住之前的消息。这部分内容包含在 Context 的 AgentWorkflow 中。
如果 Context 参数被传入时,代理将使用它来继续对话:
# 导入异步编程所需的模块
import asyncio
import os
# 从llama_index.core.agent.workflow模块导入FunctionAgent类,用于创建基于函数的智能代理
from llama_index.core.agent.workflow import FunctionAgent
# 从llama_index.core.workflow模块导入Context类,用于管理代理的对话上下文
from llama_index.core.workflow import Context
# 从llama_index.llms.openai模块导入OpenAI类,用于集成OpenAI语言模型
from llama_index.llms.openai import OpenAI
# 创建一个带有记忆功能的智能代理
# 只指定llm和system_prompt,不指定tools
agent = FunctionAgent(
llm=OpenAI(model="gpt-4o-mini"),
system_prompt="你是一名乐于助人的助手,可以记住用户信息并进行多轮对话。请始终友好、自然地与用户交流。",
)
# 定义主异步函数
async def main():
try:
# 打印智能代理对话演示标题
print("🤖 智能代理对话演示")
# 打印分隔线
print("=" * 50)
# 创建对话上下文对象,用于存储代理的对话历史
ctx = Context(agent)
# 第一轮对话:告诉代理我的名字
print("\n📝 第一轮对话:")
print("-" * 30)
# 运行代理,传入用户输入和上下文
response = await agent.run("我的名字是张三", ctx=ctx)
# 打印用户输入
print(f"👤 用户: 我的名字是张三")
# 打印代理回复
print(f"🤖 代理: {response}")
# 第二轮对话:询问代理我的名字
print("\n📝 第二轮对话:")
print("-" * 30)
# 运行代理,传入用户输入和上下文
response = await agent.run("你还记得我的名字吗?", ctx=ctx)
# 打印用户输入
print(f"👤 用户: 你还记得我的名字吗?")
# 打印代理回复
print(f"🤖 代理: {response}")
# 打印对话演示完成提示
print("\n✅ 对话演示完成!")
except Exception as e:
# 捕获异常并打印错误信息
print(f"❌ 运行出错: {e}")
print("请检查网络连接和API密钥设置")
# 程序入口点
# 如果直接运行此脚本,则执行main函数
if __name__ == "__main__":
asyncio.run(main())
5. 添加RAG功能 #
现在我们可以使用LlamaIndex创建一个文档搜索工具。默认情况下,我们的 VectorStoreIndex 将使用一个 text-embedding-ada-002 使用OpenAI的embeddings来嵌入和检索文本。
我们修改过的 starter.py 应该看起来像这样:
# 导入异步编程所需的模块
import asyncio # 用于支持异步操作
# 导入LlamaIndex的核心组件
# FunctionAgent: 用于创建基于函数的智能代理
# OpenAI: OpenAI语言模型的集成
from llama_index.core.agent.workflow import FunctionAgent # 导入函数型智能代理
from llama_index.llms.openai import OpenAI # 导入OpenAI语言模型
from llama_index.core import (
VectorStoreIndex,
SimpleDirectoryReader,
) # 导入向量索引和目录读取器
# 加载data目录下的所有文档
documents = SimpleDirectoryReader("data").load_data() # 读取data文件夹中的文档
# 基于加载的文档创建向量存储索引
index = VectorStoreIndex.from_documents(documents) # 创建向量索引
# 从索引创建查询引擎
query_engine = index.as_query_engine() # 创建查询引擎
# 定义一个简单的计算器工具函数
# 该函数接收两个浮点数参数,返回它们的乘积
def multiply(a: float, b: float) -> float:
"""用于计算两个数字的乘积。"""
return a * b # 返回a和b的乘积
# 定义文档搜索工具函数
# 这是一个异步函数,用于根据问题搜索文档并返回答案
async def search_documents(query: str) -> str:
"""用于根据自然语言问题检索文档内容并返回答案。"""
response = await query_engine.aquery(query) # 异步查询文档
return str(response) # 返回查询结果的字符串
# 创建一个带有计算器和文档搜索工具的智能代理
# tools: 代理可用的工具列表
# llm: 使用的语言模型(此处为OpenAI的gpt-4o-mini)
# system_prompt: 定义代理行为的系统提示
agent = FunctionAgent(
tools=[multiply, search_documents], # 指定可用工具
llm=OpenAI(model="gpt-4o-mini"), # 指定使用的语言模型
system_prompt="""你是一名乐于助人的助手,可以进行数学计算并检索文档来回答用户问题。""", # 系统提示(中文)
)
# 定义主异步函数
async def main():
# 运行代理,向其提出一个中文问题,包含文档检索和数学计算
response = await agent.run("红楼梦主要人物有哪些?另外,7乘以8等于多少?")
# 打印代理的回答
print(str(response)) # 输出代理的回复
# 程序入口点
# 如果直接运行此脚本,则执行main函数
if __name__ == "__main__":
asyncio.run(main()) # 启动主异步函数
这将输出类似以下内容:《红楼梦》的主要人物包括:贾宝玉、林黛玉、薛宝钗。另外,7乘以8等于56。
该代理现在可以无缝切换使用计算器和搜索文档来回答问题。
6. 存储RAG索引 #
为了避免每次重新处理文档,你可以将索引持久化到磁盘:
# 导入异步编程所需的模块
+import asyncio
# 导入os模块,用于判断目录是否存在
+import os
# 从llama_index.core.agent.workflow模块导入FunctionAgent类,用于创建基于函数的智能代理
+from llama_index.core.agent.workflow import FunctionAgent
# 从llama_index.llms.openai模块导入OpenAI类,用于集成OpenAI语言模型
+from llama_index.llms.openai import OpenAI
# 从llama_index.core模块导入向量索引、目录读取器、存储上下文和索引加载函数
from llama_index.core import (
VectorStoreIndex,
SimpleDirectoryReader,
+ StorageContext,
+ load_index_from_storage,
+)
# 加载data目录下的所有文档
+documents = SimpleDirectoryReader("data").load_data()
# 判断storage目录是否存在
+if os.path.exists("storage"):
# 如果storage目录存在,则从磁盘加载索引
+ storage_context = StorageContext.from_defaults(persist_dir="storage")
# 从存储中加载索引 这样就不需要重新处理文档了
+ index = load_index_from_storage(storage_context)
# 从加载的索引创建查询引擎
+ query_engine = index.as_query_engine()
+else:
# 如果storage目录不存在,则新建索引并持久化到磁盘
+ index = VectorStoreIndex.from_documents(documents)
# 将索引数据保存到"storage"目录
+ index.storage_context.persist("storage")
# 从加载的索引创建查询引擎
+ query_engine = index.as_query_engine()
# 定义一个简单的计算器工具函数,接收两个浮点数参数,返回它们的乘积
def multiply(a: float, b: float) -> float:
"""用于计算两个数字的乘积。"""
+ return a * b
# 定义文档搜索工具函数,这是一个异步函数,根据问题检索文档并返回答案
async def search_documents(query: str) -> str:
"""用于根据自然语言问题检索文档内容并返回答案。"""
+ response = await query_engine.aquery(query)
+ return str(response)
# 创建一个带有计算器和文档搜索工具的智能代理
agent = FunctionAgent(
tools=[multiply, search_documents], # 指定可用工具
llm=OpenAI(model="gpt-4o-mini"), # 指定使用的语言模型
+ system_prompt="""你是一名乐于助人的助手,可以进行数学计算并检索文档来回答用户问题。""", # 系统提示
)
# 定义主异步函数
async def main():
# 运行代理,向其提出一个包含文档检索和数学计算的中文问题
response = await agent.run("红楼梦主要人物有哪些?另外,7乘以8等于多少?")
# 打印代理的回答
+ print(str(response))
# 程序入口点,如果直接运行此脚本,则执行main函数
if __name__ == "__main__":
+ asyncio.run(main())