源代码
本教程介绍如何使用一种特殊方法加载源代码文件并进行语言解析:代码中的每个顶级函数和类都将加载到单独的文档中。任何未加载到函数和类中的剩余顶级代码将加载到单独的文档中。
这种方法有可能提高对源代码的问答模型准确性。
支持的代码解析语言有
- C (*)
- C++ (*)
- C# (*)
- COBOL
- Elixir
- Go (*)
- Java (*)
- JavaScript (需要包 esprima)
- Kotlin (*)
- Lua (*)
- Perl (*)
- Python
- Ruby (*)
- Rust (*)
- Scala (*)
- TypeScript (*)
标有 (*) 的项需要 tree_sitter 和 tree_sitter_languages 包。使用 tree_sitter 添加对其他语言的支持很简单,尽管这目前需要修改 LangChain。
用于解析的语言可以进行配置,以及激活基于语法的分割所需的最小行数。
如果未明确指定语言,LanguageParser 将(如果存在)从文件名扩展名推断出一种语言。
%pip install -qU esprima esprima tree_sitter tree_sitter_languages
import warnings
warnings.filterwarnings("ignore")
from pprint import pprint
from langchain_community.document_loaders.generic import GenericLoader
from langchain_community.document_loaders.parsers import LanguageParser
from langchain_text_splitters import Language
loader = GenericLoader.from_filesystem(
    "./example_data/source_code",
    glob="*",
    suffixes=[".py", ".js"],
    parser=LanguageParser(),
)
docs = loader.load()
len(docs)
6
for document in docs:
    pprint(document.metadata)
{'content_type': 'functions_classes',
 'language': <Language.PYTHON: 'python'>,
 'source': 'example_data/source_code/example.py'}
{'content_type': 'functions_classes',
 'language': <Language.PYTHON: 'python'>,
 'source': 'example_data/source_code/example.py'}
{'content_type': 'simplified_code',
 'language': <Language.PYTHON: 'python'>,
 'source': 'example_data/source_code/example.py'}
{'content_type': 'functions_classes',
 'language': <Language.JS: 'js'>,
 'source': 'example_data/source_code/example.js'}
{'content_type': 'functions_classes',
 'language': <Language.JS: 'js'>,
 'source': 'example_data/source_code/example.js'}
{'content_type': 'simplified_code',
 'language': <Language.JS: 'js'>,
 'source': 'example_data/source_code/example.js'}
print("\n\n--8<--\n\n".join([document.page_content for document in docs]))
class MyClass:
    def __init__(self, name):
        self.name = name
    def greet(self):
        print(f"Hello, {self.name}!")
--8<--
def main():
    name = input("Enter your name: ")
    obj = MyClass(name)
    obj.greet()
--8<--
# Code for: class MyClass:
# Code for: def main():
if __name__ == "__main__":
    main()
--8<--
class MyClass {
  constructor(name) {
    this.name = name;
  }
  greet() {
    console.log(`Hello, ${this.name}!`);
  }
}
--8<--
function main() {
  const name = prompt("Enter your name:");
  const obj = new MyClass(name);
  obj.greet();
}
--8<--
// Code for: class MyClass {
// Code for: function main() {
main();
解析器可以对小文件禁用。
参数 parser_threshold 指示源代码文件必须具有的最小行数,以便使用解析器进行分段。
loader = GenericLoader.from_filesystem(
    "./example_data/source_code",
    glob="*",
    suffixes=[".py"],
    parser=LanguageParser(language=Language.PYTHON, parser_threshold=1000),
)
docs = loader.load()
len(docs)
1
print(docs[0].page_content)
class MyClass:
    def __init__(self, name):
        self.name = name
    def greet(self):
        print(f"Hello, {self.name}!")
def main():
    name = input("Enter your name: ")
    obj = MyClass(name)
    obj.greet()
if __name__ == "__main__":
    main()
分割
对于那些过大的函数、类或脚本,可能需要额外的分割。
loader = GenericLoader.from_filesystem(
    "./example_data/source_code",
    glob="*",
    suffixes=[".js"],
    parser=LanguageParser(language=Language.JS),
)
docs = loader.load()
from langchain_text_splitters import (
    Language,
    RecursiveCharacterTextSplitter,
)
API 参考:Language | RecursiveCharacterTextSplitter
js_splitter = RecursiveCharacterTextSplitter.from_language(
    language=Language.JS, chunk_size=60, chunk_overlap=0
)
result = js_splitter.split_documents(docs)
len(result)
7
print("\n\n--8<--\n\n".join([document.page_content for document in result]))
class MyClass {
  constructor(name) {
    this.name = name;
--8<--
}
--8<--
greet() {
    console.log(`Hello, ${this.name}!`);
  }
}
--8<--
function main() {
  const name = prompt("Enter your name:");
--8<--
const obj = new MyClass(name);
  obj.greet();
}
--8<--
// Code for: class MyClass {
// Code for: function main() {
--8<--
main();
使用 Tree-sitter 模板添加语言
使用 Tree-Sitter 模板扩展语言支持涉及几个基本步骤
- 创建新的语言文件:
- 首先在指定目录 (langchain/libs/community/langchain_community/document_loaders/parsers/language) 中创建一个新文件。
- 根据现有语言文件(如 cpp.py)的结构和解析逻辑来建模此文件。
- 您还需要在 langchain 目录 (langchain/libs/langchain/langchain/document_loaders/parsers/language) 中创建一个文件。
 
- 解析语言细节:
- 模仿 cpp.py文件中使用的结构,并根据您要引入的语言进行调整。
- 主要改动涉及调整块查询数组以适应您正在解析的语言的语法和结构。
 
- 模仿 
- 测试语言解析器:
- 为了彻底验证,为新语言生成一个测试文件。在指定目录 (langchain/libs/community/tests/unit_tests/document_loaders/parsers/language) 中创建 test_language.py。
- 遵循 test_cpp.py的示例,为新语言中解析的元素建立基本测试。
 
- 为了彻底验证,为新语言生成一个测试文件。在指定目录 (langchain/libs/community/tests/unit_tests/document_loaders/parsers/language) 中创建 
- 集成到解析器和文本分割器中:
- 将您的新语言集成到 language_parser.py文件中。确保更新LANGUAGE_EXTENSIONS和LANGUAGE_SEGMENTERS以及LanguageParser的文档字符串,以便识别和处理添加的语言。
- 此外,确认您的语言已包含在 text_splitter.py中的Language类中,以进行正确解析。
 
- 将您的新语言集成到 
通过遵循这些步骤并确保全面的测试和集成,您将成功地使用 Tree-Sitter 模板扩展语言支持。
祝您好运!