LlamaIndex学习1:基本模型对话

LlamaIndex基本模型对话 - 不同API的调用方式

从这篇文章开始学习LlamaIndex,它是一个强大的数据框架,专门为解决LLM与数据之间的”信息鸿沟”问题设计的。简单来说,它就像是给大语言模型装上了”眼睛”,让模型能够看到并理解我们自己的数据。

这篇文章主要记录我如何使用LlamaIndex调用不同平台的模型API,特别是一些非官方支持的模型平台。

1. OpenRouter平台模型调用

OpenRouter作为一个模型聚合平台,提供了多种模型的统一访问方式。使用LlamaIndex提供的内置工具可以轻松连接OpenRouter:

import os
from dotenv import load_dotenv
load_dotenv()
from llama_index.llms.openrouter import OpenRouter
from llama_index.core.llms import ChatMessage

# 不需要指定url,因为OpenRouter类里默认使用openrouter的api url
llm = OpenRouter(
    model="deepseek/deepseek-chat-v3-0324:free",
    api_key=os.getenv("OPEN_ROUTER_API_KEY"),
)

message = ChatMessage(role="user", content="给我讲个小笑话")

# 非流式
# resp = llm.chat([message])
# print(resp)

# 流式
resp = llm.stream_chat([message])
for r in resp:
    print(r.delta, end="")
print("\n\n")
print("========" * 2)

使用OpenRouter的优势在于它为多个模型提供统一接口,且有一些免费调用额度。

2. 非官方支持平台的模型调用

对于一些非官方支持的API(如SiliconFlow等国内平台),我们可以使用官方内置的OpenAILike类:

import os
from dotenv import load_dotenv
load_dotenv()
from llama_index.llms.openai_like import OpenAILike
from llama_index.core.llms import ChatMessage

llm = OpenAILike(
    model="Qwen/Qwen2.5-7B-Instruct",
    api_key=os.getenv("SILICONFLOW_API_KEY"),
    api_base=os.getenv("SILICONFLOW_BASE_URL"),
    is_chat_model=True # OpenAILike如果不指定这个,返回值会被截断
)

# 非流式
# resp = llm.chat([ChatMessage(role="user", content="今天是几号")])
# print(f"完整响应: {resp}")

# 流式
resp = llm.stream_chat(
    [ChatMessage(role="user", content="请以我是小明来进行造句")]
)
for r in resp:
    print(r.delta, end="")
print("\n")
print("========" * 2)

3. 关于模型输出被截断的问题

在使用OpenAILike类调用第三方API时,经常会遇到输出被截断的问题。这主要与以下因素有关:

3.1 is_chat_model参数的重要性

is_chat_model参数决定了LlamaIndex如何与模型交互:

is_chat_model: bool = Field(
    default=False,
    description=(
        "Set True if the model exposes a chat interface (i.e. can be passed a"
        " sequence of messages, rather than text), like OpenAI's"
        " /v1/chat/completions endpoint."
    ),
)
  • is_chat_model=True时:使用chat接口,发送消息序列
  • is_chat_model=False时:使用completion接口,将消息转换为文本

3.2 OpenAI的两种API接口

OpenAI提供两种主要接口:

  1. Chat Completions (/v1/chat/completions)

    • 接收消息数组作为输入
    • 每条消息有rolecontent字段
    • 适用于对话应用
  2. Completions (/v1/completions)

    • 接收单个文本字符串
    • 适用于文本补全

3.3 解决输出截断问题的方法

  1. 正确设置is_chat_model参数

    llm = OpenAILike(
        model="Qwen/Qwen2.5-7B-Instruct",
        api_key=os.getenv("SILICONFLOW_API_KEY"),
        api_base=os.getenv("SILICONFLOW_BASE_URL"),
        is_chat_model=True,  # 对SiliconFlow等平台通常需要设为True
    )
  2. 使用非流式API获取完整响应

    # 非流式方法更可靠
    resp = llm.chat([ChatMessage(role="user", content="给我讲个小笑话")])
    print(f"完整响应: {resp}")
  3. 直接使用底层OpenAI客户端

    from openai import OpenAI
    
    client = OpenAI(
        api_key=os.getenv("SILICONFLOW_API_KEY"),
        base_url=os.getenv("SILICONFLOW_BASE_URL")
    )
    
    response = client.chat.completions.create(
        model="Qwen/Qwen2.5-7B-Instruct",
        messages=[{"role": "user", "content": "给我讲个小笑话"}],
        stream=False  # 非流式更可靠
    )
    
    print(response.choices[0].message.content)

4. 最佳实践与提醒

  1. 检查API提供商文档

    • 确认API是支持chat接口还是completion接口
    • 了解流式输出的特殊要求
  2. 环境变量设置

    • 使用load_dotenv()确保环境变量正确加载
    • 检查.env文件格式和变量名
  3. 错误处理

    • 添加异常捕获,了解具体问题
    • 打印完整的错误信息
  4. 流式输出收集

    # 收集所有片段,确保完整输出
    all_chunks = []
    for chunk in resp:
        all_chunks.append(chunk.delta)
        print(chunk.delta, end="", flush=True)
    
    # 合并所有片段
    full_response = "".join(all_chunks)