LlamaIndex 系列(四):入门案例(阿里云百炼适配)
本文以阿里云百炼为模型底座,演示 LlamaIndex 入门案例:OpenAILike 接入通义千问、FunctionAgent 工具调用智能体、Context 多轮对话记忆、RAG 文档检索与索引持久化,并给出完整可运行代码。
一、项目背景
大模型落地应用时,仅靠模型自身的通用能力远远不够:企业私有数据(设备手册、工艺文件、生产记录)如何被模型理解并正确引用,才是工程化的核心问题。LlamaIndex 正是为解决这一问题而生的数据框架,它把文档解析、分块、向量化、检索、提示词组装等繁琐环节封装成标准组件,让开发者专注于业务逻辑本身。
在国内生产环境中,直接调用海外模型服务存在网络与合规成本。阿里云百炼平台提供 OpenAI 兼容接口与免费额度,配合通义千问系列模型,是国产化适配的主流选择。本系列文章以 LlamaIndex 为骨架、阿里云百炼为模型底座,从零演示一个可运行的入门案例,覆盖:工具调用智能体、多轮对话记忆、RAG 检索与索引持久化。
二、技术方案
很多开发者把 LlamaIndex 简单等同于 RAG 框架,但官方将数据增强型大模型应用归纳为五大核心形态:
- Agents 智能体:由 LLM 驱动的自主决策程序,绑定各类工具与记忆组件,运行推理循环动态选择执行动作,适合复杂开放式任务
- Workflows 工作流:事件驱动的通用编排底座,用于组织多阶段逻辑与 LLM 调用,是框架底层的核心抽象
- 结构化数据提取:依托 Pydantic 定义目标结构,从 PDF、网页等非结构化文档中类型安全地提取标准化信息
- Query Engines 查询引擎:端到端单次问答链路,标准 RAG 实现载体
- Chat Engines 对话引擎:面向多轮交互会话,自动维护历史上下文
理解这五大形态,才能跳出 Demo,设计出可落地的生产级应用。本案例的技术选型如下:
- 模型接入:使用 OpenAILike 连接百炼的 OpenAI 兼容端点,注意参数名是
api_base(传base_url会被静默忽略) - 智能体:FunctionAgent + 自定义工具函数,要求模型支持原生 function calling(百炼 qwen-plus / qwen-max / qwen-turbo 均支持)
- 多轮记忆:Context 对象在多次 run() 调用之间持久化会话上下文
- RAG 检索:SimpleDirectoryReader 读取文档 → VectorStoreIndex 建索引 → query_engine 检索;embedding 使用百炼 text-embedding-v3(1024 维,中英文)
- 索引持久化:StorageContext + load_index_from_storage,避免每次启动重复解析文档与计算向量
环境要求:Python >= 3.10 且 < 4.0。安装有三种方式:
- Pip 快速安装:
pip install llama-index(基础包含 core、llms-openai、embeddings-openai、readers-file) - 自定义按需安装:如 Ollama 本地模型 + HuggingFace Embedding,只装
llama-index-core等必要包 - 源码编译安装:clone 仓库后以 poetry 安装核心库与各集成包
三、系统架构
整体分为三层:
- 模型层:阿里云百炼通义千问负责生成与工具决策,text-embedding-v3 负责语义向量化,均经 OpenAI 兼容端点接入
- 编排层:FunctionAgent 推理循环决定"调用哪个工具 / 是否检索文档",Context 维护跨轮记忆,Workflow 承载复杂流程编排
- 数据层:SimpleDirectoryReader 读取本地文档 → VectorStoreIndex 构建索引 → query_engine 执行检索 → StorageContext 持久化到 storage/ 目录
数据流转:用户提问 → 智能体判断意图并选择动作(工具调用或文档检索)→ 执行结果回填提示词 → LLM 生成最终答案返回。
四、实施过程
4.1 环境配置
获取百炼 API Key 后写入 .env 文件(比 export 更稳定,不受终端与启动方式影响),并安装 python-dotenv:
pip install python-dotenv
DASHSCOPE_API_KEY=sk-xxx
4.2 基础智能体:工具调用
创建 starter.py,实现一个具备乘法计算工具的智能体:
import asyncio
import os
from dotenv import load_dotenv
from llama_index.core.agent.workflow import FunctionAgent
from llama_index.llms.openai_like import OpenAILike
load_dotenv()
api_key = os.environ["DASHSCOPE_API_KEY"]
llm = OpenAILike(
model="qwen-plus",
api_key=api_key,
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
is_chat_model=True,
is_function_calling_model=True,
)
def multiply(a: float, b: float) -> float:
"""两个数字相乘"""
return a * b
agent = FunctionAgent(
tools=[multiply],
llm=llm,
system_prompt="你是助手,可以完成两个数字相乘计算。",
)
async def main():
response = await agent.run("1234 * 4567 等于多少?")
print(str(response))
if __name__ == "__main__":
asyncio.run(main())
运行输出:1234 × 4567 = 5,635,678。
执行流程:用户问题 + 工具描述传入 LLM → 模型选择工具并填充参数 → 执行函数 → 整合结果生成回答。框架推荐异步写法,可提升应用并发性能。
4.3 增加多轮对话记忆
依靠 Context 对象持久化会话上下文:同一个 ctx 上的多次 run() 共享对话记忆;不传 ctx 则每次都是全新会话。
import asyncio
import os
from dotenv import load_dotenv
from llama_index.core.agent.workflow import FunctionAgent
from llama_index.core.workflow import Context
from llama_index.llms.openai_like import OpenAILike
load_dotenv()
llm = OpenAILike(
model="qwen-plus",
api_key=os.environ["DASHSCOPE_API_KEY"],
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
is_chat_model=True,
is_function_calling_model=True,
)
def multiply(a: float, b: float) -> float:
"""两个数字相乘"""
return a * b
agent = FunctionAgent(
tools=[multiply],
llm=llm,
system_prompt="你是助手,可以完成两个数字相乘计算。",
)
async def main():
ctx = Context(agent)
response = await agent.run("我叫Logan", ctx=ctx)
print("第1轮:", str(response))
response = await agent.run("我的名字是什么?", ctx=ctx)
print("第2轮:", str(response))
response = await agent.run("我叫Logan,12乘以12等于多少?", ctx=ctx)
print("第3轮:", str(response))
response = await agent.run("我的名字是什么?")
print("无ctx对照:", str(response))
if __name__ == "__main__":
asyncio.run(main())
执行效果:第 1 轮打招呼;第 2 轮能答出名字(记忆生效);第 3 轮记忆与工具调用共存;无 ctx 对照轮完全不记得之前对话。Context 内部维护会话的 memory(对话历史)与 state,跨 run() 保留,多智能体场景下还可作为共享黑板传递结构化状态。
4.4 为智能体接入 RAG 检索能力
准备测试文档:将任意 .txt 文件放入 data/ 目录即可(示例使用官方 Paul Graham 随笔)。注意:RAG 依赖 embedding 模型,若不配置框架会默认回退到 OpenAI 并报错,必须把 LLM 与 embedding 同时切到百炼。
import asyncio
import os
from dotenv import load_dotenv
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.core.agent.workflow import FunctionAgent
from llama_index.embeddings.openai_like import OpenAILikeEmbedding
from llama_index.llms.openai_like import OpenAILike
load_dotenv()
API_KEY = os.environ["DASHSCOPE_API_KEY"]
API_BASE = "https://dashscope.aliyuncs.com/compatible-mode/v1"
Settings.llm = OpenAILike(
model="qwen-plus",
api_key=API_KEY,
api_base=API_BASE,
is_chat_model=True,
is_function_calling_model=True,
)
Settings.embed_model = OpenAILikeEmbedding(
model_name="text-embedding-v3",
api_key=API_KEY,
api_base=API_BASE,
)
documents = SimpleDirectoryReader("data").load_data()
index = VectorStoreIndex.from_documents(documents, show_progress=True)
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=Settings.llm,
system_prompt="你可以进行数学计算,也可以检索文档回答问题。",
)
async def main():
response = await agent.run("作者大学时期做了什么?7乘以8等于多少?")
print(response)
if __name__ == "__main__":
asyncio.run(main())
智能体会自动判断何时调用计算工具、何时检索文档,一次提问同时完成"文档问答 + 数学计算"两类任务。
4.5 RAG 索引持久化
避免每次启动重复解析文档,推荐"有缓存则加载、无则构建并保存"的模式:
import asyncio
import os
from pathlib import Path
from dotenv import load_dotenv
from llama_index.core import (
Settings, SimpleDirectoryReader, StorageContext,
VectorStoreIndex, load_index_from_storage,
)
from llama_index.embeddings.openai_like import OpenAILikeEmbedding
from llama_index.llms.openai_like import OpenAILike
load_dotenv()
API_KEY = os.environ["DASHSCOPE_API_KEY"]
API_BASE = "https://dashscope.aliyuncs.com/compatible-mode/v1"
Settings.llm = OpenAILike(
model="qwen-plus", api_key=API_KEY, api_base=API_BASE,
is_chat_model=True, is_function_calling_model=True,
)
Settings.embed_model = OpenAILikeEmbedding(
model_name="text-embedding-v3", api_key=API_KEY, api_base=API_BASE,
)
PERSIST_DIR = "./storage"
if Path(PERSIST_DIR).exists() and any(Path(PERSIST_DIR).iterdir()):
print(">> 检测到已持久化的索引,直接加载(跳过文档解析)...")
storage_context = StorageContext.from_defaults(persist_dir=PERSIST_DIR)
index = load_index_from_storage(storage_context)
else:
print(">> 首次运行:解析文档并构建索引...")
documents = SimpleDirectoryReader("data").load_data()
index = VectorStoreIndex.from_documents(documents, show_progress=True)
index.storage_context.persist(persist_dir=PERSIST_DIR)
print(f">> 索引已保存到 {PERSIST_DIR}")
query_engine = index.as_query_engine()
async def main():
response = await query_engine.aquery("作者大学时期做了什么?")
print(response)
if __name__ == "__main__":
asyncio.run(main())
以 75KB 文档实测,storage/ 目录共五个文件:
| 文件 | 大小 | 内容 |
|---|---|---|
| docstore.json | 137KB | 文档库:分块文本、节点元数据、分块与源文档的溯源关系 |
| index_store.json | 2KB | 索引结构:节点与索引、节点与向量的映射 |
| default__vector_store.json | 501KB | 向量数据(体积最大):文本向量、向量到源文档映射 |
| graph_store.json | 18B | 知识图谱存储(本例未建图索引,为空壳) |
| image__vector_store.json | 72B | 图像向量存储(本例无图像,为空壳) |
两点提醒:
- 即使加载已持久化的索引,查询时仍要用 embedding 模型向量化问题,因此 Settings.embed_model 在加载路径同样必需,省掉会在查询时报错
- 若使用第三方向量数据库,可用
VectorStoreIndex.from_vector_store(vector_store)重建索引,注意向量维度需与 text-embedding-v3 的 1024 维对齐
文档越大,解析与 embedding 成本越高,持久化的收益越明显。
4.6 拓展方向
- 扩展更多自定义工具
- 切换各类开源 / 闭源大模型
- 通过系统提示词定制智能体行为
- 开启流式输出
- 搭建人机交互工作流
- 实现多智能体协同系统
五、应用价值
- 工业知识问答:设备手册、工艺文件、质检标准的私有数据检索问答,替代人工翻阅
- 文档自动化:利用结构化数据提取能力,批量处理 PDF / 网页中的表单与参数信息
- 智能体应用:将工具调用能力接入 MES 查询、SCADA 取数、报表生成等系统,实现自主作业
- 国产化适配:百炼平台免费额度 + 通义千问,成本可控、数据合规
- 工程效率:索引持久化避免重复解析与向量化,降低启动开销,便于生产部署
六、SEO关键词
LlamaIndex、阿里云百炼、RAG、FunctionAgent、智能体、通义千问、OpenAILike、text-embedding-v3、向量检索、多轮对话记忆
推荐阅读
更多工业 AI、智能制造与技术实践文章
YOLO目标检测模型调参入门:从训练参数到检测效果优化
YOLO目标检测模型调参入门指南:详解 epochs、imgsz、batch、模型大小、conf、IoU 等核心参数的作用与调节方法,给出工业视觉、疲劳驾驶、缺陷检测等 AI 项目的调参顺序与实验对比思路,帮助初学者在精度、速度与显存之间找到平衡。
Linux系统篇(二十二)——文件(六):目标文件与 ELF 深度解析:从编译到加载的全景揭秘
从目标文件出发,逐层解剖ELF头部、节头表与程序头表,讲透静态链接重定位、动态链接GOT/PLT以及程序从编译到加载的完整过程。
陶瓷浮雕盘印刷视觉定位方案:8K线扫相机 + 暗场光源 + 旋转平台
针对最大Φ320mm带浮雕、釉面反光的陶瓷盘自动印刷定位难题,提出8K线扫相机 + 低角度暗场光源 + 旋转平台 + 编码器同步 + 模板匹配的完整视觉定位方案,输出X/Y/θ坐标,可与Trio运动控制器联动实现闭环印刷。
局域网服务器如何实现外网访问:Ubuntu 22.04 搭建 FRP 内网穿透服务器
工业现场、企业局域网和工厂 MES 系统中,服务器没有公网 IP 时如何实现外网远程访问?本文以 Ubuntu 22.04 为例,完整演示 FRP 内网穿透方案:frps 服务端配置、frpc 客户端配置、Systemd 开机自启、多工厂统一接入、HTTPS 安全架构以及完整的故障排查与安全建议。
RIP软件底层逻辑全解析:从CMYK墨量控制到PRN灰度网点数据
本文深入数码印刷RIP软件的底层逻辑:CMYK曲线与单通道/总墨量限制如何控制物理边界,打印机线性化与ICC特性文件如何实现精准色彩复制,灰度PRN数据与位深度(1/2/3位)如何驱动可变网点喷头,以及半色调方法、PPI/DPI匹配和常见印刷故障的排查指南。
Linux系统篇(五)——工具篇(一):搞懂 Linux 包管理,玩转 Vim 编辑器
从软件安装底层逻辑讲透 yum/apt 包管理器工作原理,再深入 Vim 多模式操作与高效快捷键,为 Linux 开发打下坚实基础。
