构建你的第一个 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)
五、迭代与改进
第一个版本上线后,收集真实用户反馈进行迭代:
- 检索质量改进:从纯向量检索改为混合检索(向量 + BM25)
- 切分策略优化:根据文档结构自适应切分,而不是固定字符数
- 引用来源:在回答中标注引用的文档片段
- 多文档关联:支持跨文档问答
- 对话历史:加入聊天记录作为上下文
六、部署方案
开发完成后部署到生产环境:
最小化部署: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 不是银弹——它抽象了常见模式但在高度定制化的场景下可能会成为限制。理解它背后的设计模式和原理,在合适的场景下灵活使用,才是正确的方式。
延伸阅读
- 📺 B 站播放列表:Build with Andrew — 和吴恩达一起构建 APP
- 📚 更多学习资源,请访问 deeplearning.ai 官网