ZeroOne AI
← 返回文章列表

LlamaIndex 系列(四):入门案例(阿里云百炼适配)

👁 1
分类:工业AI

本文以阿里云百炼为模型底座,演示 LlamaIndex 入门案例:OpenAILike 接入通义千问、FunctionAgent 工具调用智能体、Context 多轮对话记忆、RAG 文档检索与索引持久化,并给出完整可运行代码。

一、项目背景

大模型落地应用时,仅靠模型自身的通用能力远远不够:企业私有数据(设备手册、工艺文件、生产记录)如何被模型理解并正确引用,才是工程化的核心问题。LlamaIndex 正是为解决这一问题而生的数据框架,它把文档解析、分块、向量化、检索、提示词组装等繁琐环节封装成标准组件,让开发者专注于业务逻辑本身。

在国内生产环境中,直接调用海外模型服务存在网络与合规成本。阿里云百炼平台提供 OpenAI 兼容接口与免费额度,配合通义千问系列模型,是国产化适配的主流选择。本系列文章以 LlamaIndex 为骨架、阿里云百炼为模型底座,从零演示一个可运行的入门案例,覆盖:工具调用智能体、多轮对话记忆、RAG 检索与索引持久化。

二、技术方案

很多开发者把 LlamaIndex 简单等同于 RAG 框架,但官方将数据增强型大模型应用归纳为五大核心形态:

理解这五大形态,才能跳出 Demo,设计出可落地的生产级应用。本案例的技术选型如下:

环境要求:Python >= 3.10 且 < 4.0。安装有三种方式:

  1. Pip 快速安装:pip install llama-index(基础包含 core、llms-openai、embeddings-openai、readers-file)
  2. 自定义按需安装:如 Ollama 本地模型 + HuggingFace Embedding,只装 llama-index-core 等必要包
  3. 源码编译安装:clone 仓库后以 poetry 安装核心库与各集成包

三、系统架构

整体分为三层:

数据流转:用户提问 → 智能体判断意图并选择动作(工具调用或文档检索)→ 执行结果回填提示词 → 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.json137KB文档库:分块文本、节点元数据、分块与源文档的溯源关系
index_store.json2KB索引结构:节点与索引、节点与向量的映射
default__vector_store.json501KB向量数据(体积最大):文本向量、向量到源文档映射
graph_store.json18B知识图谱存储(本例未建图索引,为空壳)
image__vector_store.json72B图像向量存储(本例无图像,为空壳)

两点提醒:

文档越大,解析与 embedding 成本越高,持久化的收益越明显。

4.6 拓展方向

五、应用价值

六、SEO关键词

LlamaIndex、阿里云百炼、RAG、FunctionAgent、智能体、通义千问、OpenAILike、text-embedding-v3、向量检索、多轮对话记忆

评论(0