甘肃建设网站首页,上海景朋建设工程有限公司网站,网站代码制作软件,wordpress怎样实现前台编辑一、核心设计原则 整页为单 Chunk#xff1a;将单页保险文档作为 1 个检索单元#xff08;Chunk#xff09;#xff0c;保留内容逻辑关联性#xff1b; 元数据对齐#xff1a;文档入库的元数据字段与提问提取的元数据字段完全一致#xff0c;确保过滤检索精准#xff…一、核心设计原则整页为单 Chunk将单页保险文档作为 1 个检索单元Chunk保留内容逻辑关联性元数据对齐文档入库的元数据字段与提问提取的元数据字段完全一致确保过滤检索精准混合检索元数据过滤精准定位 Chunk 向量 / 关键词检索匹配 Chunk 内内容兼顾精度与效率。二、流程总览原始保险文档OCR文本→ 提取文档元数据 → 整页Chunk元数据上传至Dify知识库 ↑ ↓ 用户提问 → 提取提问元数据 → 元数据过滤检索Dify知识库 → 获取匹配Chunk → LLM生成回答三、第一步文档元数据提取 整页 Chunk 入库Dify1. 定义通用元数据字段保险类文档适配元数据字段字段类型说明通用化doc_type字符串文档类型如 “保险产品介绍”“保险条款”issuer字符串发行机构如 “保险公司名称”update_time字符串文档更新时间如 “YYYY 年 MM 月”applicable_area数组适用地区如 [“香港”,“澳门”]supported_currencies数组支持的保单货币类型如 [“美元”,“港元”]core_tags数组核心检索标签如 [“长期 IRR”,“回本周期”,“红利权益”,“退保规则”]data_modules数组文档包含的逻辑模块如 [“产品基础”,“收益案例”,“权益规则”,“条款约束”]key_numbers数组核心数值带单位如 [“5 年缴费”,“7% IRR”,“50 万美元保费”]2. 文档元数据提取函数LLM 驱动import os import json import requests from openai import OpenAI from dotenv import load_dotenv # 环境变量加载通用配置 load_dotenv() LLM_API_KEY os.getenv(LLM_API_KEY) DIFY_API_KEY os.getenv(DIFY_API_KEY) DIFY_BASE_URL os.getenv(DIFY_BASE_URL, https://api.dify.ai/v1) DIFY_KNOWLEDGE_BASE_ID os.getenv(DIFY_KNOWLEDGE_BASE_ID) # 初始化LLM客户端通用适配OpenAI/国产模型 llm_client OpenAI(api_keyLLM_API_KEY) def extract_document_metadata(ocr_text): 通用函数从保险文档OCR文本中提取结构化元数据 :param ocr_text: 单页保险文档的OCR文本动态输入 :return: 通用化元数据字典 prompt f # 任务提取保险类文档的RAG检索专用元数据整页为1个Chunk # 输入文本 {ocr_text} # 提取规则 1. 严格基于文本内容未提及的字段填空字符串/空数组不编造任何信息 2. doc_type提取文档类型如保险产品介绍、保险条款 3. core_tags提取所有可用于检索的核心关键词如收益、权益、规则、缴费方式 4. data_modules提取文档包含的逻辑模块从[产品基础,收益案例,权益规则,条款约束,提取规则,退保规则]中选择 5. key_numbers提取所有带单位的核心数值如年限、金额、百分比 6. 输出仅保留标准JSON无解释性文字、无换行。 # 输出JSON格式 {{ doc_type: , issuer: , update_time: , applicable_area: [], supported_currencies: [], core_tags: [], data_modules: [], key_numbers: [] }} try: response llm_client.chat.completions.create( modelgpt-3.5-turbo, # 可替换为国产模型如通义千问、文心一言 messages[ {role: system, content: 你是保险文档元数据提取专家输出仅符合格式的JSON}, {role: user, content: prompt} ], temperature0.0, # 无幻觉严格基于文本提取 response_format{type: json_object}, timeout10 ) metadata json.loads(response.choices[0].message.content) # 空值清洗确保格式统一 for key in metadata: if isinstance(metadata[key], list) and len(metadata[key]) 0: metadata[key] [] elif isinstance(metadata[key], str) and metadata[key].strip() : metadata[key] return metadata except Exception as e: print(f文档元数据提取失败{e}) # 返回空元数据兜底 return { doc_type: , issuer: , update_time: , applicable_area: [], supported_currencies: [], core_tags: [], data_modules: [], key_numbers: [] }3. 整页 Chunk 上传至 Dify 知识库def upload_full_page_to_dify(full_page_text, metadata, doc_unique_id): 通用函数将整页文档作为1个Chunk上传至Dify知识库 :param full_page_text: 整页OCR文本 :param metadata: 提取的文档元数据 :param doc_unique_id: 文档唯一标识如insurance_doc_001 url f{DIFY_BASE_URL}/knowledge_bases/{DIFY_KNOWLEDGE_BASE_ID}/documents/batch headers { Authorization: fBearer {DIFY_API_KEY}, Content-Type: application/json } # 构造Dify上传请求体单Chunk documents [ { content: full_page_text, # 整页文本作为1个Chunk metadata: metadata, # 绑定通用元数据 document_id: doc_unique_id, # 自定义唯一ID便于管理 name: f{metadata[doc_type]}_{doc_unique_id} # 文档名称 } ] payload { documents: documents, mode: overwrite # 可选append追加/overwrite覆盖 } try: response requests.post(url, headersheaders, jsonpayload, timeout30) response.raise_for_status() print(f整页Chunk上传成功ID{doc_unique_id}) except Exception as e: print(fChunk上传失败{e}) if hasattr(e, response): print(f错误详情{e.response.text}) # 文档入库主函数 def document_ingestion_pipeline(ocr_text, doc_unique_id): 文档入库流程提取元数据 → 上传Chunk :param ocr_text: 整页OCR文本 :param doc_unique_id: 文档唯一ID # 步骤1提取文档元数据 doc_metadata extract_document_metadata(ocr_text) # 步骤2上传整页Chunk元数据 upload_full_page_to_dify(ocr_text, doc_metadata, doc_unique_id)四、第二步用户提问元数据提取对齐文档元数据1. 提问元数据提取函数字段与文档元数据完全对齐def extract_query_metadata(user_query): 通用函数从用户提问中提取Dify检索用的元数据字段与文档元数据对齐 :param user_query: 用户原始提问口语化/精准化均可 :return: 结构化提问元数据用于Dify过滤检索 prompt f # 任务从用户提问中提取保险类文档RAG检索的过滤元数据 # 核心规则 1. 严格基于用户提问内容提取未提及的字段填空字符串/空数组不推测、不编造 2. 字段值需与保险文档元数据格式对齐如货币名称、模块名称统一 3. doc_type提取用户提问指向的文档类型如保险产品介绍 4. core_tags提取提问中的核心检索关键词如缴费方式、权益、金额、年限 5. data_modules提取提问指向的逻辑模块从[产品基础,收益案例,权益规则,条款约束]中选择 6. key_numbers提取提问中的核心数值带单位 7. 输出仅保留标准JSON无其他内容。 # 用户提问 {user_query} # 输出JSON格式 {{ doc_type: , issuer: , update_time: , applicable_area: [], supported_currencies: [], core_tags: [], data_modules: [], key_numbers: [] }} try: response llm_client.chat.completions.create( modelgpt-3.5-turbo, messages[ {role: system, content: 你是保险提问元数据提取助手输出仅符合格式的JSON}, {role: user, content: prompt} ], temperature0.0, response_format{type: json_object}, timeout10 ) query_metadata json.loads(response.choices[0].message.content) # 空值清洗 for key in query_metadata: if isinstance(query_metadata[key], list) and len(query_metadata[key]) 0: query_metadata[key] [] elif isinstance(query_metadata[key], str) and query_metadata[key].strip() : query_metadata[key] return query_metadata except Exception as e: print(f提问元数据提取失败{e}) # 返回空元数据兜底 return { doc_type: , issuer: , update_time: , applicable_area: [], supported_currencies: [], core_tags: [], data_modules: [], key_numbers: [] }五、第三步元数据过滤检索 LLM 生成回答1. Dify 知识库检索元数据过滤 混合检索def retrieve_from_dify(query_metadata, user_query): 通用函数调用Dify检索API基于提问元数据过滤Chunk :param query_metadata: 提问元数据 :param user_query: 用户原始提问用于向量/关键词检索 :return: Dify检索结果匹配的Chunk列表 # 构造过滤条件仅保留非空字段减少无效过滤 filter_conditions {} for key, value in query_metadata.items(): if value ! and value ! []: filter_conditions[key] value # Dify检索API参数 url f{DIFY_BASE_URL}/knowledge_bases/{DIFY_KNOWLEDGE_BASE_ID}/retrieve headers { Authorization: fBearer {DIFY_API_KEY}, Content-Type: application/json } payload { query: user_query, # 用户提问向量/关键词检索 top_k: 3, # 返回Top3匹配的Chunk filter: filter_conditions, # 元数据过滤条件对齐文档元数据 retrieval_mode: hybrid, # 混合检索关键词向量兼顾精度 score_threshold: 0.3 # 相似度阈值过滤低匹配结果 } try: response requests.post(url, headersheaders, jsonpayload, timeout20) response.raise_for_status() return response.json() except Exception as e: print(fDify检索失败{e}) if hasattr(e, response): print(f错误详情{e.response.text}) return None2. LLM 生成回答基于检索到的 Chunkdef generate_answer(retrieve_result, user_query): 通用函数基于检索到的Chunk生成精准回答 :param retrieve_result: Dify检索结果 :param user_query: 用户原始提问 :return: 结构化回答 # 无匹配结果兜底 if not retrieve_result or len(retrieve_result[documents]) 0: return 未检索到与您的问题匹配的保险文档信息请调整提问关键词。 # 提取检索到的Chunk内容整页文本 retrieved_content \n\n.join([doc[content] for doc in retrieve_result[documents]]) # 生成回答的Prompt通用化无具体产品 answer_prompt f # 任务基于保险文档信息回答用户问题 # 文档信息 {retrieved_content} # 回答规则 1. 仅使用提供的文档信息回答不编造任何内容 2. 回答简洁准确聚焦用户问题核心忽略无关信息 3. 若文档中无明确答案明确说明“文档中未提及相关信息” 4. 涉及数值/规则的需标注“非保证”等文档中的约束条件如有。 # 用户问题 {user_query} try: response llm_client.chat.completions.create( modelgpt-3.5-turbo, messages[ {role: system, content: 你是专业的保险文档解答助手回答严格基于提供的信息}, {role: user, content: answer_prompt} ], temperature0.1 # 低随机性确保回答精准 ) return response.choices[0].message.content except Exception as e: print(f回答生成失败{e}) return 回答生成失败请重试。六、第四步全流程串联通用 RAG 问答管道def insurance_rag_qa_pipeline(user_query, ocr_textNone, doc_unique_idNone): 保险类文档RAG全流程 1. 若传入OCR文本文档ID先执行文档入库 2. 提取提问元数据 → 检索 → 生成回答 # 可选文档入库首次上传时执行 if ocr_text and doc_unique_id: document_ingestion_pipeline(ocr_text, doc_unique_id) # 核心流程提问处理 → 检索 → 回答 # 步骤1提取提问元数据 query_metadata extract_query_metadata(user_query) # 步骤2Dify元数据过滤检索 retrieve_result retrieve_from_dify(query_metadata, user_query) # 步骤3生成回答 final_answer generate_answer(retrieve_result, user_query) return final_answer # 全流程测试示例 if __name__ __main__: # 示例1文档入库首次上传 sample_ocr_text 【保险产品介绍】 发行机构XX保险公司 更新时间2024年8月 支持货币美元、港元、欧元 核心收益长期总内部回报率预期超7%回本周期短至8年 权益规则支持货币转换、红利锁/解锁、受保人变更 条款约束实际收益非保证提取金额需符合保单规则 # 执行入库仅首次执行 insurance_rag_qa_pipeline( user_query, # 提问为空仅执行入库 ocr_textsample_ocr_text, doc_unique_idinsurance_doc_001 ) # 示例2用户提问检索回答 user_query 美元保单的长期IRR是多少是否有保证 answer insurance_rag_qa_pipeline(user_queryuser_query) print( 最终回答 ) print(answer)七、通用化优化建议适配所有保险类文档1. 元数据扩展可根据实际需求新增通用字段如payment_methods缴费方式数组如 [“5 年缴”,“10 年缴”,“整付”]right_types权益类型数组如 [“货币转换”,“红利解锁”,“受保人变更”]constraint_tags约束标签数组如 [“非保证收益”,“退保条件限制”]。2. 适配国产 LLM若不用 OpenAI替换llm_client为国产模型调用逻辑如通义千问、文心一言Prompt 模板完全通用# 通义千问适配示例 import dashscope dashscope.api_key os.getenv(DASHSCOPE_API_KEY) def extract_document_metadata(ocr_text): prompt ... # 保留原Prompt response dashscope.Generation.call( modelqwen-plus, messages[{role: user, content: prompt}], result_formatjson, temperature0.0 ) metadata json.loads(response.output.choices[0].message.content) return metadata3. 批量处理优化def batch_ingestion(folder_path): 批量入库文件夹中的保险文档 import glob for idx, file_path in enumerate(glob.glob(f{folder_path}/\*.txt)): with open(file_path, r, encodingutf-8) as f: ocr_text f.read() doc_unique_id finsurance_doc_{idx:03d} document_ingestion_pipeline(ocr_text, doc_unique_id)4. Dify 检索配置检索模式选择「混合检索」兼顾元数据关键词和向量相似度向量模型选择支持长文本的模型如text-embedding-3-large、m3e-large过滤逻辑Dify 支持「数组包含匹配」如supported_currencies包含 “美元” 即匹配无需完全一致。总结该方案实现了完全通用化的保险类文档 RAG 全流程文档侧整页为 Chunk 提取通用元数据无需拆分适配任意保险文档提问侧提取与文档元数据对齐的检索标签精准过滤 Chunk检索侧元数据过滤 混合检索兼顾精度与效率回答侧基于检索结果生成精准回答无编造、无冗余。全流程无具体产品名称依赖可直接复用至各类保险产品文档的 RAG 系统开发。