第二章:LLM 交互层

在上一章中,我们学习了作为"项目总控"的管道协调器,它负责协调 RAG 系统中各个功能模块。

其中最重要的协调对象之一,便是负责与大型语言模型(LLM)进行智能交互的LLM 交互层

LLM 交互层解决的核心问题

假设我们有一个需要调用多模态 AI “大脑” 来解答复杂问题的智能助手系统,将面临以下挑战:

  • 多供应商支持:可能需要使用 OpenAI 的 GPT-4o、Google 的 Gemini 或 IBM 的 WatsonX 等不同厂商的模型
  • 差异化接口规范:不同 LLM 服务提供商具有各异的 API 格式要求
  • 密钥管理复杂性:每个服务需要独立的 API 密钥认证体系
  • 流量控制需求:需处理不同服务的速率限制(Rate Limiting)策略
  • 响应格式多样性:各厂商 API 返回的数据结构存在差异

若在主系统中直接处理这些差异,将导致代码臃肿和维护困难。这正是LLM 交互层要解决的核心架构问题。

LLM集成&处理,前文传送:

[AI-video] 数据模型与架构 | LLM集成

[BrowserOS] LLM供应商集成 | 更新系统 | Sparkle框架 | 自动化构建系统 | Generate Ninja

LLM 交互层:智能模型的万能翻译官与外交官

LLM 交互层如同连接 RAG 系统与各大 AI 模型的协议转换中枢,其核心价值在于:

功能角色类比技术实现
多协议转换器语言翻译官将统一输入转换为 OpenAI/Gemini/WatsonX 等各厂商 API 要求的格式
密钥外交官安全通行证管理通过环境变量隔离存储 API 密钥,动态注入认证信息
流量调度器高速公路收费站内置速率限制感知与自适应重试机制,防止触发 API 调用限制
数据整形师格式标准化专家将异构 API 响应转换为统一数据结构,支持 JSON 等结构化输出

如何使用 LLM 交互层

RAG-Challenge-2项目中,通过APIProcessor类实现与各类 LLM 的交互。以下展示两种典型使用场景:

场景一:基础问答交互

from src.api_requests import APIProcessor# 初始化 OpenAI 处理器
llm_connector = APIProcessor("openai")# 执行问答交互
response = llm_connector.send_message(human_content="法国的首都是哪里?",system_content="你是一个知识丰富的助手"
)print(response)  # 预期输出:"法国首都是巴黎"(或类似表述)

执行流程解析:

  1. 实例化APIProcessor并指定服务商(“openai”)
  2. 通过send_message发送用户问题(human_content)与角色定义(system_content
  3. 交互层自动处理协议转换、密钥注入等底层细节
  4. 返回标准化响应内容

场景二:结构化数据获取

from src.api_requests import APIProcessor
from pydantic import BaseModel# 定义预期数据结构
class CapitalAnswer(BaseModel):city: str   # 城市字段country: str # 国家字段# 初始化处理器
llm_connector = APIProcessor("openai")# 请求结构化响应
response_dict = llm_connector.send_message(human_content="法国的首都是哪里?",system_content="请以JSON格式返回首都信息",is_structured=True,        # 启用结构化模式response_format=CapitalAnswer # 绑定数据模型
)print(response_dict)  # 预期输出:{'city': '巴黎', 'country': '法国'}

关键技术亮点:

  • 采用pydantic.BaseModel定义数据契约
  • is_structured标志位触发JSON响应解析
  • 自动校验响应结构与数据模型的一致性

底层架构

⭕适配器模式

APIProcessor类(位于src/api_requests.py)是交互层的核心实现,其设计采用"适配器模式"来兼容多厂商API。

前文传送:
10.STL中stack和queue的基本使用(附习题)
在这里插入图片描述
适配器模式就像电源转接头,让不兼容的接口能一起工作。如何实现的呢?再套一层😋

协议适配器工作流

在这里插入图片描述

核心组件实现

  1. 多厂商适配器基类
# 来源:src/api_requests.py(简化版)
import os
from dotenv import load_dotenv
from openai import OpenAIclass APIProcessor:"""统一交互入口"""def __init__(self, provider="openai"):self.provider = provider.lower()self.processor = self._init_processor()  # 动态加载适配器def _init_processor(self):if self.provider == "openai":return BaseOpenaiProcessor()elif self.provider == "ibm":return BaseIBMAPIProcessor()# 支持其他厂商扩展...def send_message(self, **kwargs):"""消息转发入口"""return self.processor.send_message(**kwargs)class BaseOpenaiProcessor:"""OpenAI协议适配器"""def __init__(self):load_dotenv()  # 加载环境变量self.llm = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))  # 密钥注入self.default_model = 'gpt-4o-mini-2024-07-18'  # 默认模型版本def send_message(self, model=None, **kwargs):"""OpenAI专用请求封装"""params = {"model": model or self.default_model,"messages": [{"role": "system", "content": kwargs.get("system_content")},{"role": "user","content": kwargs.get("human_content")}]}# 执行API调用completion = self.llm.chat.completions.create(**params)return completion.choices[0].message.content  # 响应解析

实现了一个支持多AI厂商API调用的适配器系统,核心是通过统一接口屏蔽不同厂商API的差异。

核心组件

APIProcessor类(主入口)

  • 初始化时通过provider参数指定厂商(如openai/ibm
  • 自动创建对应的厂商适配器实例(如BaseOpenaiProcessor
  • 提供统一的send_message方法转发请求

BaseOpenaiProcessor类(厂商实现

  • 专属OpenAI的初始化流程:
    • 加载环境变量获取API密钥
    • 预置默认模型版本
  • 请求处理逻辑:
    • 组装符合OpenAI规范的请求结构
    • 包含system/user角色的消息体
    • 自动选择默认模型(可覆盖)
    • 解析返回结果的第一条消息

设计特点

  1. 开闭原则:新增厂商只需添加新适配器类,无需修改主入口代码
  2. 环境隔离:各厂商的密钥管理和请求逻辑相互独立
  3. 默认配置内置常用模型版本降低调用复杂度

⭕调用示例

processor = APIProcessor("openai")
response = processor.send_message(system_content="你是一个翻译助手",human_content="Hello world"
)
  1. 高级功能实现
  • 密钥安全管理通过.env文件隔离敏感信息,防止密钥硬编码
  • 流量控制:集成api_request_parallel_processor模块实现
    • 自动重试机制(网络波动容错)
    • 动态速率调节(基于API反馈实时调整QPS)
    • 批量请求优化(提升吞吐量)
  • 结构化校验:利用pydantic模型实现响应数据的模式校验与自动修复

总结

LLM交互层作为RAG系统的"外交中枢",通过:

  • 协议抽象:统一不同厂商API的调用差异
  • 安全隔离集中管理敏感认证信息
  • 弹性通信:内置智能重试与流量整形
  • 数据契约:强化结构化数据可靠性

(我们会发现,如果抽象的好的话,许多想实现的小功能,都有对应的库或者方案可以直接像适配器一样调用,我们只需要 改一些参数即可)

使上层业务逻辑能够专注于知识处理流程,而不必深陷多厂商API的兼容性泥潭。

这种分层设计显著提升了系统的可维护性与可扩展性。

下一章:文档解析器


第三章:文档解析器

在上一章中,我们了解了LLM交互层——与强大AI模型对话的通用翻译器。

但在系统能够提出智能问题并获得答案之前,它需要理解源文档中的信息。想象我们拥有一个装满珍贵书籍(PDF)的大型图书馆,但它们都是原始的纸质文档!我们无法搜索、用计算机轻松阅读或提取具体数据。

这正是文档解析器大显身手的时刻。

向量检索重要性在前文有提到:
[Andrej Karpathy] 大型语言模型作为新型操作系统

文档解析器解决的核心问题

假设我们有一批来自不同公司的PDF报告,这些报告包含丰富的信息:常规文本、详细表格和说明性图片。要构建能够回答"根据财务报告,X公司2023年的营收是多少?"这类问题的智能系统,首先需要读取理解这些PDF文档。

PDF文档存在天然复杂性

  1. 格式混杂性:混合文本、图像和表格的复杂排版
  2. 结构模糊性:简单复制粘贴可能导致结构丢失或表格错位
  3. 数据非标性:显示优化的布局不利于机器解析

文档解析器的核心使命是:

  1. 全要素提取:完整获取文本、表格和图像
  2. 语义结构理解:识别段落归属、表格边界和图片关联
  3. 数字格式重构将异构数据转换为系统可处理的标准化格式

⭕文档解析器:智能数字档案员

文档解析器如同精通多模态的档案管理员

当输入原始PDF时,它不仅拍摄页面快照,而是深度解析每个元素

功能角色技术实现
智能扫描仪采用docling库实现PDF深度解析,支持OCR光学字符识别
数据萃取器将复杂表格转换为Markdown结构化数据,保留表格行列关系
内容整合器按页面组织文本块,识别标题层级,建立跨页面引用关系
数字归档系统输出标准化JSON格式,支持后续向量化处理

之后会在py相关专栏,探索这个库(🕳+1)
在这里插入图片描述

如何使用文档解析器

通过管道协调器触发文档解析流程:

python main.py parse-pdfs

核心代码逻辑如下:

# 来源:src/pipeline.py(简化版)
from src.pdf_parsing import PDFParserclass Pipeline:def parse_pdf_reports(self):"""PDF解析总控方法"""pdf_dir = self.paths.raw_reports_path   # 原始PDF存储路径output_dir = self.paths.parsed_reports_path  # 解析结果输出路径parser = PDFParser(output_dir=output_dir,csv_metadata_path=self.paths.subset_path  # 可选元数据关联)parser.parse_and_export(doc_dir=pdf_dir)  # 启动解析流程

执行流程解析:

  1. 路径初始化:通过_initialize_paths方法建立输入/输出目录结构
  2. 解析器配置:加载docling文档转换器,启用表格检测和OCR功能([11])
  3. 批量处理:遍历指定目录下的所有PDF文件进行异步解析([18])
  4. 结果序列化:将结构化数据保存为JSON文件,保留原始文档SHA1哈希作为文件名

输出示例(data/debug/parsed_reports/xxx.json):

{"metainfo": {"sha1_name": "f5d2...a89c","pages_amount": 42,"company_name": "TechCorp"},"content": [{"page": 1,"blocks": [{"type": "heading", "text": "2023年度财务报告"},{"type": "paragraph", "text": "本年度总收入..."}]}],"tables": [{"table_id": 0,"markdown": "| 季度 | 营收(百万) |\n|------|-------------|\n| Q1   | 120         |","page": 5}]
}

底层架构

文档解析器采用分层处理架构:

在这里插入图片描述

核心组件详解:

1. PDFParser 类

class PDFParser:def __init__(self, output_dir: Path, csv_metadata_path: Path = None):self.doc_converter = self._create_document_converter()  # 初始化转换引擎self.metadata_lookup = self._parse_csv_metadata(csv_metadata_path)  # 加载元数据def _create_document_converter(self):"""配置文档转换引擎"""return DocumentConverter(enable_ocr=True,       # 启用图像文字识别table_detection_mode=2 # 增强表格检测)

2. ⭕文档转换引擎

  • 基于docling库实现多线程解析
  • 支持PDF/Word格式转换
  • 表格检测采用CNN神经网络识别表格边界
CNN神经网络

一种模仿人眼视觉原理深度学习模型,通过局部感知和层次化提取特征(如边缘→纹理→物体部分→整体),自动识别图像中的模式。

CNN神经网络识别表格边界,就像用放大镜扫描表格图片,通过局部感知自动找到横竖线条的交汇处最终框出表格的外框和内部格子。

3. JsonReportProcessor 类

class JsonReportProcessor:def assemble_tables(self, tables_raw_data, data):"""表格结构化处理"""for table in tables_raw_data:# 转换复杂表格为Markdowntable_md = self._table_to_md(table)# 建立表格与页面的映射关系yield {"table_id": idx,"markdown": table_md,"page_ref": data['tables'][idx]['prov'][0]['page_no']}

关键技术突破:

  • 版面分析算法:采用计算机视觉技术识别文档元素空间关系
  • 增量式OCR:仅在检测到图像文本时触发识别,优化处理速度
  • 表格重建引擎:通过行列检测算法还原复杂合并单元格
增量式OCR

一种动态识别技术,仅对文档中新修改或新增的部分进行文字识别,避免全量重复处理,类似"只扫描最新添加的笔迹"。

行列检测算法是一种用于在图像中识别并定位表格、表单等行列结构的计算机视觉技术。其核心思想是通过分析图像中的水平或垂直线条分布,将像素按行或列分组,从而提取结构化数据。

行列检测算法

通过边缘检测投影分析找到密集的水平/垂直直线群,根据直线聚类结果划分行列区域。

常用霍夫变换投影直方图峰值检测实现。

代码(Python+OpenCV)

import cv2
import numpy as npdef detect_grid(image_path):# 读取图像并转为灰度img = cv2.imread(image_path)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 二值化处理_, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)# 霍夫线变换检测直线lines = cv2.HoughLinesP(thresh, 1, np.pi/180, 100, minLineLength=100, maxLineGap=10)# 绘制检测结果for line in lines:x1,y1,x2,y2 = line[0]cv2.line(img, (x1,y1), (x2,y2), (0,255,0), 2)return img

使用示例:

result = detect_grid("table.png")
cv2.imwrite("result.jpg", result)

应用场景:

  • 文档扫描中的表格识别
  • 票据数据提取
  • 答题卡自动阅卷
  • 财务报表数字化
霍夫变换

通过投票机制在图像中找出直线、圆等几何形状的方法,比如让所有可能的直线“投票”给最可能存在的形状。

投影直方图峰值检测

将图像像素按方向(如水平/垂直)投影统计,通过找直方图的最高点定位目标位置(如文字行或物体边缘)。

详见之后的opencv专栏~

总结

文档解析器作为RAG系统的数据入口,通过:

  • 多模态解析:融合文本、图像和表格处理能力
  • 智能重构:将印刷文档转化为机器可读的语义网络
  • 弹性扩展:支持插件式集成新文档格式

为后续的向量化存储和语义检索奠定了高质量数据基础。这种精细化的预处理机制,使得原始文档中的隐性知识得以显性化表达,极大提升了系统的事实性回答能力。

下一章:文档准备与格式化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/89157.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/89157.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/89157.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Golang 并发快速上手

文章目录1. 为什么要用协程?1.1 进程与线程1.2 协程1.3 线程和协程的区别线程协程1.4 Go 协程(goroutines)和协程(coroutines)2.Go 协程基本内容2.1 channel2.2 select2.3 future 模式3. 实践示例3.1 并发处理多个网络…

ESP32轻松实现UDP无线通信

ESP32支持UDP通信,这是一种轻量级、高效的通信协议,适用于需要快速数据传输但对数据可靠性要求不高的场景。以下是关于ESP32如何实现UDP通信的详细说明: 1. UDP协议简介及其适用场景 UDP(用户数据报协议)是一种无连接的…

Electron实现“仅首次运行时创建SQLite数据库”

在桌面应用中,SQLite因其轻量、嵌入式特性成为本地存储的热门选择。但若重复初始化数据库,会导致数据覆盖或冗余。本文将详解如何让Electron应用仅在首次启动时创建SQLite数据库,后续启动直接连接现有库。一、核心逻辑与实现原理 核心思路&am…

阿里开源AI大模型ThinkSound如何为视频配上灵魂之声

目录 前言 一、当AI解决视频配音的困境 二、引入“思维链”:让AI像专业音效师一样思考 三、背后的技术支撑 四、未来ThinkSound会如何改变我们的世界? 总结 🎬 攻城狮7号:个人主页 🔥 个人专栏:《AI前沿技术要闻…

图论(1):多叉树

多叉树一、基础知识1. 图 & 树2. 模板2.1 建图二、简单循环1. 【模板】树的路径求和2. 道路修建(改)3. 联合权值4. 毛毛虫树三、自顶向下/自底向上1. 医疗中心2. 【模板】树的直径3. 【模板】最大子树和4. 信号放大器一、基础知识 1. 图 & 树 …

楼宇自动化:Modbus 在暖通空调(HVAC)中的节能控制(一)

引言**在当今的建筑领域,楼宇自动化正扮演着愈发关键的角色,它致力于提升建筑的舒适度、安全性以及能源效率。而暖通空调(HVAC)系统作为楼宇自动化中的核心部分,其能耗在整个建筑能耗中占比相当高,据相关数…

【SpringBoot】注册条件+自动配置原理+自定义starter

注册条件注入到容器内实体类型对象的属性都是null,这些对象并没有什么实际的意义,因为实体类的对象就是来封装对象的,结果你这些对象中什么都没有;解决方法是1.给这些属性赋值然后再注入bean但是这些属性又是固定的不是很好&#…

Server reports Content-Length Mismatch 的根源与解决方案

“服务器声明604字节,Yum却期待28680字节”——当包管理器与仓库服务器之间的信任崩塌时,会发生什么?问题重现 yum install package_name ... Interrupted by header callback: Server reports Content-Length: 604 but expected size is: 28…

基于 Python/PHP/Node.js 的淘宝 API 商品数据抓取开发教程

在电商数据分析、竞品监控等场景中,抓取淘宝商品数据是常见需求。淘宝开放平台(Open Platform)提供了标准化的 API 接口,通过合法途径调用可高效获取商品信息。本文将分别基于 Python、PHP、Node.js 三种语言,详解淘宝…

【Tensor的创建】——深度学习.Torch框架

目录 1 Tensor概述 2 Tensor的创建 2.1 基本的创建方式 2.1.1 torch.tensor 2.1.2 torch.Tensor 2.2 创建线性和随机张量 2.2.1 创建线性张量 2.2.2 随机张量 1 Tensor概述 PyTorch会将数据封装成张量(Tensor)进行计算,张量就是元素为…

Python脚本批量修复文件时间戳,根据文件名或拍摄日期

实现以下功能 更正文件的 修改时间批量修改指定文件夹中的特定后缀的文件根据文件名中的日期修改(优先)根据 jpg 文件属性中的拍摄日期修改根据 mp4 文件属性中的创建媒体日期修改模拟运行(Dry Run)模式 依赖 若需要基于jpg文件属…

[Mysql] Connector / C++ 使用

一、Connector / C 使用 要使用 C 语言连接 MySQL,需要使用 MySQL 官网提供的库,可以去官网进行下载:MySQL :: MySQL Community Downloads 我们使用 C 接口库来进行连接,要正确使用,还需要做一些准备工作&#xff1a…

【PDF识别改名】使用京东云OCR完成PDF图片识别改名,根据PDF图片内容批量改名详细步骤和解决方案

京东云OCR识别PDF图片并批量改名解决方案一、应用场景在日常办公和文档管理中,经常会遇到大量 PDF 文件需要根据内容进行分类和命名的情况。例如:企业合同管理系统需要根据合同编号、日期等内容自动命名 PDF 文件图书馆数字化项目需要将扫描的图书章节按…

stm32-modbus-rs485程序移植过程

背景 【modbus学习笔记】Modbus协议解析_modus协议中0.001如何解析-CSDN博客 【Modbus学习笔记】stm32实现Modbus(从机)并移植_stm32 modbus数据处理-CSDN博客 继上篇成功移植modbus从机例程之后,我要尝试移植主机的程序。经提醒,可用野火的modbus代码…

Spring MVC 执行流程详解:一次请求经历了什么?

Spring MVC 执行流程详解:一次请求经历了什么? 引言 在现代 Web 开发中,Spring MVC 作为 Spring 框架的重要组成部分,广泛应用于构建灵活、可扩展的 Java Web 应用。作为一个基于 MVC(Model-View-Controller&#xff0…

Vue 3的核心机制-解析事件流、DOM更新、数据请求、DOM操作规范及组件库DOM操作的解决方案

文章目录概要整体介绍vue 中dom操作推荐方案实例概要 从Vue 3的核心机制出发,结合场景、应用与实例,系统化解析事件流、DOM更新、数据请求、DOM操作规范及组件库DOM操作的解决方案: 整体介绍 ⚡️ 一、事件流处理机制 核心机制 • 三个阶段…

Python从入门到高手9.2节-Python字典的操作方法

目录 9.2.1 字典的操作 9.2.2 字典的查找 9.2.3 字典的修改 9.2.4 字典的添加 9.2.5 字典的删除 9.2.6 今天你逛街了吗 9.2.1 字典的操作 字典类型是一种抽象数据类型,抽象数据类型定义了数据类型的操作方法,在本节的内容中,教同学们彻…

omniparser v2 本地部署及制作docker镜像(20250715)

关于 omniparser v2 本地部署,网上资料不算多,尤其是对于土蔷内用户,还是有些坑的。 1、安装步骤 可参考两个CSDN博客: (1)大模型实战 - ‘OmniParser-V2本地部署安装 链接 (2)…

自己写个 `rsync` + `fswatch` 实时增量同步脚本,干掉 Cursor AI、Sublime Text 的SFTP等 插件!

自己写个 rsync fswatch 实时增量同步脚本,干掉 Cursor AI、Sublime Text 的 SFTP等 插件! 作为一个码农,我最头疼的事情之一就是编辑器同步代码到服务器这块。用过各种各样的sftp、rsync插件,感觉不好用。。 我琢磨着&#xff1…

linux中at命令的常用用法。

Linux 中 at 命令用于安排一次性定时任务,需要用到在某个时间只需要执行一次的命令的时候,可以使用at 1:安装at # Debian/Ubuntu sudo apt install at# CentOS/RHEL sudo yum install at2:启动at sudo systemctl start atd # 启…