- 人工智能
- AI Agent
- Agent 框架
- 大模型
- 工具调用
- RAG
- 提示工程
- 强化学习
【免费下载链接】agent-core
openJiuwen agent-core可提供AI Agent开发、运行、调优与演进相关的全套SDK能力
导读
Parser是 openJiuwen agent-core 检索与索引链路(Parser → Chunker → Extractor → Indexer)中的第一个处理环节,为文档解析定义了一套统一的异步接口:无论是本地 PDF、Word、Excel,还是微信公众号文章、普通网页 URL,都可以通过同一套parse/lazy_parse/supports语义接入知识库构建流程。本文以该抽象基类的 API 文档为主体,结合仓库中 base.py 的真实实现、AutoParser 的自动路由设计、KnowledgeBase 的调用链以及单元测试,系统讲解 Parser 的接口契约、底层钩子、返回数据模型、扩展机制与实战用法,读完即可掌握如何在 agent-core 中理解、选用甚至自定义文档解析器。
一、Parser 在检索索引链路中的定位
在 openJiuwen agent-core 的检索模块中,知识库构建遵循一套流水线式处理模型。打开 openjiuwen/core/retrieval/init.py 可以看到,检索模块被划分为若干 Processor 子类,其继承关系定义在 openjiuwen/core/retrieval/indexing/processor/base.py:
Processor:所有处理器的抽象基类(ABC),强制子类实现async process(*args, **kwargs);Parser:文档解析器,将「文件路径 / URL 等文档源」转换为结构化的Document对象列表;Chunker:对解析出的长文本进行切片;Extractor:抽取知识三元组等结构化信息;Splitter:句子级切分。
其中Parser的定义位于 openjiuwen/core/retrieval/indexing/processor/parser/base.py,类注释明确写道:"Document parser abstract base class (inherits from Processor)"——它本身并不直接解析任何具体格式,而是先抽象出「解析文档」这一动作的通用契约,再交给下面的具体解析器去实现。
二、核心接口契约:parse / lazy_parse / supports 逐方法解析
按照 API 文档,Parser基类对外暴露三个核心方法。下面逐一结合源码 base.py 讲解其签名、默认行为与设计意图。
2.1 async parse:统一入口,返回 Document 列表
async def parse( self, doc: str, doc_id: str = "", llm_client: Optional[Model] = None, **kwargs ) -> List[Document]:参数说明:
| 参数 | 类型 | 默认值 | 含义 |
|---|---|---|---|
doc | str | 必填 | 文档源,可以是本地文件路径、HTTP/HTTPS URL 等 |
doc_id | str | "" | 文档 ID,用于在向量库中唯一标识该文档;不传则由调用方生成(见下文 KnowledgeBase 用法) |
llm_client | Optional[Model] | None | 可选的 LLM 客户端,用于图片 caption 等基于大模型的增强处理(如 PDF/DOCX/图片中的插图描述) |
**kwargs | Any | — | 可变参数,透传其他额外配置(如file_name、timeout、verify、include_header等) |
返回:List[Document],即解析产出的文档对象列表(可能为单个或为空列表)。
从源码看,基类的parse默认实现并非空壳,而是一个完整的模板方法(template method):
content = await self._parse(doc, llm_client=llm_client) if content: return [Document(id_=doc_id, text=content, metadata={})] return []也就是说:
- 基类
parse调用私有的async _parse(self, file_path, llm_client=None) -> Optional[str]钩子获取纯文本内容; - 若拿到非空文本,则包装为一个
Document(id_=doc_id, text=content, metadata={})返回; - 若内容为空(
None或空),返回空列表[]。
因此,最简单的自定义解析器只需实现_parse返回文本字符串即可复用基类的包装逻辑(测试 test_auto_file_parser.py 中的TestParser正是这么做的)。
2.2 async lazy_parse:懒加载异步迭代器
async def lazy_parse(self, doc: str, doc_id: str = "", **kwargs) -> AsyncIterator[Document]:参数:与parse基本一致(不含llm_client独立位置参数,但可通过kwargs透传)。
返回:AsyncIterator[Document],即文档的异步迭代器(async generator)。
基类提供了默认实现:先调用parse拿到完整列表,再逐个yield:
docs = await self.parse(doc, doc_id=doc_id, **kwargs) for d in docs: yield d这种「一次性解析 + 流式产出」的默认实现适合大多数场景;对于超大文件,子类可以覆写lazy_parse实现真正的逐块惰性解析,避免一次性把整个文档载入内存。
2.3 process:兼容 Processor 抽象方法的适配层
Processor是抽象基类,强制要求实现async process(*args, **kwargs)。Parser通过以下方式满足该约束:
async def process(self, *args: Any, **kwargs) -> Any: """Compatible with Processor abstract method, defaults to calling parse.""" return await self.parse(*args, **kwargs)这使得 Parser 可以无缝嵌入任何面向 Processor 的统一调用框架,在索引流水线中与其他处理器保持一致的调用形态。
2.4 supports:格式支持探测
def supports(self, doc: str) -> bool: return False基类默认返回False(不支持任何源),交由子类按自身能力覆写。supports是自动路由机制的核心判定函数——KnowledgeBase.parse_urls 在解析 URL 前会先调用它做前置过滤,AutoParser 也依靠它决定把任务分发给哪个子解析器。
2.5 私有钩子 _parse:真正干活的地方
_parse是基类留给子类实现的文本提取钩子,签名如下:
async def _parse(self, file_path: str, llm_client: Optional[Model] = None) -> Optional[str]: pass子类覆写它返回解析出的纯文本(Optional[str]),例如 TxtMdParser 用aiofiles读取文件并借助charset_normalizer自动检测编码;JSONParser 将 JSON 格式化为带缩进的可读文本。值得注意的是,部分子类(如 ExcelParser、ImageParser)直接覆写了公开的parse方法以返回多条Document,而非走_parse单文本通道。
三、返回载体:Document 数据模型
parse的返回值类型Document定义在 openjiuwen/core/retrieval/common/document.py,它是基于 pydantic 的BaseModel,核心字段包括:
id_:文档 ID(字符串);text:文档文本内容(字符串);metadata:字典形式的元数据(Dict[str, Any]),默认空字典。
同文件还定义了TextChunk(切片数据模型,含embedding向量字段,可通过from_document从Document派生)与MultimodalDocument(支持 text / image / audio / video 多模态字段的文档模型,add_field支持链式调用,并提供content、dashscope_input两种嵌入输入格式),可用于多模态检索场景。
此外,AutoFileParser.parse 在返回前还会统一增强元数据:
document.metadata.update({ "doc_id": doc_id, "title": file_name, "file_path": doc, "file_ext": file_ext, })即自动为每个文档补充doc_id、title(默认取文件名,可通过 kwargs 的file_name覆盖)、file_path与file_ext,方便后续检索结果的溯源与展示。
四、llm_client 参数:多模态 caption 能力
parse的第三个参数llm_client承载着一个重要能力:对文档中的图片生成描述文本(caption),从而让图片信息也能参与语义检索。相关实现集中在 captioner.py 的ImageCaptioner类:
- 支持列表为
["gpt-4o", "gpt-5", "qwen3-vl", "qwen-vl"]开头的视觉语言模型(VLM);传入的Model的model_config.model_name不匹配时会给出告警,未传llm_client时则直接禁用 caption 能力; - 内置的
IMAGE_CAPTION_PROMPT要求模型输出「面向语义检索」的详细定性描述(覆盖文字、图表、表格、版式等),并强调只输出描述、不加前缀; _llm_call_async将图片以data:{mime_type};base64,...的格式随多模态消息发送给llm_client.invoke;cp_image会把图片复制到images目录(默认SAVED_IMAGE_DIR = "images"),同时为.jfif补充了image/jpeg的 MIME 映射。
具体使用场景包括:PDFParser逐页提取图片并调用caption_images生成说明(pdf_parser.py);WordParser对 DOCX 段落内嵌图片生成 caption(word_parser.py);ImageParser直接对图片文件生成 caption 并把图片路径写入metadata["image_path"](image_parser.py)。
五、从基类到实现:Parser 家族的自动路由架构
Parser基类之下,仓库提供了三层递进的具体实现。从 parser/init.py 导出的符号可以看到完整的家族:AutoParser、AutoFileParser、AutoLinkParser、TxtMdParser、PDFParser、WordParser、ExcelParser、JSONParser、HTMLFileParser、WebPageParser、WeChatArticleParser、ImageParser以及两个工具函数parse_wechat_article_url、parse_web_page_url。
5.1 AutoParser:统一入口的路由器
AutoParser 是面向调用方的顶层路由器:
- 构造时可分别注入
link_parser与file_parser(默认分别为AutoLinkParser与AutoFileParser); - 通过正则
HTTP_URL_PATTERN(^https?://\S+)判断输入是否为 URL:是则交给AutoLinkParser,否则交给AutoFileParser; supports与parse都按同一路由逻辑委托给对应子解析器;两者都不支持时parse返回[]。
这意味着:一个知识库只需配置 AutoParser,即可同时接收微信文章链接、普通网页链接与本地文件,无需区分 parse_urls 与 parse_files 两套 API。
5.2 AutoFileParser:基于插件注册表的文件解析器
AutoFileParser 采用插件式架构,核心是一个全局注册表_PARSER_REGISTRY: Dict[str, Callable[[], Parser]](扩展名小写 → 解析器工厂)。其行为要点:
- 初始化时
_ensure_parsers_loaded()动态导入所有内置解析器模块,触发@register_parser装饰器完成注册; parse先校验文件存在(否则抛出RETRIEVAL_INDEXING_FILE_NOT_FOUND错误),再按扩展名查表(未知格式抛出RETRIEVAL_INDEXING_FORMAT_NOT_SUPPORT错误并列出支持的扩展名),拿到实例后调用其parse并增强元数据;supports对不存在的文件直接返回False;get_supported_formats()返回当前注册的全部扩展名列表;register_new_parser(file_extension, parser_factory)支持在运行时动态注册新格式。
内置文件解析器的注册与格式对应关系如下:
| 解析器 | 注册扩展名 | 解析策略 |
|---|---|---|
| TxtMdParser | .txt/.md/.markdown(含大写) | 异步读文件,charset-normalizer自动检测编码 |
| PDFParser | .pdf | pdfplumber提取文本;300dpi 裁切页面图片并生成 caption |
| WordParser | .docx | python-docx解析,标题样式转 Markdown 标题,表格转 Markdown 表格,内嵌图片生成 caption |
| ExcelParser | .xlsx/.csv/.tsv | 每个工作表的每行、每列各产出一条 Document(行检索 + 列检索),include_header控制是否带表头前缀 |
| JSONParser | .json | 解析并格式化为缩进 JSON 文本 |
| HTMLFileParser | .htm/.html | BeautifulSoup(优先 lxml)解析,按 selector 列表提取正文 |
| ImageParser | .png/.jpg/.jpeg/.webp/.gif/.jfif | 生成 caption,metadata["image_path"]暴露图片路径供多模态嵌入 |
5.3 AutoLinkParser:按 URL 模式路由的链接解析器
AutoLinkParser 将 URL 解析抽象为「路由表」:每条路由是(pattern_or_callable, parser)元组,按顺序匹配,首个命中者胜出。默认路由为:
- 微信公众号文章 URL(
WECHAT_MP_URL_PATTERN,即^https?://(?:mp\.weixin\.qq\.com|.*?\.weixin\.qq\.com)/s\b.*)→WeChatArticleParser; - 其余 http(s) URL(
HTTP_URL_PATTERN)→WebPageParser。
路由模式既可以是正则re.Pattern,也可以是返回bool的可调用对象,因此可以非常灵活地扩展新的 URL 站点解析器。WebPageParser 继承自HTMLFileParser,通过httpx.AsyncClient抓取页面,并暴露timeout(默认 30.0 秒)、user_agent(默认 Chrome UA)、verify(SSL 校验,可为True/False/ CA 路径 /ssl.SSLContext)、client(复用共享 httpx 客户端)等可配置项;WeChatArticleParser 则定位div#js_content节点提取正文,metadata["source_type"]标记为"wechat_article"。此外还导出了便捷函数parse_web_page_url与parse_wechat_article_url,可免去实例化直接调用。
六、在知识库中的实际调用链
Parser的真正价值体现在知识库构建流程中。KnowledgeBase 的构造函数接收parser参数,并提供两个解析入口:
- parse_files(knowledge_base.py):遍历
file_paths列表,为每个文件生成file_id = str(uuid.uuid4()),以file_name为附加参数调用parser.parse(file_path, file_id, file_name=file_name),逐文件累积Document;未配置 parser 时抛出RETRIEVAL_KB_PARSER_NOT_FOUND,单个文件解析失败仅记录日志并跳过; - parse_urls(knowledge_base.py):先调用
parser.supports(url)做前置过滤,不支持的 URL 跳过并告警;随后以随机 UUID 为doc_id调用parser.parse(url, doc_id=doc_id)。当 parser 配置为 AutoParser/AutoLinkParser 时,微信与普通网页链接会被自动路由。
解析出的Document列表随后进入add_documents流水线,依次完成切片(Chunker)、向量化与索引写入,最终供retrieve检索使用。整个链路印证了 Parser 作为索引流水线「第一道工序」的定位。
七、实战扩展:如何编写并注册自定义解析器
基于Parser基类与AutoFileParser的插件架构,扩展一种新文件格式只需三步:
第一步,继承 Parser 并实现_parse(或直接覆写parse)。
from openjiuwen.core.retrieval.indexing.processor.parser.base import Parser class MyFormatParser(Parser): async def _parse(self, file_path: str, llm_client=None) -> str | None: # 读取并提取文本,返回 str;失败返回 None ...第二步,用@register_parser装饰器注册扩展名。该装饰器定义在 auto_file_parser.py,接收扩展名列表,内部统一转为小写后写入全局注册表:
from openjiuwen.core.retrieval.indexing.processor.parser.auto_file_parser import register_parser @register_parser([".myfmt", ".MYFMT"]) class MyFormatParser(Parser): ...第三步,验证。AutoFileParser.get_supported_formats()应包含新扩展名,AutoFileParser().supports("x.myfmt")返回True,parse后metadata中会自动带上doc_id/title/file_path/file_ext。若希望在运行时(不修改代码)注册,可调用AutoFileParser.register_new_parser(".myfmt", lambda: MyFormatParser())。
单元测试 test_auto_file_parser.py 完整覆盖了装饰器注册(含多扩展名、大小写归一化)、动态注册、支持格式查询、文件不存在与未知格式的报错路径;test_auto_parser.py 则验证了 AutoParser 对 URL 与本地文件的正确分派以及不支持输入返回空列表的行为,可作为自定义解析器测试的参考模板。
八、小结
Parser作为 openJiuwen agent-core 检索索引链路中所有解析器的抽象基类,用三个公开方法(parse/lazy_parse/supports)加上一个私有钩子(_parse)定义了稳定、简洁、可异步的接口契约;在此之上,AutoParser 将文件与链接两大类解析器统一收口,配合插件式注册表与 URL 路由表,实现了"一个入口解析一切"的开发体验。理解这套基类设计,是深入定制知识库文档解析、接入多模态检索或扩展私有格式的第一步——相关的 API 文档原文位于 docs/zh/2.开发指南/API文档/openjiuwen.core/retrieval/indexing/processor/parser/base.md,结合上述源码与测试即可按需扩展。
- 人工智能
- AI Agent
- Agent 框架
- 大模型
- 工具调用
- RAG
- 提示工程
- 强化学习
【免费下载链接】agent-core
openJiuwen agent-core可提供AI Agent开发、运行、调优与演进相关的全套SDK能力
相关推荐
openJiuwen agent-core 文档重排(Reranker)基类 API 全解析:从抽象接口到三种内置实现
openJiuwen agent core 文档重排(Reranker)基类 API 全解析:从抽象接口到三种内置实现 本文深入剖析 openJiuwen ag
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习openJiuwen agent-core 文本向量化:Embedding 抽象基类接口设计与多后端实现深度解析
openJiuwen agent core 文本向量化:Embedding 抽象基类接口设计与多后端实现深度解析 导读 本文以 openJiuwen agent
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习openJiuwen agent-core 检索索引解析器基类 Parser 详解:文档解析接口的抽象设计与插件化扩展
openJiuwen agent core 检索索引解析器基类 Parser 详解:文档解析接口的抽象设计与插件化扩展 本文聚焦 openJiuwen agen
人工智能AI AgentAgent 框架大模型工具调用RAG提示工程强化学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考