search_from_ragflow.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import requests
  2. import sys
  3. from config.logger import setup_logging
  4. from plugins_func.register import register_function, ToolType, ActionResponse, Action
  5. from typing import TYPE_CHECKING
  6. if TYPE_CHECKING:
  7. from core.connection import ConnectionHandler
  8. TAG = __name__
  9. logger = setup_logging()
  10. # 定义基础的函数描述模板
  11. SEARCH_FROM_RAGFLOW_FUNCTION_DESC = {
  12. "type": "function",
  13. "function": {
  14. "name": "search_from_ragflow",
  15. "description": "从知识库中查询信息",
  16. "parameters": {
  17. "type": "object",
  18. "properties": {"question": {"type": "string", "description": "查询的问题"}},
  19. "required": ["question"],
  20. },
  21. },
  22. }
  23. @register_function(
  24. "search_from_ragflow", SEARCH_FROM_RAGFLOW_FUNCTION_DESC, ToolType.SYSTEM_CTL
  25. )
  26. def search_from_ragflow(conn: "ConnectionHandler", question=None):
  27. # 确保字符串参数正确处理编码
  28. if question and isinstance(question, str):
  29. # 确保问题参数是UTF-8编码的字符串
  30. pass
  31. else:
  32. question = str(question) if question is not None else ""
  33. ragflow_config = conn.config.get("plugins", {}).get("search_from_ragflow", {})
  34. base_url = ragflow_config.get("base_url", "")
  35. api_key = ragflow_config.get("api_key", "")
  36. dataset_ids = ragflow_config.get("dataset_ids", [])
  37. url = base_url + "/api/v1/retrieval"
  38. headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
  39. # 确保payload中的字符串都是UTF-8编码
  40. payload = {"question": question, "dataset_ids": dataset_ids}
  41. try:
  42. # 使用ensure_ascii=False确保JSON序列化时正确处理中文
  43. response = requests.post(
  44. url,
  45. json=payload,
  46. headers=headers,
  47. timeout=5,
  48. verify=False,
  49. )
  50. # 显式设置响应的编码为utf-8
  51. response.encoding = "utf-8"
  52. response.raise_for_status()
  53. # 先获取文本内容,然后手动处理JSON解码
  54. response_text = response.text
  55. import json
  56. result = json.loads(response_text)
  57. if result.get("code") != 0:
  58. error_detail = result.get("error", {}).get("detail", "未知错误")
  59. error_message = result.get("error", {}).get("message", "")
  60. error_code = result.get("code", "")
  61. # 安全地记录错误信息
  62. logger.bind(tag=TAG).error(
  63. f"RAGFlow API调用失败,响应码:{error_code},错误详情:{error_detail},完整响应:{result}"
  64. )
  65. # 构建详细的错误响应
  66. error_response = f"RAG接口返回异常(错误码:{error_code})"
  67. if error_message:
  68. error_response += f":{error_message}"
  69. if error_detail:
  70. error_response += f"\n详情:{error_detail}"
  71. return ActionResponse(Action.RESPONSE, None, error_response)
  72. chunks = result.get("data", {}).get("chunks", [])
  73. contents = []
  74. for chunk in chunks:
  75. content = chunk.get("content", "")
  76. if content:
  77. # 安全地处理内容字符串
  78. if isinstance(content, str):
  79. contents.append(content)
  80. elif isinstance(content, bytes):
  81. contents.append(content.decode("utf-8", errors="replace"))
  82. else:
  83. contents.append(str(content))
  84. if contents:
  85. # 组织知识库内容为引用模式
  86. context_text = f"# 关于问题【{question}】查到知识库如下\n"
  87. context_text += "```\n\n\n".join(contents[:5])
  88. context_text += "\n```"
  89. else:
  90. context_text = "根据知识库查询结果,没有相关信息。"
  91. return ActionResponse(Action.REQLLM, context_text, None)
  92. except requests.exceptions.RequestException as e:
  93. # 网络请求异常
  94. error_type = type(e).__name__
  95. logger.bind(tag=TAG).error(
  96. f"RAGflow网络请求失败,异常类型:{error_type},详情:{str(e)}"
  97. )
  98. # 根据异常类型提供更详细的错误信息和解决方案
  99. if isinstance(e, requests.exceptions.ConnectTimeout):
  100. error_response = "RAG接口连接超时(5秒)"
  101. error_response += "\n可能原因:RAGflow服务未启动或网络连接问题"
  102. error_response += "\n解决方案:请检查RAGflow服务状态和网络连接"
  103. elif isinstance(e, requests.exceptions.ConnectionError):
  104. error_response = "无法连接到RAG接口"
  105. error_response += "\n可能原因:RAGflow服务地址错误或服务未运行"
  106. error_response += "\n解决方案:请检查RAGflow服务地址配置和服务状态"
  107. elif isinstance(e, requests.exceptions.Timeout):
  108. error_response = "RAG接口请求超时"
  109. error_response += "\n可能原因:RAGflow服务响应缓慢或网络延迟"
  110. error_response += "\n解决方案:请稍后重试或检查RAGflow服务性能"
  111. elif isinstance(e, requests.exceptions.HTTPError):
  112. # 处理HTTP错误状态码
  113. if hasattr(e.response, "status_code"):
  114. status_code = e.response.status_code
  115. error_response = f"RAG接口HTTP错误(状态码:{status_code})"
  116. # 尝试获取响应内容中的错误信息
  117. try:
  118. error_detail = e.response.json().get("error", {}).get("message", "")
  119. if error_detail:
  120. error_response += f"\n错误详情:{error_detail}"
  121. except:
  122. pass
  123. else:
  124. error_response = f"RAG接口HTTP异常:{str(e)}"
  125. else:
  126. error_response = f"RAG接口网络异常({error_type}):{str(e)}"
  127. return ActionResponse(Action.RESPONSE, None, error_response)
  128. except Exception as e:
  129. # 其他异常
  130. error_type = type(e).__name__
  131. logger.bind(tag=TAG).error(
  132. f"RAGflow处理异常,异常类型:{error_type},详情:{str(e)}"
  133. )
  134. # 提供详细的错误信息
  135. error_response = f"RAG接口处理异常({error_type}):{str(e)}"
  136. return ActionResponse(Action.RESPONSE, None, error_response)