
第八章:语义搜索与 RAG
在 BERT 之前 Google 只是关键词搜索,当你把程序的出错信息(特别是带有本地文件路径)往 Google 一贴,什么也搜索不出来,此时就能体现低级和高级程序员的不同水平。 现在形势不同,自从一篇 BERT 的论文(Pre-Training of Deep Bidirectional Transformers for Language Understanding) 发表(2018年) 数月后, Google 把
BERT整合进它的搜索引擎中,特别是加上各种 AI 工具,从此程序员不用再为出错信息而交流了。这就是语义搜索(semantic search)的威力.很早就听说过
RAG(Retrieval-Augmented Generation) 已过时的论调,然而实际学习 AI 时总也避不开RAG. 因为微调模型的少, 再加上模型的上下文窗口太小, 所以有了RAG, 持RAG过时之说大概是因为模型支持的上下文不断增大,原本以RAG片段作为提示词一部分的内容可以全部塞进上下文窗口中, 但对于长短期记忆和大量的资料库的检索,RAG仍然有其存在的价值。语义搜索和 RAG 是否也可以集成到 Lucene, Solr, Elasticsearch 等搜索引擎中,以提升搜索的准确性和效率呢?
语义搜索的几个概念和通常做法
- 稠密搜索(dense retrieval): 从向量数据库中搜索与当前文本向量相似的一些文档,比如 10 个文档. 稠密搜索就是粗泛的大面积快速搜索。
- 重排序(reranking): 对稠密搜索结果重排序(更精细的比较相似度),比如取前 3 个文档. 稠密搜索筛选,重排序进行精选,重排序也可让 LLM 介入. 有一个相关的论文 Multi-Stage Document Ranking with BERT, 常称作 monoBERT 方法
- RAG:通过包括资料分片,向量化存储,对输入向量化后检索相似文档,作为输入提供给 AI 模型,让 AI 基于它们生成结果的全过程

第七章:高级文本生成技术与工具
在上一章中已经从
AutoModelForCausalLM,AutoTokenizer,pipeline过渡到了稍微高那么一层的llama-cpp-python的使用, 这一章将继续学习LLM的使用, 到真正能训练,微调模型还远着呢。 其中大部分的内容都在学习LangChain的过程中有所掌握,包括记忆机制, 智能体工具调用等,所以这方面的内容没有具体展开。本章所覆盖的在不对模型作微调的情况下提升文本生成质量的方法论与技术:
- 模型输入/输出:模型加载与调用, 用 llama-cpp-python 演示
- 记忆机制:增强模型的上下文记忆能力,查看
LangChain短期记忆相关日志 LangChain 核心组件之短期记忆 - 智能体系统:整合外部工具实现复杂行为,用
LangChain1.0 后的create_agent()将会非常简单 - 链式架构:模块化方法与组件的衔接组合, 这是
LangChain0.x 的架构,1.0 后不再使用链式架构
本章进到
LangChain的学习当中,本人对LangChain已经有了一定程度的了解,由于LangChain1.0 于 2025 年 10 月份才正式发布, 显然写作本书的时候用的还是LangChain 0.x的版本,而LangChain1.0 带来了巨大的变化,所以学习当中会把书中的例子改写为LangChain 1.x的版本。下载 llama-cpp 的 GGUF 单文件模型: Phi-3-mini-4k-instruct-q4.gguf
Read More
第六章:提示词工程(Prompt Engineering)
还是继续学习怎么使用生成模型, 这本书也只能涉及到 Prompt Engineering 了, 另外两个高层次的 Content Engineering 和 Harness Engineering 必须找别的资料.
主要为文本生成而训练的模型通常被称为生成式预训练模型(Generative Pre-trained Transformers-GPT), 将要学习如何设计高效的提示词, 了解生成模型, 研究它们的推理, 输出的验证和评估.
由于使用了新的
transformers版本(5.8.0), 以下的代码与书中有所不同1from transformers import pipeline 2 3pipe = pipeline("text-generation", model="microsoft/Phi-3-mini-4k-instruct", trust_remote_code=False) 4messages = [ 5 {"role": "user", "content": "Create a funny joke about chickens."}, 6] 7output = pipe(messages) 8print(output)输出的信息包含
Read Moreuser和assistant两部分, 因为pipeline()有一个默认的参数return_full_text=True(同时返回用户和 LLM 的消息)
第五章:文本聚类与主题建模(Text Clustering and Topic Modeling)
继续巩固 LLM 的基础知识,文本聚类与主题建模是 NLP 中的两个概念,文本聚类就是文本按语义分类,如猫狗一块,苹果西瓜在一起,足球篮球放一堆, 而它们的分类名就是主题了,如动物,水果,体育。主题范围有大有小,水果可以延展到食物,体育可以缩小到球类,语义越相近,就离得越近,这其实就是物以类聚。
可用嵌入模型进行聚类,与文本聚类相关的主题建模方法是 BERTopic. 下面是用 Hugging Face 上的
arxiv_nlp数据集来进行本章的学习,Hugging Face 还真是一个宝藏啊,估计一些禁书都能在里面找到。arxiv_nlp包含了 1991 年到 2024 年来自 ArXiv cs.CL(计算与语言)板块 44949 篇摘要。1from datasets import load_dataset 2dataset = load_dataset("maartengr/arxiv_nlp")得到的 dataset 是
Read More
第四章:文本分类
文本分类(Text Classification) 是 NLP 中常见的任务之一,如不同语义的分类,动物,植物; 肉类,还是水果,蔬菜,开心还是悲伤,或业务分类等。 表示模型和生成模型在文本分类中的作用不容忽视。
下面是用预训练模型对 Hugging Face 上的电影评论数据集
rotten_tomatoes进行文本分类的测试。1from datasets import load_dataset 2data = load_dataset("rotten_tomatoes") 3print(data)里面包含三部分的数据
train训练集,validation验证集,test测试集。我们将用训练集训练模型,使用测试集来验证结果, 附加的验证集用来验证模型的泛化能力。rotten_tomatoes中记录有两个字段,分别为text: 电影评论文本label: 电影评论的标签,0 代表负面评论,1 代表正面评论。

前面差不多历经了 LangChain 学习和组件的以下底,中, 高三个阶段
- 底层的 LangGraph 的 GraphState, 是 LangChain 的基石,做一个 AI Agent 的内部表现形式就是一个状态图
- LangChain 的
init_chat_model(), Prompt Engineering, 用于一次性的与模型的对话,想要实现短长期记忆,工具调用,实现起来很麻烦,就得前进到下一层 - LangChain 的
create_agent(), Context Engineering, 有了开箱即用的短长期记忆,自动的工具调用,Human-in-the-loop, 并且也可以实现多 Agent - DeepAgents 的
create_deep_agent(), Harness Engineering, 要做一个完备功能的 Agent 就得靠它了,它自动提供了像计划,自动管理上下文 支持 Skills, 内置工具,需要处理复杂任务时自动启动子 Agent
下面就来探索一下它的内置的功能, 先分析一个最简单的例子看看背后发生了什么
依赖安装:
uv add deepagents langchain-ollama
Read Moredeepagents会连带安装langchain,langchain-anthropic,langchain-google-genai和wcmatch。langchain会安装它的传递依赖,像langchain-core,langgraph之类。langchain-ollama用来使用本地Ollama模型的。
第三章:LLM 的内部机制
这一章才是本书的最重要的部分,一个支撑现在大语言模型的基石,那就是 Transformer 模型, 占据了本书约 12% 的篇幅。学完分词与词嵌入后,现在开始探究 Transformer 模型的工作原理。我们把
Transformer LLM看成是一个接收文本输入并生成响应的系统, 模型总是在预测下一个 Token, 每个 Token 的生成都是模型的一次前向传播(forward pass). 在生成当前 Token 后,会将该生成的 Token 追加到输入序列中,作为下一次预测的输入( 或者说调整下次生成的提示词), 如此循环往复,逐个生成 Token,直到完成整段响应——这种机制称为自回归(autoregressive) 生成。这种使用生成的前一个 Token 又作为输入来生成下一个 Token 的模型被称为自回归模型(autoregressive model)。而 BERT 是双向(Bidirectional)编码模型。
前向传播的组成, 分词器后就是由
Read MoreTransformer堆叠而成的神经网络,最后是一个 LM head, 它负责将 Transformer 块的输出转换为 Token 的概率分数。
第一章:大语言模型简介
应该还是在前年读了 《Build a Large Language Model (From Scratch)》前面一小部分,就中断了, 如今又找来一本相关的书籍 《Hands-On Large Language Models》试着啃一啃,能明白多少是多少。拿着中英文的两个版本对照着看,有些中文翻译最好还是不译的好。 这里只会一些杂乱的笔记,算不得什么记要,重要的信息仍然在书上。
学习中相关的测试代码放在 GitHub 仓库 yabqiu/Hands-On-Large-Language-Models, 主要是在 macOS 苹果芯片上进行的测试。虽然官方有一个相应的仓库 HandsOnLLM/Hands-On-Large-Language-Models, 但作为沉浸式学习,亲自根据自己的口味撸一遍代码是非常必要的,所以也会发现我学习时的代码与书中不完全相同。
文字的计算机语义处理有过
Bag-of-words,word2vec,sequence-to-sequence, 再就是BERT,GPT这些概念了。 写作 "Attention Is All You Need" 这篇论文的作者们真是太伟大了,拿不到诺贝尔奖,也应该给他们个图灵奖,虽然其中的技术并非很高级, 但这篇论文在AI发展史中绝对有着里程碑式的意义。模型从大的功能分为
- 仅编码的表示模型(representation model),如种种嵌入模型,都比较小的,约几百兆大小, 像 BERT(bidirectional encoder representations from Transformers)
- 生成模型(generative model), 关注生成文本, 通常不会被训练用于生成嵌入, 像 GPT(Generative Pre-trained Transformer)

在往
Deep Agents的路径还要继续啃下一些基础知识,其中之一就是多 Agent 协作(Multi-agent)。复杂的系统需要多个Agent(智能体)同共完成, 不那么复杂的系统可以用动态的Prompt,Tool, 或Model来切换。多 Agent 的好处是每个 Agent 有自己的上下文,工具,专业领域的知识, 可以独立开发,分布式部署,多个 Agent 能并行执行,加速工作与烧钱的速度。LangChain在构建多 Agent 系统时,有以下几种常见模式:- Subagents(子 Agent): 主从 Agent 方式,子 Agent 作为主 Agent 的工具使用,由主 Agent 指挥子 Agent 干活
- Handoffs(任务交接): 任务可转交给(以 Tool 方式)其他 Agent,其他 Agent 的结果可直接返回给用户,
hand off就是传球的意思 - Skills(技能): 动态加载特定的 Prompt 和知识,用单一
Agent控制按需加载技能,本质上它是单 Agent - Router(路由):由一个路径控制任务如何分配给不同的 Agent,结果汇集成一个组合的响应
- Custom workflow(自定义工作流):用更底层的
LangGraph定制工作流程,以上模型均可嵌入到工作流中
下面贴上每种类型的组件和时序图(顺便给自己的 Hugo 加上
Read Moretabs标签页功能,以方便对比切换和节约滚动条)
一接触
LangChain就有种停不下来的感觉,在Deep Agents与底层的LangGraph之间,还是想把LangChain的核心组件搞明白一些, 本文是学习Streaming的笔记。Streaming给人的第一印象就是用ChatGPT聊天时机器回复时是一个字一个字蹦出来的,因为这就是LLM的思维方式,不断的预测下一个 Token.有个疑问: 这种预测下一个 Token 方式, 中国产的
LLM放到Ollama中运行是怎么实现的过滤敏感词的呢?前端一个字一个字蹦出来的效果反应到后台 API 响应(以 Ollama 为例)格式是
Content-Type为application/x-ndjson,这种格式是Newline Delimited JSON,即每行是一个 JSON 对象,以\n分隔,Transfer-Encoding为chunked,表示数据是以分块传输的,所以客户端只要一个个Chunk的输出就是那种效果了。从
LLM的那种流式(Chunk)输出也能体会出Markdown在逐字显示内容时的优势,自上而下,自然而然的清晰结构。下面是
Read MoreLangChain中使用ChatOllama模型时,服务端响应数据的片断: