原创:朱元禄,转载必须说明来源和出处,如做培训必须说明来源,不得照抄
说在前面的话 01
进入实操前,我先把今天这一段的学习目标说清楚。
我们今天学的不是"背RAG概念",而是学会一项企业最常用、最能落地的AI工程能力:把大模型从"闭卷瞎答"变成"开卷有据"。
你学完这段,你至少能掌握三个就业能力:第一,面试时面试官问你,什么是 RAG :你能把 RAG 用一句话讲明白:先查资料,再回答。
第二,掌握真正企业级得落地场景:你能把 RAG 的完整闭环跑起来:准备资料、切分、向量化、入库、检索TopK、组装Prompt、输出答案和引用。
第三,你能做最基本的工程验收:答案有没有引用来源?引用里有没有关键证据?模型有没有胡编?
这三点为什么对就业重要?因为企业招"Agent工程师/AI应用工程师",最看重的不是你会不会背名词,而是你能不能做出可验证、可追溯、可交付的AI功能。企业看重得是能真正能解决问题得能力和价值。
RAG 是目前企业落地最常见的第一站,所以把这一段学扎实,你就已经具备了"能交付一个企业级AI核心模块"的底座。
说在前面的话 02 - 学习目标:学完你到底"会了什么",能掌握什么求职能力
-
目标1:能解释清楚
- 我能用"开卷考试"讲清 RAG:为什么需要、解决什么问题、和普通聊天有什么区别。
-
目标2:能跑通闭环
- 我能跑通 7 步闭环,不是只会调用模型。
-
目标3:能输出证据
- 我能做到"答案 + 引用片段"一起输出,让结果可复核。
-
目标4:能做最小调优
- 我知道 k 是翻几页、chunk_size 是便签大小、Prompt 是紧箍咒,能通过小实验看到效果变化。
-
目标5:能迁移到真实业务
- 题库问答只是例子,同样方法能迁移到:客服知识库、制度问答、SOP问答、产品手册助手、代码库检索问答。
说着前面得话 03:就业价值:学了这段你在职场上"能做什么事"
-
从就业角度,这段内容带来的价值非常明确:
- 你不再只是"会用AI聊天",而是能做出一个企业能用的功能模块:知识库问答/资料检索问答。
-
这类能力在岗位上通常对应:
- Agent工程师
- AI应用工程师
- 企业知识库/RAG工程师
- 智能客服/智能助手解决方案工程师
面试时面试官最常问的也就是这些:
- "你怎么避免大模型胡说?"
- "你怎么让回答有依据?"
- "你怎么做权限与可追溯?"
RAG 闭环就是最标准、最常见、最好落地的答案。
说在前面得话 04:学完能写进简历的"可量化表述"(给你直接复制)
简历表述1
基于 LangChain + DeepSeek 搭建 RAG 闭环(文档切分、向量化、FAISS入库、TopK检索、Prompt组装、引用输出),实现"面试题库问答"原型。
简历表述2
实现答案引用片段展示与"资料不足不编造"约束,提升回答可追溯性与可靠性。
简历表述3
具备 RAG 基础调优能力:通过调整 chunk_size/chunk_overlap/k 与提示词模板优化召回效果与幻觉控制。
1. 回到正文
讲课稿为商业版权文件
下面只粘贴实战代码
python
import os
from typing import List
from langchain_openai import ChatOpenAI
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.documents import Document
def build_docs() -> List[Document]:
texts = [
"分库分表常见的全局唯一ID方案包括:雪花算法(Snowflake)、UUID、数据库号段模式(segment)、Redis自增、Leaf等。核心权衡是:有序性、可用性、时钟回拨风险、跨机房一致性。",
"雪花算法(Snowflake)通常由时间戳+机器ID+序列号组成,优点是大致有序且性能高;风险点是时钟回拨,需要容错与监控。",
"号段模式(segment)通过数据库提前分配一段ID区间给业务方本地发号,优点是稳定且不依赖时钟;缺点是需要维护号段与容灾。",
"分布式事务一致性常见思路:2PC/3PC、TCC、Saga、可靠消息最终一致性。选择取决于业务可接受的延迟与补偿复杂度。",
"幂等指同一个请求执行一次或执行多次,最终结果一致。常见实现:唯一请求号+去重表、分布式锁、状态机/版本号、数据库唯一索引。",
"限流常见算法:固定窗口、滑动窗口、漏桶、令牌桶。限流用于保护系统,避免突发流量压垮下游。",
"熔断是当下游故障时快速失败,防止雪崩;常配合降级与重试策略。常见指标:错误率、超时率、RT。",
"JVM GC 常见算法:标记-清除、标记-整理、复制算法;分代收集结合新生代/老年代特点提升效率。",
"常见垃圾收集器:Serial、Parallel、CMS、G1、ZGC、Shenandoah。选择取决于吞吐、延迟目标与堆大小。",
"面试中判断候选人是否真正做过分库分表,要追问:分片键怎么选、跨分片查询怎么做、扩容迁移怎么做、全局ID怎么发、事务一致性怎么处理。",
"面试中评估并发能力可追问:线程安全、锁粒度、无锁结构、CAS、内存模型、性能瓶颈定位。",
"面试中评估项目深度:是否能讲清权衡、边界条件、故障处理、监控指标、以及为什么这样设计而不是另一种。",
]
return [Document(page_content=t, metadata={"source": "interview_kb"}) for t in texts]
def build_vectorstore(docs: List[Document]) -> FAISS:
splitter = RecursiveCharacterTextSplitter(chunk_size=220, chunk_overlap=40)
chunks = splitter.split_documents(docs)
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
vs = FAISS.from_documents(chunks, embeddings)
return vs
def build_llm() -> ChatOpenAI:
api_key = os.getenv("DEEPSEEK_API_KEY")
if not api_key:
raise RuntimeError("Missing env var DEEPSEEK_API_KEY")
return ChatOpenAI(
model="deepseek-chat",
api_key=api_key,
base_url="https://api.deepseek.com",
temperature=0.2,
)
def answer_question(vs: FAISS, llm: ChatOpenAI, question: str, k: int = 4) -> None:
retriever = vs.as_retriever(search_kwargs={"k": k})
retrieved = retriever.get_relevant_documents(question)
context = "\n\n".join([f"[片段{i+1}] {d.page_content}" for i, d in enumerate(retrieved)])
prompt = f"""你是"面试数字人题库助手"。请严格根据【参考资料】回答【问题】。
要求:
1) 必须基于资料作答;资料不足就回答"资料不足,无法确定",不要编造。
2) 回答要清晰分点。
3) 最后给出"追问建议"(面试官可以继续问什么)1-3条。
【参考资料】
{context}
【问题】
{question}
"""
resp = llm.invoke(prompt)
print("\n" + "=" * 90)
print(f"问题:{question}\n")
print("【引用片段TopK】")
for i, d in enumerate(retrieved, 1):
print(f"{i}. {d.page_content}")
print("\n【DeepSeek回答】")
print(resp.content)
def main():
docs = build_docs()
vs = build_vectorstore(docs)
llm = build_llm()
questions = [
"分库分表如何生成全局唯一ID?分别说说Snowflake和号段模式的优缺点。",
"什么是幂等?在支付回调或订单创建场景中怎么保证幂等?",
"JVM GC 常见算法有哪些?G1 的目标是什么?",
]
for q in questions:
answer_question(vs, llm, q, k=4)
if __name__ == "__main__":
main()