AI Agent从无到有44: RAG 文档切分策略深度解析——从长度切割到语义边界

NLP工程化训练体系:300个可执行知识原子构建工业级能力 自然语言处理(NLP)作为人工智能落地最广的领域之一,其核心挑战早已从模型架构演进转向工程化稳定性与生产可靠性。理解文本预处理的Unicode陷阱、小样本场景下prompt工程的实际边界、微调中梯度爆炸的现场熔断机制,以及ONNX Runtime部署时的精度归因分析,构成了现代NLP工程师的关键能力图谱。这些能力并非孤立知识点,而是围绕数据泄漏、梯度失稳、部署衰减、长尾失效、服务超时五大高频失败模式组织的可验证单元。本体系以PyTorch和Hugging Face为基座,强调去平台化、去黑箱化与去时序依赖, 阅读详情

纲要

  • 文档切分在 RAG 系统中的核心作用与必要性
  • 四种主流切分策略的剖析与选型
    • 基于长度切分:固定 Token 数分割
    • 基于文本架构切分:保留段落与句子边界
    • 基于文档格式切分:解析 Markdown、JSON 等结构化数据
    • 基于语义切分:利用模型判定语义边界(实验性)
  • LangChain 切分器组件速览
    • CharacterTextSplitter:基础字符切分
    • RecursiveCharacterTextSplitter:递归式通用切分器
    • MarkdownHeaderTextSplitter:保留标题元数据的 Markdown 切分器
    • SemanticChunker(实验性):基于嵌入向量的语义切分
  • 完整可运行示例:使用 RecursiveCharacterTextSplitter 进行本地文档切分
  • 切分器选型建议与最佳实践

引言

在构建检索增强生成(RAG)应用时,文档加载与向量化存储之间,存在一个关键且影响深远的环节:文本切分。切分策略的优劣直接决定了后续向量检索的命中精度,以及大语言模型所能获取的上下文质量。若切分粒度过粗,文本片段可能超出模型的上下文窗口,导致关键信息被截断;若粒度过细,语义完整性遭到破坏,模型将难以理解上下文的连贯含义,进而产生不准确的回答。

LangChain 作为构建 LLM 应用的主流框架,提供了一套层次化、可组合的文本切分工具集。从最直接的按字符长度切割,到基于文档结构的分割,再到引入模型判定边界的智能切分,开发者可以根据实际场景灵活选用。本文将深入剖析四种核心切分策略的实现原理与适用场景,并通过可直接运行的代码示例,展示如何在本地环境中高效实施文档切分。

为什么必须切分文档?

在 RAG 流水线中,对原始文档进行切分并非可有可无的步骤,而是由技术约束与业务需求共同决定的必要操作:

  • 模型上下文窗口限制:无论是 GPT-4 还是各类开源大语言模型,其上下文窗口(Context Window)均有最大 Token 数限制。长文档(如报告、书籍)必须被拆分为多个片段,方可被模型有效处理。
  • 检索精准度提升:将长文档分割为语义相对独立的段落或句子后,向量相似性搜索能够更精准地定位与用户查询最相关的信息片段,而非返回包含大量无关噪声的整页内容。
  • 嵌入成本与效果控制:嵌入模型通常按 Token 计费或受限于最大输入长度。合理的片段大小不仅能够控制成本,还能确保生成的嵌入向量更聚焦于特定主题,提升检索效果。

四种切分策略详解

基于长度切分

这是最直观的切分方式,即指定一个固定的 Token 数或字符数作为切分阈值,按照该长度对文本进行分割,并允许相邻片段之间保留一定比例的重叠内容,以防止关键信息在分割点被意外截断。

CharacterTextSplitter 配合 tiktoken 分词器即可实现此类切分。其核心参数包括:

  • chunk_size:每个片段的最大长度(以 Token 或字符计)。
  • chunk_overlap:相邻片段之间的重叠长度。
  • encoding_name:指定使用的分词编码(如 cl100k_base 对应 GPT-4 所使用的编码)。
from langchain_text_splitters import CharacterTextSplitter

# 使用 tiktoken 编码器进行切分
splitter = CharacterTextSplitter.from_tiktoken_encoder(
    encoding_name="cl100k_base",
    chunk_size=100,
    chunk_overlap=20
)

注意:该方式实现简单,但完全忽略文本的自然边界(如句子、段落),容易在句中进行切割,破坏语义连贯性。仅适用于对语义要求极低的场景,或作为其他切分策略的兜底方案。

基于文本架构切分

RecursiveCharacterTextSplitter 是 LangChain 官方推荐的通用切分器,它采用递归尝试的策略来平衡长度限制与语义完整性。其工作流程如下:

  1. 首先按优先级最高的分隔符(如双换行符 \n\n)尝试分割。
  2. 若分割后的片段仍超过 chunk_size,则自动降级使用下一个优先级的分隔符(如单换行符 \n、句号、逗号等)继续分割。
  3. 重复此过程,直至所有片段长度符合要求。

这种递归机制使得切分结果最大程度地保留了段落和句子的自然边界,是一种兼顾长度约束与语义保留的折中方案,适用于绝大多数通用文本。

from langchain_text_splitters import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=100,
    chunk_overlap=20,
    separators=["\n\n", "\n", "。", ",", " ", ""],  # 按优先级从高到低排列
    keep_separator=False  # 是否在结果中保留分隔符
)

基于文档格式切分

对于 Markdown、JSON 等具有明确结构特征的文档,利用文档本身的标记进行切分能够获得更好的语义完整性。

  • Markdown 文档:MarkdownHeaderTextSplitter 根据标题层级(#、##、### 等)对文档进行拆分,并将各级标题作为元数据附加到每个片段中,便于在检索时提供层次化的上下文信息。
  • JSON 数据:JsonSplitter 能够按 JSON 对象或数组元素进行拆分,确保每个片段仍为合法的 JSON 结构。
from langchain_text_splitters import MarkdownHeaderTextSplitter

markdown_doc = """
# 第一章
这是第一章的内容...
## 第一节
第一节的详细描述...
"""

headers_to_split_on = [
    ("#", "Header 1"),
    ("##", "Header 2"),
]

splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
splits = splitter.split_text(markdown_doc)

基于语义切分(实验性)

SemanticChunker 是 LangChain 中处于实验阶段的切分器,它尝试从根本上解决语义完整性问题。其核心机制是:首先将文本拆分为单个句子,然后计算相邻句子嵌入向量之间的余弦相似度,当相似度低于预设阈值时,判定此处为语义边界,执行切分。

这种方式能够最大程度地保证每个片段在语义上独立且完整,非常适合对切分质量要求极高的场景。然而,由于需要调用外部嵌入模型进行计算,其处理速度较慢且会产生额外成本。目前该功能尚处于实验阶段,API 在未来版本中可能发生变化。

from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai.embeddings import OpenAIEmbeddings

# 需要配置 OpenAI API Key
embeddings = OpenAIEmbeddings()
splitter = SemanticChunker(
    embeddings=embeddings,
    breakpoint_threshold_type="percentile",  # 可选: "percentile", "standard_deviation", "interquartile"
    breakpoint_threshold_amount=95  # 百分位数阈值
)

完整可运行代码:使用 RecursiveCharacterTextSplitter 本地演示

以下示例使用 RecursiveCharacterTextSplitter 对一份模拟的产品手册进行切分,并详细输出每个切分后片段的长度与内容。该过程完全本地运行,无需调用任何外部 API。

环境准备

pip install langchain langchain-text-splitters

核心代码实现

from langchain_core.documents import Document
from langchain_text_splitters import RecursiveCharacterTextSplitter

def main():
    # 1. 构造示例文档,模拟真实产品手册
    raw_text = """
    产品名称:智能温控水杯 X-200
    功能描述:
    1. 实时显示水温,精确到 ±0.5°C。
    2. 支持手机 App 远程设置目标温度。
    3. 内置 5000mAh 电池,可续航 48 小时。
    4. 采用 316 不锈钢内胆,安全健康。
    5. 具有过热保护功能,超过 99°C 自动断电。

    使用说明:
    - 首次使用前请用清水冲洗内胆。
    - 长按电源键 3 秒开机,蓝牙自动配对。
    - 可通过 App 调节温度范围:40°C~100°C。

    注意事项:
    - 请勿将杯体浸入水中清洗。
    - 充电时请使用 5V/2A 适配器。
    """
    doc = Document(
        page_content=raw_text.strip(),
        metadata={"source": "product_manual", "version": "v1.0"}
    )

    # 2. 创建切分器实例,配置关键参数
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=100,           # 每段最大字符数
        chunk_overlap=20,         # 段间重叠字符数,用于维持上下文连贯
        separators=["\n\n", "\n", "。", ",", " ", ""],
        keep_separator=False,
        length_function=len,      # 默认使用 len() 计算长度,也可替换为 Token 计数器
    )

    # 3. 执行切分并展示结果
    split_docs = splitter.split_documents([doc])
    print(f"原始文档长度:{len(raw_text)} 字符,成功切分为 {len(split_docs)} 个片段。\n")
    
    for i, d in enumerate(split_docs, 1):
        print(f"--- 片段 {i}(字符数:{len(d.page_content)})---")
        print(d.page_content)
        print(f"元数据:{d.metadata}\n")

if __name__ == "__main__":
    main()

代码运行说明

  1. 确保 Python 环境版本不低于 3.9。
  2. 执行 pip install langchain langchain-text-splitters 安装所需依赖。
  3. 将上述代码保存为 split_demo.py 文件,并在终端中运行 python split_demo.py。
  4. 观察输出结果,可见原始文本已按自然段落边界切分,每个片段的长度基本控制在 100 字符以内,且相邻片段之间保留了适当的重叠字符(如“实时显示水温”等上下文),有效维持了语义的连贯性。

切分器选型建议与实践指南

应用场景推荐切分器关键考量因素
通用文本、快速原型验证RecursiveCharacterTextSplitter适用性最广,平衡长度与语义,为多数场景的默认首选。
高度结构化文档(Markdown)MarkdownHeaderTextSplitter保留标题层次结构,便于在检索时利用层级元数据进行筛选。
结构化数据(JSON)JsonSplitter严格遵循数据结构,确保每个切分片段的合法性。
需极高质量语义边界SemanticChunker(实验性)利用嵌入模型判定语义边界,但需承担额外计算成本与 API 延迟。

此外,在配置 chunk_size 与 chunk_overlap 时,需综合考虑以下因素:

  • 嵌入模型的最大输入长度:chunk_size 不应超过所选嵌入模型的 max_seq_length。
  • 下游 LLM 的上下文窗口:片段长度应远小于模型窗口限制,并为系统指令和用户问题预留空间。
  • 数据集的平均段落长度:观察目标文档的段落结构,使切分后的片段尽可能与自然段落对齐。

API 速览

本节对涉及的核心切分器 API 进行梳理,以便开发者快速查阅。

1. CharacterTextSplitter

  • 所属库:langchain_text_splitters
  • 方法签名:
    • from_tiktoken_encoder(cls, encoding_name: str, chunk_size: int, chunk_overlap: int, **kwargs)
    • split_documents(documents: List[Document]) -> List[Document]
  • 核心参数:
    • encoding_name:tiktoken 编码名称,如 cl100k_base。
    • chunk_size:最大长度(以 Token 计)。
    • chunk_overlap:重叠长度。
  • 返回值:List[Document],每个 Document 对象包含切分后的文本及其元数据。

2. RecursiveCharacterTextSplitter

  • 所属库:langchain_text_splitters
  • 方法签名:
    • __init__(self, chunk_size: int, chunk_overlap: int, separators: List[str], keep_separator: bool = False, length_function: Callable = len, **kwargs)
    • split_documents(documents: List[Document]) -> List[Document]
  • 核心参数:
    • separators:按优先级从高到低排列的分隔符列表。
    • length_function:计算片段长度的函数,默认为 len,可替换为 Token 计数器。
  • 返回值:List[Document]。

3. MarkdownHeaderTextSplitter

  • 所属库:langchain_text_splitters
  • 方法签名:
    • __init__(self, headers_to_split_on: List[Tuple[str, str]], **kwargs)
    • split_text(text: str) -> List[Document]
  • 核心参数:
    • headers_to_split_on:列表,每个元素为 (HTML标签, 元数据键名) 的元组。
  • 返回值:List[Document],每个片段的 metadata 中包含对应的标题层级信息。

4. SemanticChunker

  • 所属库:langchain_experimental.text_splitter
  • 方法签名:
    • __init__(self, embeddings: Embeddings, breakpoint_threshold_type: str, breakpoint_threshold_amount: float, **kwargs)
    • split_documents(documents: List[Document]) -> List[Document]
  • 核心参数:
    • embeddings:嵌入模型实例,需实现 embed_documents 和 embed_query 方法。
    • breakpoint_threshold_type:阈值类型,可选 percentile、standard_deviation、interquartile。
  • 返回值:List[Document]。

完整 Demo 示例

以下提供一个端到端的 HTML 可视化演示页面,通过模拟文本输入实时展示 RecursiveCharacterTextSplitter 的切分效果。该 Demo 为独立前端应用,无需后端服务。

运行说明

  1. 将以下 HTML 代码保存为 splitter_demo.html 文件。
  2. 使用现代浏览器(如 Chrome、Firefox)直接打开该文件。
  3. 在文本框中输入或修改待切分的文本,调整 chunk_size 与 chunk_overlap 滑块。
  4. 实时观察切分结果,每个片段将以独立卡片形式呈现。

代码说明

  • 核心逻辑:使用纯 JavaScript 模拟 RecursiveCharacterTextSplitter 的递归分割算法,依据预定义的分隔符优先级对输入文本进行切分。
  • 交互设计:提供滑块和实时反馈,帮助开发者直观理解不同参数对切分结果的影响。
  • 技术点:展示了字符级递归分割的算法实现,以及前端事件驱动模型的基本应用。

技术点总结

  • 递归分隔符优先级处理逻辑的实现。
  • 滑块控件与文本渲染的动态绑定。
  • 实时可视化反馈机制。

Demo 代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RecursiveCharacterTextSplitter 可视化演示</title>
    <style>
        * {
            box-sizing: border-box;
            font-family: system-ui, -apple-system, sans-serif;
        }
        body {
            background: #f7f9fc;
            padding: 2rem;
            display: flex;
            flex-direction: column;
            align-items: center;
        }
        .container {
            max-width: 960px;
            width: 100%;
            background: white;
            border-radius: 16px;
            padding: 2rem;
            box-shadow: 0 4px 20px rgba(0,0,0,0.08);
        }
        h1 {
            font-size: 1.6rem;
            font-weight: 600;
            margin-bottom: 0.5rem;
            color: #0b1a33;
        }
        .sub {
            color: #5e6f8d;
            font-size: 0.95rem;
            margin-bottom: 2rem;
            border-left: 4px solid #3b82f6;
            padding-left: 1rem;
        }
        .config {
            display: flex;
            flex-wrap: wrap;
            gap: 2rem;
            background: #f0f4fe;
            padding: 1.2rem 1.5rem;
            border-radius: 12px;
            margin-bottom: 1.5rem;
        }
        .config-item {
            flex: 1 1 160px;
        }
        .config-item label {
            display: block;
            font-weight: 500;
            font-size: 0.85rem;
            color: #1e293b;
            margin-bottom: 4px;
        }
        .config-item input[type="range"] {
            width: 100%;
            accent-color: #3b82f6;
        }
        .config-item .value {
            font-size: 0.9rem;
            font-weight: 600;
            color: #0b1a33;
            float: right;
        }
        textarea {
            width: 100%;
            min-height: 140px;
            padding: 0.8rem 1rem;
            border: 1px solid #d1d9e8;
            border-radius: 10px;
            font-size: 0.95rem;
            line-height: 1.6;
            resize: vertical;
            font-family: inherit;
            margin-bottom: 1.5rem;
            transition: border 0.2s;
        }
        textarea:focus {
            outline: none;
            border-color: #3b82f6;
            box-shadow: 0 0 0 3px rgba(59,130,246,0.15);
        }
        .stats {
            display: flex;
            justify-content: space-between;
            font-size: 0.9rem;
            color: #334155;
            margin-bottom: 1.5rem;
            padding-bottom: 0.5rem;
            border-bottom: 1px solid #e9edf4;
        }
        .chunks-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
            gap: 1rem;
        }
        .chunk-card {
            background: #fafcff;
            border: 1px solid #e2e9f3;
            border-radius: 10px;
            padding: 0.8rem 1rem;
            transition: all 0.1s;
        }
        .chunk-card:hover {
            border-color: #b0c8e8;
            background: #ffffff;
        }
        .chunk-header {
            display: flex;
            justify-content: space-between;
            font-size: 0.75rem;
            font-weight: 500;
            color: #62748c;
            border-bottom: 1px dashed #dce3ef;
            padding-bottom: 4px;
            margin-bottom: 6px;
        }
        .chunk-content {
            font-size: 0.9rem;
            line-height: 1.5;
            word-break: break-word;
            color: #0a1a2f;
        }
        .empty {
            color: #94a3b8;
            font-style: italic;
            padding: 1rem 0;
        }
        .tag {
            background: #dbeafe;
            color: #1e4b8a;
            padding: 0.15rem 0.6rem;
            border-radius: 20px;
            font-size: 0.75rem;
        }
        @media (max-width: 600px) {
            body { padding: 1rem; }
            .container { padding: 1rem; }
            .config { flex-direction: column; gap: 0.6rem; }
        }
    </style>
</head>
<body>
<div class="container">
    <h1>📄 递归字符切分器 · 实时演示</h1>
    <div class="sub">基于优先级分隔符递归分割,保持语义边界 | 完全前端模拟</div>

    <div class="config">
        <div class="config-item">
            <label>📏 chunk_size <span class="value" id="sizeVal">100</span></label>
            <input type="range" id="chunkSize" min="20" max="300" value="100" step="5">
        </div>
        <div class="config-item">
            <label>🔗 chunk_overlap <span class="value" id="overlapVal">20</span></label>
            <input type="range" id="chunkOverlap" min="0" max="80" value="20" step="5">
        </div>
        <div class="config-item" style="flex: 0 0 auto;">
            <label>分隔符优先级</label>
            <span style="font-size:0.8rem; color:#334155;">\n\n → \n → 。 → , → 空格</span>
        </div>
    </div>

    <textarea id="textInput" placeholder="在此输入或粘贴待切分的文本...">产品名称:智能温控水杯 X-200
功能描述:
1. 实时显示水温,精确到 ±0.5°C。
2. 支持手机 App 远程设置目标温度。
3. 内置 5000mAh 电池,可续航 48 小时。
4. 采用 316 不锈钢内胆,安全健康。
5. 具有过热保护功能,超过 99°C 自动断电。

使用说明:
- 首次使用前请用清水冲洗内胆。
- 长按电源键 3 秒开机,蓝牙自动配对。
- 可通过 App 调节温度范围:40°C~100°C。

注意事项:
- 请勿将杯体浸入水中清洗。
- 充电时请使用 5V/2A 适配器。</textarea>

    <div class="stats">
        <span>📝 原始字符数: <strong id="origLen">0</strong></span>
        <span>🧩 切分片段: <strong id="chunkCount">0</strong></span>
        <span>⚡ 总字符数 (含重叠): <strong id="totalLen">0</strong></span>
    </div>

    <div id="chunksContainer" class="chunks-grid"></div>
</div>

<script>
    (function() {
        const textInput = document.getElementById('textInput');
        const chunkSizeSlider = document.getElementById('chunkSize');
        const chunkOverlapSlider = document.getElementById('chunkOverlap');
        const sizeVal = document.getElementById('sizeVal');
        const overlapVal = document.getElementById('overlapVal');
        const origLen = document.getElementById('origLen');
        const chunkCount = document.getElementById('chunkCount');
        const totalLen = document.getElementById('totalLen');
        const container = document.getElementById('chunksContainer');

        // 模拟 RecursiveCharacterTextSplitter 的核心逻辑
        function recursiveSplit(text, chunkSize, chunkOverlap, separators) {
            if (!text || text.length === 0) return [];

            // 如果文本长度 <= chunkSize,直接返回
            if (text.length <= chunkSize) {
                return [text];
            }

            // 尝试按当前分隔符列表分割
            for (let sep of separators) {
                if (sep === '') continue; // 跳过空分隔符(兜底逻辑单独处理)
                const parts = text.split(sep);
                if (parts.length > 1) {
                    // 检查分割后的每个部分,如果都 <= chunk_size,则递归处理每个部分
                    let allFit = true;
                    for (let p of parts) {
                        if (p.length > chunkSize) {
                            allFit = false;
                            break;
                        }
                    }
                    if (allFit) {
                        // 递归处理每个部分,注意重叠逻辑:此处简化,仅对每个部分单独切分
                        let result = [];
                        for (let p of parts) {
                            if (p.length === 0) continue;
                            // 若 p 仍大于 chunk_size(理论上不会,但防御)
                            if (p.length > chunkSize) {
                                result = result.concat(recursiveSplit(p, chunkSize, chunkOverlap, separators));
                            } else {
                                result.push(p);
                            }
                        }
                        return result;
                    }
                }
            }

            // 兜底:按字符切分(对应 separators 中的 "")
            let chunks = [];
            let start = 0;
            while (start < text.length) {
                let end = Math.min(start + chunkSize, text.length);
                let chunk = text.substring(start, end);
                chunks.push(chunk);
                start = end - chunkOverlap;
                if (start <= 0) start = end;
                if (start >= text.length) break;
            }
            return chunks;
        }

        function updateDisplay() {
            const raw = textInput.value;
            const chunkSize = parseInt(chunkSizeSlider.value, 10);
            const chunkOverlap = parseInt(chunkOverlapSlider.value, 10);
            sizeVal.textContent = chunkSize;
            overlapVal.textContent = chunkOverlap;

            // 定义分隔符优先级
            const separators = ['\n\n', '\n', '。', ',', ' ', ''];

            // 执行切分
            const chunks = recursiveSplit(raw, chunkSize, chunkOverlap, separators);

            // 更新统计
            origLen.textContent = raw.length;
            chunkCount.textContent = chunks.length;
            const totalChars = chunks.reduce((sum, c) => sum + c.length, 0);
            totalLen.textContent = totalChars;

            // 渲染
            if (chunks.length === 0) {
                container.innerHTML = '<div class="empty">暂无切分结果,请在上方输入文本。</div>';
                return;
            }

            let html = '';
            chunks.forEach((chunk, idx) => {
                const isOverlap = (idx > 0 && chunk.length > 0);
                html += `
                    <div class="chunk-card">
                        <div class="chunk-header">
                            <span>#${idx + 1}</span>
                            <span>${chunk.length} 字符 ${isOverlap ? '🔁' : ''}</span>
                            <span class="tag">${chunk.length <= chunkSize ? '✓' : '⚠️'}</span>
                        </div>
                        <div class="chunk-content">${escapeHtml(chunk)}</div>
                    </div>
                `;
            });
            container.innerHTML = html;
        }

        // 简单防 XSS
        function escapeHtml(text) {
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }

        // 事件绑定
        textInput.addEventListener('input', updateDisplay);
        chunkSizeSlider.addEventListener('input', updateDisplay);
        chunkOverlapSlider.addEventListener('input', updateDisplay);

        // 初始渲染
        updateDisplay();
    })();
</script>
</body>
</html>

参考文档

官方文档

参考链接

总结

文档切分作为 RAG 流水线中的关键预处理步骤,直接决定了检索质量与生成效果的上限。RecursiveCharacterTextSplitter 以其递归尝试的机制,在通用文本场景中提供了最佳的长度控制与语义平衡,成为绝大多数应用的首选。

对于高度结构化的 Markdown 或 JSON 文档,选用 MarkdownHeaderTextSplitter 与 JsonSplitter 能够更充分地利用结构信息。而实验性的 SemanticChunker 则代表了未来的发展方向——通过引入模型推理来精准划定语义边界,尽管目前存在性能开销,但对于追求极致质量的应用具有重要价值。

合理配置切分参数(chunk_size 与 chunk_overlap),并结合具体业务场景进行调优,是构建高性能 RAG 应用的基础工程实践。

【信息科学与工程学】计算机科学与自动化——第三百零五篇 计算机系统中的各类运算操作01 编号类型领域运算操作运算类型算法算法的详细设计及数学分析参数列表及参数的数值设计应用场景 (100+条)集合运算​1集合运算关系代数并集 (Union)集合运算归并排序去重合并两个集合,去除重复元素。时间复杂度 O(n+m),n,m为两集合大小。输入:集合A, B。输出:A∪B。数据集成、多表结果合并、去重后的全量数据提取。2集合运算关系代数交集 (Intersection)集合运算哈希交集找出同时属于两个集合的元素。平均时间复杂度 O(min(n,m)),最坏 O(n*m)。输入:集合A, B。输出:A∩ 阅读详情

相关推荐

【信息科学与工程学】计算机科学与自动化——第二百零九篇 软件硬件集成开发环境指南01

编号类型环境知识/特性/机制涉及因素/参数/属性列表关联知识与标准法规001需求/追溯集成机制软件开发环境/集成的软硬件系统开发环境把需求条目、用户故事、规格说明、变更请求与设计、代码、测试、缺陷、构建、发布版本建立双向追溯链,形成从“业务目标—系统需求—软件/硬件需求—验证确认—运行反馈”的全生命周期闭环,同时引入影响分析和合规映射。需求属性:需求唯一ID、需求标题、需求来源(客户/内部/法规)、需求类型(功能/性能/安全/可靠性/可维护性)、优先级(Must/Should/Could)、版本、状态(草稿

weixin_49199313的博客 30

AI Agent规划模块深拆——任务分解步骤规划策略选择与执行计划

概要:规划模块是AI Agent认知层的核心枢纽,负责将模糊目标转化为可执行计划,通过任务分解、步骤规划和策略选择三大职责解决目标模糊、依赖混乱和无法并行的问题。其产出任务树和执行计划,强调覆盖率、并行度、可验证性和成本可控四个质量指标,并支持主动和按需两种规划模式。模块具备可解释性、自适应粒度和成本模型,可衔接多Agent协作与外部存储,通过单元测试、接口契约和用户控制感保障工程化落地与可用性。

lza_csdn2019的博客 701

【信息科学与工程学】【通信工程】第三百零六篇 IPv6/SRv6服务链中的学科知识01

序号数据类型 (主类)数据类型 (子类)示例/说明存储/表示方式备注/应用场景2246生物信息型DNA序列ATGC碱基序列FASTA格式基因组2247生物信息型RNA序列AUGC碱基序列FASTA转录组2248生物信息型蛋白质序列氨基酸序列FASTA蛋白组2249生物信息型基因注释GFF/GTF文件Gene annotation功能2250生物信息型变异数据VCF文件Variant call formatSNP/INDEL2251生物信息型表达矩阵基因×样本Expression matrix (FPKM/T

weixin_49199313的博客 93

LangChain官方RAG架构实战拆解:从玩具Demo到生产级落地

RAG(检索增强生成)是一种将外部知识库与大语言模型协同工作的关键技术,其核心原理在于通过向量检索精准定位相关文档片段,再交由LLM进行语义整合与生成。技术价值体现在显著降低幻觉率、提升答案准确性与可溯源性,广泛应用于智能客服、企业知识库、金融研报分析等需强事实依据的场景。然而,真实工程落地远非调用as_retriever()或invoke()即可达成——它要求深入理解检索策略(如MMR重排序)、分块逻辑(chunk_size与overlap的权衡)、向量库选型(Chroma仅适合开发,Pinecone/W

weixin_33755649的博客 443

SAP销售订单POD实操:从VL01N创建到VLPOD差异处理,保姆级避坑指南

本文详细解析SAP销售订单POD全流程,从VL01N创建到VLPOD差异处理,提供保姆级避坑指南。涵盖核心业务逻辑、前置配置、销售订单创建、交货单处理及差异解决方案,帮助用户高效管理供应链执行环节,确保财务与物流的准确对接。

weixin_27219587的博客 626

IOS APP上架被拒 4.3(a) - Design - Spam,成功

成功解决IOS APP上架被拒 4.3(a) - Design - Spam,本篇博客记录了详细过程

qq_40147106的博客 6909

一文带你了解HuggingFace Transformer 理论基础,Transformer 实战,十万字精读

在 Hugging Face 的库中,Pipeline(流水线)是最高层、最易用的推理 API。如果把直接调用 PyTorch 底层代码比作“驾驶手动挡赛车”(需要精细控制离合、油门和换挡),那么 Pipeline 就是一辆开箱即用的“全自动无人驾驶汽车”。你只需要输入目的地(文本),它就能直接把你送到终点(预测结果)。你不需要知道到底该用 BERT 还是 T5。你只需要告诉 Pipeline 你的任务目标文本生成、翻译、问答、图像分类),它就会自动为你匹配一套默认的最佳预训练模型和分词器。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 553

红外气体检测方案解析:从NDIR原理到物联网终端设计实践

气体检测是工业安全与环境监测的核心需求,其技术原理主要基于气体分子对特定物理或化学信号的响应。非色散红外(NDIR)技术作为一种物理检测方法,通过测量气体分子对特定波长红外光的吸收来定量浓度,因其不依赖化学反应,具备寿命长、抗干扰强和响应快等优势。在工程实践中,红外气体检测方案的价值在于为物联网终端设备提供了高可靠、低功耗的感知能力,广泛应用于工业过程监控、环境空气质量监测以及智能家居安全预警等场景。本文以一套集成了Microchip MCU、Axetris红外光源和Pyreos热释电传感器的参考设计为例,

weixin_30954817的博客 393

6 款电商 AI 图片生成软件实测|国内 + 跨境卖家工具清单

电商 AI 作图工具已经从 "能不能用" 进入了 "好不好用" 的阶段。对于绝大多数卖家而言,现在的 AI 工具已经可以覆盖 60%-80% 的基础商品图需求,显著降低拍摄和设计成本。选择工具的核心逻辑不是 "哪款最强",而是 "哪款最适配你的品类、平台规模和团队能力"。垂直电商工具胜在工作流效率,通用生图工具强在创意上限,模板类工具赢在上手速度。建议根据自身业务阶段,搭配 1-2 款主力工具 + 1 款辅助工具,形成适合自己的视觉生产流程。

Mardi_Ladin的博客 396

ArcGIS小白必看:5分钟搞定面要素转点要素+自动计算经纬度坐标(附常见报错解决方案)

本文为ArcGIS新手详细解析了面要素转点要素并自动计算经纬度坐标的完整流程。核心在于正确理解和使用坐标系,并掌握ArcToolbox中的“要素转点”等工具。文章深入剖析了常见报错(如坐标系未定义、字段计算失败)的根源,提供了从基础操作到Python脚本自动化的实战解决方案,确保数据转换的准确与高效。

weixin_29284885的博客 575

芯片ATE测试PAT(Part Average Testing)学习总结-20250916

文章摘要:零件平均测试(PAT)是半导体制造中基于统计学的质量控制方法,分为静态和动态两种类型。静态PAT通过预先设定的固定限值(每6-8批次更新)筛选异常芯片,计算采用稳健平均值和四分位间距。动态PAT则根据实时数据调整限值,能更精确识别异常而不误判合格芯片。两种方法均采用"均值±6倍标准差"的计算公式,但动态PAT具有更好的适应性和准确性。该方法通过统计分析提高了芯片产品的质量和可靠性。

歌颂苦难的行为是无耻的; 1190

视频隐私脱敏工程化:CSRT/KCF追踪算法在本地推理中的实现与边界

在短视频内容合规审查中,动态遮挡(Dynamic Masking)是高频且高耗时的环节。传统手动关键帧打码不仅效率低下,且在目标快速移动或遮挡时极易出现遮罩漂移。本文从计算机视觉工程角度,解析基于CSRT与KCF算法的目标追踪方案在视频隐私处理中的技术路径、性能权衡及落地实践。

Mysssone的博客 223

华为OD机试真题2025双机位A卷 C++ 实现【采购订单】

在一个采购系统中,采购申请(PR)需要经过审批后才能生成采购订单(PO)。每个PR包含商品的单价(假设相同商品的单价一定是一样的)及数量信息。系统要求对商品进行分类处理:单价高于100元的商品需要单独处理,单价低于或等于100元的相同商品可以合并到同一采购订单PO中。针对单价低于100的小额订单,如果量大可以打折购买。

MISAYAONE的博客 674

我用 GPUWorks 在 M1 Pro 上搭了个发票识别原型

公司里经常要看电子发票。我想先做个小原型:把 PDF 发给一个自己部署的图文模型,让它提取发票类型、日期、交易双方和金额,再把结果交给同事核对。这个原型不用先接财务系统,先看看从部署到调用要走多少步,模型返回的内容能不能帮上忙。

鸽芷咕的博客 2万+

数学建模学习(121):Python实现模糊AHP(Fuzzy AHP)——从原理到实践

Python实现模糊AHP(Fuzzy AHP)

全栈川川 1541

【100分- 求最多可以派出多少支团队】(题目+思路+Java&C++&Python解析+在线测试)

用数组代表每个人的能力,一个比赛活动要求参赛团队的最低能力值为N,每个团队可以由1人或者2人组成,且1个人只能参加1个团队,计算出最多可以派出多少只符合要求的团队。

m0_73659489的博客 313

您您这可以把问小白的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。AI导出鸭

第三层是格式编译层。这个决策背后的判断很清晰:一个批量导出工具的价值,不在于“试三次”,而在于你真正用它处理了几十份技术文档、访谈记录或课程讲义之后,它是否值得留在你的工作流里。问小白的会话列表通过分页接口加载,AI导出鸭 在页面运行时建立旁路监听,捕获每一次分页请求返回的完整对话清单,包括会话 ID、标题、时间戳和隐藏的元数据字段。让AI导出回归优雅——这句话说的是:导出不该是体力活,而应该是一次完整的、可预期的文件交付。注意:这里的“批量”指的是左侧列表里的多个独立会话,不是一条会话内的多轮对话。

laoyunsi的博客 246

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

AI Agent之核心框架

A: 显式 Thought 有三类价值:可解释性(便于人类审计)、可调试性(定位哪一步选错工具)、学习信号(可做监督微调或评估中间步骤质量)。ReAct 把推理与 可执行行动 绑定,每一步行动后都有 真实 Observation 反馈,从而用工具结果约束生成,降低闭卷幻觉。做完不等于结束——还要 评估做得好不好,把 教训 记下来,下次 带着教训重试,反思作为 记忆,影响后续尝试的策略。工作流程:Action → Evaluation → Reflection → Retry。A: 普通 CoT 只在。

剑雨巍巍的博客 199

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

河道漂浮物目标检测数据集

目标检测,yolo,河道漂浮物目标检测数据集

DL_data_set的博客 201

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

【从零理解 Spring AI · 12】MCP 的两种角色:做客户端还是做服务端

上一篇讲了 MCP 的概念:标准协议、三大角色、M+N 替代 M×N。

nice_lcj520的博客 500

AI 应用开发工程师技术实践:大模型接入、通用组件封装与性能优化

本文提出AI应用从PoC到生产的核心挑战:模型调用的持续可用、可控与可优化。通过构建统一LLM网关实现多供应商路由与故障转移,封装对话、工具调用与RAG组件以解耦业务逻辑,结合前缀缓存、批处理与流式背压治理等性能优化手段,形成“接通→接稳→接快”的工程路径,最终以工程化能力决定AI应用的生产可用性。

2301_79189962的博客 558

大模型 Embedding 与向量相似度详解

Embedding 解决的问题:计算机不懂文字,但懂数字│▼文本 → 向量(1024维浮点数数组)│▼相似度解决的问题:怎么判断两个向量(文本)有多接近│▼余弦相似度:看向量方向的夹角,越接近0°越相似│▼最终效果:语义搜索——理解意思,而非字面匹配一句话总结:Embedding 把文字变成数字,余弦相似度比较数字的方向,两者结合实现了"理解语义"的搜索。

T3165919332的博客 90

AI前沿日报 · 2026-11-04 | 祛魅时刻:Astra“纯读权重“神话的崩塌

①Astra"裸权重通吃"被spaCy创始人Honnibal精准祛魅——仅1/3实验真裸读,数学能力提升依赖Python+50次迭代;②Simon Willison用Qwen 3.8-27B端侧复现权重空间编程;③Nvidia开源Auto-Ontology自动知识图谱;④$800开源全域抓取机器人Stringman;⑤OpenAI悄然重开Codex训练开关引信任危机;⑥DeepMind发布Gemini 4 Argon机器人基础模型;⑦美国科技巨头隐性AI债务达3.2万亿美元,6个月增90%。

johnsong2009的博客 573

GPT-1 架构和计算细节

下面配合框图,对 GPT-1 的每个组件做公式展开 + 数值实例(配置:12 层 × 768,12 头,FFN 3072,词表 40478,共 117M 参数)。GPT-1 把翻译模型的编码器-解码器砍掉一半,只留解码器,然后以"预测下一个词"为目标在 BooksCorpus 上预训练。与 2017 原版的四个架构差异(框图中标 ★):h0=E[token]+Epos[position],E∈R40478×768, Epos∈R512×768h^0 = E[\text{token}] + E_{pos}[\

eloudy的专栏 278

终端 AI 审计与 “龙虾” 类智能体风险治理:从可见性到闭环溯源

生成式 AI 办公普及之后,数据泄露风险逐步下沉到终端。员工将合同、源代码、客户资料粘贴至公有大模型,以及龙虾(OpenClaw)这类本地开源 AI 智能体的滥用,成为企业安全新挑战。传统网络边界防护存在审计盲区,本文从风险链路拆解、核心能力模型、分级治理策略、落地踩坑点以及技术局限性多角度,分享终端侧 AI 安全治理的实践思路。

2401_86491085的博客 640

2.53 基于极稀疏指纹的室内定位注意力图元学习

该论文发表于IEEE Transactions on Mobile Computing(TMC)2026年6月,面向极稀疏指纹条件下的WiFi室内定位,针对指纹采集人力成本高、标记指纹稀缺时定位精度大幅下降的痛点,提出注意力图元学习模型AGML(Attentional Graph Meta‑Learning),结合图神经网络、元学习、两种指纹数据增强与分布对齐技术,在标记指纹极少的场景实现高精度室内定位,同时公开了多套真实+仿真定位数据集用于基准测试。场景:二维室内空间,障碍物造成信号遮挡,

weixin_42963026的博客 338
上一篇: AI Agent从无到有43: LangChain 数据加载器全解析 — PDF、网页、CSV 与自定义 Loader
下一篇: AI Agent从无到有45: LangChain 嵌入模型实战 — 从文本到向量
Wang's Blog
博客等级 码龄12年 7419粉丝 2410原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值