文章目录

LangChain

LangChain 是一个开源框架,专门用来简化大型语言模型(LLM)应用的开发,帮你快速把模型能力接 入实际业务。它的核心价值在于降低集成成本,让开发者无需从零搭建就能实现复杂功能。

发展历程

2022年10月:作为 Python 工具发布。

2023年2月:支持 TypeScript。

2023年4月:扩展至多种 JavaScript 环境。

2025年11月:OceanBase AI 数据库兼容 LangChain。

典型应用场景

自动化任务 :邮件分类、合同审查、会议纪要生成。

多模态应用 :图像描述、语音助手。

代码辅助 :生成、解释或调试代码。

个性化推荐 :定制化内容生成。

核心组件

  • 模型接口 :支持 OpenAI、Anthropic 等主流 LLM,方便切换和扩展。
  • 提示模板 :预设结构化提示词,提升生成效果和一致性。
  • 链(Chains) :串联多个步骤,支持条件和循环逻辑,适合复杂任务。
  • 代理(Agents) :动态调用工具(如搜索、API),实现自动化操作。
  • 记忆模块 :短期和长期记忆结合,增强上下文理解。
  • 数据索引 :连接外部数据源(如数据库、PDF),提升生成准确性。

会话模板

LangChain 提供了灵活的会话模板系统,支持多轮对话和上下文管理。

ChatPromptTemplate

在 LangChain 里:

  • PromptTemplate:用于单轮文本提示(prompt)
  • ChatPromptTemplate:用于多轮对话(system / human / ai)

👉 ChatPromptTemplate = 对话剧本 + 可替换变量

1.导入 ChatPromptTemplate

from langchain_core.prompts import ChatPromptTemplate

这是 LangChain 最核心的 Prompt 组件之一,不依赖具体模型(OpenAI、Claude、Qwen 都能用)。

2.定义 messages(对话模板)

messages = [
('system','你是一位智者,你的名字是{name}'),
('human','你好{name},你感觉如何?'),
('ai','你好!我的状态非常好!'),
('human','你叫什么名字呢?'),
('ai','我叫{name}'),
('human','{user_input}')
]

这里是重点 👇

(1)消息角色说明
角色 含义
system 系统设定(人设、规则)
human 用户输入
ai AI 的历史回答
(2)这是一个「已存在历史对话」的模板

你不是只写一句 prompt,而是:

  • AI 已经有人设

  • 已经有历史对话

  • 当前用户再继续说一句话 {user_input}

👉 非常适合 对话机器人 / Agent / Chat 记忆场景

(3) {} 是占位符(变量)
{name}
{user_input}

这些变量会在 运行时替换

3.用 messages 创建会话模板

prompt = ChatPromptTemplate.from_messages(messages)

这一句的作用:

把“对话结构 + 变量占位符”变成一个 可复用的 Prompt 对象

4.传入参数,生成最终消息

print(prompt.format_messages(
    name='guo',
    user_input='你的朋友是谁呢?'
))

发生了什么?

  • {name} → ‘guo’

  • {user_input} → ‘你的朋友是谁呢?’

最终输出的是:

👉 一组 Message 对象列表(不是普通字符串)

运行后的实际效果

等价于下面这段“真实对话”:

System: 你是一位智者,你的名字是 guo
Human: 你好 zhang, 你感觉如何?
AI: 你好!我的状态非常好!
Human: 你叫什么名字呢?
AI: 我叫 guo
Human: 你的朋友是谁呢?

⚠ 这正是 大模型最喜欢的输入格式

from langchain_core.prompts import ChatPromptTemplate

message = [
    ('system','你是一位智者,你的名字是{name}'),
    ('human','你好{name},你感觉如何?'),
    ('ai','你好!我的状态非常好!'),
    ('human','你叫什么名字呢?'),
    ('ai','我叫{name}'),
    ('human','{user_input}')
]

prompt=ChatPromptTemplate(message)
print(prompt.format_messages(name='guo',user_input='你的朋友是谁'))
[SystemMessage(content='你是一位智者,你的名字是guo', additional_kwargs={}, response_metadata={}), HumanMessage(content='你好guo,你感觉如何?', additional_kwargs={}, response_metadata={}), AIMessage(content='你好!我的状态非常好!', additional_kwargs={}, response_metadata={}, tool_calls=[], invalid_tool_calls=[]), HumanMessage(content='你叫什么名字呢?', additional_kwargs={}, response_metadata={}), AIMessage(content='我叫guo', additional_kwargs={}, response_metadata={}, tool_calls=[], invalid_tool_calls=[]), HumanMessage(content='你的朋友是谁', additional_kwargs={}, response_metadata={})]

为什么要用 ChatPromptTemplate?(而不是字符串拼接)

传统方式(不推荐)
prompt = f"""
你是一位智者,你的名字是 guo
你好 guo,你感觉如何?
...
"""

问题:

  • 不支持多角色
  • 不利于 Agent / Memory
  • 不可组合
ChatPromptTemplate 的优势
优点 说明
多轮对话 原生支持 system/human/ai
变量安全 自动校验缺失变量
可组合 可与 Memory / Chain / Agent 结合
模型无关 OpenAI / Claude / 本地模型都能用

示例

from langchain_core.prompts import ChatPromptTemplate

message = [
    ('system','你是一位智者,你的名字是{name}'),
    ('human','你好{name},你感觉如何?'),
    ('ai','你好!我的状态非常好!'),
    ('human','你叫什么名字呢?'),
    ('ai','我叫{name}'),
    ('human','{user_input}')
]

# #会话模板
prompt=ChatPromptTemplate(message)
#参数传入
print(prompt.format_messages(name='guo',user_input='你的朋友是谁'))

LangChain Message

这是 LangChain 体系里最底层、最稳定的抽象。

底层原理

SystemMessage —— 系统指令(人格 + 规则)
sy=SystemMessage(
    content="你是一个智能体",
    additonal_kwargs={"智能体名字": 'guo'}
)

SystemMessage 的作用

  • 给模型设定身份 / 行为规则

  • 权重最高(一般模型不会轻易违背)

等价于对模型说:

“接下来你必须按这个身份来回答

additional_kwargs 是什么?
additional_kwargs={'智能体名字':'guo'}

这是一个 扩展字段

  • 不一定会被模型“直接理解”

  • 但会在 Agent / Tool / 自定义模型 中非常有用

  • 常用于:

    • 存 metadata

    • 标注角色

    • 业务标识

👉 模型输入 = content

👉 系统/程序用 = additional_kwargs

HumanMessage —— 用户输入

hu=HumanMessage(
    content='请问你叫什么名字'
)

代表真实用户的一次提问。

在聊天模型里等价于:

User: 请问你叫什么名字
AIMessage —— AI 的历史回复
ai=AIMessage(
    content="我的名字叫guo"
)

表示:

  • 这是 已经发生过的一次 AI 回答

  • 常用于:

    • 构造对话上下文

    • 回放历史

    • 测试 / 回放日志

打印结果说明了什么?
for msg in[sy,hu,ai]:
    print(msg.type,msg.content)

你打印的是:

一个标准的 Chat Messages List

👉 这是 ChatModel / Agent / Memory 的通用输入

Message vs PromptTemplate(非常关键)

❓ 什么时候用

Message?

场景 推荐
精细控制历史对话 ✅ Message
Agent / Tool ✅ Message
手动构造上下文 ✅ Message
❓ 什么时候用ChatPromptTemplate?
场景 推荐
带变量的模板 ✅ Prompt
批量生成 ✅ Prompt
少写重复代码 ✅ Prompt
实际项目中:二者结合
PromptTemplate → 生成 messages
Message → 直接拼历史 / 插 Memory

Message 在真实项目里的典型用法

1.构造一段“完整对话历史”

messages = [
    SystemMessage(content='你是一个智能体'),
    HumanMessage(content='你好'),
    AIMessage(content='你好,有什么可以帮你?'),
    HumanMessage(content='你叫什么名字?')
]

👉 直接喂给模型即可

2.从 PromptTemplate 转成 Message(底层一致)

from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
   ('system', '你是一个智能体'),
   ('human', '{question}')
])
msgs = prompt.format_messages(question='你叫什么名字?')

Message 的 type 属性(调试必会)

for msg in [sy, hm, ai]:
    print(msg.type, msg.content)

输出类似

system 你是一个智能体
human 请问智能体叫什么名字?
ai 我叫guo

👉 模型内部就是靠 type 区分角色

示例

from langchain_core.messages import SystemMessage,HumanMessage,AIMessage

sy=SystemMessage(
    content="你是一个智能体",
    additonal_kwargs={"智能体名字": 'guo'}
)

hu=HumanMessage(
    content='请问你叫什么名字'
)

ai=AIMessage(
    content="我的名字叫guo"
)

for msg in[sy,hu,ai]:
    print(msg.type,msg.content)

下面我只围绕你这段代码,给你写一份从“为什么存在 怎么用 什么时候用”的完整教程

这一步其实已经进入 LangChain Prompt 体系里很高级、但非常有价值的部分了。

ChatMessagePromptTemplate

创建一条“自定义角色”的消息模板,并在运行时把变量填进去,生成一条 Message

这不是普通的 system / human / ai,而是你自己定义的角色

导入

from langchain_core.prompts import (
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
    AIMessagePromptTemplate,
    ChatMessagePromptTemplate,
)

这里导入了 四种 MessagePromptTemplate:

类名 用途
SystemMessagePromptTemplate system 角色模板
HumanMessagePromptTemplate human 角色模板
AIMessagePromptTemplate ai 角色模板
ChatMessagePromptTemplate 自定义角色模板 ⭐

定义带变量的模板字符串

prompt = '有一种英雄主义就是在认清{subject}的真相后,依然热爱{subject}。'

这里:

  • {subject} 是 占位符

  • 同一个变量可以出现多次

  • 会在 format 时统一替换

创建“自定义角色”的消息模板(重点)

chat_message_prompt=ChatMessagePromptTemplate.from_template(
    template=prompt,
    role='张无忌'
)

这是本示例的核心

ChatMessagePromptTemplate 的意义

它允许你:

  • 自定义角色名(不局限 system / human / ai)

  • 构造 多智能体 / 剧情 / 旁白 / 工具角色

这里的角色是:

role='张无忌'

这在 Message 层会表现为:

type ='张无忌'

运行时传参,生成 Message

print(chat_message_prompt.format(subject='江湖'))

这一步发生了什么?

  • {subject} → ‘江湖’

  • 返回的是 一条 Message 对象

Message 的结构大致是:

role: 张无忌
content: 有一种英雄主义就是在认清江湖的真相后,依然热爱江湖。

示例:

from langchain_core.prompts import ChatMessagePromptTemplate

prompt='有一种英雄主义就是在认清{subject}的真相后,依然热爱{subject}。'

chat_message_prompt=ChatMessagePromptTemplate.from_template(
    template=prompt,
    role='张无忌'
)

print(chat_message_prompt.format(subject='江湖'))

为什么要用 ChatMessagePromptTemplate?(核心价 值)

❓ 不能用 AIMessagePromptTemplate 吗?

可以,但不够强。

方式 限制
AIMessagePromptTemplate 只能是 ai
ChatMessagePromptTemplate 任意角色名 ⭐
把它放进真实对话里(进阶用法)

现在只生成了一条 Message,

真实项目一定是“多条Message组合”

示例:和 system / human 一起用

from langchain_core.prompts import(
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
    ChatPromptTemplate
)

chat_prompt=ChatPromptTemplate.from_messages([
    SystemMessagePromptTemplate.from_template(
        '你正在扮演一部{subject}世界'
    ),
    HumanMessagePromptTemplate.from_template(
        "请发表一句{subject}感悟"
    ),
])

messages=chat_prompt.format_messages(subject='江湖')

for m in messages:
    print(m.type,":",m.content)

和 Message 的关系(必须搞清)

PromptTemplate → Message 的转化关系

ChatMessagePromptTemplate
       ↓ format()
ChatMessage (Message)
       ↓
ChatModel / Agent

PromptTemplate 永远不会直接喂模型

喂模型的永远是 Message

好,这一步我们就真的把「梅长苏」交给模型

目标只有一个:

你构造的自定义角色 Message,如何真正驱动大模型说话

我会用最清晰、最短路径带你走完这一跳。

模型(完整实战)

整体流程

字符串(固化)->模版(参数)->斗轮对话(角色)->会话(字符串)->消息模版

ChatMessagePromptTemplate
       ↓ format()
Message(role=梅长苏)
       ↓
ChatModel(如 ChatOpenAI)
       ↓
AIMessage(模型输出)

你前面已经完成了 80%,现在只补最后 20%。

准备工作:需要的包

如果你用 OpenAI / 兼容接口:

pip install langchain-core langchain-openai

完整示例代码

导入(全部是最新路径)

from langchain_core.prompts import(
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
    ChatPromptTemplate
)

构造完整对话 Prompt

chat_prompt=ChatPromptTemplate.from_messages([
    SystemMessagePromptTemplate.from_template(
        '你正在扮演一部{subject}世界'
    ),
    HumanMessagePromptTemplate.from_template(
        "请发表一句{subject}感悟"
    ),
])

SystemMessage 在这里起的是**“锁人格”**的作用

没有它,模型容易跑偏

把 Prompt 变成真正的 Message

messages=chat_prompt.format_messages(subject='江湖')

你此刻得到的是类似:

system : 你正在扮演一部江湖世界
human : 请发表一句江湖感悟

初始化模型(真正“交给模型”的瞬间)

llm = ChatOpenAI(
    model="gpt-4o-mini",  # 示例,可换
    temperature=0.7
)

调用模型,获取回复

response = llm.invoke(messages)
print(response.content)

增强检索

增强检索(Enhanced Retrieval)通常指在信息检索或大模型应用中,通过更聪明的检索+ 更好的上下文组织,显著提升答案的准确性、相关性和可解释性。最常见的落地形态就是 RAG(Retrieval Augmented Generation,检索增强生成)

1.为什么需要增强检索?

传统大模型的问题:

  • ❌ 只靠参数记忆,不掌握你自己的数据

  • ❌ 容易“幻觉”

  • ❌ 无法实时更新知识

增强检索的目标:

先把“对的资料”找出来,再让模型基于资料回答

2.典型架构(RAG标准流程)

用户问题
   ↓
Query 改写 / 扩展(可选)
   ↓
向量化(Embedding)
   ↓
向量数据库检索(Top-K)
   ↓
结果重排(Re-ranking)
   ↓
上下文拼接(Context Window)
   ↓
LLM 生成答案

3.关键“增强”点

查询增强(Query Enhancement)

让“问题”更适合被检索:

  • 同义词扩展
  • 多语言转换
  • 多 Query 并行检索(Multi-Query)

示例:

用户: K8s 网络问题

→ 扩展为:

  • Kubernetes CNI
  • Pod 网络通信
  • Service 网络原理

检索增强(Hybrid Retrieval)

不要只用向量检索

常见组合:

  • 向量检索(语义)
  • 关键词检索(BM25)
  • 结构化过滤(时间 / 标签 / 权限)

👉 Hybrid Search = 真实生产必选

重排增强(Re-ranking)

第一轮检索只是“可能相关”

第二轮用更强模型排序:

  • Cross-Encoder
  • LLM Re-ranker

效果:

👉 Top-5 质量 ≫ Top-50 原始结果

上下文增强(Context Engineering)

不是“拼越多越好”:

  • Chunk 粒度控制(200–500 tokens)
  • 去重
  • 保留标题 / 来源
  • 加引用标记(source id)

生成约束(Grounded Generation)

强制模型:

  • 只基于提供内容回答
  • 找不到就说“不知道”

Prompt 示例:

仅根据以下资料回答问题,
如果资料中没有答案,请明确说明“资料不足”。

4.常见技术栈

  • Embedding:OpenAI / BGE / E5
  • Vector DB:FAISS / Milvus / Weaviate
  • Keyword:Elasticsearch / OpenSearch
  • Orchestration:LangChain / LlamaIndex
  • API:FastAPI + Redis
  • 部署:Docker + K8s

5.增强检索 ≠ 只为大模型

同样适用于:

  • 企业知识库
  • 代码搜索
  • 运维故障定位
  • 日志 / 文档问答

LangChain 文本切分

从本地 txt 文件 → 自动识别编码 → 使用 LangChain 进行文本切分

这是 RAG / AI Agent 的第一步。

1.、为什么要做文本切分?

RAG(检索增强生成) 中,大模型不能直接吃下整篇长文档:

  • LLM 有 上下文长度限制
  • 检索是 按“文本块(chunk)”进行
  • 文本过大 → 检索不准 / 成本高

👉 所以必须先 切分文档

2.环境准备

安装依赖(新版 LangChain)

pip install -U langchain langchain-text-splitters chardet

正确导入(重点)

from langchain_text_splitters import RecursiveCharacterTextSplitter
import chardet

旧写法已废弃

from langchain.text_splitter import RecursiveCharacterTextSplitter  # 不推荐

3.完整示例代码

from langchain_text_splitters import RecursiveCharacterTextSplitter
import chardet

# 文件路径
file_path= 'text2/story.txt'

# 获取文本字符集
def get_encoding(file_path):
    with open(file_path, 'rb') as f:
        data=f.read()
        encoding = chardet.detect(data)['encoding']
        return encoding

# 获取数据
with open(file_path, 'r',encoding=get_encoding(file_path)) as f:
    data=f.read()

# 文件切分器
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=50,        # 每个文本块最大长度(字符数)
    chunk_overlap=20,     # 相邻文本块的重叠长度
    length_function=len,  # 长度计算函数(中文用 len 即可)
    add_start_index=True  # 是否记录原文起始位置
)

# 执行文本切分
docs=text_splitter.create_documents([data])

# 输出切分结果
for i in docs:
    print(i)

4.切分器参数逐个解释

chunk_size

chunk_size=50

含义:

  • 每个文本块的 最大字符数
  • 太大 → 检索不精确
  • 太小 → 上下文碎片化

📌 经验值

场景 推荐
中文文档 300-800
英文文档 500-1000
代码 200-400

chunk_overlap

chunk_overlap=20

含义:

  • 相邻文本块 重复的字符数
  • 防止语义被“切断”

示意:

chunk1: ABCDEFGHIJ
chunk2: HIJKLMNOP

📌 一般设置为 chunk_size 的 10%~30%

length_function

length_function=len
  • len :按字符数(中文推荐)
  • 英文 + token 场景可换成 tokenizer

add_start_index=True

add_start_index=True

切分后 Document 会包含:

doc.metadata["start_index"]

📌 用途:

溯源(告诉用户“答案来自哪一段”)

很好,这一步非常关键 👍

你已经从 递归字符切分 走到了 字符切分(CharacterTextSplitter,这是理解 RAG 切分原理的分水岭。

下面我接着你的代码,把 CharacterTextSplitter 字符切割写成一篇完整教程,并且会 对比RecursiveCharacterTextSplitter,让你真正“懂为什么要用哪个”。

LangChain 字符切割

使用 CharacterTextSplitter 按指定分隔符(中文逗号)切分文本

适合结构规则、格式统一的文本。

1.什么是 CharacterTextSplitter?

CharacterTextSplitter 是“最基础、最可控”的文本切分器。

一句话理解:

按你指定的分隔符切文本,再控制每块长度和重叠

不会智能判断语义,而是 严格按规则执行。

2.什么时候该用 CharacterTextSplitter?

✅ 适合场景:

  • 文本结构非常规则
  • 有明确分隔符:
    • 中文:
    • 英文:. \n
  • 日志、配置、对话、FAQ

❌ 不适合:

  • 长文档
  • 自然语言段落复杂
  • 小说 / 技术文档

3.环境准备

pip install -U langchain-text-splitters chardet

导入:

from langchain_text_splitters import CharacterTextSplitter
import chardet

4.完整示例代码(逐行讲解)

from langchain_text_splitters import CharacterTextSplitter
import chardet

# 文件路径
file_path='./text2/story.txt'

# 获取文本字符集
def get_encoding(file_path):
    with open(file_path, 'rb') as f:
        data=f.read()
        encoding = chardet.detect(data)['encoding']
        return encoding

# 获取数据
with open(file_path, 'r',encoding=get_encoding(file_path)) as f:
    data=f.read()

# 文件切分器
text_splitter = CharacterTextSplitter(
    separator='.',             # 指定分隔符(英文句号)
    chunk_size=50,             # 每个文本块最大长度
    chunk_overlap=20,          # 相邻文本块重叠部分
    length_function=len,       # 长度计算方式
    add_start_index=True,      # 记录原文起始索引
    is_separator_regex=False   # 分隔符是否为正则
)

# 执行切分
docs=text_splitter.create_documents([data])

# 查看切分结果
for i in docs:
    print(i)

5.CharacterTextSplitter

参数详解

separator

separator='.'

含义:

  • 用什么字符来“切”
  • 不包含在结果文本中

常见示例:

文本类型 separator
中文句子
中文短句
英文句子 .
段落 \n\n

chunk_size

chunk_size=50
  • 控制单个 chunk 最大长度

  • 超过会继续拆分

📌 字符切分时:

chunk_size 是硬约束

chunk_overlap

chunk_overlap=20

作用:

  • 防止上下文断裂

  • 保留语义连续性

📌 一般设置为 chunk_size 的 20% 左右

add_start_index

add_start_index=True

切分后 Document.metadata 会包含:

{'start_index': 123}

👉 RAG 溯源 / 高亮定位必备

is_separator_regex

is_separator_regex=False
False(当前)
  • separator被当作普通字符串

  • ',' 就是中文逗号

True(高级)
separator=r'[,。;]'
is_separator_regex=True

👉 可用正则 多分隔符切割

6.与 RecursiveCharacterTextSplitter 对比(非常重要)

项目 Character Recursive
是否智能
是否可控
语义完整性 一般
使用场景 规则文本 自然语言
RAG 推荐度 ⭐⭐ ⭐⭐⭐⭐⭐

👉 真实项目中 90% 用 Recursive

太好了 👍

你已经进入 RAG / Agent 中“最容易拉开差距的一块”——代码文档切割

下面我承接你这段代码,写一篇完整、工程向的「代码文档切割教程」,并结合 为什么它对程序员Agent 非常重要

LangChain 代码文档切割

使用 RecursiveCharacterTextSplitter.from_language 按编程语言结构切割代码

这是构建 代码问答 / Code Agent / 自动代码分析 的基础。

1.为什么“代码”不能用普通文本切割?

如果用普通文本切割代码,会出现问题:

❌ 语义被破坏

for i in range(1,
11):

❌ 函数 / 类被切散

❌ Agent 无法理解上下文

👉 代码有结构,必须“按语言规则切"

2.LangChain 是怎么支持“代码切割”的?

LangChain 内置了 多语言代码解析规则,核心就是:

RecursiveCharacterTextSplitter.from_language(...)

它会根据语言,优先按:

  • 函数
  • 代码块
  • 空行
  • 缩进

进行 递归切割

3.支持的编程语言

from langchain_text_splitters import Language
print([e.value for e in Language])

常见输出(示例):

['python', 'java', 'js', 'go', 'cpp', 'html', 'markdown', 'sql', ...]

📌 熟悉的 Python / Java / Go

4.完整示例代码

from langchain_text_splitters import(
    Language,
    RecursiveCharacterTextSplitter
)

# print([i.value for i in Language])

PYTHON_CODE='''
def sum()
    a=0
    for i in range(1,11):
        a+=i
    print(a)
    
sum()
'''

# 创建分割器
code_splitter=RecursiveCharacterTextSplitter.from_language(
    language=Language.PYTHON,  # 指定语言
    chunk_size=50,             # 每个代码块最大长度
    chunk_overlap=10,          # 代码块重叠
)

python_docs=code_splitter.create_documents([PYTHON_CODE])

# 解析
for i in python_docs:
    print(i)

5.切割结果

输出是 Document 对象列表:

page_content='def sum()
    a=0
    for i in range(1,11):'
page_content='a+=i
    print(a)
    
sum()'

👉 函数整体被保留,不会被乱切。

6.from_language()

以 Language.PYTHON 为例,优先级类似:

\n\n → defclass → 缩进块 → 行

👉 优先保留:

  • 一个完整函数
  • 一个完整类
  • 一个逻辑代码块

这对:

  • 代码搜索
  • 错误定位
  • 自动重构
  • Code Review Agent

极其重要

7.chunk_size / overlap 在代码里的经验值

推荐配置

场景 chunk_size overlap
小函数 200 20
中等模块 400 40
大文件 800 100

📌 代码切割不宜太小

8.与普通 RecursiveCharacterTextSplitter 的区别

项目 普通文本 代码语言版
语义完整性 一般 ⭐⭐⭐⭐⭐
是否识别函数
是否识别类
Code Agent 适用

👉 代码一定要用 from_language()

9.真实工程中的典型应用

  1. 代码问答 Agent

    “这个函数是干嘛的?”

    → 检索对应函数代码 → LLM 解释

  2. 自动代码审查

    “有没有性能问题?”

    → 定位 for / while / IO 逻辑

  3. DevOps / CI Agent

    • 解析 Helm / YAML
    • 解析 Terraform
    • 解析 K8s 配置
Language.YAML
Language.JSON

10.进阶

多语言代码切割(仓库级)

splitter_map = {
    ".py": Language.PYTHON,
    ".go": Language.GO,
    ".java": Language.JAVA
}

自动选择切割器。

很好,这一步已经进入 RAG / Agent 工程里非常“专业”的层级—— Token 级切割 👍

很多人只会“字符切割”,真正做线上系统的一定会用 token 切割

下面我承接你这段代码,写一篇完整的 Token 切割(tiktoken)教程,并把它和前面的字符 / 递归切割彻底对比清楚

LangChain Token 切割

使用 tiktoken 按「模型 token 数」切分文本

这是构建 真实可上线 RAG / Agent 系统 的关键步骤。

1.为什么一定要学 Token 切割?

大模型真正关心的不是:

  • ❌ 字符数

  • ❌ 行数

而是:

Token

如果你只按字符切割:

  • 中文 / 英文 token 比例不同

  • 实际 token 数可能超上下文

  • 上线后 直接报错 or 成本失控

👉 Token 切割 = 工程级切割

2.什么是 tiktoken?

tiktoken 是 OpenAI 官方的 Tokenizer

  • 把文本 → token

  • 精确对齐模型的计费 & 上下文限制

  • LangChain 内置支持

安装:

pip install tiktoken

3.代码在做什么?

现在用的是

CharacterTextSplitter.from_tiktoken_encoder(...)

含义是:

tiktoken 来计算长度,而不是 len()

也就是说:

  • 切分 :token
  • 而不是字符

4.完整示例代码

from langchain_text_splitters import CharacterTextSplitter, RecursiveCharacterTextSplitter
import chardet,tiktoken

# 文件路径
file_path='./text2/story.txt'

# 获取文本字符集
def get_encoding(file_path):
    with open(file_path, 'rb') as f:
        data=f.read()
        encoding = chardet.detect(data)['encoding']
        return encoding

# 获取数据
with open(file_path, 'r',encoding=get_encoding(file_path)) as f:
    data=f.read()

# 创建分割器
token_splitter = CharacterTextSplitter.from_tiktoken_encoder(
    separator='。',   # 指定分隔符:按句号切分(中文小说自然句子)
    chunk_size=10,    # 每个 chunk 最大 token 数(实验值,可调
    chunk_overlap=2,  # 相邻 chunk 重叠 token 数,保证上下文连续
)

token_docs = token_splitter.create_documents([data])

# 获取token解析器
enc=tiktoken.get_encoding('cl100k_base')

for i,doc in enumerate(token_docs):
    print(f"Chunk {i}")  # chunk 序号
    print(f"Token count: {len(enc.encode(doc.page_content))}")  # 实际 token 数
    print(doc.page_content)   # 文本内容
    print("="*50)

5.Token切割参数详解

chunk_size

chunk_size=50

含义:

每个文本块最多 50 个 token

不是字符!

示例对比:

文本 字符数 Token 数
Hello world 11 2
我爱自然语言处理 8 6~8

chunk_overlap

chunk_overlap=5
  • 相邻 chunk 共享 5 个 token
  • 防止语义被截断

📌 推荐比例:10%~20%

6.Token 切割 vs 字符切割 vs 递归切割

维度 字符切割 递归切割 Token 切割
是否语义优先
是否对齐模型
是否防超长
上线安全性 ⭐⭐⭐⭐⭐

👉 **上线系统:**Token 切割必选

7.为什么不用 Recursive + token 一步完成?

原因:

  • Recursive:保证语义

  • Token:保证安全

👉 工程上是“组合拳”

示例:

# 第一次:语义切割
semantic_docs = recursive_splitter.create_documents(texts)

# 第二次:token 切割
safe_docs = token_splitter.split_documents(semantic_docs)

8.如何验证 token 数?(进阶)

import tiktoken

enc = tiktoken.get_encoding("cl100k_base")
print(len(enc.encode(doc.page_content)))

9.真实生产环境推荐配置

通用文档(中文)

chunk_size = 300
chunk_overlap = 50

GPT-4 / GPT-4o

  • 上下文:8k / 32k
  • 检索 TopK:3~5

LangChain 文档加载器

示如何使用 LangChain 和 community loaders 加载各种格式文档

这是 RAG / AI Agent 的第一步:把原始数据读入为 Document 对象列表。

1.为什么需要 Document Loader?

在 RAG / Agent 流程中:

  1. LLM 无法直接读取文件
  2. 文件格式多样:Markdown / CSV / JSON / HTML / PDF
  3. Document Loader 能:
    • 解析不同文件格式
    • 返回 Document 对象(包含文本 + metadata)
    • 与后续 切割、Embedding、向量数据库 无缝对接

2.Markdown 文件加载

from langchain_community.document_loaders import TextLoader

# 加载markdown文件
loader=TextLoader('./text/MD示例.md',encoding='utf-8')
docs=loader.load()
for i in docs:
    print(i.page_content)

要点

  • TextLoader 是最基础 loader
  • 适合 .md 、 .txt 等纯文本
  • 每个 Document 包含:
    • page_content : 文本内容
    • metadata : 文件信息(路径、来源等)

3.目录加载(批量文件)

pip install unstructured
pip install "unstructured[csv]"
pip install python-magic-bin 系统依赖库结合Python实现文件类型检索功能
from langchain_community.document_loaders import TextLoader

# 检索text目录中有几个csv文件
loader=TextLoader('./text/MD示例.md',encoding='utf-8')
docs=loader.load()
for i in docs:
    print(i.page_content)

要点

  • glob 支持通配符,例如:
    • *.md → 所有 Markdown
    • *.txt → 所有文本
  • 注意:
    • .html 和 .rst 默认不加载
    • 可以结合 unstructured 或 python-magic 增强识别能力

4.CSV 文件加载

# 获取csv列数据
from langchain_community.document_loaders import CSVLoader
import chardet

# 文件路径
file_path='./text/score.csv'

# 获取文本字符集
def get_encoding(file_path):
    with open(file_path, 'rb') as f:
        data=f.read()
        encoding = chardet.detect(data)['encoding']
        return encoding

loader=CSVLoader(file_path,encoding=get_encoding(file_path),source_column='英语')
docs=loader.load()
for i in docs:
    print(i.metadata)

要点

  • 支持:
    • 全文加载(每行一个 Document)
    • 指定列加载
  • Document.metadata 默认包含行号和文件名

5.HTML 文件加载

from langchain_community.document_loaders import BSHTMLLoader

loader = BSHTMLLoader('./text/index.html')
docs=loader.load()
for i in docs:
    print(i.page_content)

要点

  • 自动提取 HTML 中的文本内容
  • 支持保留标签或纯文本
  • 适合网页抓取 / 爬虫场景

6.JSON 文件加载

pip install jq
from langchain_community.document_loaders import JSONLoader

loader=JSONLoader(
    file_path='./text/simple_prompt.json',
    jq_schema='.template',
    text_content=False
)
docs=loader.load()
print(docs)

要点

  • jq_schema 是 JSONPath 风格选择器
  • text_content :
    • False → 保留原始 JSON 结构
    • True → 全部转换为字符串
  • 可用于配置文件、Prompt 模板、API 数据

7.PDF 文件加载

from langchain_community.document_loaders import PyPDFLoader

loader=PyPDFLoader('./text/pulsar.pdf')
pages=loader.load_and_split()
for i in pages:
    print(i)

要点

  • 每页一个 Document
  • load() → 整个 PDF 当作一个 Document
  • load_and_split() → 按页拆分
  • 可以和 RecursiveCharacterTextSplitter 或 token_splitter 配合使用

8.文档加载器使用经验总结

类型 Loader 推荐使用场景 注意事项
Markdown / TXT TextLoader 文本文件、笔 记 支持 encoding
CSV CSVLoader 表格 / 数据列 可指定列,需注意编码
HTML BSHTMLLoader 网页 / 抓取 可保留标签,需依赖 BeautifulSoup4
JSON JSONLoader 配置 / API 数 据 jq_schema 提取字段
PDF PyPDFLoader 文档 / 论文 load_and_split 按页拆分
目录批量 DirectoryLoader 批量文件 glob 支持通配符
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐