Contributing to langchaingo
2026/9/16 14:37:07 网站建设 项目流程

Contributing to langchaingo

【免费下载链接】langchaingoLangChain for Go, the easiest way to write LLM-based programs in Go项目地址: https://gitcode.com/GitHub_Trending/la/langchaingo

First off, thanks for taking the time to contribute! ❤️ All types of contributions are encouraged and valued. See the Table of Contents for different ways to help and details about how this project handles them. ...


And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:

  • Star the project
  • Tweet about it ...
可以看到:第一个 chunk 保留了顶层标题 `# Contributing to langchaingo` 与引言段落;引用块被整体保留并以前缀 `> ` 还原 Markdown 语义;每个 chunk 之间由 `---` 分隔。 ## 二、MarkdownTextSplitter 的核心机制 ### 2.1 统一接口 所有分割器都实现 [TextSplitter](https://link.gitcode.com/i/d164aaf1579fc056534b1bc02897aed0) 接口,只有一个方法: ```go type TextSplitter interface { SplitText(text string) ([]string, error) }

MarkdownTextSplitter在 markdown_splitter.go 中定义,结构体字段与构造函数NewMarkdownTextSplitter一一对应:

type MarkdownTextSplitter struct { ChunkSize int ChunkOverlap int SecondSplitter TextSplitter CodeBlocks bool ReferenceLinks bool HeadingHierarchy bool JoinTableRows bool LenFunc func(string) int }

2.2 解析与逐块分派

SplitText(markdown_splitter.go)的流程分两步:

  • 使用gitlab.com/golang-commonmark/markdown解析器把 Markdown 源码解析成 token 流(markdown.New(markdown.XHTMLOutput(true)));
  • 构造markdownContext(持有游标startAt/endAt、token 列表、分块参数、当前标题栈等状态),调用splitText()逐 token 扫描。

主循环(markdown_splitter.go)是一个典型的按 Markdown 块类型分派switch

Token 类型处理函数对应 Markdown 元素
HeadingOpenonMDHeaderH1~H6 标题
TableOpenonMDTable表格
ParagraphOpenonMDParagraph段落
BlockquoteOpenonMDQuote引用块
BulletListOpenonMDBulletList无序列表
OrderedListOpenonMDOrderedList有序列表
ListItemOpenonMDListItem列表项(可能嵌套子列表)
CodeBlockonMDCodeBlock缩进代码块
FenceonMDFence围栏代码块
HronMDHr分割线---
其他跳到对应关闭标签之后跳过

每个处理函数先通过indexOfCloseTag(markdown_splitter.go)找到与当前开始标签配对的关闭标签位置(该辅助函数用反射表closeTypes维护"开始类型→关闭类型"的映射,并正确处理嵌套计数),再针对该块类型做语义化切割,最后把产出的小片段通过joinSnippet汇入当前块。

2.3 标题栈:chunk 的前缀标题从哪来

onMDHeader(markdown_splitter.go)是这套机制的核心。它从 token 中取出HLevel与标题文本,构造形如## Second header: h2的标题行;同时维护一个hTitleStack

  • 若开启HeadingHierarchy(对应选项WithHeadingHierarchy),当前块会被前缀上从顶层到当前层级的全部标题(用换行连接、忽略空层级),这正是样例中多个 chunk 都带有多级标题前缀(如# Fourth header: h1\n## Fifth header: h2\n#### Sixth header: h4)的原因;
  • 每个标题出现时都会先applyToChunks()触发一次"封块",因此标题天然成为 chunk 的边界——新标题总是开启新块,并把标题作为该块及后续块的前缀。

applyToChunks(markdown_splitter.go)负责最终成块:

  • 若当前块长度未超过ChunkSize + ChunkOverlap,直接作为一个 chunk;
  • 若超过,则交给SecondSplitter二次切分(默认是 NewRecursiveCharacter,分隔符依次为\n\n\n、);
  • 最终为每个 chunk 前缀标题,且通过hTitlePrepended标志保证标题只被写入一次。

三、从样例看输出规律:chunk 边界与标题前缀

对照 example_markdown_header_512.md 的实际输出,可以总结出以下可复现的规律:

3.1 标题是硬边界

样例中每一个##/###/####标题都开启一个新的 chunk。例如"Reporting Bugs"一节,#### Before Submitting a Bug Report标题多次出现,每次都被单独成块,且新块会携带当前完整的标题层级前缀:

#### Before Submitting a Bug Report - Make sure that you are using the latest version.

3.2 同级标题连续出现时合并到相邻块

连续出现的标题(如### Reporting Bugs后紧跟#### Before Submitting a Bug Report)会被合并在同一个块内,体现为"标题即内容前缀"的设计:

### Reporting Bugs #### Before Submitting a Bug Report A good bug report shouldn't leave others needing to chase you up for more information. ...

3.3 引用块整体保留

文档中的>引用(如开篇的"支持项目的方式"、I Have a Question前的提示、Legal Notice)被完整保留,且每行以>前缀还原。这在onMDQuote(markdown_splitter.go)中通过递归克隆子上下文并把每个子 chunk 用formatWithIndent(chunk, "> ")缩进实现。

3.4 多级列表保序保缩进

样例中的目录(Table of Contents)是一个三层嵌套的无序列表。onMDListItem(markdown_splitter.go)递归处理子列表,indentLevel控制缩进,二级及以下列表项会附加两个空格的前缀。因此输出中的层级缩进与原文一致:

## Table of Contents - [I Want To Contribute](#i-want-to-contribute) - [Reporting Bugs](#reporting-bugs) - [Before Submitting a Bug Report](#before-submitting-a-bug-report) - [How Do I Submit a Good Bug Report?](#how-do-i-submit-a-good-bug-report)

3.5 长块触发二次分割

当段落较长、超出 512 字符时,applyToChunks会把当前块交给SecondSplitter再次切分,切分后每个子块仍会前缀标题。这也是"内容充实度不缩水"的保障:不会因为块超长而丢弃信息。

四、参数配置全解析

MarkdownTextSplitter的所有行为都由 options.go 中的函数式选项控制。下表汇总全部相关参数及其默认值(默认值定义于 token_splitter.go 与DefaultOptions):

选项函数默认值作用
WithChunkSize(n)512单个 chunk 的目标最大长度;超出后触发二次切分
WithChunkOverlap(n)100相邻 chunk 的重叠量,用于保持上下文连续;本例测试用 64
WithSecondSplitter(s)递归字符分割器超长块的二次切分器,默认分隔符\n\n\n
WithCodeBlocks(bool)false是否保留围栏/缩进代码块;false 时直接丢弃
WithReferenceLinks(bool)false是否把[text][label]引用式链接用定义处的 URL 补全;默认丢弃引用定义
WithHeadingHierarchy(bool)false是否在每个 chunk 前缀完整标题层级;true 时样例中会出现多级标题前缀
WithJoinTableRows(bool)false表格是否按行独立成块;false 时每行一个 chunk 并自动补表头
WithLenFunc(fn)utf8.RuneCountInString计算字符串长度的函数,决定"长度"口径(字符数/字节数/token 数)

几个要点:

  • 长度口径可换:默认用 Unicode 字符数统计;测试 TestMarkdownHeaderTextSplitter_LenFunc 展示了用tiktoken-gocl100k_base编码按token 数计块的用法,这对对齐 LLM 上下文窗口很有价值。
  • 表格行为:splitTableRows 默认按行切分,且每行 chunk 会自动补上表头与---分隔行;开启WithJoinTableRows(true)后则把多行合并到接近 ChunkSize 为止。测试 TestMarkdownHeaderTextSplitter_Table 对两种行为均有断言。
  • 代码块WithCodeBlocks(true)时,围栏代码块以\n\``语言\n内容```\n形式原样输出(见onMDFence,[markdown_splitter.go](https://link.gitcode.com/i/13d99729b9aae39602edc65eb2c39864));缩进代码块按 CommonMark Spec 4.4 每行补 4 空格(onMDCodeBlock`)。关闭时两者被丢弃。
  • 内联元素splitInline(markdown_splitter.go)在ReferenceLinks=false时把软换行\n、硬换行\\\n**/*/~~强调、行内代码`、链接、图片等逐一还原,保证 chunk 仍是合法 Markdown。

五、如何复现与落地使用

5.1 复现本样例

在仓库根目录执行:

go test ./textsplitter/ -run TestMarkdownHeaderTextSplitter -v

该测试会读取 example.md,用WithChunkSize(512)WithChunkOverlap(64)分割,并重新写出 example_markdown_header_512.md,你可以在本地看到完全一致的输出(测试还同时覆盖了纯标题分割、表格、列表、代码块、内联元素、LenFunc 等 6 组用例)。

5.2 在自己的 RAG 流程中使用

最小可用示例:

import ( "github.com/tmc/langchaingo/schema" "github.com/tmc/langchaingo/textsplitter" ) func main() { splitter := textsplitter.NewMarkdownTextSplitter( textsplitter.WithChunkSize(512), textsplitter.WithChunkOverlap(64), textsplitter.WithHeadingHierarchy(true), textsplitter.WithCodeBlocks(true), ) docs, err := textsplitter.CreateDocuments(splitter, []string{markdownSource}, nil) if err != nil { panic(err) } for _, doc := range docs { _ = schema.Document{PageContent: doc.PageContent, Metadata: doc.Metadata} } }

【免费下载链接】langchaingoLangChain for Go, the easiest way to write LLM-based programs in Go项目地址: https://gitcode.com/GitHub_Trending/la/langchaingo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询