[Feature] C++ Extension: Introduce DocNode, TextSplitterBase, SentenseSplitter#1022
[Feature] C++ Extension: Introduce DocNode, TextSplitterBase, SentenseSplitter#1022CompromisedKiwi wants to merge 79 commits intoLazyAGI:mainfrom
DocNode, TextSplitterBase, SentenseSplitter#1022Conversation
Summary of ChangesHello @CompromisedKiwi, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a substantial architectural shift by migrating several core RAG (Retrieval Augmented Generation) components, specifically DocNode, NodeTransform, and TextSplitterBase, from Python to C++. The primary motivation behind this migration is to significantly enhance the performance of compute-intensive operations within the RAG pipeline. The changes establish a robust hybrid Python-C++ framework, leveraging pybind11 for interoperability and a structured C++ project layout, ensuring that performance gains are achieved without sacrificing the flexibility of Python-based logic where appropriate. Highlights
Changelog
Ignored Files
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
本次 PR 将 DocNode / NodeTransform / TextSplitterBase / SentenceSplitter 等核心能力迁移到 C++ 扩展,以提升性能,这是一个很好的方向。代码结构清晰,分为了 core、adaptor 和 binding 三层,并且使用了 pybind11、xxHash、sentencepiece 等现代 C++ 库。然而,我发现了一些严重的问题需要合并前解决:
- 存在多处线程安全(竞态条件)和内存安全(悬垂指针)的隐患,可能导致程序崩溃或未定义行为。
- 部分 pybind11 绑定代码引用了未实现的 C++ 方法,会导致编译失败。
- 在 C++ 与 Python 交互的逻辑中存在一些参数和返回值处理的 bug。
我已经在代码中留下了具体的审查意见,请仔细查看。修复这些问题后,这将是一次非常有价值的性能优化贡献。
wzh1994
left a comment
There was a problem hiding this comment.
PR Summary:
目的
本 PR 为 LazyLLM 的 C++ 扩展层引入三个核心类——DocNode、TextSplitterBase、SentenceSplitter,并将 CI 中原有的"仅编译 C++ 扩展"作业升级为"编译 + Python 回归测试"全流程作业。
变更文件与原因
.github/workflows/main.yml——cpp_ext_test作业大幅扩展:增加环境变量(各厂商 API Key)、安装测试依赖、下载测试数据集、构建 C++ 扩展后执行cmake --install,再跑basic_tests和advanced_tests,确保 C++ 扩展在 Linux/macOS/Windows 三平台上与 Python 侧功能回归一致。.github/workflows/publish_release.yml——少量清理(删除多余空行/步骤),与新构建流程对齐。csrc/下新增/修改的 C++ 源文件(diff 被截断,但从 PR 标题可推断)——实现DocNode(文档节点数据结构)、TextSplitterBase(分割器基类)、SentenceSplitter(句子级分割器)的 pybind11 绑定,供 Python 侧通过LAZYLLM_ENABLE_CPP_OVERRIDE=1热替换原有纯 Python 实现。
关键设计决策
- CI 作业加了
if: always(),即使前置clone作业失败也会执行,这可能是为了确保 C++ 构建状态始终可见,但也意味着在 clone 失败时会产生无意义的失败日志。 - 使用
cmake --install ... --component lazyllm_cpp将编译产物直接安装到工作区的lazyllm/目录下,避免修改sys.path,保持与 pip 安装后的目录结构一致。 - 环境变量
LAZYLLM_ENABLE_CPP_OVERRIDE=1作为运行时开关,允许 Python 回归测试在有/无 C++ 扩展两种模式下复用同一套用例。 - 测试依赖按平台拆分(
requirements_linux.txt/requirements_mac.txt),Windows 仅安装通用依赖。
潜在风险
if: always()可能导致 checkout 步骤失败后后续步骤连锁报错,建议改为if: needs.clone.result == 'success'或至少在 checkout 步骤加容错。git clone下载测试数据集使用PERSONAL_GITHUB_TOKEN,若 secret 未配置则回退到github.token,对 fork 仓库的 PR 可能因权限不足而失败。- CI 新增大量厂商 API Key 环境变量,外部贡献者的 PR 将无法获取这些 secret,需确认测试用例在 key 缺失时能优雅跳过。
- diff 被截断,无法审查 C++ 实现本身(内存管理、线程安全、与 Python GIL 的交互),建议重点审查 pybind11 绑定中的生命周期和异常传播。
timeout-minutes: 120对三平台 build + 全量回归来说偏长,可能掩盖卡死问题。
Findings:
- total_issues: 33
- logic: 14
- safety: 6
- style: 4
- exception: 3
- maintainability: 2
- type: 2
- design: 1
- performance: 1
auto reviewed by BOT (claude-opus-4-6)
📌 PR 内容 / PR Description
lazyllm_cpp扩展更新,涉及四个RAG相关类:DocNode、_TextSplitterBase、SentenceSplitter。架构设计(core / adaptor / binding)
core层(csrc/core/include,csrc/core/src)DocNode、TextSplitterBase、SentenceSplitter、Tokenizer接口、split与merge策略。string_view、并发)adaptor层(csrc/adaptor)std::any参数编解码、GIL 获取、统一调用入口)。AdaptorBaseWrapper、DocumentStore(缓存 Python 对象,回调wrapper)。binding层(csrc/binding)export_doc_node.cpp、export_text_splitter_base.cpp、export_sentence_splitter.cpp。三方依赖(CMake 声明)
依赖声明位于
csrc/cmake/third_party.cmakepybind11:C++/Python 绑定层实现。Python3(Interpreter + Development)xxHash:高性能哈希能力(如内容哈希相关路径)。cpp_tiktoken:tokenizer 编解码能力(TiktokenTokenizer后端)。pcre2等传递依赖。utf8proc:Unicode 文本处理支持。ThreadPool(header-only,本地引入)csrc/core/include/thread_pool.hppprogschj/ThreadPool(header-only)NodeTransform::batch_forward并行执行。设计哲学:core 与 binding 分离
本 PR 统一遵循“core 负责算法,binding 负责 Python 语义”的原则:
kwargs、命名兼容与类型多态输入。std::any。string_view使用与未使用点已使用
string_view的加速点TextSplitterBase::split_text输入视图:csrc/core/src/text_splitter_base.cpp:31split_recursive、split_by_functions、split_text_while_keeping_separatorvector<string_view>,减少中间拷贝。当前未完全
string_view化的点merge_chunks阶段输出仍为vector<string>(需要所有权与后续 decode/拼接安全性)。SentenceSplitter合并时维护Chunk.text(因为 overlap 回填、拼接、trim 都需要稳定可拥有字符串)。TiktokenTokenizer::encode仍需先转 std::string(底层依赖接口限制),因此部分 merge 路径仍有字符串拷贝行为。Python 侧接入方式(DocNode vs TextSplitterBase / SentenceSplitter)
本 PR 在 Python 侧采用了两种不同的 C++ 接入策略,分别服务于不同的稳定性与扩展性诉求:
@cpp_class(整类替换)@cpp_proxy(实例代理)整体上,这一设计实现了“核心对象强下沉”与“可扩展流程渐进加速”的分层目标。
进度
✅ 变更类型 / Type of Change
🧪 如何测试 / How Has This Been Tested?
LAZYLLM_ENABLE_CPP_OVERRIDE=1test_doc_node.py, test_transform.pyrag_online.py⚡ 更新后的用法示例 / Usage After Update
开启环境变量
LAZYLLM_ENABLE_CPP_OVERRIDE=1后lazy会自动加载cpp扩展(linux环境如果加载
.so失败需要指定标准库路径export LD_PRELOAD=/lib/x86_64-linux-gnu/libstdc++.so.6)