demo_bidi_rag.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. # -*- coding: utf-8 -*-
  2. """
  3. BidiRag 使用示例 - 演示如何使用 BidiRag 类进行 HTML 文档检索
  4. 功能:
  5. 1. 加载 HTML 文档
  6. 2. 使用不同的 RAG 方法进行检索
  7. 3. 支持关键词检索
  8. 4. 支持自然语言查询
  9. """
  10. import os
  11. from loguru import logger
  12. from bdirag.bidi_rag import BidiRag
  13. def demo_basic_usage():
  14. """基础使用示例"""
  15. print("=" * 80)
  16. print("示例 1: 基础使用 - BM25 HTML Tree 方法")
  17. print("=" * 80)
  18. # 1. 初始化 BidiRag(使用 BM25 HTML Tree 方法,适合 HTML 文档)
  19. rag = BidiRag(
  20. rag_method='bm25_html_tree', # 使用 BM25 HTML Tree 方法
  21. chunk_size=512,
  22. chunk_overlap=50
  23. )
  24. # 2. 添加 HTML 文档
  25. html_files = [
  26. "examples/sample_data.html", # 假设的 HTML 文件
  27. # "data/documents/announcement1.html",
  28. # "data/documents/announcement2.html",
  29. ]
  30. # 如果示例文件不存在,使用文本替代
  31. if not any(os.path.exists(f) for f in html_files):
  32. print("未找到 HTML 文件,使用示例文本...")
  33. sample_texts = [
  34. """
  35. <html>
  36. <body>
  37. <h1>招标公告</h1>
  38. <p>项目名称:大连长兴岛经济技术开发区交流岛街道办事处2026年5月至6月政府采购意向</p>
  39. <p>采购单位:大连长兴岛经济技术开发区交流岛街道办事处</p>
  40. <p>采购项目名称:交流岛滨海路夜间出行照明提升工程</p>
  41. <p>预算金额:147.060000万元(人民币)</p>
  42. <p>采购需求:在滨海路安装太阳能路灯200盏(单排)</p>
  43. <p>预计采购时间:2026-05</p>
  44. </body>
  45. </html>
  46. """,
  47. """
  48. <html>
  49. <body>
  50. <h1>中标公告</h1>
  51. <p>项目名称:XX市智慧交通系统建设项目</p>
  52. <p>采购人:XX市交通运输局</p>
  53. <p>中标人:XX科技有限公司</p>
  54. <p>中标金额:5000万元</p>
  55. <p>项目内容:交通信号控制系统、视频监控系统、交通流量监测系统</p>
  56. </body>
  57. </html>
  58. """
  59. ]
  60. rag.add_texts(sample_texts)
  61. else:
  62. rag.add_documents(html_files)
  63. print(f"\n已加载 {rag.get_document_count()} 个文档\n")
  64. # 3. 检索文档 - 使用关键词
  65. print("-" * 80)
  66. print("检索 1: 查找'招标人'和'中标人'相关信息")
  67. print("-" * 80)
  68. results = rag.retrieve(
  69. query="招标人和中标人",
  70. top_k=3,
  71. keywords=["招标人", "中标人", "采购人", "中标"]
  72. )
  73. for i, (doc, score) in enumerate(results, 1):
  74. print(f"\n结果 {i} (相似度: {score:.3f}):")
  75. print(doc.page_content[:200])
  76. print("...")
  77. print("\n" + "=" * 80)
  78. def demo_keyword_search():
  79. """关键词搜索示例"""
  80. print("\n示例 2: 关键词搜索")
  81. print("=" * 80)
  82. # 初始化
  83. rag = BidiRag(rag_method='bm25')
  84. # 添加示例数据
  85. sample_docs = [
  86. "招标公告:本项目招标人为XX市财政局,项目预算100万元",
  87. "中标公告:中标人为XX建设有限公司,中标金额98万元",
  88. "采购公告:采购单位XX医院,采购医疗设备一批",
  89. "中标公告:本项目中标人为XX科技公司,中标价格50万元",
  90. ]
  91. rag.add_texts(sample_docs)
  92. # 搜索特定关键词
  93. print("\n搜索关键词:'招标人'")
  94. results = rag.search_keywords(["招标人"], top_k=5)
  95. for i, doc in enumerate(results, 1):
  96. print(f"{i}. {doc.page_content}")
  97. print("\n搜索关键词:'中标人'")
  98. results = rag.search_keywords(["中标人"], top_k=5)
  99. for i, doc in enumerate(results, 1):
  100. print(f"{i}. {doc.page_content}")
  101. print("\n搜索关键词:'招标人' AND '中标人'")
  102. results = rag.search_keywords(["招标人", "中标人"], top_k=5)
  103. for i, doc in enumerate(results, 1):
  104. print(f"{i}. {doc.page_content}")
  105. print("\n" + "=" * 80)
  106. def demo_different_methods():
  107. """不同 RAG 方法对比"""
  108. print("\n示例 3: 不同 RAG 方法对比")
  109. print("=" * 80)
  110. # 准备相同的测试数据
  111. test_texts = [
  112. "招标公告:XX市政府采购项目,招标人:XX局,预算200万",
  113. "中标公告:中标人XX公司,中标金额180万,项目:信息化建设",
  114. "采购意向:XX学校设备采购,采购单位:XX学校,预计采购时间2026年",
  115. ]
  116. # 测试不同的方法
  117. methods = ['bm25', 'tfidf', 'keyword', 'naive']
  118. for method in methods:
  119. print(f"\n测试方法: {method}")
  120. print("-" * 40)
  121. try:
  122. rag = BidiRag(rag_method=method)
  123. rag.add_texts(test_texts)
  124. # 检索
  125. results = rag.retrieve(
  126. query="招标人信息",
  127. top_k=2,
  128. keywords=["招标人", "采购人"]
  129. )
  130. for i, (doc, score) in enumerate(results, 1):
  131. print(f" {i}. (score: {score:.3f}) {doc.page_content[:100]}...")
  132. except Exception as e:
  133. print(f" 方法 {method} 失败: {e}")
  134. print("\n" + "=" * 80)
  135. def demo_query_with_answer():
  136. """完整问答示例"""
  137. print("\n示例 4: 完整问答(需要 LLM)")
  138. print("=" * 80)
  139. # 注意:这个方法需要配置 LLM
  140. print("注意:此示例需要配置 LLM 客户端")
  141. print("如果您有 OpenAI API key,可以这样使用:\n")
  142. example_code = '''
  143. from openai import OpenAI
  144. # 初始化 LLM 客户端
  145. llm_client = OpenAI(
  146. api_key="your-api-key",
  147. base_url="https://api.openai.com/v1"
  148. )
  149. # 使用 BidiRag
  150. rag = BidiRag(
  151. rag_method='naive',
  152. llm_client=llm_client,
  153. llm_model='gpt-4o'
  154. )
  155. rag.add_texts([
  156. "招标公告:招标人XX局,项目预算100万",
  157. "中标公告:中标人XX公司,金额98万"
  158. ])
  159. # 完整问答
  160. result = rag.query(
  161. query="谁是招标人?",
  162. keywords=["招标人", "采购人"]
  163. )
  164. print("答案:", result.answer)
  165. print("检索到的文档数:", len(result.retrieved_docs))
  166. '''
  167. print(example_code)
  168. print("=" * 80)
  169. def demo_html_structure_aware():
  170. """HTML 结构感知检索示例"""
  171. print("\n示例 5: HTML 结构感知检索(推荐用于招投标公告)")
  172. print("=" * 80)
  173. # BM25 HTML Tree 方法会保留 HTML 结构信息
  174. rag = BidiRag(rag_method='bm25_html_tree')
  175. html_content = """
  176. <html>
  177. <body>
  178. <div class="announcement">
  179. <h1>政府采购中标公告</h1>
  180. <table>
  181. <tr><td>项目名称</td><td>办公设备采购项目</td></tr>
  182. <tr><td>采购人</td><td>XX市财政局</td></tr>
  183. <tr><td>中标人</td><td>XX办公设备有限公司</td></tr>
  184. <tr><td>中标金额</td><td>50万元</td></tr>
  185. <tr><td>采购内容</td><td>电脑、打印机、复印机等办公设备</td></tr>
  186. </table>
  187. </div>
  188. </body>
  189. </html>
  190. """
  191. rag.add_texts([html_content])
  192. # 检索表格中的结构化信息
  193. results = rag.retrieve(
  194. query="中标人信息",
  195. top_k=3,
  196. keywords=["中标人", "采购人", "中标金额"]
  197. )
  198. print(f"\n找到 {len(results)} 个相关结果:")
  199. for i, (doc, score) in enumerate(results, 1):
  200. print(f"\n结果 {i} (score: {score:.3f}):")
  201. print(doc.page_content)
  202. print("\n" + "=" * 80)
  203. def main():
  204. """运行所有示例"""
  205. print("\n" + "🚀 " * 20)
  206. print("BidiRag 使用示例")
  207. print(" " * 20 + "\n")
  208. # 运行示例
  209. demo_basic_usage()
  210. demo_keyword_search()
  211. demo_different_methods()
  212. demo_query_with_answer()
  213. demo_html_structure_aware()
  214. print("\n✅ 所有示例运行完成!")
  215. print("\n提示:")
  216. print("1. 对于招投标公告,推荐使用 'bm25_html_tree' 方法")
  217. print("2. 可以使用 keywords 参数精化检索结果")
  218. print("3. 如果需要生成答案,需要配置 LLM 客户端")
  219. print("4. 可用的 RAG 方法:", BidiRag(rag_method='bm25').list_available_methods())
  220. if __name__ == "__main__":
  221. main()