配音

构建你的第一个 AI 应用

课程简介

跟着吴恩达从零开始构建一个实用的 AI 应用。

🎬 本课程视频:Build with Andrew — 和吴恩达一起构建 APP


构建你的第一个 AI 应用:从想法到部署的完整流程

一、从一个简单想法开始

构建 AI 应用的第一步不是选择技术栈,而是定义问题。好的 AI 应用始于一个清晰的问题定义。

对于我们的实战项目,目标是构建一个"AI 知识问答助手"——用户上传自己的文档(PDF、Markdown、文本),然后可以针对文档内容提问,AI 基于文档内容来回答。这就是典型的 RAG 应用。

二、RAG 架构详解

RAG 架构是当前构建 AI 应用最流行的范式,整个系统分为三个核心阶段。

阶段一:文档处理与索引

用户上传文档后,系统需要将文档内容转化为可搜索的索引。

第一步是文档解析。不同格式需要不同的解析器——PDF 用 PyMuPDF 或 pdfplumber、Markdown 用 markdown 库、Word 用 python-docx。解析后的输出是纯文本。

第二步是文档切分。将长文档切割成适当大小的片段(Chunk)。切分策略很重要:按段落切(保持语义完整)、按固定长度切(控制 token 数)、按层级切(标题+内容)。一个好的切分策略是递归字符切分——先按段落切、如果段落太长再按句子切、句子太长按固定字符数切。

第三步是向量化。用嵌入模型(如 OpenAI 的 text-embedding-3-small、Sentence Transformers 系列)将每个 Chunk 编码为向量。

第四步是存储到向量数据库。支持选项包括 Pinecone(托管服务,最简单上手)、Weaviate/Qdrant/Milvus(自托管开源方案)、ChromaDB/Pinecone(本地开发用小数据量)。

阶段二:检索

用户发来一个问题时,系统需要从向量库中检索最相关的文档片段。

流程:
1. 用同样的嵌入模型将用户问题编码为向量
2. 在向量数据库中执行近似最近邻搜索,找到与问题向量最相似的 Top-K 个 Chunk
3. 返回检索到的文本片段及其相似度分数

核心参数:
- K 值(检索数量):太小可能漏掉相关信息,太大可能引入噪声。通常 3-5
- 相似度阈值:低于此阈值的片段不返回,避免引入无关信息
- 检索策略:除了向量相似度,还可以结合 BM25(关键词匹配)做混合检索

阶段三:生成

系统将检索到的相关文档片段和用户问题组装到一起,发送给 LLM。

Prompt 模板设计示例:

你是一位知识问答助手。基于以下文档内容回答用户问题。
如果文档中没有相关信息,请明确说明你不知道,不要编造答案。

文档内容:
{context}

用户问题:{question}

关键设计要点:明确指出模型不要编造答案——这有助于减少幻觉。要求模型引用原文——回答中标注信息来源片段。

三、技术栈选择

对于我们的原型应用,推荐以下技术栈:

后端:Python + FastAPI——快速构建 API,自动生成文档,类型检查支持好
前端:Streamlit——最快速的原型 UI,用纯 Python 就能构建交互界面
LLM API:OpenAI API 或 Claude API——成熟的 API,开箱即用
嵌入模型:OpenAI Embeddings 或 Sentence Transformers——前者托管、后者可自部署
向量数据库:ChromaDB——本地开发最简选择,数据以文件形式存储

四、原型构建:逐步实现

步骤 1:项目初始化

mkdir ai-qa-assistant && cd ai-qa-assistant
python -m venv venv
source venv/bin/activate
pip install fastapi uvicorn chromadb sentence-transformers streamlit langchain

步骤 2:文档处理模块

核心函数:读取文档、切分 Chunk、生成嵌入、存入向量数据库。

import chromadb
from sentence_transformers import SentenceTransformer

# 初始化
model = SentenceTransformer('all-MiniLM-L6-v2')
client = chromadb.Client()
collection = client.create_collection("knowledge_base")

def process_document(text, doc_id, chunk_size=500):
    chunks = []
    for i in range(0, len(text), chunk_size):
        chunk = text[i:i+chunk_size]
        chunks.append(chunk)

    embeddings = model.encode(chunks).tolist()
    for idx, (chunk, emb) in enumerate(zip(chunks, embeddings)):
        collection.add(
            ids=[f"{doc_id}_{idx}"],
            embeddings=[emb],
            metadatas=[{"doc_id": doc_id, "chunk_index": idx}],
            documents=[chunk]
        )
    return len(chunks)

步骤 3:问答模块

def answer_question(question, k=3):
    # 检索
    q_emb = model.encode([question]).tolist()
    results = collection.query(query_embeddings=q_emb, n_results=k)

    context = "\n\n".join(results['documents'][0])

    # 生成
    prompt = '''基于以下文档回答问题。如果文档中没有相关信息,请说不知道。

文档内容:
{context}

问题:{question}'''.format(context=context, question=question)

    # 调用 LLM API
    response = openai_client.chat.completions.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt}]
    )
    return response.choices[0].message.content

步骤 4:Streamlit 前端

import streamlit as st

st.title("📚 AI 知识问答助手")
uploaded_file = st.file_uploader("上传文档", type=["pdf", "txt", "md"])
if uploaded_file:
    text = uploaded_file.read().decode()
    n_chunks = process_document(text, uploaded_file.name)
    st.success(f"已处理文档,共 {n_chunks} 个片段")

question = st.text_input("请输入你的问题")
if question:
    answer = answer_question(question)
    st.write(answer)

五、迭代与改进

第一个版本上线后,收集真实用户反馈进行迭代:

  1. 检索质量改进:从纯向量检索改为混合检索(向量 + BM25)
  2. 切分策略优化:根据文档结构自适应切分,而不是固定字符数
  3. 引用来源:在回答中标注引用的文档片段
  4. 多文档关联:支持跨文档问答
  5. 对话历史:加入聊天记录作为上下文

六、部署方案

开发完成后部署到生产环境:

最小化部署:Streamlit Cloud + ChromaDB 文件存储 + OpenAI API(适合个人项目)
标准化部署:Docker + FastAPI + PostgreSQL + 向量数据库 + K8s(适合团队项目)
全托管方案:LangChain + 向量数据库 SaaS + 云函数(无需管理基础设施)

七、总结

RAG 架构是构建 AI 应用的最佳起点。核心流程三步:文档处理与索引 → 检索相关片段 → 基于片段生成回答。从简单的原型开始,按真实反馈迭代改进——这是构建成功的 AI 应用的普适方法论。

八、从原型到生产的工程考量

当你的 RAG 应用原型验证成功后,从原型到生产还需要考虑一系列工程问题:

向量数据库的生产化:ChromaDB 适合原型开发,生产环境建议使用 Pinecone(托管、高性能)、Weaviate(自托管、支持混合检索)或 Milvus(大规模、分布式)。生产级向量数据库需要支持高并发、持久化、备份恢复和水平扩展。

嵌入模型的选择:原型阶段用的 all-MiniLM-L6-v2 在英文场景表现好。生产环境需要考虑:多语言支持(intfloat/multilingual-e5-large)、嵌入维度与向量数据库的兼容性、推理延迟和吞吐量要求。

LLM 的成本控制:生产环境中 API 调用费用是一笔持续的开支。优化策略包括:使用更便宜的模型处理简单问题、缓存常见问题的答案、使用提示词压缩减少 token 消耗、批处理非实时请求。

RAG 的评估:如何衡量 RAG 系统的质量?推荐使用 RAGAS 框架,从以下维度评估:忠实度(Faithfulness)——回答是否基于检索到的文档、答案相关性(Answer Relevance)——回答是否针对问题、上下文相关性(Context Relevance)——检索到的文档是否与问题相关。

用户反馈循环:在应用中嵌入用户反馈机制——回答下方的点赞/点踩按钮、用户提交正确回答的修改、问题分类统计。这些反馈数据是持续改进系统的最宝贵资源。

将以上考量纳入你的开发计划,RAG 应用就能从“能用的原型”进化为“可靠的生产系统”。

九、LangChain 框架的实战应用

LangChain 是目前最流行的 LLM 应用开发框架,它抽象了与 LLM 交互的常见模式,让 RAG 应用的开发更加高效。

核心组件
- Models:LLM 模型的统一接口——支持 OpenAI、Anthropic、开源模型等。切换模型只需修改一行配置。
- Prompts:提示词模板和管理的规范框架——支持变量注入、示例选择、输出解析器。
- Indexes:文档加载、切分、向量化、存储的标准流程——支持 PDF、网页、数据库等多种数据源。
- Chains:将多个 LLM 调用和工具调用组合成处理流水线——一个链的输出是下一个链的输入。
- Agents:赋予 LLM 工具调用能力,让它能自主规划和执行多步骤任务。

实用模式

from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.text_splitter import RecursiveCharacterTextSplitter

# 加载文档
loader = TextLoader("docs.txt")
documents = loader.load()

# 文档切分
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500, chunk_overlap=50
docs = text_splitter.split_documents(documents)

# 向量化存储
vectorstore = Chroma.from_documents(
    documents=docs,
    embedding=OpenAIEmbeddings()
)

# 检索问答链
qa_chain = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(model="gpt-4"),
    chain_type="stuff",
    retriever=vectorstore.as_retriever()
)

# 运行
result = qa_chain.invoke("你的问题")
print(result)

调试和可观测性:LangSmith 是 LangChain 的调试平台——可以追踪每次 LLM 调用的输入输出、记录 token 消耗、比较不同提示词版本的效果。在开发 RAG 应用时,LangSmith 的 Trace 功能是定位问题的利器。

LangChain 不是银弹——它抽象了常见模式但在高度定制化的场景下可能会成为限制。理解它背后的设计模式和原理,在合适的场景下灵活使用,才是正确的方式。

延伸阅读