深求·墨鉴实战案例中医古籍OCR实体识别知识图谱构建端到端方案1. 引言当古籍遇见AI一场跨越千年的对话想象一下你面前有一本泛黄的中医古籍纸张脆弱墨迹斑驳。你想快速查找其中关于“黄芪”的所有配伍方剂或者想理清“伤寒”与“温病”的理论脉络。传统方法下你需要一页页翻阅、摘抄、整理耗时耗力还可能遗漏关键信息。这正是我们团队最近遇到的实际挑战。一家专注于中医药文化传承的研究机构拥有大量珍贵的古籍扫描件他们希望将这些沉睡在图片中的知识“唤醒”构建一个可查询、可分析、可关联的数字化知识库。经过多方评估我们选择了「深求·墨鉴」作为这项工程的起点。这不仅因为它强大的OCR能力更因为它背后DeepSeek-OCR-2引擎对复杂版式、古籍字体的出色适应性。今天我就来分享我们如何以「深求·墨鉴」为核心串联起从图片文字识别到知识图谱构建的完整技术链路打造一个真正可用的中医古籍智能解析系统。2. 项目全景从图片到知识图谱的四步跃迁我们的目标很明确输入一张古籍图片输出一个结构化的知识网络。整个过程可以分解为四个核心阶段形成一个清晰的流水线OCR文字提取利用「深求·墨鉴」将古籍图片中的文字精准转化为可编辑的数字化文本。文本预处理与清洗对OCR结果进行纠错、断句、标点恢复使其接近现代可读文本。中医实体识别与关系抽取使用自然语言处理技术自动识别文本中的人名、方剂名、药材名、病症名等实体并抽取出它们之间的“治疗”、“组成”、“禁忌”等关系。知识图谱构建与可视化将识别出的实体和关系存入图数据库并构建前端界面供研究人员查询和探索。下面我将重点拆解第一步和第三步展示「深求·墨鉴」如何无缝嵌入这个技术栈并成为关键的数据入口。3. 实战第一步用深求·墨鉴批量“唤醒”古籍文字单张图片的手动上传解析对于研究级项目来说效率太低。我们需要的是批量化、自动化的处理能力。幸运的是「深求·墨鉴」提供了完善的API接口让我们可以将其集成到自动化流水线中。3.1 搭建批量处理环境我们首先在内部服务器上部署了「深求·墨鉴」的Docker镜像确保所有古籍图片数据在本地处理保障数据安全。核心处理脚本用Python编写逻辑非常清晰。import os import requests from PIL import Image import json import time class DeepSeekOCRProcessor: def __init__(self, api_base_urlhttp://localhost:8000): self.api_url f{api_base_url}/api/ocr # 假设墨鉴API端点 self.headers {Content-Type: application/json} def process_image(self, image_path): 处理单张图片调用墨鉴OCR API try: # 1. 读取并准备图片 with open(image_path, rb) as img_file: img_data img_file.read() # 2. 构建API请求根据墨鉴实际API调整 # 这里模拟一个表单上传请求 files {image: (os.path.basename(image_path), img_data, image/jpeg)} data {output_format: markdown} # 指定输出为Markdown # 3. 发送请求 response requests.post(self.api_url, filesfiles, datadata) response.raise_for_status() # 4. 解析响应 result response.json() markdown_text result.get(text, ) confidence result.get(confidence, 0) return { success: True, text: markdown_text, confidence: confidence, source_image: image_path } except Exception as e: print(f处理图片 {image_path} 时出错: {e}) return {success: False, error: str(e)} def batch_process(self, image_dir, output_dir): 批量处理一个目录下的所有图片 os.makedirs(output_dir, exist_okTrue) image_extensions [.jpg, .jpeg, .png, .bmp] processed_results [] for filename in os.listdir(image_dir): if any(filename.lower().endswith(ext) for ext in image_extensions): image_path os.path.join(image_dir, filename) print(f正在处理: {filename}) # 调用单张处理 result self.process_image(image_path) if result[success]: # 保存OCR结果 base_name os.path.splitext(filename)[0] output_path os.path.join(output_dir, f{base_name}.md) with open(output_path, w, encodingutf-8) as f: f.write(result[text]) # 记录元数据 result[output_file] output_path processed_results.append(result) print(f 成功保存到: {output_path} (置信度: {result[confidence]:.2%})) else: print(f 处理失败: {result[error]}) # 避免请求过快适当延迟 time.sleep(0.5) # 生成处理报告 self.generate_report(processed_results, output_dir) return processed_results def generate_report(self, results, output_dir): 生成批量处理报告 successful [r for r in results if r[success]] failed [r for r in results if not r[success]] report { total_images: len(results), successful: len(successful), failed: len(failed), avg_confidence: sum(r[confidence] for r in successful) / len(successful) if successful else 0, details: results } report_path os.path.join(output_dir, processing_report.json) with open(report_path, w, encodingutf-8) as f: json.dump(report, f, ensure_asciiFalse, indent2) print(f\n处理完成报告已保存至: {report_path}) print(f总计: {len(results)} 张成功: {len(successful)}失败: {len(failed)}) # 使用示例 if __name__ __main__: processor DeepSeekOCRProcessor() # 批量处理古籍图片目录 image_directory ./data/ancient_books/scans output_directory ./data/ancient_books/ocr_results results processor.batch_process(image_directory, output_directory)3.2 处理效果与挑战应对在实际运行中「深求·墨鉴」对清晰扫描的古籍页面表现非常出色。其Markdown输出格式完美保留了原文的段落结构甚至能较好地处理古籍中常见的竖排文字和注释小字。我们遇到的主要挑战和解决方案生僻字与异体字识别部分古籍中的异体字OCR识别率较低。解决方案我们建立了一个中医古籍专用字典对OCR结果进行后处理校正。同时利用「深求·墨鉴」API可能返回的字符位置信息对低置信度的字符进行高亮标注方便人工二次校对。版面复杂古籍常有双行小注、眉批、印章等复杂元素。解决方案得益于DeepSeek-OCR-2的先进检测能力「深求·墨鉴」能较好地区分主体文字和注释。我们在后处理规则中根据文本块的位置和字体大小自动为眉批、注释添加特定的Markdown标签如引用块或[批注]便于后续区分。图片质量不均部分老扫描件存在墨迹扩散、背景污渍。解决方案在调用OCR前增加一个简单的图像预处理环节使用OpenCV进行对比度增强、二值化去污能显著提升识别效果。4. 实战第二步从文本到知识——实体识别与图谱构建OCR得到了干净的Markdown文本这只是第一步。真正的价值在于从这些文本中提取出结构化的知识。我们构建了一个中医领域的命名实体识别模型。4.1 构建中医领域实体识别模型我们采用BERTCRF的经典架构但在BERT预训练阶段加入了大量现代中医教材、药典、方剂学文献进行领域自适应预训练让模型更好地理解中医术语的上下文。import torch import torch.nn as nn from transformers import BertModel, BertTokenizer from torchcrf import CRF class TCM_NER_Model(nn.Module): 中医命名实体识别模型 def __init__(self, bert_path, num_tags, dropout_rate0.1): super(TCM_NER_Model, self).__init__() # 加载领域增强过的BERT self.bert BertModel.from_pretrained(bert_path) self.bert_config self.bert.config # BERT输出维度 - 标签维度 self.hidden2tag nn.Linear(self.bert_config.hidden_size, num_tags) self.dropout nn.Dropout(dropout_rate) # CRF层用于序列标注 self.crf CRF(num_tags, batch_firstTrue) # 实体标签定义示例 self.tag_dict { O: 0, # 其他 B-HERB: 1, # 药材-开始 I-HERB: 2, # 药材-内部 B-FORMULA: 3, # 方剂-开始 I-FORMULA: 4, # 方剂-内部 B-SYMPTOM: 5, # 病症-开始 I-SYMPTOM: 6, # 病症-内部 B-MERIDIAN: 7, # 经络-开始 I-MERIDIAN: 8, # 经络-内部 } self.idx2tag {v: k for k, v in self.tag_dict.items()} def forward(self, input_ids, attention_mask, labelsNone): # BERT编码 outputs self.bert(input_idsinput_ids, attention_maskattention_mask) sequence_output outputs.last_hidden_state # [batch, seq_len, hidden] sequence_output self.dropout(sequence_output) emissions self.hidden2tag(sequence_output) # [batch, seq_len, num_tags] if labels is not None: # 训练模式计算CRF损失 loss -self.crf(emissions, labels, maskattention_mask.bool(), reductionmean) return loss else: # 预测模式维特比解码得到最优标签序列 predictions self.crf.decode(emissions, maskattention_mask.bool()) return predictions # 实体识别推理示例 def extract_tcm_entities(text, model, tokenizer, devicecuda): 从一段文本中提取中医实体 model.eval() # 分词和编码 inputs tokenizer(text, return_tensorspt, truncationTrue, max_length512) input_ids inputs[input_ids].to(device) attention_mask inputs[attention_mask].to(device) with torch.no_grad(): predictions model(input_ids, attention_mask) # 将预测的标签ID转换回标签 pred_tags [model.idx2tag[idx] for idx in predictions[0]] # 将子词标签对齐到原始词语 tokens tokenizer.convert_ids_to_tokens(input_ids[0]) entities [] current_entity None current_text for token, tag in zip(tokens, pred_tags): if token in [[CLS], [SEP], [PAD]]: continue # 处理子词前缀## if token.startswith(##): current_text token[2:] else: # 保存上一个实体 if current_entity: entities.append({ text: current_text, type: current_entity }) # 开始新的实体或重置 if tag.startswith(B-): current_entity tag[2:] current_text token elif tag.startswith(I-): if current_entity tag[2:]: current_text token else: # 不连续的I标签按新实体处理 if current_entity: entities.append({ text: current_text, type: current_entity }) current_entity tag[2:] current_text token else: # O current_entity None current_text # 处理最后一个实体 if current_entity: entities.append({ text: current_text, type: current_entity }) return entities # 使用示例 if __name__ __main__: device torch.device(cuda if torch.cuda.is_available() else cpu) # 加载模型和分词器 model_path ./models/tcm_bert_ner tokenizer BertTokenizer.from_pretrained(model_path) model TCM_NER_Model(model_path, num_tagslen(model.tag_dict)).to(device) model.load_state_dict(torch.load(f{model_path}/best_model.pt, map_locationdevice)) # 示例文本来自OCR结果 ocr_text 《伤寒论》有云太阳病头痛发热汗出恶风桂枝汤主之。 桂枝汤方桂枝三两芍药三两甘草二两炙生姜三两大枣十二枚。 上五味以水七升微火煮取三升去滓适寒温服一升。 entities extract_tcm_entities(ocr_text, model, tokenizer, device) print(识别出的实体) for entity in entities: print(f - {entity[text]} [{entity[type]}])4.2 关系抽取与知识图谱构建识别出实体后我们进一步使用规则和轻量级模型结合的方式抽取出实体间的关系。例如“桂枝汤”与“桂枝”之间存在“包含”关系“桂枝汤”与“太阳病”之间存在“治疗”关系。我们将所有实体和关系存入Neo4j图数据库构建的知识图谱片段如下图所示概念图(桂枝汤:方剂)-[包含]-(桂枝:药材) (桂枝汤:方剂)-[包含]-(芍药:药材) (桂枝汤:方剂)-[治疗]-(太阳病:病症) (太阳病:病症)-[症状]-(头痛:症状) (太阳病:病症)-[症状]-(发热:症状)研究人员现在可以通过Cypher查询语言轻松查询诸如“所有包含桂枝的方剂”、“治疗发热的所有方剂及其组成”等复杂问题。5. 端到端流水线集成最后我们将所有环节集成到一个统一的流水线中实现从古籍图片上传到知识图谱可视化的全自动处理。class AncientBookKnowledgePipeline: 古籍知识提取端到端流水线 def __init__(self, ocr_processor, ner_model, ner_tokenizer, graph_db_connector): self.ocr_processor ocr_processor self.ner_model ner_model self.ner_tokenizer ner_tokenizer self.graph_db graph_db_connector def process_book_page(self, image_path, page_number, book_id): 处理单页古籍提取知识并存入图谱 print(f处理古籍 {book_id} 第 {page_number} 页...) # 步骤1: OCR文字提取 ocr_result self.ocr_processor.process_image(image_path) if not ocr_result[success]: print(fOCR失败: {ocr_result.get(error)}) return None markdown_text ocr_result[text] # 步骤2: 文本预处理简化的清洗和分句 clean_text self.preprocess_text(markdown_text) sentences self.split_into_sentences(clean_text) # 步骤3: 对每句话进行实体识别和关系抽取 page_knowledge { book_id: book_id, page: page_number, sentences: [], entities: [], relations: [] } for sent in sentences: # 实体识别 entities extract_tcm_entities(sent, self.ner_model, self.ner_tokenizer) # 关系抽取基于规则示例 relations self.extract_relations(sent, entities) sentence_info { text: sent, entities: entities, relations: relations } page_knowledge[sentences].append(sentence_info) page_knowledge[entities].extend(entities) page_knowledge[relations].extend(relations) # 步骤4: 知识入库 self.graph_db.insert_page_knowledge(page_knowledge) print(f 完成识别出 {len(page_knowledge[entities])} 个实体{len(page_knowledge[relations])} 条关系) return page_knowledge def preprocess_text(self, text): 文本预处理去除多余空格、换行简单纠错 # 这里可以加入更复杂的古籍文本清洗逻辑 import re # 合并因换行断开的词语古籍常见 text re.sub(r([^\n])\n([^\n]), r\1\2, text) # 标准化空格 text re.sub(r\s, , text).strip() return text def split_into_sentences(self, text): 简单分句针对古籍文言文特点优化 # 古籍常用句末标点 sentence_delimiters r[。\.\!\?;] sentences re.split(sentence_delimiters, text) return [s.strip() for s in sentences if s.strip()] def extract_relations(self, sentence, entities): 基于规则的关系抽取示例 relations [] entities_in_sentence [(e[text], e[type]) for e in entities] # 简单规则如果句子中有“方”和“组成”则建立方剂-药材关系 if 方 in sentence and any(e[1] FORMULA for e in entities_in_sentence): formula_entities [e for e in entities if e[type] FORMULA] herb_entities [e for e in entities if e[type] HERB] for formula in formula_entities: for herb in herb_entities: relations.append({ head: formula[text], relation: contains, tail: herb[text], source_sentence: sentence }) return relations # 流水线使用示例 def main(): # 初始化各组件 ocr_processor DeepSeekOCRProcessor(api_base_urlhttp://localhost:8000) # 加载NER模型假设已训练好 ner_model, ner_tokenizer load_ner_model(./models/tcm_ner) # 初始化图数据库连接 graph_db Neo4jConnector(uribolt://localhost:7687, userneo4j, passwordpassword) # 创建流水线 pipeline AncientBookKnowledgePipeline(ocr_processor, ner_model, ner_tokenizer, graph_db) # 处理一本古籍的所有页面 book_id 伤寒论_宋刻本 scan_directory f./data/books/{book_id}/scans for page_file in sorted(os.listdir(scan_directory)): if page_file.endswith((.jpg, .png)): page_num int(re.search(r\d, page_file).group()) image_path os.path.join(scan_directory, page_file) # 执行端到端处理 knowledge pipeline.process_book_page(image_path, page_num, book_id) # 可以实时保存进度或发送到前端展示 if knowledge: save_intermediate_result(knowledge, book_id, page_num)6. 总结技术落地带来的价值与展望通过这个端到端的方案我们成功地将堆积如山的古籍扫描件转化为了一个活化的数字知识库。回顾整个项目「深求·墨鉴」在其中扮演了至关重要的“翻译官”角色以其高精度的OCR能力为后续所有高级NLP任务提供了高质量的文本原料。项目带来的实际价值研究效率倍增研究人员从“翻书找资料”变为“查询知识图谱”查找特定药材的所有古籍记载从数小时缩短到秒级。发现隐藏关联通过图谱分析发现了某些方剂在不同典籍中演变的脉络以及药材配伍的潜在规律。文化遗产保护为珍贵的古籍建立了数字副本和结构化知识库实现了永久性保存和便捷传播。赋能现代应用结构化知识可用于开发智能问诊辅助、方剂推荐、教学培训等现代应用。未来展望识别精度再提升针对更模糊、破损的古籍结合图像修复技术与OCR进一步提升识别率。理解深度加强引入大语言模型不仅识别实体和简单关系还能理解古籍中复杂的医理阐述和辩证逻辑。交互体验优化构建更友好的可视化前端让非技术人员也能像浏览地图一样“浏览”中医知识图谱。这个案例证明将像「深求·墨鉴」这样优秀的垂直工具与领域特定的AI模型相结合能够解决传统方法难以应对的复杂问题。技术不再是冰冷的代码而是成为了连接古今、活化知识的桥梁。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。