从零开始:前端转型AI agent直到就业第五天-第十一天

0 阅读14分钟

前言

接近8.9年老前端了,34岁,双非普本,坐标广州,25年底被裁员,然后这三个月内也有去投简历,也有面试,有一些推进到二面然后就没有下文,不禁感叹现在的大环境实在不怎么样,而且前端在AI的冲击下也是最受影响的,除了音视频,图形化方面还能蹦跶一下,AI已经能完成80-90%的前端工作,在学历以及就业背景都不是特别强的情况下,一般的前端哪怕你技术还不错,你也很缺竞争力;在失业这三个月经历了持续学习、迷茫到看到曙光,决定要转型自学做AI agent;

大纲

  • 前一天心路历程
  • 前一天的时间分配(不限于学习,也会有运动)
  • 前一天的知识总结(前期或许较少)

心路历程

很久一段时间没有更新了,并不是断更了,而是慢慢地进入了状态,最近都是每天早上起来学习直到晚上

时间分配

一般早上8点起来学习到中午12点休息2-3个小时继续学习到晚上8点,然后开始整理文档发到博客

知识总结

不知不觉间,已经整理了很多相关的文档对于这个赛道的知识体系有一个粗略的认知并且有了一定的基础

image.png

今天发一下今天学到的知识体系发一下吧:

RAG检索增强生成

第一章:RAG 思想与核心价值

1.1 什么是 RAG?

通俗理解

想象一下:

你有一个非常聪明但有点健忘的朋友(大语言模型,LLM)。他知道很多常识,但如果你问他:“我们上周三开会时说了什么?” 他就傻眼了,因为他没有那天的记忆。

RAG 就是给这个朋友配了一个笔记本。每次你问问题,他先快速翻笔记本(检索),找到相关记录,然后结合自己的理解来回答你(生成)。

  • 没有 RAG:LLM 只靠训练时记住的知识回答 → 容易“已读乱回”(幻觉)或“已读不回”(知识陈旧)
  • 有了 RAG:LLM 先查你给的知识库,再基于这些知识回答 → 答案更准确、可溯源
官方定义

RAG(Retrieval-Augmented Generation,检索增强生成) 是一种将信息检索大语言模型生成能力相结合的技术架构。

核心公式:RAG = 检索(Retrieval) + 增强(Augmented) + 生成(Generation)

环节作用
检索从知识库中找到与问题相关的信息片段
增强把这些片段作为“上下文”注入到提示词中
生成LLM 基于增强后的提示词生成最终答案
RAG vs 微调(Fine-tuning)
对比维度RAG微调
知识更新只需更新知识库,无需重新训练需要重新训练模型
可解释性答案可追溯到原始文档难以追溯知识来源
实现成本低,无需 GPU 训练高,需要训练算力
实时性秒级生效小时/天级
适用场景知识频繁更新、私有文档问答改变模型风格、行为或学习特定格式

💡 一句话建议:想让模型知道新事实 → 用 RAG;想改变模型行为方式 → 考虑微调。


1.2 RAG 能解决什么问题?

问题说明RAG 如何解决
知识截止日期GPT-4 知识截止于 2023 年 10 月注入最新的文档(如今天的新闻)
模型幻觉LLM 会编造不存在的“事实”强制基于检索到的上下文回答
私有领域知识公司内部文档、产品手册、法律条文将这些文档作为知识库
动态更新知识每天变化(如股价、政策)只需更新向量库,秒级生效
答案可溯源用户想知道“你从哪里知道的”返回答案时可附带来源文档

1.3 RAG 工作流程全景图

RAG 分为两大阶段

阶段一:索引阶段(Indexing)—— 离线准备知识库
原始文档 → 文档加载 → 文本拆分 → 文本块 → 向量化 → 向量数据库
   │           │          │         │        │         │
 PDF/Word     读取     切分成块   小片段   转成向量   存储检索

这个阶段不需要用户等待,可以在后台定期执行(如每晚更新一次)。

阶段二:检索与生成阶段(Retrieval & Generation)—— 在线回答问题
用户问题 → 向量化 → 问题向量 → 向量数据库相似度搜索 → Top-K 相关文本块
                                                              ↓
最终答案 ← 大语言模型 ← 构建 Prompt(上下文 + 问题) ← ────────┘
一个完整的例子

假设你上传了一份《2024年公司休假政策》文档:

步骤阶段发生了什么
1索引文档被切分成块 → 向量化 → 存入向量库
2检索你问:“春节放假几天?” → 问题被向量化
3检索向量库找到最相关的文本块(含“春节假期7天”)
4生成Prompt = “根据上下文回答:春节放假几天? 上下文:春节假期7天...”
5生成LLM 回答:“根据公司政策,春节放假7天。”

第一章小结

核心概念一句话总结
RAG先查资料,再回答问题,让 LLM 有据可依
索引阶段离线准备知识库(文档→向量库)
检索+生成阶段在线回答问题(问题→检索→生成)
RAG vs 微调RAG 给知识,微调改能力

第二章:RAG 核心原理(纯概念,无代码)

本章只讲原理,不涉及任何代码或框架。所有 LangChain 实现放在第四章。

2.1 索引阶段原理

2.1.1 文档加载

目标:将各种格式的原始文档读取为程序可处理的纯文本。

挑战:不同格式有不同复杂度

格式挑战原理说明
PDF表格、图片、多列布局需要解析器提取文字流
Word复杂格式、嵌入对象需要解压并提取文本
Markdown标题层级需保留标题可作为结构信息
HTML标签噪声需去除标签,保留正文
纯文本最简单直接读取
2.1.2 文本拆分(Chunking)

为什么需要拆分?

  1. LLM 上下文窗口限制:模型一次能处理的文本长度有限
  2. 检索精度:小块更容易精准匹配问题,大块会引入噪声
  3. 成本控制:只发送相关片段,节省 token 费用

核心概念

概念含义示例
chunk_size单个文本块的最大长度500 字符 或 200 tokens
chunk_overlap相邻块之间的重叠长度50 字符,保留上下文连续性
separators优先切割的位置段落 > 句子 > 词语 > 字符

重叠的作用

文档: [A段开头...中间部分...B段结尾]
                    ↓
块1: [A段开头...中间部分]
块2: [中间部分...B段结尾]  ← 重叠部分防止信息被切断
2.1.3 文本向量化(Embedding)

什么是向量化?

将文本转换为固定维度的浮点数数组(向量),语义相似的文本在向量空间中距离更近

"苹果很好吃" → [0.12, -0.34, 0.56, ..., 0.78]  (1536维)
"水果很美味" → [0.11, -0.33, 0.55, ..., 0.79]  (距离很近,语义相似)

"汽车很快"   → [-0.45, 0.23, -0.67, ..., 0.12]  (距离很远,语义不同)

关键原则:索引阶段和检索阶段必须使用同一个 Embedding 模型,否则向量空间不匹配,无法正确比较。

2.1.4 向量数据库存储

存储的内容结构:

┌─────────────────────────────────────────────┐
│              向量数据库中的一条记录           │
├─────────────────────────────────────────────┤
│  向量:[0.12, -0.34, 0.56, ..., 0.78]       │
│  原始文本:"春节假期共7天"                    │
│  元数据:{"source": "holiday.pdf", "page": 3}│
└─────────────────────────────────────────────┘

2.2 检索与生成阶段原理

2.2.1 问题向量化

将用户问题用与索引阶段相同的 Embedding 模型转换为向量。

2.2.2 相似度搜索

常用相似度算法

算法直观理解公式
余弦相似度关注方向是否一致(最常用)`cos(θ) = (A·B)/(AB)`
欧氏距离关注绝对距离远近d = √Σ(Ai-Bi)²
点积向量已归一化时等价于余弦A·B

Top-K 检索:返回与问题向量最相似的 K 个文本块。

2.2.3 构建 Prompt

核心思想:将检索到的文本块作为“上下文”注入到提示词中。

标准 RAG Prompt 模板结构

你是一个基于以下上下文回答问题的助手。

<上下文>
{这里放检索到的相关文本块}
</上下文>

问题:{用户的问题}

请基于以上上下文回答。如果上下文中没有相关信息,请说"我不知道"。
2.2.4 LLM 生成

大语言模型接收包含“上下文+问题”的 Prompt,基于上下文生成答案,而不是依赖自己的训练记忆。


第二章小结

概念一句话解释
文本拆分把长文档切成小块,便于检索
chunk_size每块多大
chunk_overlap块之间重叠多少
向量化把文字转成数字数组
相似度搜索找最接近问题向量的文本块
Top-K返回最相似的 K 个块
Prompt把“上下文+问题”打包发给 LLM

第三章:向量数据库选型

3.1 为什么需要向量数据库?

传统数据库(如 MySQL)无法高效进行向量相似度搜索

能力传统数据库向量数据库
精确匹配✅ 快❌ 不支持
模糊搜索⚠️ 慢❌ 不支持
向量相似度❌ 不支持✅ 快
标量过滤✅ 支持✅ 支持(多数)

向量数据库专为向量搜索设计,提供:

  • 高效索引:HNSW、IVF 等算法实现毫秒级搜索
  • 相似度计算:内置余弦、欧氏距离等
  • 混合搜索:向量 + 标量过滤

3.2 常用向量数据库对比

数据库类型性能易用性扩展性最佳场景
Chroma嵌入式中等⭐⭐⭐⭐⭐学习原型、小项目
FAISS⭐⭐⭐本地研究、无需持久化
PgvectorPostgreSQL扩展中高⭐⭐⭐⭐已有 PostgreSQL 栈
Milvus云原生极高⭐⭐极高十亿级向量生产环境
Redis内存数据库极高⭐⭐⭐⭐超低延迟场景
Elasticsearch搜索引擎⭐⭐⭐需要混合搜索
各数据库详解

Chroma

  • 轻量级,纯 Python,API 极其简单
  • 数据持久化到本地磁盘
  • 适合:学习 RAG、原型验证、小规模应用

FAISS

  • Facebook 开源,C++ 核心,性能强悍
  • 本质是库而非完整数据库(无持久化,需自己管理)
  • 适合:学术研究、本地实验、对性能要求高但不需分布式

Pgvector

  • PostgreSQL 官方扩展,SQL 语法操作向量
  • 复用现有 PG 基础设施(备份、高可用、权限)
  • 适合:团队已有 PostgreSQL,不想引入新组件

Milvus

  • 云原生架构,支持十亿级向量
  • 功能最全:混合搜索、动态 schema、多副本
  • 适合:大规模生产系统、需要分布式扩展

Redis

  • 内存级速度,毫秒级响应
  • 支持向量搜索作为辅助功能
  • 适合:超低延迟场景、已有 Redis 基础设施

Elasticsearch

  • 老牌搜索引擎,现支持向量
  • 最大优势:关键词搜索 + 向量搜索混合
  • 适合:需要同时支持精确关键词匹配和语义匹配

3.3 选型决策树

开始
  │
  ├─ 只是学习/原型 → Chroma
  │
  ├─ 已有 PostgreSQL → Pgvector
  │
  ├─ 十亿级向量 / 云原生 → Milvus
  │
  ├─ 需要超低延迟(<10ms)→ Redis
  │
  ├─ 需要关键词+向量混合 → Elasticsearch
  │
  └─ 本地研究/高性能 → FAISS

第四章:LangChain 实战(精简版)

本章只讲核心常用代码,次要内容简要带过。

4.1 环境准备

pip install langchain langchain-community chromadb openai tiktoken
# 按需安装:unstructured pypdf docx2txt jq redis dashscope

4.2 核心组件速览

组件作用常用类
文档加载器读取各种格式文档TextLoader, PyPDFLoader, CSVLoader, Docx2txtLoader, JSONLoader
文本分割器切分长文档RecursiveCharacterTextSplitter(首选)
Embedding模型文本向量化OpenAIEmbeddings, HuggingFaceEmbeddings, DashScopeEmbeddings
向量数据库存储与检索Chroma(学习), Redis(生产), FAISS(本地)
检索器查询相关文档as_retriever(k=4)
LLM生成答案ChatOpenAI, init_chat_model(阿里千问)
Prompt模板组装提示词PromptTemplate, ChatPromptTemplate

4.3 文档加载器(常用示例)

# 纯文本
from langchain_community.document_loaders import TextLoader
loader = TextLoader("file.txt", encoding="utf-8")
docs = loader.load()

# PDF
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("file.pdf", extraction_mode="plain")
docs = loader.load()

# Word
from langchain_community.document_loaders import Docx2txtLoader
loader = Docx2txtLoader("file.docx")
docs = loader.load()

# CSV
from langchain_community.document_loaders.csv_loader import CSVLoader
loader = CSVLoader(file_path="file.csv")
docs = loader.load()

# JSON
from langchain_community.document_loaders import JSONLoader
loader = JSONLoader(file_path="file.json", jq_schema=".", text_content=False)
docs = loader.load()

其他加载器(Markdown、HTML、目录批量等)用法类似,按需查阅文档。

4.4 文本分割器

from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,      # 每块最大字符数
    chunk_overlap=50,    # 块间重叠
)
chunks = splitter.split_documents(docs)

4.5 Embedding 模型

# OpenAI
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")

# HuggingFace 本地(中文推荐)
from langchain_community.embeddings import HuggingFaceEmbeddings
embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-large-zh")

# 阿里千问
from langchain_community.embeddings import DashScopeEmbeddings
embeddings = DashScopeEmbeddings(model="text-embedding-v3", dashscope_api_key=api_key)

4.6 向量数据库

# Chroma(学习推荐)
from langchain_community.vectorstores import Chroma
vector_store = Chroma.from_documents(chunks, embeddings, persist_directory="./db")
vector_store.persist()

# Redis(生产推荐)
from langchain_community.vectorstores import Redis
vector_store = Redis.from_documents(docs, embeddings, redis_url="redis://localhost:6379", index_name="my_index")

# FAISS(本地快速)
from langchain_community.vectorstores import FAISS
vector_store = FAISS.from_documents(chunks, embeddings)
vector_store.save_local("./faiss_index")

4.7 检索器

retriever = vector_store.as_retriever(search_kwargs={"k": 4})  # 返回 Top-4

4.8 LLM 模型

# OpenAI
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)

# 阿里千问
from langchain.chat_models import init_chat_model
llm = init_chat_model(model="qwen-plus", model_provider="openai", api_key=api_key, base_url="https://dashscope.aliyuncs.com/compatible-mode/v1")

4.9 Prompt 模板

from langchain_core.prompts import PromptTemplate

template = """基于以下上下文回答问题:
上下文:{context}
问题:{question}"""
prompt = PromptTemplate(template=template, input_variables=["context", "question"])

4.10 完整 RAG Chain

from langchain_core.runnables import RunnablePassthrough

def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)

rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | prompt
    | llm
)

result = rag_chain.invoke("你的问题")
print(result.content)

4.11 完整问答实例(阿里千问 + Redis)

# complete_rag_example.py
import os
from langchain.chat_models import init_chat_model
from langchain_community.document_loaders import Docx2txtLoader
from langchain_core.prompts import PromptTemplate
from langchain_classic.text_splitter import CharacterTextSplitter
from langchain_core.runnables import RunnablePassthrough
from langchain_community.embeddings import DashScopeEmbeddings
from langchain_community.vectorstores import Redis

# 1. 初始化 LLM
llm = init_chat_model(
    model="qwen-plus",
    model_provider="openai",
    api_key=os.getenv("aliQwen-api"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)

# 2. Prompt 模板
prompt_template = """
请使用以下提供的文本内容来回答问题。仅使用提供的文本信息,
如果文本中没有相关信息,请回答"抱歉,提供的文本中没有这个信息"。

文本内容:{context}
问题:{question}
回答:
"""
prompt = PromptTemplate(template=prompt_template, input_variables=["context", "question"])

# 3. Embedding
embeddings = DashScopeEmbeddings(model="text-embedding-v3", dashscope_api_key=os.getenv("aliQwen-api"))

# 4. 加载文档
loader = Docx2txtLoader("alibaba-java.docx")
documents = loader.load()

# 5. 分割文档
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)

# 6. 创建 Redis 向量库
vector_store = Redis.from_documents(
    documents=documents,
    embedding=embeddings,
    redis_url="redis://localhost:6379",
    index_name="my_index",
)

# 7. 检索器
retriever = vector_store.as_retriever(search_kwargs={"k": 2})

# 8. RAG Chain
def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)

rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | prompt
    | llm
)

# 9. 提问
result = rag_chain.invoke("00000和A0001分别是什么意思")
print(result.content)

第五章:参数调优与最佳实践

5.1 核心参数调优指南

chunk_size 选择
文档类型推荐值原因
产品问答200-300 字符每个问答短小精悍
技术文档500-800 字符段落通常较长
法律条文300-500 字符条款需保持独立
长篇文章1000-1500 字符保持上下文连贯
chunk_overlap 设置
chunk_overlap = chunk_size × (10% ~ 20%)
Top-K 选择
K 值适用场景优点缺点
3答案集中在少数段落精准可能遗漏信息
5通用推荐平衡-
10需要广泛上下文信息全面噪声增多,成本增加

5.2 进阶优化技术(简介)

技术一句话说明
多查询检索将问题改写成多个角度,分别检索后合并
父文档检索存小块(精准匹配),返回大块(完整上下文)
自查询检索从问题中提取语义条件 + 元数据过滤条件
重排序检索更多结果,用更强模型重新排序取 Top-K

5.3 常见问题排查

问题可能原因解决方案
答案不相关chunk 太大含噪声减小 chunk_size
丢失关键信息chunk 太小切断上下文增大 chunk_sizeoverlap
检索不到问题表述与文档不匹配使用多查询检索
回答“不知道”但有文档Embedding 模型不适合中文BAAI/bge-large-zh
速度慢向量库太大添加索引、使用 GPU
成本高Top-K 或 chunk 太大减小 K 和 chunk_size

5.4 推荐起步配置

splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
retriever = vector_store.as_retriever(search_kwargs={"k": 4})

目标

成为AI agent工程师并且就业

帮助

需要大家的关注跟点赞,你们的关注点赞就是对我最大的鼓励,或许以后待以后我技术成熟时,你们中间的大佬还可以捞一捞我,感谢