Add File
This commit is contained in:
235
main/ds_chat.py
Normal file
235
main/ds_chat.py
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
"""
|
||||||
|
深度思考的对话实现,需要多步骤的思考和校验,才能最后回答用户的问题,至多校验三次
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from init import llm
|
||||||
|
import json
|
||||||
|
import json5
|
||||||
|
from full_index_search import full_search,adjust_ctx_size,jieba_fenci,full_search_logic,one_doc_search
|
||||||
|
from k_database import QA
|
||||||
|
|
||||||
|
#深度思考
|
||||||
|
def DS_chat(query,history):
|
||||||
|
|
||||||
|
try:
|
||||||
|
i=0
|
||||||
|
yield gen_event_data({"step":i,"rsp":f"{query}--检查是否需要补全或重写?"})
|
||||||
|
result =DS_chat0(query,history)
|
||||||
|
new_query = deal_llm_think_json_data(result)
|
||||||
|
|
||||||
|
print(new_query)
|
||||||
|
yield gen_event_data({"step":i,"rsp":new_query})
|
||||||
|
|
||||||
|
seg_list = jieba_fenci(new_query)
|
||||||
|
yield gen_event_data({"rsp":f"搜索关键词 {seg_list}"})
|
||||||
|
|
||||||
|
#至多三次深度回答
|
||||||
|
for i in range(1,4):
|
||||||
|
|
||||||
|
for result in search_ctx_chat(new_query,seg_list):
|
||||||
|
try:
|
||||||
|
data = deal_llm_think_json_data(result)
|
||||||
|
answer = json.loads(data)
|
||||||
|
except Exception as e:
|
||||||
|
print(e,data)
|
||||||
|
yield gen_event_data({"step":i,"rsp":f"{data}"})
|
||||||
|
break
|
||||||
|
if answer["code"]==100: #中间ixnxi
|
||||||
|
yield gen_event_data({"step":i,"rsp":answer["content"]})
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
#其它结果
|
||||||
|
if answer["code"]==200 or answer["code"]==202:
|
||||||
|
yield gen_event_data({"step":i,"rsp":answer["content"]})
|
||||||
|
#QA.create(question=new_query,answer=answer["content"],ref="深度思考")
|
||||||
|
return answer["content"]
|
||||||
|
elif answer["code"]==201:#单个文件回答
|
||||||
|
yield gen_event_data({"step":i,"rsp":f'找到相关文件: {answer["name"]}'})
|
||||||
|
answer["question"]=new_query
|
||||||
|
yield from one_doc_chat(answer)
|
||||||
|
#QA.create(question=new_query,answer=answer["name"],ref="深度思考")
|
||||||
|
return answer["name"]
|
||||||
|
elif answer["code"]==404:
|
||||||
|
yield gen_event_data({"step":i,"rsp":f'重新搜索关键字:{answer["keywords"]}'})
|
||||||
|
seg_list = answer["keywords"]
|
||||||
|
else:#出错
|
||||||
|
break
|
||||||
|
#end for
|
||||||
|
except Exception as e :
|
||||||
|
yield gen_event_data({"step":-1,"rsp":f"对话出现错误:{e}"})
|
||||||
|
|
||||||
|
if i==3:
|
||||||
|
yield gen_event_data({"step":i,"rsp":"对不起,没有找到你想要的答案!"})
|
||||||
|
#QA.create(question=query,answer="对不起,没有找到你想要的答案!",ref="深度思考")
|
||||||
|
return "对不起,没有找到你想要的答案!"
|
||||||
|
|
||||||
|
|
||||||
|
def gen_event_data(json_data):
|
||||||
|
json_str = "data: " + json.dumps(json_data) + "\n\n"
|
||||||
|
return json_str.encode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def deal_llm_think_json_data(data):
|
||||||
|
#print("==============================")
|
||||||
|
#print(data)
|
||||||
|
#去掉思考过程
|
||||||
|
if data.find("<think>")>=0 and data.find("</think>")>0:
|
||||||
|
end = data.find("</think>")
|
||||||
|
data = data[end+8:]
|
||||||
|
if data.find("```json") >=0:
|
||||||
|
begin = data.find("{")
|
||||||
|
end = data.rfind("}")
|
||||||
|
data = data[begin:end+1]
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#多轮对话,生成新问题
|
||||||
|
def DS_chat0(query,history):
|
||||||
|
# 获取当前日期和星期
|
||||||
|
today = datetime.datetime.now()
|
||||||
|
# 获取今天是星期几,使用weekday()方法(周一=0, 周日=6)
|
||||||
|
weekday_number = today.weekday()
|
||||||
|
|
||||||
|
system_prompt=f"""
|
||||||
|
今天是{today.strftime('%Y-%m-%d')} 星期{weekday_number+1}。
|
||||||
|
你是一个支持多轮问答的智能助手,你需要根据历史对话信息和本次问题来判断需不需改写问题,重新生成一个更加准确的问题.
|
||||||
|
|
||||||
|
并按照如下步骤来分析执行改写情况
|
||||||
|
1.特别是本次问题用他、她或它来指代历史对话中对象的情景,如果历史对话中有明确的对象,就需要用历史对话中明确的对象来本次问题的代词。
|
||||||
|
|
||||||
|
如:历史对话中有["中国的国土面积是多少",...],
|
||||||
|
本次问题是"他的人口有多少",则需要将本次问题中的“他”换成历史对话中的“中国”,生成新的问题"中国的人口有多少"
|
||||||
|
|
||||||
|
2.如果多多条历史记录的,就用最近对话中对象来指代,如:
|
||||||
|
|
||||||
|
示例1
|
||||||
|
历史对话:["杭州是个美丽的城市","他的GDP是多少"]
|
||||||
|
本次问题: 他在2024年的常驻人口是多少
|
||||||
|
生成问题: 杭州在2024年的常驻人口是多少
|
||||||
|
|
||||||
|
示例2
|
||||||
|
历史对话:["杭州是个美丽的城市","他的GDP是多少","他在2024年的常驻人口是多少","厦门也是一个美丽的城市"]
|
||||||
|
本次问题:他的旅游忘记是什么时候
|
||||||
|
生成问题:厦门的旅游旺季是什么时候
|
||||||
|
|
||||||
|
3.其它需要改写的情况,改写后语句的关键字可以更有利于后续检索的
|
||||||
|
|
||||||
|
|
||||||
|
切记!!!不输出其它任何信息!!!
|
||||||
|
|
||||||
|
历史对话:(时间越早排序越靠前)
|
||||||
|
```
|
||||||
|
{history}
|
||||||
|
```
|
||||||
|
|
||||||
|
本次问题:
|
||||||
|
{query}
|
||||||
|
|
||||||
|
生成问题:
|
||||||
|
"""
|
||||||
|
messages = [{'role': 'user', 'content': system_prompt}]
|
||||||
|
response = llm.chat(
|
||||||
|
messages=messages,
|
||||||
|
stream=False,
|
||||||
|
) # get a new response from the model where it can see the function response
|
||||||
|
|
||||||
|
return response[0]["content"]
|
||||||
|
|
||||||
|
#检索上下文回答
|
||||||
|
def search_ctx_chat(query,seg_list):
|
||||||
|
|
||||||
|
#全文检索相关知识
|
||||||
|
context,meta = full_search_logic(query,30,seg_list)
|
||||||
|
context = adjust_ctx_size(context)
|
||||||
|
count = len(context)
|
||||||
|
ctx = []
|
||||||
|
for i in range(count):
|
||||||
|
ctx.append({"name":meta[i][0],"path":meta[i][1],"base":meta[i][2]})
|
||||||
|
|
||||||
|
yield json.dumps({"code":100,"content":f"找到{count}个相关信息{ctx}"})
|
||||||
|
|
||||||
|
system_prompt=f"""
|
||||||
|
你是一个知识问答的助手,你可以根据提供的上下文信息来回答用户的问题,并能按如下步骤来深度思考准确回答问题:
|
||||||
|
1.首先判断上下文和问题的相关性,如果上下文足以回答问题的,按如下json格式进行输出
|
||||||
|
{{"code":200,"content":"回答的内容"}}
|
||||||
|
2.如果提供的上下文不足以准确回答信息,但某个上下文和上下文提供的文件对回答问题的相关性已经具备,需要进一步检索该文件内容来回答信息的。
|
||||||
|
可以按如下json格式回答信息
|
||||||
|
{{"code":201,"name":"对应的文件名","path":"文件路径","base":"知识库"}}
|
||||||
|
3.如果提供的上下文和文件完全不足以回答问题时,你可以调整优化问题关键字列表,让助手重新检索上下文,如:
|
||||||
|
A.删除掉一些和问题相关度不高的关键字,让检索的范围变大,找到更合适的上下文
|
||||||
|
B.根据问题的情况更换、调整或生成一些新关键字,重新检索,以便更好的回答问题
|
||||||
|
C.使用更合适的同义词替换现有关键字
|
||||||
|
最后输出json格式格式如下:
|
||||||
|
{{"code":404,"keywords":["关键词1","关键词2","关键词n"]}}
|
||||||
|
4.如果这个问题是一个常识性的问题,不需要上下文,只使用大模型内部知识就可以回答的,可以按如下json方式进行输出
|
||||||
|
{{"code":202,"content":"回答的内容"}}
|
||||||
|
|
||||||
|
5.一定按json格式进行输出,回答的内容中有特殊符号如"的需要进行转化为\",不要影响json的输出的格式。
|
||||||
|
|
||||||
|
上下文:
|
||||||
|
```
|
||||||
|
{context}
|
||||||
|
```
|
||||||
|
|
||||||
|
上下文对应的文件名称和路径信息:
|
||||||
|
```
|
||||||
|
{ctx}
|
||||||
|
```
|
||||||
|
|
||||||
|
问题:
|
||||||
|
{query}
|
||||||
|
|
||||||
|
问题关键字:
|
||||||
|
{seg_list}
|
||||||
|
|
||||||
|
"""
|
||||||
|
messages = [{'role': 'user', 'content': system_prompt}]
|
||||||
|
|
||||||
|
|
||||||
|
response = llm.chat(
|
||||||
|
messages=messages,
|
||||||
|
stream=False,
|
||||||
|
) # get a new response from the model where it can see the function response
|
||||||
|
|
||||||
|
yield response[0]["content"]
|
||||||
|
|
||||||
|
|
||||||
|
def one_doc_chat(chat):
|
||||||
|
query = chat["question"]
|
||||||
|
context= one_doc_search(chat["question"],chat["base"],chat["name"],chat["path"])
|
||||||
|
|
||||||
|
context = adjust_ctx_size(context)
|
||||||
|
|
||||||
|
system_prompt=f"""
|
||||||
|
你是一个知识问答的助手。
|
||||||
|
你可以根据提供的上下文信息来回答用户的问题,上下文中排在前面的可信度越高,越应该优先采纳。
|
||||||
|
如果提供的上下文不足以回答问题时,你可以回答'对不起,暂时没有找到相关的信息,无法回答你的问题'
|
||||||
|
|
||||||
|
上下文:
|
||||||
|
```
|
||||||
|
{context}
|
||||||
|
```
|
||||||
|
|
||||||
|
问题:
|
||||||
|
{query}
|
||||||
|
|
||||||
|
"""
|
||||||
|
messages = [{'role': 'user', 'content': system_prompt}]
|
||||||
|
responses = llm.chat(
|
||||||
|
messages=messages,
|
||||||
|
stream=True,
|
||||||
|
) # get a new response from the model where it can see the function response
|
||||||
|
json_str=""
|
||||||
|
try:
|
||||||
|
for response in responses:
|
||||||
|
json_str = "data: " + json.dumps({'rsp':response[0]["content"]}) + "\n\n"
|
||||||
|
yield json_str.encode("utf-8")
|
||||||
|
|
||||||
|
#QA.create(question=query,answer=response[0]["content"],ref="深度思考")
|
||||||
|
return response[0]["content"]
|
||||||
|
except Exception as e:
|
||||||
|
json_str = "data: " + json.dumps({"rsp": f"大模型运行出现错误:{e}, 请检查配置是否正确或者网络通信是否通畅!\n如果是本地大模型还请检查大模型是否正常启动!"}) + "\n\n"
|
||||||
|
yield json_str.encode("utf-8")
|
||||||
Reference in New Issue
Block a user