👋 写在前面
大家好,我是正在独立开发 “AI 智能就业/人岗匹配系统” 的程序员。 之前在我的 《45天实战复盘:从零开发 AI 系统的血泪史》 中,提到了ai开发的经验。今天这篇专门把其中的核心技术点,拆碎了讲讲。
如果你对 AI 落地、RAG 优化或 Agent 开发感兴趣,欢迎去主页翻阅我的实战笔记。
🧠 RAG 技术拆解:如何让 AI 读懂你的“私房话”?
在 AI 开发中,我们经常听到 RAG (检索增强生成) 这个词。
很多开发者会有疑问: “为什么不能直接把文档发给大模型?为什么要搞向量库这么复杂的东西?”
今天我们通过一个 “企业内部岗位招聘助手” 的 80 行 Python 小 Demo,带大家彻底搞懂 RAG 在 AI 开发中的核心作用。
1. 为什么我们需要 RAG?
想象一下,你把公司内部的招聘文档扔给 ChatGPT 或 豆包,问它:“我们要招的 Python 工程师薪资范围是多少?”
大模型会一脸懵圈,或者开始胡编乱造(幻觉)。因为:
- 数据隐私:大模型训练时没见过你们公司的内网文档。
- 上下文限制:你不可能把几千个岗位的 JD 一次性全部粘贴到对话框里(太长了,且费钱)。
RAG 的作用就是给大模型配了一个“超级图书管理员” :
- 用户提问 -> 2. 管理员(向量库)去书架翻书 -> 3. 找到关键那一页 -> 4. 递给大模型读 -> 5. 大模型回答。
2. 实战 Demo:打造“智能招聘顾问”
我们将使用 纯 Python + ChromaDB(向量库) + 火山引擎豆包(大模型 & Embedding) 来实现。
🛠️ 环境准备
Bash
pip install chromadb volcengine-python-sdk
💻 核心代码 (不到 100 行)
这个脚本模拟了一个真实场景:HR 系统里有几个特殊的内部岗位,我们希望 AI 能准确回答相关问题。
import os
import chromadb
from volcenginesdkarkruntime import Ark
# --- 1. 配置火山引擎 (大脑与眼睛) ---
# 请替换为你的真实 Key 和 Endpoint ID
os.environ["VOLC_API_KEY"] = "你的_API_KEY"
LLM_ID = "ep-xxxx-llm" # 豆包 Pro-1.6 (负责回答)
EMBED_ID = "ep-xxxx-embed" # 豆包 Embedding (负责把字变成数字)
client = Ark(api_key=os.environ.get("VOLC_API_KEY"))
chroma = chromadb.Client()
collection = chroma.get_or_create_collection(name="internal_jobs")
# --- 工具函数:调用火山引擎将文本转化为向量 ---
def get_embedding(text):
resp = client.embeddings.create(model=EMBED_ID, input=[text])
return resp.data[0].embedding
# --- 2. 知识入库 (模拟企业私有数据) ---
# 这里的薪资和代号是外界大模型绝对无法知道的“私有知识”
print("🏗️ 正在构建企业岗位数据库...")
jobs = [
"岗位:代号'夜鹰'后端开发。部门:秘密行动组。薪资:Base 50k + 期权。要求:精通 Rust,能接受封闭开发。",
"岗位:行政专员。部门:后勤部。薪资:8k-10k。要求:熟练使用 Excel,性格开朗,负责下午茶采购。",
"岗位:AI 训练实习生。部门:算法中台。薪资:500/天。要求:了解 RAG 原理,熟悉 Python,有论文发表优先。",
]
# 将文本变成向量,存入 ChromaDB
for i, job in enumerate(jobs):
vec = get_embedding(job)
collection.add(ids=[f"job_{i}"], embeddings=[vec], documents=[job])
print(f"✅ {len(jobs)} 个内部岗位已入库!\n")
# --- 3. RAG 核心流程 (检索 + 生成) ---
def ask_recruiter(question):
print(f"👤 用户提问: {question}")
# [Step A: 检索] 把问题变成向量,去数据库找答案
query_vec = get_embedding(question)
results = collection.query(query_embeddings=[query_vec], n_results=1)
# 获取找到的最相关的那段 JD
retrieved_info = results['documents'][0][0]
print(f"📖 向量库检索到的内部情报: {retrieved_info}")
# [Step B: 生成] 把“情报”和“问题”拼在一起,喂给大模型
prompt = f"""
你是一名招聘助手。请根据下面的【内部岗位信息】回答用户问题。
如果信息里没有,就说不知道。
【内部岗位信息】:
{retrieved_info}
【用户问题】:
{question}
"""
# [Step C: 回答]
resp = client.chat.completions.create(
model=LLM_ID,
messages=[{"role": "user", "content": prompt}]
)
return resp.choices[0].message.content
# --- 4. 效果演示 ---
if __name__ == "__main__":
# 测试 1:问一个模糊的意图
print("-" * 50)
answer1 = ask_recruiter("我想找个工资高、写代码的工作,最好是保密部门的")
print(f"\n🤖 AI 回答: {answer1}\n")
# 测试 2:问一个具体的福利
print("-" * 50)
answer2 = ask_recruiter("行政那边负责什么?")
print(f"\n🤖 AI 回答: {answer2}")
3. 运行结果解析
当你运行这段代码,你会看到类似这样的输出:
场景一:查询高薪保密岗位
用户提问: "我想找个工资高、写代码的工作..."
向量库检索: 找到了 "岗位:代号'夜鹰'...薪资:Base 50k..." 这条数据。
AI 回答: "推荐您申请 '夜鹰'后端开发 岗位。该岗位属于秘密行动组,薪资为 Base 50k 加期权,要求精通 Rust 并能接受封闭开发。"
💡 关键点:大模型本身不知道什么是“夜鹰”岗位,是 ChromaDB 找到了这条私有数据,喂给了大模型,大模型才能回答出来。
4. 总结:RAG 在开发中的三重价值
通过这个 Demo,我们可以清晰地看到 RAG 在 AI 系统中的角色:
✅ 1. 外挂知识库 (Long-term Memory)
大模型就像一个只读的硬盘,训练完数据就定死了。
RAG 是外接 USB 硬盘。企业的文档、最新的新闻、每天更新的数据库,都可以通过 RAG 实时“插入”给大模型,而无需重新训练模型。
✅ 2. 消除幻觉 (Grounding)
如果你问大模型“夜鹰岗位的薪资”,它可能会瞎编。
但在 RAG 模式下,我们强制要求它**“根据检索到的信息回答”**。如果向量库里没找到,它就会老实说不知道。这让 AI 在严肃场景(医疗、法律、招聘)变得可用。
✅ 3. 数据安全 (Privacy)
你的私有数据不需要传给大模型厂商去训练。数据只存在你本地的向量库(ChromaDB)里,只有在提问时,才会抽取相关的 一小段 发送给大模型进行推理。
一句话总结:
RAG = 搜索引擎(找资料) + 大语言模型(写报告)。它让通用的 AI 变成了懂你业务的专家。