第四章:大模型(LLM)

第十一部分:LLM + RAG 构建私有领域专家

第四节:Rag实战:使用通义千问api实现调用一个本地模型的Rag


一、任务背景与目标

在实际应用中,我们往往既想要 云端高质量的向量检索能力,又希望 生成部分能完全在本地运行,避免数据外泄、满足合规与私有化需求。

解决方案:

  • 通义千问 API 提供优质的 Embedding 向量化能力,用于检索阶段。

  • 本地部署的大模型(如 Llama3、Mistral、Vicuna 等)完成生成阶段。

这就是典型的 Hybrid RAG 架构:云端负责“理解文档与检索”,本地负责“生成答案”。


二、整体架构

工作流程如下:

  1. 文档切片:将长文档分割成小块(chunk),避免超长输入。

  2. 调用通义千问嵌入 API:将文本块编码为向量。

  3. 构建向量数据库(FAISS/Milvus):存储和检索向量。

  4. 用户提问 → 转换为向量 → 检索相关文档片段。

  5. 拼装 Prompt:将检索到的上下文与用户问题结合。

  6. 调用本地大模型:由本地大模型基于检索到的上下文生成答案。

图示流程:

用户问题 → 通义嵌入 → 向量检索 → 上下文拼装
                                ↓
                         本地 Llama3 生成答案

三、关键步骤与实现

1. 文档切片与预处理
def chunk_text(text, size=500, overlap=100):
    chunks = []
    start = 0
    while start < len(text):
        end = min(len(text), start + size)
        chunks.append(text[start:end])
        start += size - overlap
    return chunks
  • 推荐 500-1000 字符/句子 为一个 chunk。

  • overlap 保证上下文连续性。


2. 调用通义千问 API 生成 Embedding
import requests, os

API_KEY = os.getenv("DASHSCOPE_API_KEY")
BASE_URL = "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"

def embed_texts(texts):
    url = f"{BASE_URL}/embeddings"
    headers = {"Authorization": f"Bearer {API_KEY}"}
    data = {"model": "text-embedding-v4", "input": texts}
    resp = requests.post(url, headers=headers, json=data)
    return [item["embedding"] for item in resp.json()["data"]]

3. 构建 FAISS 向量数据库
import faiss, numpy as np

def build_faiss(chunks):
    vectors = np.array(embed_texts(chunks)).astype("float32")
    faiss.normalize_L2(vectors)
    index = faiss.IndexFlatIP(vectors.shape[1])
    index.add(vectors)
    return index, chunks

4. 检索与 Prompt 拼装
def retrieve(query, index, chunks, top_k=3):
    q_vec = np.array(embed_texts([query])).astype("float32")
    faiss.normalize_L2(q_vec)
    scores, idxs = index.search(q_vec, top_k)
    return [chunks[i] for i in idxs[0]]

def build_prompt(query, retrieved):
    context = "\n".join(retrieved)
    return f"""
你是专业助手,请基于以下资料回答问题。

资料:
{context}

问题:{query}
答案:
"""

5. 使用本地大模型生成
from transformers import AutoTokenizer, AutoModelForCausalLM

LOCAL_MODEL = "/path/to/llama3"
tokenizer = AutoTokenizer.from_pretrained(LOCAL_MODEL)
model = AutoModelForCausalLM.from_pretrained(LOCAL_MODEL, device_map="auto")

def generate(prompt):
    inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
    outputs = model.generate(**inputs, max_new_tokens=300)
    return tokenizer.decode(outputs[0], skip_special_tokens=True)

6. 完整查询流程
def rag_query(query, index, chunks):
    retrieved = retrieve(query, index, chunks)
    prompt = build_prompt(query, retrieved)
    return generate(prompt)

# 示例:
# docs = open("法律法规.txt").read()
# chunks = chunk_text(docs)
# index, chunks = build_faiss(chunks)
# print(rag_query("合同法的主要内容是什么?", index, chunks))

四、优化策略

  1. 向量库优化:百万级文档可用 Milvus/HNSW,提升检索速度。

  2. Reranker 精排:先召回 top-50,再用 cross-encoder 精排。

  3. Prompt 控制:只取 top-3-5,避免本地模型输入超长。

  4. 量化模型:使用 Llama3 8bit/4bit QLoRA 降低显存占用。

  5. 缓存与并发:对常见问题缓存结果,支持多用户并发。


五、典型应用场景

  • 法律问答系统:私有化部署,保护敏感合约文档。

  • 企业知识库:本地大模型结合内部资料,实现“AI 知识专家”。

  • 医疗辅助:结合医学文档,提供诊断参考(必须合规+人工复核)。


六、小结

本节我们实现了一个 通义嵌入 API + 本地生成模型 的 RAG 系统:

  • 通义 API 提供高质量 embedding;

  • FAISS 负责高效检索;

  • 本地大模型 完成最终生成,保证私有化和合规性。

这是一种 混合 RAG 架构,兼顾了 准确性、私有化和灵活性,非常适合企业内部文档问答、法律合规、医疗知识库等场景。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐