引路者👇:

一、前置知识:LLM 前端框架选型对比

二、环境搭建:Chainlit 安装与问题解决

2.1 基础安装步骤

2.2 Fly本人所遇见问题解决

三、Chainlit 前端开发:构建 LLM 对话界面

3.1 基础聊天界面代码(app_chat_ui.py)

3.2 运行与效果

3.3 前端控制流图(CFG)

四、RAG 核心流程实现:从数据准备到检索生成

4.1 RAG 架构图

4.2 数据准备阶段:构建私域向量数据库

4.2.1 数据加载与索引构建

4.2.2 数据准备流程说明

4.3 应用阶段:集成 Chainlit 实现 RAG 对话

4.4 RAG 效果验证

五、Embedding 模型配置:本地与在线方案

5.1 本地 Embedding 模型(推荐,数据不泄露)

5.2 在线 Embedding 模型(需联网,适合快速验证)

5.3 模型选择建议

六、多模态 RAG 扩展:支持图像 / 图表检索

6.1 多模态 RAG 架构图

6.2 多模态数据加载示例

6.3 多模态检索实现

七、项目部署与优化建议

7.1 部署流程

7.2 性能优化建议

八、总结


        在大语言模型(LLM)应用开发中,前端交互体验与后端检索能力是核心竞争力。Chainlit 作为专注 LLM 应用的对话式前端框架,能快速构建流畅的聊天界面;而 RAG(检索增强生成)技术则可解决 LLM 知识局限、幻觉等问题,二者结合能打造出 “交互友好 + 回答精准” 的 AI 应用。接下来,跟着Fly一起来试试吧!

一、前置知识:LLM 前端框架选型对比

在开发 LLM 应用前,需先选择合适的前端框架。目前主流的 Python 前端框架有 Chainlit、Streamlit、Gradio,三者定位与适用场景差异显著,需根据需求选择:

对比维度 Chainlit Streamlit Gradio
核心定位 专注 LLM 对话应用的前端框架 通用数据可视化 / Web App 框架 机器学习模型 Demo 快速构建工具
核心优势 1. 原生支持多轮对话与流式输出2. 内置工具调用 / 思维链可视化3. 与 LangChain/LlamaIndex 深度集成 1. 脚本式开发,学习曲线平缓2. 丰富数据组件(图表 / 表单)3. 数据科学生态适配好 1. 几行代码生成 UI2. 支持多模态输入输出3. 与 Hugging Face 无缝衔接
适用场景 AI 助手、LLM 工具调用演示、智能问答 数据仪表盘、BI 分析、原型展示 模型 Demo 分享、ML 竞赛演示
上手难度 中等(需理解 LLM 应用逻辑) 低(纯 Python 脚本) 极低(复制模板即可)
典型命令 chainlit run app.py streamlit run app.py gr.Interface(...).launch()

选型结论:若开发 LLM 对话类应用(如智能问答、AI 助手),Chainlit 是最优选择,其对话交互体验与 LLM 生态集成能力远超其他框架。本篇文章后续均基于 Chainlit 开发。

二、环境搭建:Chainlit 安装与问题解决

Chainlit 安装过程中可能遇到依赖版本冲突,需按以下步骤操作,确保环境稳定:

2.1 基础安装步骤

  1. 创建虚拟环境(推荐,避免依赖冲突)
# 创建虚拟环境
python -m venv rag_venv
# 激活环境(Windows)
rag_venv\Scripts\activate
# 激活环境(macOS/Linux)
source rag_venv/bin/activate
  1. 安装 Chainlit 与依赖
# 先安装指定版本的pydantic(解决版本冲突)
pip install pydantic==2.9.2
# 安装Chainlit
pip install chainlit
# 安装LlamaIndex(RAG核心框架)
pip install llama-index-core llama-index-embeddings-huggingface llama-index-llms-openai
# 安装向量数据库(本文用Milvus,也可选择FAISS/Chroma)
pip install pymilvus
  1. 验证安装
# 运行Chainlit默认示例
chainlit hello

        若终端输出Your app is available at http://localhost:8000,且浏览器能打开聊天界面,说明安装成功。

2.2 Fly本人所遇见问题解决

问题:运行chainlit hello时出现PydanticUserError: CodeSettings is not fully defined原因:pydantic 版本过高,Chainlit 对高版本 pydantic 兼容性不足解决方案:卸载高版本 pydantic,安装指定版本

pip uninstall pydantic
pip install pydantic==2.9.2

三、Chainlit 前端开发:构建 LLM 对话界面

        Chainlit 通过装饰器(@cl.on_chat_start/@cl.on_message)简化前端逻辑开发,核心是 “会话初始化 + 消息处理” 两大流程。以下实现一个基础聊天界面,并集成 LlamaIndex 的聊天引擎。

3.1 基础聊天界面代码(app_chat_ui.py)

import chainlit as cl
from llama_index.core import Settings
from llama_index.llms.openai import OpenAI
from llama_index.core.chat_engine import SimpleChatEngine

# Chainlit会话初始化:聊天开始时执行
@cl.on_chat_start
async def start():
    """
    1. 初始化LLM模型
    2. 创建聊天引擎
    3. 存储引擎到会话(供后续消息处理使用)
    4. 发送欢迎消息
    """
    # 1. 配置OpenAI LLM(也可替换为本地模型如DeepSeek)
    Settings.llm = OpenAI(
        model="gpt-3.5-turbo",
        temperature=0.1,  # 控制输出随机性,越低越严谨
        max_tokens=1024,
        streaming=True  # 开启流式输出,提升交互体验
    )
    
    # 2. 创建简单聊天引擎
    chat_engine = SimpleChatEngine.from_defaults()
    
    # 3. 存储到用户会话(不同用户会话隔离)
    cl.user_session.set("chat_engine", chat_engine)
    
    # 4. 发送欢迎消息
    await cl.Message(
        author="AI助手",
        content="你好!我是基于Chainlit开发的AI助手,有什么可以帮你的吗?"
    ).send()

# Chainlit消息处理:接收用户消息并生成回复
@cl.on_message
async def main(message: cl.Message):
    """
    1. 从会话中获取聊天引擎
    2. 初始化空回复消息
    3. 流式生成回复(逐token输出)
    4. 发送完整回复
    """
    # 1. 获取会话中的聊天引擎
    chat_engine = cl.user_session.get("chat_engine")
    
    # 2. 初始化空回复(作者设为AI)
    msg = cl.Message(content="", author="AI助手")
    
    # 3. 流式处理用户消息(避免用户等待太久)
    # cl.make_async:将同步函数转为异步,适配Chainlit异步机制
    res = await cl.make_async(chat_engine.stream_chat)(message.content)
    
    # 逐token输出回复,提升交互流畅度
    for token in res.response_gen:
        await msg.stream_token(token)
    
    # 4. 发送完整回复
    await msg.send()

3.2 运行与效果

# 运行前端界面(-w:文件修改时自动重启)
chainlit run app_chat_ui.py -w

打开浏览器访问http://localhost:8000,可看到如下界面,支持多轮对话与流式输出:

3.3 前端控制流图(CFG)

       Chainlit 前端逻辑分为 “会话初始化” 与 “消息处理” 两大流程,用流程图表示如下:

四、RAG 核心流程实现:从数据准备到检索生成

        基础聊天界面仅依赖 LLM 自身知识,存在 “知识过时、幻觉” 等问题。RAG 通过 “检索私域数据 + 增强 Prompt” 解决这些问题,核心流程分为数据准备阶段(离线)与应用阶段(在线)。

4.1 RAG 架构图

4.2 数据准备阶段:构建私域向量数据库

该阶段需将私域数据(如 PDF、TXT)转为向量并存储,代码如下(app_chat_basic_rag.py):

4.2.1 数据加载与索引构建

from llama_index.core import (
    VectorStoreIndex,
    SimpleDirectoryReader,
    Settings,
    StorageContext,
    load_index_from_storage
)
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.openai import OpenAI
from llama_index.core.memory import ChatMemoryBuffer
from llama_index.core.chat_engine.types import ChatMode

# 1. 全局配置:设置LLM与Embedding模型
def init_global_settings():
    # 配置LLM(可替换为本地模型如DeepSeek)
    Settings.llm = OpenAI(
        model="gpt-3.5-turbo",
        temperature=0.1,
        streaming=True
    )
    # 配置Embedding模型(本地部署,避免API依赖)
    Settings.embed_model = HuggingFaceEmbedding(
        model_name="BAAI/bge-small-zh-v1.5",  # 中文支持好,轻量高效
        cache_folder="./embed_cache"  # 模型缓存目录,避免重复下载
    )

# 2. 构建向量索引(仅需执行一次,后续可加载)
def build_vector_index(data_dir="./data", index_dir="./index"):
    """
    data_dir:私域数据目录(存放PDF/TXT等)
    index_dir:索引持久化目录
    """
    # 加载数据(支持多格式:PDF/TXT/JSON等)
    reader = SimpleDirectoryReader(input_dir=data_dir)
    documents = reader.load_data(show_progress=True)  # 显示加载进度
    
    # 构建向量索引
    index = VectorStoreIndex.from_documents(
        documents,
        show_progress=True  # 显示向量化进度
    )
    
    # 持久化索引(避免下次重复构建)
    index.storage_context.persist(persist_dir=index_dir)
    print(f"索引构建完成,存储在{index_dir}目录")

# 3. 从持久化目录加载索引
def load_vector_index(index_dir="./index"):
    storage_context = StorageContext.from_defaults(persist_dir=index_dir)
    index = load_index_from_storage(storage_context)
    return index

# 4. 创建RAG聊天引擎(集成检索与记忆)
async def create_rag_chat_engine(index_dir="./index"):
    # 加载索引
    index = load_vector_index(index_dir)
    
    # 构建聊天记忆(存储多轮对话历史,限制1024token)
    memory = ChatMemoryBuffer.from_defaults(token_limit=1024)
    
    # 创建RAG聊天引擎
    chat_engine = index.as_chat_engine(
        chat_mode=ChatMode.CONTEXT,  # 基于检索上下文回答
        memory=memory,
        system_prompt="""
        你是基于私域数据的AI助手,仅根据检索到的文档内容回答问题,
        若文档中没有相关信息,直接说明“未找到相关知识”,禁止编造回答。
        """
    )
    return chat_engine

# 初始化配置并构建索引(首次运行时执行)
if __name__ == "__main__":
    init_global_settings()
    # 构建索引(仅需执行一次,后续注释掉)
    build_vector_index(data_dir="./data", index_dir="./index")

4.2.2 数据准备流程说明

  1. 数据加载:通过SimpleDirectoryReader读取./data目录下的私域数据(支持 PDF、TXT、DOCX 等);
  2. 文本分割:默认按句子分割,确保每个文本块语义完整且不超过 Embedding 模型的 token 限制;
  3. 向量化:使用BAAI/bge-small-zh-v1.5模型将文本块转为 768 维向量,该模型对中文支持优秀且轻量;
  4. 持久化:将向量索引存储到./index目录,下次使用时直接加载,无需重复处理数据。

4.3 应用阶段:集成 Chainlit 实现 RAG 对话

        将 RAG 聊天引擎与 Chainlit 前端结合,实现 “用户提问→检索私域数据→增强生成” 的完整流程,代码如下(app_rag_chat.py):

import chainlit as cl
from app_chat_basic_rag import init_global_settings, create_rag_chat_engine

# 初始化全局配置(LLM+Embedding)
init_global_settings()

# 会话初始化:创建RAG聊天引擎
@cl.on_chat_start
async def start():
    # 异步创建RAG聊天引擎
    chat_engine = await create_rag_chat_engine(index_dir="./index")
    
    # 存储引擎到会话
    cl.user_session.set("chat_engine", chat_engine)
    
    # 发送欢迎消息
    await cl.Message(
        author="RAG AI助手",
        content="你好!我已加载私域数据,可回答相关问题~"
    ).send()

# 消息处理:基于RAG生成回答
@cl.on_message
async def main(message: cl.Message):
    # 获取RAG聊天引擎
    chat_engine = cl.user_session.get("chat_engine")
    
    # 初始化空回复
    msg = cl.Message(content="", author="RAG AI助手")
    
    # 流式生成RAG增强回答
    res = await cl.make_async(chat_engine.stream_chat)(message.content)
    
    # 逐token输出
    for token in res.response_gen:
        await msg.stream_token(token)
    
    # 发送回复
    await msg.send()

    # (可选)显示检索到的相关文档
    related_docs = res.source_nodes
    if related_docs:
        doc_content = "\n\n".join([doc.node.get_content()[:200] + "..." for doc in related_docs[:2]])
        await cl.Message(
            author="参考文档",
            content=f"检索到相关文档(前2条):\n{doc_content}",
            parent_id=msg.id  # 关联到主回复,显示在下方
        ).send()

4.4 RAG 效果验证

  1. ./data目录放入私域数据(如 “公司产品手册.pdf”);
  2. 首次运行app_chat_basic_rag.py构建索引;
  3. 运行 RAG 聊天界面:
chainlit run app_rag_chat.py -w

五、Embedding 模型配置:本地与在线方案

Embedding 模型是 RAG 检索效果的核心,需根据 “是否联网”“数据安全性” 选择本地或在线模型。以下提供两种常用方案:

5.1 本地 Embedding 模型(推荐,数据不泄露)

使用 Hugging Face 的开源模型,本地部署,代码如下(embeddings.py):

from llama_index.embeddings.huggingface import HuggingFaceEmbedding

def get_local_embedding(model_name="BAAI/bge-small-zh-v1.5"):
    """
    获取本地Embedding模型
    model_name:可选模型:
    - BAAI/bge-small-zh-v1.5(中文轻量)
    - moka-ai/m3e-base(中文通用)
    - sentence-transformers/all-MiniLM-L6-v2(英文通用)
    """
    embed_model = HuggingFaceEmbedding(
        model_name=model_name,
        cache_folder="./embed_cache",  # 模型缓存目录
        model_kwargs={"device": "cpu"}  # 无GPU则设为cpu,有GPU可设为cuda
    )
    return embed_model

5.2 在线 Embedding 模型(需联网,适合快速验证)

使用 Ollama 或 OpenAI 的在线模型,无需本地下载,代码如下:

from llama_index.embeddings.ollama import OllamaEmbedding
from llama_index.embeddings.openai import OpenAIEmbedding

def get_ollama_embedding(base_url="http://localhost:11434"):
    """Ollama在线Embedding(需本地启动Ollama服务)"""
    embed_model = OllamaEmbedding(
        model_name="nomic-embed-text:latest",
        base_url=base_url
    )
    return embed_model

def get_openai_embedding(api_key="your-api-key"):
    """OpenAI Embedding(需API密钥)"""
    embed_model = OpenAIEmbedding(
        model="text-embedding-3-small",
        api_key=api_key
    )
    return embed_model

5.3 模型选择建议

场景 推荐模型 优势
中文私域数据 BAAI/bge-small-zh-v1.5 中文语义理解好,轻量快速
英文通用数据 sentence-transformers/all-MiniLM-L6-v2 通用性强,体积小
快速验证(无 GPU) Ollama nomic-embed-text 无需本地下载,在线调用
高准确率需求 OpenAI text-embedding-3-large 检索准确率高,需 API 付费

六、多模态 RAG 扩展:支持图像 / 图表检索

        传统 RAG 仅处理文本数据,多模态 RAG 可支持图像、图表等非文本数据,通过视觉语言模型(VLM)实现跨模态检索。以下是多模态 RAG 的核心流程与代码示例。

6.1 多模态 RAG 架构图

6.2 多模态数据加载示例

使用 LlamaIndex 的多模态加载器,支持图像与 PDF 中的图表提取,代码如下:

from llama_index.core import SimpleDirectoryReader
from llama_index.readers.file import ImageReader, PDFReader

def load_multimodal_data(data_dir="./multimodal_data"):
    """
    加载多模态数据(文本+图像+PDF)
    """
    # 配置多模态加载器
    readers = {
        ".jpg": ImageReader(),
        ".png": ImageReader(),
        ".pdf": PDFReader(),  # 支持提取PDF中的文本与图表
        ".txt": SimpleDirectoryReader()
    }
    
    # 加载数据
    reader = SimpleDirectoryReader(
        input_dir=data_dir,
        file_extractor=readers
    )
    documents = reader.load_data(show_progress=True)
    return documents

6.3 多模态检索实现

需使用支持多模态的向量数据库(如 Milvus),并结合 VLM 模型编码图像,代码片段如下:

from pymilvus import MilvusClient
from llama_index.llms.openai import OpenAI

# 1. 初始化Milvus多模态向量库
client = MilvusClient(uri="./multimodal_milvus.db")
client.create_collection(
    collection_name="multimodal_collection",
    dimension=768  # 与Embedding模型输出维度一致
)

# 2. 图像编码(使用GPT-4V)
def encode_image(image_path):
    llm = OpenAI(model="gpt-4-vision-preview")
    response = llm.complete(
        f"描述这张图像的内容,用于语义检索:<image>{image_path}</image>"
    )
    # 将图像描述文本向量化
    embed_model = get_local_embedding()
    return embed_model.get_text_embedding(response.text)

# 3. 多模态检索
def multimodal_search(query, top_k=3):
    #  query可为文本或图像路径
    if query.endswith((".jpg", ".png")):
        # 图像查询:先编码为文本描述,再向量化
        query_embedding = encode_image(query)
    else:
        # 文本查询:直接向量化
        query_embedding = get_local_embedding().get_text_embedding(query)
    
    # Milvus检索
    results = client.search(
        collection_name="multimodal_collection",
        data=[query_embedding],
        limit=top_k
    )
    return results

七、项目部署与优化建议

7.1 部署流程

  1. 前端部署:将 Chainlit 应用打包为 Docker 镜像,或部署到云服务器(如 AWS EC2);
  2. 后端部署:向量数据库(Milvus)部署为服务,LLM 若为本地模型,需部署到 GPU 服务器;
  3. 环境变量:敏感信息(如 API 密钥、数据库地址)通过.env文件管理,代码中读取:
# 读取.env文件
from dotenv import load_dotenv
import os

load_dotenv()  # 加载.env文件
openai_api_key = os.getenv("OPENAI_API_KEY")
milvus_uri = os.getenv("MILVUS_URI")

7.2 性能优化建议

  1. 文本分割优化:根据 Embedding 模型的 token 限制调整分割长度(如 BGE 模型建议 256-512token),并添加 10% 重叠,避免语义断裂;
  2. 检索优化:向量数据库创建索引(如 Milvus 的 IVF_FLAT 索引),提升检索速度;
  3. 缓存优化:对高频查询结果缓存(如使用 Redis),减少重复检索与 LLM 调用;
  4. 流式输出:始终开启 LLM 流式输出(streaming=True),提升用户等待体验。

八、总结

本文通过 Chainlit+RAG 实现了一个私域知识问答系统,核心收获如下:

  1. 前端开发:掌握 Chainlit 的会话管理与流式消息处理,能快速构建 LLM 对话界面;
  2. RAG 流程:理解数据准备(加载→分割→向量化→存储)与应用(检索→增强 Prompt→生成)的全流程;
  3. 模型配置:根据场景选择本地 / 在线 Embedding 模型,平衡性能与安全性。

如果实践操作中遇到其他问题,也可以在评论区留言,Fly帮你在线答疑!!!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐