@[toc]
本文将介绍如何结合 TextIn 文档解析能力和 Coze 平台搭建一个高效的个人知识库应用。通过对比实验,展示 TextIn 在复杂格式文档(表格、图片、多栏排版)解析方面的优势,以及这种预处理如何显著提升 Coze 知识库的问答效果。
从真实的需求场景开始
作为从2023年就开始在AIGC应用落地领域摸爬滚打的实践者,我亲身经历了行业浪潮的几轮更迭:从“百模大战”的喧嚣,到提示词工程成为显学,再到RAG技术成为企业AI落地最常见的场景,直至如今工程化、Agentic的框架让一切变得更简单。在这个过程中,我接触了大量来自客户的真实需求与痛点。
在诸多AI落地方案中,RAG(检索增强生成)因其相对较低的门槛和清晰的实现路径,往往成为企业尝试AI的第一个切入点。技术选型的路径也相当典型:先选基座大模型,再定向量化模型与检索框架,随后引入重排序(Rerank)等技术优化召回效果,同时不断打磨贴近用户场景的提示词工程——这一切努力,都指向同一个目标:提升RAG问答的质量与可靠性。
然而,当我们一步步走完这个技术堆叠的流程后,往往会发现一个现实:每一项技术优化带来的效能提升,都存在明显的边际递减效应。在达到某个瓶颈后,一个根本性的规律便会浮现:唯有从源头入手,提升数据本身的质量,才能显著改善模型的理解、召回与推理效果。
于是,一个有趣的“回归”现象开始在业内出现:当大家在框架、模型与工程技巧上“卷”到一定程度后,最终又纷纷回过头来,聚焦到那个最基础、却也最关键的环节——数据处理。原因很明确:想要实质性地提升模型效果,就必须从预处理阶段入手,优化元数据的结构、清晰度与信息密度。高质量的输入,才是高质量输出的根本保障。
但数据处理从来不是一个新话题,它之所以至今仍是AI落地的重中之重,正是因为其背后充满了长期存在的挑战。现实世界中的数据极少是“理想状态”下的纯文本或规整的结构化数据。它们更多是以复杂格式存在:混杂着表格、图片、示意图、多栏排版,甚至手写注释。表格之中常有嵌套、合并单元格与跨页引用;图表与正文之间存在着逻辑关联;版式本身就承载着信息层次。恰恰是这些“不规整”的部分,才是信息的关键所在,也恰恰是传统处理流程中最容易丢失或误读的部分。
因此,当下真正的破局点,或许不在于追逐更复杂的模型或架构,而在于能否专业、精准、结构化地处理好这些复杂的原始材料。 这既是当前AI应用深化过程中无法绕行的挑战,也恰恰是提升系统效果最扎实的路径。
文档解析有什么痛点
在构建基于RAG的个人或企业知识库时,文档解析是数据处理流水线的第一道关卡,也是最容易引入“噪声”与“损耗”的环节。其核心痛点集中体现在对非纯文本、非结构化复杂文档的处理无力上。
首先,格式兼容与识别难题无处不在。现实中的文档格式多样(PDF、扫描图片、Word、PPT),尤其是由纸质文件扫描或图像生成的PDF,传统的简单文本提取方法几乎无法处理,需要依赖OCR技术,而OCR本身的准确率又受限于图像质量与版面复杂度。
其次,复杂版面与多模态元素的解析是主要失分项。技术文档、研究报告中的多栏排版、页眉页脚、表格(尤其是含合并单元格、跨页表格)、图表、公式以及图文混排,在常规解析过程中极易丢失其原有的逻辑结构与关联语义。表格数据可能被拆散成无意义的文字碎片,图表与正文说明分离,导致下游的向量化与检索根本无法理解内容的真实含义。
最终,这种源头上的信息“失真”或“缺失”,会直接传导至RAG系统的末端。当检索到的文档片段本身就支离破碎、缺少关键上下文时,无论后续的召回模型如何优化、提示词如何精巧,大模型都难以生成准确、可靠的答案。因此,解决文档解析的深度与精度问题,是提升整个知识库应用效能的关键前提。
TextIn -- 复杂结构文档的解析神器
面对上述文档解析的核心痛点,TextIn 提供了专业级的解决方案。它专为精准解析和深度理解复杂格式文档而生,能够将混杂的表格、图片、图表及其逻辑关系,高质量地还原为结构化、机器可读的文本与数据。
下面我将会用一次在Coze上实际操作的例子来展示如何使用TextIn,以及效果如何。
Coze + TextIn 搭建一个 RAG 知识库
本次实验将利用Coze平台提供的低代码能力,快速搭建一个RAG应用。我所选取的语料是一份关于国外🚀技术的研究报告,它与我在实际业务需求中遇到的文档类型极为相似,具有以下四个典型特征:
- 文档格式不统一、排版不规范
- 存在大量图片与文字环绕排版的复杂版面
- 包含了结构复杂的表格,甚至出现了表格被分页截断的情况
- 涉及大量专业、复杂的数据内容。
用 Coze 自带的文档解析,完成最基础的 RAG
由于 Coze 的使用方式并不是这篇文章的重点,所以我省略了 Coze 使用过程的描述。如果不熟悉 Coze 的朋友,也欢迎通过 这里 进行体验,真的是很方便的工具。我们现在只专注在文档处理效果上。
上面三张图是我用 Coze 自带的文档解析得到的结果,其实可以看到,效果上可以看到以下几个特点:
- 对于表格格式可以较完整的解析,甚至有合并单元格的情况也可以解析
- 对于页面的上标题,页眉、页脚等,没有正确解析应有的格式,而是单纯解析成了分行的文字
- 对于图片,没有顺利解析成功,只是把图片标题解析出来。
- 分页时的上下文没有做特殊的连贯逻辑处理。 那么基于这种效果,RAG 问答出来的效果怎么样呢?
Coze 默认解析效果
可以看到,基于 Coze 的解析效果的问答,虽然语料可以被基本召回,但由于在文档解析时,有很多标题以及图片说明样式的文字被解析成内容,以至于形成了新的数据噪点,以至于在推理时,有些结论不太准确,比如对于中程🚀的分类不是特别精准。这其实就是典型的解析时带来的数据损失带来的推理不准确的场景之一。
用 TextIn 通用文档解析助手代替 Coze 文档处理节点
接下来,我们用 TextIn 先一步处理一遍语料,帮我们把内容更精准的提取,并优化成大模型解析时更方便的格式。
可以看到,在 TextIn 做文档处理时:
- 精准的解析了表格数据
- 解析了图片在文档中的位置
- 解析了标题及页眉、页脚、图片注脚等内容
- 分页时解析并标注了连贯的内容
还有不得不提的是,TextIn 提供了很方便的批量导入和导出的功能,文档中的图片会随着 Markdown 格式打包成 zip,这样你可以在本地打开文件,导出成 PDF 等其他格式。很方便!
原来 Coze 中直接解析存在的问题,
都已经不存在。下一步我们再将导出的 PDF 导入到 Coze 知识库中,供我们召回推理,我们来看看效果。
TextIn 预处理数据召回推理效果
在参数、基座模型一致的情况下,可以看到推理结果已经更完整了。这说明,语料质量的提升,有效的提高了推理的效果。
总结
其实除了这个简单的实验,我还尝试了更多种不同数据的处理效果,但因为这些数据是真实的客户数据,所以我不便展现在文章中,基于在多种复杂场景(包括技术手册、财务报告及学术论文等)下的内部测试与对比分析,我综合评估了两种方案的核心表现。以下为模拟的、具有代表性的对比数据摘要,可供参考:
| 评估维度 | 传统文档解析方案 | TextIn 专业解析方案 | 提升与说明 |
|---|---|---|---|
| 复杂表格结构还原准确率 | 约 70% - 80% | 约 88% - 96% | 对合并单元格、嵌套表、跨页表格的识别与结构化重建能力有根本性突破。 |
| 图文混排内容理解度 | 低(图文分离,关联丢失) | 高(可解析版面关系,搭配 OCR 和 I2T 模型生成图片的语义描述) | 实现了图片与周围文字的关联分析,保留了图文一体的完整语义。 |
| 多栏/复杂版面文本顺序保真度 | 差(文本块顺序混乱常见) | 优(按人类阅读逻辑顺序输出) | 有效解决多栏、分栏、文本框等复杂版面导致的文本错序问题。 |
| 非文本元素(图表/公式)处理 | 通常忽略或作为图片丢弃 | 可识别、分类并提取关键信息 | 将图表、公式等元素转换为可被检索和推理的语义化描述。 |
| 结构化数据召回率(实验场景) | 约 75% - 85% | 约 85% - 92% | 在基于文档内容的精准数据查询任务中,关键信息的召回率大幅提升。 |
| 端到端解析平均耗时(每页) | 约 1-3 秒 | 约 4-7 秒 | 更深入的版面分析与语义理解增加了单页处理时间,但换取了高质量的结构化输出。 |
| 下游任务综合准确率提升 | 基准 | 相对提升 35%-70% | 为后续的检索、问答、分析等任务提供了高质量输入,带来整体效果的跃升。 |
| 总体拥有成本(TCO)考量 | 初始直接成本较低 | 初始处理成本明确增加 | 但,显著减少了后续为修正错误、补充缺失信息所投入的巨大人力与调优成本,长期投资回报率(ROI)显著为正。 |
模拟对比结果清晰地表明,针对复杂、非结构化文档,专业的解析工具如TextIn,相比传统通用方案,在信息提取的准确度、完整性和结构化程度上实现了跨越式的进步。这种源头上的质量提升,为构建高可靠性的RAG系统、知识库乃至更广泛的AI应用,提供了坚实的数据地基。它验证了在AI工程化落地的进程中,在数据预处理环节进行精准而深入的投入,是突破效果瓶颈、实现价值最大化的关键路径。
扩展
上面通过一个简单实验和一些数据说明了 TextIn 在数据处理上带来的提升。接下来还想给大家介绍一些关于 TextIn 的其他内容,比如 API 使用,他带来的惊喜实在很多。
- TextIn 提供的 10s 跑通接口示例
import json
import requests
from typing import Dict, Optional
from dataclasses import dataclass
class OCRClient:
def __init__(self, app_id: str, secret_code: str):
self.app_id = app_id
self.secret_code = secret_code
def recognize(self, file_content: bytes, options: dict) -> str:
# 构建请求参数
params = {}
for key, value in options.items():
params[key] = str(value)
# 设置请求头
headers = {
"x-ti-app-id": self.app_id,
"x-ti-secret-code": self.secret_code,
"x-ti-client-source": "sample-code-v1.0",
# 方式一:读取本地文件
"Content-Type": "application/octet-stream"
# 方式二:使用URL方式
# "Content-Type": "text/plain"
}
# 发送请求
response = requests.post(
f"https://api.textin.com/ai/service/v1/pdf_to_markdown",
params=params,
headers=headers,
data=file_content
)
# 检查响应状态
response.raise_for_status()
return response.text
def main():
# 创建客户端实例
client = OCRClient("7d6975f5396174d027d0f515446862a1", "0e2f10a32b05dd3df030d3966e289f61")
# 读取图片文件
# 方式一:读取本地文件
with open("example.png", "rb") as f:
file_content = f.read()
# 方式二:使用URL方式(需要将headers中的Content-Type改为'text/plain')
# file_content = "https://example.com/path/to/your.pdf"
# 设置转换选项
options = dict(
)
try:
response = client.recognize(file_content, options)
# 保存完整的JSON响应到result.json文件
with open("result.json", "w", encoding="utf-8") as f:
f.write(response)
# 解析JSON响应以提取markdown内容
json_response = json.loads(response)
if "result" in json_response and "markdown" in json_response["result"]:
markdown_content = json_response["result"]["markdown"]
with open("result.md", "w", encoding="utf-8") as f:
f.write(markdown_content)
print(response)
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
main()
const axios = require('axios');
const fs = require('fs').promises;
class OCRClient {
constructor(appId, secretCode) {
this.appId = appId;
this.secretCode = secretCode;
this.baseUrl = 'https://api.textin.com/ai/service/v1/pdf_to_markdown';
}
async recognize(fileContent, options) {
const params = new URLSearchParams();
for (const [key, value] of Object.entries(options)) {
params.append(key, value.toString());
}
const url = `${this.baseUrl}${params.toString() ? '?' + params.toString() : ''}`;
const response = await axios({
method: 'post',
url: url,
data: fileContent,
headers: {
'x-ti-app-id': this.appId,
'x-ti-secret-code': this.secretCode,
'x-ti-client-source': 'sample-code-v1.0',
// 方式一:读取本地文件
'Content-Type': 'application/octet-stream'
// 方式二:使用URL方式
// 'Content-Type': 'text/plain'
},
responseType: 'text'
});
return response.data;
}
}
async function main() {
const client = new OCRClient('7d6975f5396174d027d0f515446862a1', '0e2f10a32b05dd3df030d3966e289f61');
try {
// Read PDF file
// 方式一:读取本地文件
const fileContent = await fs.readFile('example.png');
// 方式二:使用URL方式(需要将headers中的Content-Type改为'text/plain')
// const fileContent = Buffer.from('https://example.com/path/to/your.pdf');
const options = {
};
const response = await client.recognize(fileContent, options);
// 保存完整的JSON响应到result.json文件
await fs.writeFile('result.json', response);
// 解析JSON响应以提取markdown内容
const jsonResponse = JSON.parse(response);
if (jsonResponse.result?.markdown) {
await fs.writeFile('result.md', jsonResponse.result.markdown);
}
console.log(response);
} catch (error) {
console.error('Error:', error.message);
}
}
main();
- 智能文档抽取的 API 请求示例
import requests
url = "https://api.textin.com/ai/service/v3/entity_extraction"
payload = {
# 您要抽取的文件
"file": {
"file_url": "https://web-api.textin.com/open/image/download?filename=54efc36a05cf475aa6b39137b0717726"
},
# 定义抽取的schema
"schema": {
"type": "object",
"properties": {
"商品": {
"type": ["string","null"],
"description": ""
},
"商品列表": {
"type": "array",
"description": "",
"items": {
"type": "object",
"properties": {
"名称": {
"type": ["string","null"],
"description": ""
},
"类型": {
"type": ["string","null"],
"description": ""
}
},
"required": ["名称","类型"]
}
}
},
"required": [
"商品",
"商品列表"
]
},
# 解析相关参数
"parse_options":{
"crop_dewarp":1,
"get_image":"both"
},
# 抽取高级配置
"extract_options":{
"generate_citations": True,
"stamp": True
}
}
# 设置API key
headers = {
"x-ti-app-id": "<api-key>", #需替换为你的x-ti-app-id
"x-ti-secret-code": "<api-key>", #需替换为你的x-ti-secret-code
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
更多的内容大家可以去看官方的 API 文档 这里还有一个 TextIn 官方提供的 OCR 识别小 Demo,也挺有意思 https://ai.feishu.cn/file/JHpIbDt4EosaarxV0H3c85mandf?pre_pathname=%2Fdrive%2Ffolder%2FD4aof9zjRlv0GOdOlpsc8FejnCc&previous_navigation_time=1766851927440
最后,给大家分享部分我这次测试用的语料,大家可以上手亲自试一试。
TextIn 在复杂文档解析中展现的核心价值,在于它精准地将现实世界的非结构化信息(如复杂表格、图文混排)转化为机器可理解的高质量结构化数据。这验证了在AI应用落地的进程中,专业级的数据预处理绝非可有可无的环节,而是决定最终效果上限的基石。它体现的是一种“数据与模型并重”的工程化思维:源头上的微小提升,能为下游的检索、问答等任务带来显著的全局性优化。展望未来,从企业知识管理到智能风控,这一“专业预处理+AI平台”的模式,为各行各业可靠地释放复杂文档的价值,提供了一条清晰且高效的路径。
