大数跨境
0
0

如何使用 PyPDF 和 LangChain构建自定义 PDF 解析器?

如何使用 PyPDF 和 LangChain构建自定义 PDF 解析器? AI Agent 领域
2025-07-03
0
导读:PDF虽好,但提取其内容却没那么简单!简单的方式帮你提取pdf内容!

PDF 文件无处不在,你可能在各种地方都见过它们,比如大学论文、电费账单、办公合同、产品手册等等。它们非常常见,但处理起来却并不像看起来那么简单。假设你想从 PDF 中提取有用信息,比如读取文本、将其拆分为各个部分,或者获取一个快速摘要。这听起来似乎很简单,但当你真正尝试时,就会发现并非如此。

与 Word 或 HTML 文件不同,PDF 文件并不以一种整洁、易于阅读的方式存储内容。它们的设计初衷是为了看起来美观,而不是为了被程序读取。文本可能到处都是,被分割成奇怪的块,散布在页面上,或者与表格和图像混杂在一起。这使得从它们中获取干净、结构化的数据变得非常困难。

接下来,我们将构建一个能够处理这种混乱局面的工具。我们将创建一个自定义的 PDF 解析器,它可以:

  • 在页面级别提取并清理 PDF 中的文本,可选地保留布局格式以获得更好的格式化效果
  • 处理图像元数据提取
  • 通过检测跨页面重复的行来移除不需要的页眉和页脚,从而减少噪声
  • 检索详细的文档和页面级别元数据,如作者、标题、创建日期、旋转角度和页面大小
  • 将内容拆分为便于进一步进行自然语言处理(NLP)或大型语言模型(LLM)处理的可管理部分

项目结构

在开始之前,最好组织一下项目文件,以便清晰和可扩展。

custom_pdf_parser/

├── parser.py           
├── langchain_loader.py  
├── pipeline.py          
├── example.py     
├── requirements.txt     # 依赖项列表
└── __init__.py         # (可选)标记目录为 Python 包

你可以将 __init__.py 文件留空,因为它的主要作用仅仅是表明这个目录应该被视为一个 Python 包。接下来我将逐步解释其余文件的用途。

所需工具(requirements.txt)

所需的库有:

  • PyPDF:一个纯 Python 库,用于读取和写入 PDF 文件。我们将使用它从 PDF 文件中提取文本。
  • LangChain:一个用于构建具有语言模型的情境感知应用程序的框架(我们将用它来处理和链接文档任务)。它将用于正确处理和组织文本。

使用以下命令安装它们:

pip install pypdf langchain

如果你想整齐地管理依赖项,可以创建一个 requirements.txt 文件,内容如下:

pypdf
langchain
requests

然后运行以下命令:

pip install -r requirements.txt

PDF 解析器(parser.py)

核心类 CustomPDFParser 使用 PyPDF 从每页 PDF 中提取文本和元数据。它还包含清理文本、提取图像信息(可选)以及移除每页上经常出现的重复页眉或页脚的方法。

  • 它支持保留布局格式
  • 它提取诸如页码、旋转角度和媒体框尺寸等元数据
  • 它可以过滤掉内容太少的页面
  • 文本清理会移除多余的空白,同时保留段落分隔

以下是实现所有这些功能的代码:

import os
import logging
from pathlib import Path
from typing import List, Dict, Any
import pypdf
from pypdf import PdfReader
# 配置日志以显示信息及以上的消息
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class CustomPDFParser:
def __init__(
      self,extract_images: bool = False,preserve_layout: bool = True,remove_headers_footers: bool = True,min_text_length: int = 10
  )
:

      """
      使用选项初始化解析器,以提取图像、保留布局、移除重复的页眉/页脚以及设置页面的最小文本长度。
      参数:
          extract_images:是否从页面中提取图像信息
          preserve_layout:是否在文本提取中保留布局间距
          remove_headers_footers:是否检测并移除页眉/页脚
          min_text_length:页面被视为有效的最小文本长度
      """

      self.extract_images = extract_images
      self.preserve_layout = preserve_layout
      self.remove_headers_footers = remove_headers_footers
      self.min_text_length = min_text_length
def extract_text_from_page(self, page: pypdf.PageObject, page_num: int) -> Dict[str, Any]:
      """
      从单个 PDF 页面中提取文本和元数据。
      参数:
          page:PyPDF 页面对象
          page_num:从零开始的页面编号
      返回值:
          包含以下键的字典:
              - 'text':提取并清理后的文本字符串,
              - 'metadata':页面元数据字典,
              - 'word_count':提取文本中的单词数量
      """

      try:
# 提取文本,可选地保留布局以获得更好的格式化效果
          if self.preserve_layout:
              text = page.extract_text(extraction_mode="layout")
          else:
              text = page.extract_text()
        # 清理文本:移除多余的空白并规范段落
          text = self._clean_text(text)
        # 收集页面元数据(页面编号、旋转角度、媒体框)
          metadata = {
              "page_number": page_num + 1,  # 从 1 开始编号
              "rotation": getattr(page, "rotation"0),
              "mediabox": str(getattr(page, "mediabox"None)),
          }
          # 如果请求,可选地从页面中提取图像信息
          if self.extract_images:
              metadata["images"] = self._extract_image_info(page)
          # 返回包含该页面文本和元数据的字典
          return {
              "text": text,
              "metadata": metadata,
              "word_count": len(text.split()) if text else0
          }
      except Exception as e:
          # 记录错误,并为有问题的页面返回空数据
          logger.error(f"提取页面 {page_num} 时出错:{e}")
          return {
              "text""",
              "metadata": {"page_number": page_num + 1"error": str(e)},
              "word_count"0
          }
def _clean_text(self, text: str) -> str:
      """
      清理并规范提取的文本,保留段落分隔。
      参数:
          text:从 PDF 页面中提取的原始文本
      返回值:
          清理后的文本字符串
      """

      ifnot text:
          return""
      lines = text.split('\n')
      cleaned_lines = []
      for line in lines:
          line = line.strip()  # 移除首尾空白
          if line:
              # 非空行;保留它
              cleaned_lines.append(line)
          elif cleaned_lines and cleaned_lines[-1]:
              # 通过仅在前一行存在时保留空行来保留段落分隔
              cleaned_lines.append("")
      cleaned_text = '\n'.join(cleaned_lines)
# 将超过两个连续空行的实例减少到两个
      while'\n\n\n'in cleaned_text:
          cleaned_text = cleaned_text.replace('\n\n\n''\n\n')
      return cleaned_text.strip()
def _extract_image_info(self, page: pypdf.PageObject) -> List[Dict[str, Any]]:
      """
      从页面中提取基本图像元数据(如果可用)。
      参数:
          page:PyPDF 页面对象
      返回值:
          包含图像信息(索引、名称、宽度、高度)的字典列表
      """

      images = []
      try:
          # PyPDF 页面可以有一个 'images' 属性,列出嵌入的图像
          if hasattr(page, 'images'):
              for i, image in enumerate(page.images):
                  images.append({
                      "image_index": i,
                      "name": getattr(image, 'name'f"image_{i}"),
                      "width": getattr(image, 'width'None),
                      "height": getattr(image, 'height'None)
                  })
      except Exception as e:
          logger.warning(f"图像提取失败:{e}")
      return images

def _remove_headers_footers(self, pages_data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
      """
      移除在许多页面上出现的重复页眉和页脚。
      通过识别在超过 50% 的页面文本开头或结尾处出现的行来实现,然后移除这些行。
      参数:
          pages_data:代表每个页面提取数据的字典列表。
      返回值:
          移除页眉/页脚后的页面更新列表
      """

      # 如果页面数量足够且启用了该选项,则尝试移除
      if len(pages_data) < 3ornot self.remove_headers_footers:
          return pages_data
      # 收集每个页面文本的首行和尾行以供分析
      first_lines = [page["text"].split('\n')[0if page["text"else""for page in pages_data]
      last_lines = [page["text"].split('\n')[-1if page["text"else""for page in pages_data]
      threshold = len(pages_data) * 0.5# 超过 50% 的页面
      # 识别频繁出现的候选页眉和页脚
      potential_headers = [line for line in set(first_lines)
                          if first_lines.count(line) > threshold and line.strip()]
      potential_footers = [line for line in set(last_lines)
                          if last_lines.count(line) > threshold and line.strip()]
      # 从每个页面的文本中移除已识别的页眉和页脚
      for page_data in pages_data:
          lines = page_data["text"].split('\n')
          # 如果与频繁出现的页眉匹配,则移除页眉
          if lines and potential_headers:
              for header in potential_headers:
                  if lines[0].strip() == header.strip():
                      lines = lines[1:]
                      break
          # 如果与频繁出现的页脚匹配,则移除页脚
          if lines and potential_footers:
              for footer in potential_footers:
                  if lines[-1].strip() == footer.strip():
                      lines = lines[:-1]
                      break

          page_data["text"] = '\n'.join(lines).strip()
      return pages_data
def _extract_document_metadata(self, pdf_reader: PdfReader, pdf_path: str) -> Dict[str, Any]:
      """
      从 PDF 文档本身提取元数据。
      参数:
          pdf_reader:PyPDF PdfReader 实例
          pdf_path:PDF 文件路径
      返回值:
          包含文件信息和 PDF 文档元数据的字典
      """

      metadata = {
          "file_path": pdf_path,
          "file_name": Path(pdf_path).name,
          "file_size": os.path.getsize(pdf_path) if os.path.exists(pdf_path) elseNone,
      }
      try:
          if pdf_reader.metadata:
              # 如果可用,提取常见的 PDF 元数据键
              metadata.update({
                  "title": pdf_reader.metadata.get('/Title'''),
                  "author": pdf_reader.metadata.get('/Author'''),
                  "subject": pdf_reader.metadata.get('/Subject'''),
                  "creator": pdf_reader.metadata.get('/Creator'''),
                  "producer": pdf_reader.metadata.get('/Producer'''),
                  "creation_date": str(pdf_reader.metadata.get('/CreationDate''')),
                  "modification_date": str(pdf_reader.metadata.get('/ModDate''')),
              })
      except Exception as e:
          logger.warning(f"元数据提取失败:{e}")
      return metadata
def parse_pdf(self, pdf_path: str) -> Dict[str, Any]:
      """
      解析整个 PDF 文件。打开文件,逐页提取文本和元数据,如果配置了,则移除页眉/页脚,并汇总结果。
      参数:
          pdf_path:PDF 文件路径
      返回值:
          包含以下键的字典:
              - 'full_text':所有页面合并后的文本,
              - 'pages':包含文本和元数据的页面字典列表,
              - 'document_metadata':文件和 PDF 元数据,
              - 'total_pages':PDF 中的总页数,
              - 'processed_pages':过滤后保留的页面数量,
              - 'total_words':解析文本的总单词数
      """

      try:
          with open(pdf_path, 'rb'as file:
              pdf_reader = PdfReader(file)
              doc_metadata = self._extract_document_metadata(pdf_reader, pdf_path)
              pages_data = []
              # 遍历所有页面并提取数据
              for i, page in enumerate(pdf_reader.pages):
                  page_data = self.extract_text_from_page(page, i)
                  # 只保留文本长度足够的页面
                  if len(page_data["text"]) >= self.min_text_length:
                      pages_data.append(page_data)
              # 移除重复的页眉和页脚
              pages_data = self._remove_headers_footers(pages_data)
           # 使用双换行符作为分隔符合并所有页面文本
              full_text = '\n\n'.join(page["text"for page in pages_data if page["text"])
              # 返回最终的结构化数据
              return {
                  "full_text": full_text,
                  "pages": pages_data,
                  "document_metadata": doc_metadata,
                  "total_pages": len(pdf_reader.pages),
                  "processed_pages": len(pages_data),
                  "total_words": sum(page["word_count"for page in pages_data)
              }
      except Exception as e:
          logger.error(f"解析 PDF {pdf_path} 失败:{e}")
          raise

与 LangChain 集成(langchain_loader.py)

LangChainPDFLoader 类封装了自定义解析器,并将解析后的页面转换为 LangChain 文档对象,这些对象是 LangChain 流水线的基础构建块。

  • 它允许使用 LangChain 的 RecursiveCharacterTextSplitter 将文档拆分为更小的部分
  • 你可以自定义分块大小和重叠部分,以便用于下游的 LLM 输入
  • 这个加载器支持将原始 PDF 内容与 LangChain 的文档抽象之间进行干净的集成

其背后的逻辑如下:

from typing import List, Optional, Dict, Any
from langchain.schema import Document
from langchain.document_loaders.base import BaseLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from parser import CustomPDFParser  # 导入上面定义的解析器
class LangChainPDFLoader(BaseLoader):
   def __init__(
       self,file_path: str,parser_config: Optional[Dict[str, Any]] = None,chunk_size: int = 500, chunk_overlap: int = 50
   )
:

       """
       使用 PDF 文件路径、解析器配置和分块参数初始化加载器。
       参数:
           file_path:PDF 文件路径
           parser_config:解析器选项字典
           chunk_size:用于拆分长文本的分块大小
           chunk_overlap:拆分时的分块重叠部分
       """

       self.file_path = file_path
       self.parser_config = parser_config or {}
       self.chunk_size = chunk_size
       self.chunk_overlap = chunk_overlap
       self.parser = CustomPDFParser(**self.parser_config)
   def load(self) -> List[Document]:
       """
       加载 PDF,解析页面,并将每个页面转换为 LangChain 文档。
       返回值:
           包含页面文本和合并元数据的文档对象列表。
       """

       parsed_data = self.parser.parse_pdf(self.file_path)
       documents = []
       # 将每个页面字典转换为 LangChain 文档
       for page_data in parsed_data["pages"]:
           if page_data["text"]:
               # 合并文档级别和页面级别的元数据
               metadata = {**parsed_data["document_metadata"], **page_data["metadata"]}
               doc = Document(page_content=page_data["text"], metadata=metadata)
               documents.append(doc)
       return documents
   def load_and_split(self) -> List[Document]:
       """
       加载 PDF 并将大型文档拆分为更小的分块。
       返回值:
           拆分大型文本后的文档对象列表。
       """

       documents = self.load()
       # 使用所需的分块大小和重叠部分初始化文本拆分器
       text_splitter = RecursiveCharacterTextSplitter(
           chunk_size=self.chunk_size,
           chunk_overlap=self.chunk_overlap,
           separators=["\n\n""\n"" """]  # 分层拆分
       )
       # 将文档拆分为更小的分块
       split_docs = text_splitter.split_documents(documents)
       return split_docs

构建处理流水线(pipeline.py)

PDFProcessingPipeline 类提供了一个更高层次的接口,用于:

  • 处理单个 PDF
  • 选择输出格式(原始字典、LangChain 文档或纯文本)
  • 启用或禁用分块,并可配置分块大小
  • 处理错误和日志记录

这种抽象使得将其轻松集成到更大的应用程序或工作流中成为可能。其背后的逻辑如下:

from typing import List, Optional, Dict, Any
from langchain.schema import Document
from parser import CustomPDFParser
from langchain_loader import LangChainPDFLoader
import logging
logger = logging.getLogger(__name__)
class PDFProcessingPipeline:
   def __init__(self, parser_config: Optional[Dict[str, Any]] = None):
       """
       参数:
          parser_config:传递给 CustomPDFParser 的选项字典
       """

       self.parser_config = parser_config or {}
   def process_single_pdf(
       self,pdf_path: str,output_format: str = "langchain",chunk_documents: bool = True,chunk_size: int = 500,chunk_overlap: int = 50
   )
 -> Any:

       """
       参数:
           pdf_path:PDF 文件路径
           output_format:"raw"(字典)、"langchain"(文档)或 "text"(字符串)
           chunk_documents:是否拆分 LangChain 文档
           chunk_size:拆分时的分块大小
           chunk_overlap:拆分时的分块重叠部分
       返回值:
           按请求格式解析的内容
       """

       if output_format == "raw":
           # 使用原始 CustomPDFParser 输出
           parser = CustomPDFParser(**self.parser_config)
           return parser.parse_pdf(pdf_path)
       elif output_format == "langchain":
           # 使用 LangChain 加载器,可选地进行分块
           loader = LangChainPDFLoader(pdf_path, self.parser_config, chunk_size, chunk_overlap)
           if chunk_documents:
               return loader.load_and_split()
           else:
               return loader.load()
       elif output_format == "text":
           # 仅返回合并后的纯文本
           parser = CustomPDFParser(**self.parser_config)
           parsed_data = parser.parse_pdf(pdf_path)
           return parsed_data.get("full_text""")
       else:
           raise ValueError(f"未知的 output_format:{output_format}")

测试解析器(example.py)

让我们按照以下方式测试解析器:

import os
from pathlib import Path
def main():
   print("欢迎使用自定义 PDF 解析器!")
   print("你想做什么?")
   print("1. 查看完整的原始解析数据")
   print("2. 提取完整的纯文本")
   print("3. 获取 LangChain 文档(不分块)")
   print("4. 获取 LangChain 文档(分块)")
   print("5. 显示文档元数据")
   print("6. 显示每页元数据")
   print("7. 显示清理后的页面文本(已移除页眉/页脚)")
   print("8. 显示提取的图像元数据")
   choice = input("输入你的选择编号:").strip()
   if choice notin {'1''2''3''4''5''6''7''8'}:
       print("无效选项。")
       return
   file_path = input("输入你的 PDF 文件路径:").strip()
   ifnot Path(file_path).exists():
       print("文件未找到。")
       return
   # 初始化流水线
   pipeline = PDFProcessingPipeline({
       "preserve_layout"False,
       "remove_headers_footers"True,
       "extract_images"True,
       "min_text_length"20
   })
   # 大部分选项需要原始数据
   parsed = pipeline.process_single_pdf(file_path, output_format="raw")
   if choice == '1':
       print("\n完整的原始解析输出:")
       for k, v in parsed.items():
           print(f"{k}{str(v)[:300]}...")
   elif choice == '2':
       print("\n清理后的完整文本(截断预览):")
       print("预览前 1000 个字符:\n"+parsed["full_text"][:1000], "...")
   elif choice == '3':
       docs = pipeline.process_single_pdf(file_path, output_format="langchain", chunk_documents=False)
       print(f"\nLangChain 文档:{len(docs)}")
       print("预览前 500 个字符:\n", docs[0].page_content[:500], "...")
   elif choice == '4':
       docs = pipeline.process_single_pdf(file_path, output_format="langchain", chunk_documents=True)
       print(f"\nLangChain 分块:{len(docs)}")
       print("样本分块内容(前 500 个字符):")
       print(docs[0].page_content[:500], "...")
   elif choice == '5':
       print("\n文档元数据:")
       for key, value in parsed["document_metadata"].items():
           print(f"{key}{value}")
   elif choice == '6':
       print("\n每页元数据:")
       for i, page in enumerate(parsed["pages"]):
           print(f"第 {i+1} 页:{page['metadata']}")
   elif choice == '7':
       print("\n移除页眉/页脚后的清理文本。")
       print("显示前 3 页以及每页的前 500 个字符的文本。")
       for i, page in enumerate(parsed["pages"][:3]):  # 前 3 页
           print(f"\n--- 第 {i+1} 页 ---")
           print(page["text"][:500], "...")
   elif choice == '8':
       print("\n提取的图像元数据(如果可用):")
       found = False
       for i, page in enumerate(parsed["pages"]):
           images = page["metadata"].get("images", [])
           if images:
               found = True
               print(f"\n--- 第 {i+1} 页 ---")
               for img in images:
                   print(img)
       ifnot found:
           print("未找到图像元数据。")
if __name__ == "__main__":
   main()

运行此代码后,系统会提示你输入选择编号和 PDF 文件路径。输入这些信息后,你将看到相应的输出。我使用的 PDF 是公开可访问的,你可以使用提供的链接下载它。

运行结果

假设你已经按照上述步骤设置了项目,并且有一个名为 articles.pdf 的 PDF 文件。运行 example.py 脚本后,你将看到类似以下的交互界面和结果:

运行脚本

python example.py

交互界面和用户输入

欢迎使用自定义 PDF 解析器!
你想做什么?
1. 查看完整的原始解析数据
2. 提取完整的纯文本
3. 获取 LangChain 文档(不分块)
4. 获取 LangChain 文档(分块)
5. 显示文档元数据
6. 显示每页元数据
7. 显示清理后的页面文本(已移除页眉/页脚)
8. 显示提取的图像元数据
输入你的选择编号:5
输入你的 PDF 文件路径:/content/articles.pdf

运行结果

假设用户选择了 5 来查看文档元数据,以下是可能的输出结果:

文档元数据:
file_path: /content/articles.pdf
file_name: articles.pdf
file_size: 123456
title: Articles (a/an/the)
author: Ben Aldridge
subject: English Grammar
creator: Microsoft Word
producer: Acrobat Distiller
creation_date: D:20140301000000Z
modification_date: D:20140301000000Z

其他选项的运行结果示例

选项 1:查看完整的原始解析数据

完整的原始解析输出:
full_text: San José State University Writing Center...(截断)
pages: [{'text''San José State University Writing Center...(截断)''metadata': {'page_number': 1, 'rotation': 0, 'mediabox''[0, 0, 612, 792]'}, 'word_count': 123}, ...]
document_metadata: {'file_path''/content/articles.pdf''file_name''articles.pdf''file_size': 123456, 'title''Articles (a/an/the)''author''Ben Aldridge''subject''English Grammar''creator''Microsoft Word''producer''Acrobat Distiller''creation_date''D:20140301000000Z''modification_date''D:20140301000000Z'}
total_pages: 4
processed_pages: 4
total_words: 456

选项 2:提取完整的纯文本

清理后的完整文本(截断预览):
San José State University Writing Center
www.sjsu.edu/writingcenter
Written by Ben Aldridge

Articles (a/an/the), Spring 2014.                                                                                   1 of 4
Articles (a/an/the)

There are three articles in the English language: a, an, and the. They are placed before nouns
and show whether a given noun is general or specific.

Examples of Articles
...

选项 3:获取 LangChain 文档(不分块)

LangChain 文档:4
预览前 500 个字符:
San José State University Writing Center
www.sjsu.edu/writingcenter
Written by Ben Aldridge

Articles (a/an/the), Spring 2014.                                                                                   1 of 4
Articles (a/an/the)

There are three articles in the English language: a, an, and the. They are placed before nouns
and show whether a given noun is general or specific.

Examples of Articles
...

选项 4:获取 LangChain 文档(分块)

LangChain 分块:16
样本分块内容(前 500 个字符):
San José State University Writing Center
www.sjsu.edu/writingcenter
Written by Ben Aldridge

Articles (a/an/the), Spring 2014.                                                                                   1 of 4
Articles (a/an/the)

There are three articles in the English language: a, an, and the. They are placed before nouns
...

选项 6:显示每页元数据

每页元数据:
第 1 页:{'page_number': 1, 'rotation': 0, 'mediabox''[0, 0, 612, 792]''images': [{'image_index': 0, 'name''image_0''width': 100, 'height': 200}]}
第 2 页:{'page_number': 2, 'rotation': 0, 'mediabox''[0, 0, 612, 792]'}
第 3 页:{'page_number': 3, 'rotation': 0, 'mediabox''[0, 0, 612, 792]'}
第 4 页:{'page_number': 4, 'rotation': 0, 'mediabox''[0, 0, 612, 792]'}

选项 7:显示清理后的页面文本(已移除页眉/页脚)

移除页眉/页脚后的清理文本。
显示前 3 页以及每页的前 500 个字符的文本。

--- 第 1 页 ---
There are three articles in the English language: a, an, and the. They are placed before nouns
and show whether a given noun is general or specific.

Examples of Articles
...

--- 第 2 页 ---
The indefinite articles 'a' and 'an' are used before singular nouns that introduce something for the first time...
...

--- 第 3 页 ---
The definite article 'the' is used before singular and plural nouns when the noun is specific or particular...
...

选项 8:显示提取的图像元数据

提取的图像元数据(如果可用):

--- 第 1 页 ---
{'image_index': 0, 'name''image_0''width': 100, 'height': 200}

结论

通过上面的内容,你已经学会了如何使用开源工具构建一个灵活且强大的 PDF 处理流水线。由于它是模块化的,你可以轻松地对其进行扩展,例如使用 Streamlit 添加一个搜索栏,将分块存储在 FAISS 等向量数据库中以便进行更智能的查找,或者甚至将其集成到聊天机器人中。你无需重新构建任何东西,只需连接下一个组件即可。PDF 不再像一个封闭的盒子。通过这种方法,你可以将任何文档转换为你可以按自己意愿阅读、搜索和理解的内容。

【声明】内容源于网络
0
0
AI Agent 领域
专注AI智能体(Agentic AI)技术实践与前沿探索,涵盖LLM Agents、工具调用、RAG系统、Agent框架实战等内容,助力开发者构建下一代智能系统。
内容 353
粉丝 0
AI Agent 领域 专注AI智能体(Agentic AI)技术实践与前沿探索,涵盖LLM Agents、工具调用、RAG系统、Agent框架实战等内容,助力开发者构建下一代智能系统。
总阅读142
粉丝0
内容353