12.20 豆包大模型bug解决

This commit is contained in:
zy123 2024-12-20 17:24:49 +08:00
parent 5dcbaa5eb5
commit de254d3c29
10 changed files with 196 additions and 2761 deletions

View File

@ -205,9 +205,56 @@ def count_tokens(text):
tokens = re.findall(token_pattern, text)
return len(tokens)# 返回 tokens 数量和匹配的 token 列表
import requests
import os
def get_total_tokens(text):
"""
调用 API 计算给定文本的总 Token 数量
参数
- text (str): 需要计算 Token 的文本
- model (str): 使用的模型名称默认值为 "ep-20241119121710-425g6"
返回
- int: 文本的 total_tokens 数量
"""
# API 请求 URL
url = "https://ark.cn-beijing.volces.com/api/v3/tokenization"
# 获取 API 密钥
doubao_api_key = os.getenv("DOUBAO_API_KEY")
if not doubao_api_key:
raise ValueError("DOUBAO_API_KEY 环境变量未设置")
# 请求头
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer " + doubao_api_key
}
model = "ep-20241119121710-425g6"
# 请求体
payload = {
"model": model,
"text": [text] # API 文档中要求 text 是一个列表
}
try:
response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
response_data = response.json()
total_tokens=response_data["data"][0]["total_tokens"]
return total_tokens
except Exception as e:
print(f"获取 Token 数量失败:{e}")
return 0
@sleep_and_retry
@limits(calls=10, period=1) # 每秒最多调用10次
def doubao_model(full_user_query):
def doubao_model(full_user_query, need_extra=False):
print("call doubao...")
# 相关参数
url = "https://ark.cn-beijing.volces.com/api/v3/chat/completions"
@ -220,8 +267,8 @@ def doubao_model(full_user_query):
}
# 判断用户查询字符串的长度
token_count = count_tokens(full_user_query)
if token_count > 35000:
token_count = get_total_tokens(full_user_query)
if token_count > 31500:
selected_model = models["pro_128k"] # 如果长度超过32k直接使用128k模型
else:
selected_model = models["pro_32k"] # 默认使用32k模型
@ -252,14 +299,29 @@ def doubao_model(full_user_query):
try:
response = requests.post(url, headers=headers, json=data) # 设置超时时间为10秒
response.raise_for_status() # 如果响应状态码不是200将引发HTTPError
# 返回模型的回复内容
return response.json()["choices"][0]["message"]["content"]
# 获取响应 JSON
response_json = response.json()
# 获取返回内容
content = response_json["choices"][0]["message"]["content"]
# 获取 completion_tokens
completion_tokens = response_json["usage"].get("completion_tokens", 0)
# 根据 need_extra 返回不同的结果
if need_extra:
return content, completion_tokens
else:
return content
except requests.exceptions.RequestException as e:
# 获取状态码并处理不同的重试逻辑
status_code = response.status_code if response is not None else None
print(f"请求失败,状态码: {status_code}")
print("请求失败,完整的响应内容如下:")
print(response.text) # 打印原始的响应内容,可能是 JSON 格式,也可能是其他格式
if response is not None:
print(response.text) # 打印原始的响应内容,可能是 JSON 格式,也可能是其他格式
# 如果是 429 错误
if status_code == 429:
@ -283,7 +345,11 @@ def doubao_model(full_user_query):
# 如果到这里,说明所有尝试都失败了
print(f"请求失败,已达到最大重试次数。")
return None
if need_extra:
return None, 0
else:
return None
def generate_full_user_query(file_path, prompt_template):
"""
@ -357,8 +423,9 @@ if __name__ == "__main__":
# processed_filepath = convert_pdf_to_markdown(pdf_path_2) # 转markdown格式
# processed_filepath = pdf2txt(pdf_path_2) #纯文本提取
# user_query=generate_full_user_query(processed_filepath,prompt_template)
user_query="一年有多少天?"
res=doubao_model(user_query)
# user_query="一年有多少天?"
# res=doubao_model(user_query)
res=get_total_tokens("hh我是天才")
print(res)
# print("--------------------")
# print(user_query)

View File

@ -101,7 +101,7 @@ def replace_latex_expressions(json_str):
return fixed_str
def extract_content_from_json(string, length_threshold=5000):
def extract_content_from_json(string):
"""
输入字符串尝试解析 JSON 数据
1. 如果成功解析返回字典
@ -115,8 +115,6 @@ def extract_content_from_json(string, length_threshold=5000):
match = re.search(r'\{[\s\S]*\}', string)
if not match:
print("未找到有效的 JSON 内容。")
if len(string) > length_threshold:
return string # 返回原始字符串
return {} # 返回空字典
original_json = match.group(0)
@ -157,15 +155,9 @@ def extract_content_from_json(string, length_threshold=5000):
# 如果所有方法都失败,检查字符串长度
print("所有修复方法均失败。")
if len(string) > length_threshold:
print("字符串长度超过阈值,返回原始字符串。")
return string # 返回原始字符串
else:
print("字符串长度不超过阈值,返回空字典。")
return {} # 返回空字典
return {} # 返回空字典
def clean_json_string(json_string):
# print(json_string)
"""清理JSON字符串移除多余的反引号并解析为字典"""
return extract_content_from_json(json_string)

View File

@ -82,11 +82,6 @@ def continue_answer(original_query, original_answer, model_type=1, file_id=None)
# 尝试解析为 JSON
try:
json_data = clean_json_string(full_answer)
if not isinstance(json_data, dict):
print(f"警告: clean_json_string 返回的类型为 {type(json_data)},预期为 dict。")
print(json_data)
return {}
print("JSON 拼接成功且有效!")
return json_data
except json.JSONDecodeError as e:
print("JSON 拼接失败,错误信息如下:")
@ -101,7 +96,7 @@ def process_continue_answers(questions_to_continue, model_type, file_id):
- questions_to_continue (list of tuples): 需要继续回答的问题每个元素是 (original_query, parsed_answer)
- model_type (int): 指定使用的模型类型
- file_id (str): 可选的文件 ID默认为 None
- model_type
返回:
- dict: 继续回答后的结果合并
"""

View File

@ -3,6 +3,8 @@ import re
import time
from collections import defaultdict
from flask_app.general.doubao import get_total_tokens
from flask_app.general.model_continue_query import process_continue_answers
from flask_app.general.通义千问long import upload_file, qianwen_long
@ -136,7 +138,7 @@ def parse_json_with_duplicates(raw_string):
return []
"""输入字符串,提取 { 和 } 之间的内容,并将其解析为字典"""
if not raw_string.strip():
if not raw_string or not raw_string.strip():
return {}
match = re.search(r'\{[\s\S]*\}', raw_string)
if match:
@ -147,8 +149,8 @@ def parse_json_with_duplicates(raw_string):
print(f"json_utils: extract_content_from_json: JSON decode error: {e}")
return {}
else:
print("json_utils: extract_content_from_json: No valid JSON content found.")
return {}
print("未找到有效的 JSON 内容。")
return {} # 返回空字典
# 防止外键只有一个'一包'的情况
def process_data_based_on_key(data):
@ -375,11 +377,23 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
)
# 执行第二个查询
user_query = user_query_1 if zb_type == 1 else user_query_2
evaluation_res = qianwen_long(file_id, user_query) # 有些重复的键名只有qianwen_long_text能保留
questions_to_continue = []
temp_final={}
evaluation_res = qianwen_long(file_id, user_query,2,1,True) # 有些重复的键名只有qianwen_long_text能保留
message = evaluation_res[0]
total_tokens = evaluation_res[1]
# print(evaluation_res)
# 清理和处理响应
cleaned_evaluation_res = parse_json_with_duplicates(evaluation_res) # 处理重复键名的情况
result_data = process_data_based_on_key(cleaned_evaluation_res) # 处理不知名外键的情况
cleaned_evaluation_res = parse_json_with_duplicates(message) # 处理重复键名的情况
# print(json.dumps(cleaned_evaluation_res,ensure_ascii=False,indent=4))
if not cleaned_evaluation_res and total_tokens > 5900:
questions_to_continue.append((user_query, evaluation_res))
else:
temp_final.update(cleaned_evaluation_res)
if questions_to_continue:
continued_results = process_continue_answers(questions_to_continue, 0, file_id)
temp_final.update(continued_results)
result_data = process_data_based_on_key(temp_final) # 处理不知名外键的情况
include = ['一包', '二包', '三包', '四包', '五包']
target_values = ['技术', '设计', '实施']
updated_jsons = {}
@ -423,8 +437,8 @@ def combine_evaluation_standards(evaluation_method_path,invalid_path,zb_type):
if __name__ == "__main__":
start_time=time.time()
# truncate_file=r"C:\Users\Administrator\Desktop\招标文件-采购类\tmp2\2024-新疆-塔城地区公安局食药环分局快检实验室项目_evaluation_method.pdf"
evaluation_method_path = r'C:\Users\Administrator\Desktop\fsdownload\aba81749-5986-4492-8b4b-16db9c69a09d\ztbfile_evaluation_method.pdf'
invalid_path=r'C:\Users\Administrator\Desktop\fsdownload\91399aa4-1ee8-447d-a05b-03cd8d15ced5\ztbfile_invalid.pdf'
evaluation_method_path = r'C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\be901ea0-adc9-47b8-9ada-5c3bc0dd9434\ztbfile_evaluation_method.pdf'
invalid_path=r'C:\Users\Administrator\Desktop\文件解析问题\文件解析问题\be901ea0-adc9-47b8-9ada-5c3bc0dd9434\ztbfile.docx'
# truncate_file = "C:\\Users\\Administrator\\Desktop\\货物标\\output2\\2-招标文件统计局智能终端二次招标_evaluation_method.pdf"
# truncate_file="C:\\Users\\Administrator\\Desktop\\货物标\\output2\\广水市妇幼招标文件最新W改_evaluation_method.pdf"
# truncate_file = "C:\\Users\\Administrator\\Desktop\\fsdownload\\2d481945-1f82-45a5-8e56-7fafea4a7793\\ztbfile_evaluation_method.pdf"

View File

@ -237,7 +237,7 @@ def pure_assistant():
)
return assistant
def llm_call(question, knowledge_name,file_id, result_queue, ans_index, llm_type):
def llm_call(question, knowledge_name,file_id, result_queue, ans_index, llm_type,need_extra=False):
"""
调用不同的 LLM 模型并将结果放入结果队列
"""
@ -251,14 +251,14 @@ def llm_call(question, knowledge_name,file_id, result_queue, ans_index, llm_type
elif llm_type==2:
print(f"qianwen_long! question:{question}")
# qianwen_res,usage = qianwen_long(file_id,question) #有bug
qianwen_res = qianwen_long(file_id, question)
qianwen_res = qianwen_long(file_id, question,2,1,need_extra)
if not qianwen_res:
result_queue.put((ans_index, None)) # 如果为空字符串,直接返回 None
else:
result_queue.put((ans_index, (question, qianwen_res)))
elif llm_type==3:
# print(f"doubao! question:{question}")
doubao_res=doubao_model(question)
doubao_res=doubao_model(question,need_extra)
if not doubao_res:
result_queue.put((ans_index, None)) # 如果为空字符串,直接返回 None
else:
@ -271,14 +271,14 @@ def llm_call(question, knowledge_name,file_id, result_queue, ans_index, llm_type
print(f"LLM 调用失败,查询索引 {ans_index},错误:{e}")
result_queue.put((ans_index, None)) # 使用 None 作为失败的占位符
def multi_threading(queries, knowledge_name="", file_id="", llm_type=1):
def multi_threading(queries, knowledge_name="", file_id="", llm_type=1,need_extra=False):
if not queries:
return []
print("多线程提问starting multi_threading...")
result_queue = queue.Queue()
with concurrent.futures.ThreadPoolExecutor(max_workers=60) as executor:
future_to_index = {
executor.submit(llm_call, query, knowledge_name, file_id, result_queue, index, llm_type): index
executor.submit(llm_call, query, knowledge_name, file_id, result_queue, index, llm_type,need_extra): index
for index, query in enumerate(queries)
}

View File

@ -4,6 +4,7 @@ import re
from functools import cmp_to_key
from flask_app.general.json_utils import clean_json_string
from flask_app.general.model_continue_query import process_continue_answers
from flask_app.general.通义千问long import upload_file, qianwen_long_stream
@ -459,9 +460,18 @@ def get_requirements_with_gpt(merged_baseinfo_path, selection):
return {"error": f"无效的 selection 值: {selection}. 请选择 1、2 或 3。"}
# 调用大模型并处理响应
try:
res = qianwen_long_stream(file_id, user_query,2)
cleaned_res = clean_json_string(res)
return cleaned_res
questions_to_continue = []
qianwen_res = qianwen_long_stream(file_id, user_query,2,1,True)
message = qianwen_res[0]
parsed = clean_json_string(message)
total_tokens = qianwen_res[1]
if not parsed and total_tokens >5900:
questions_to_continue.append((user_query, message))
if questions_to_continue:
continued_results = process_continue_answers(questions_to_continue, 0, file_id)
return continued_results
else:
return parsed
except Exception as e:
return {"error": "调用大模型失败"}

View File

@ -79,9 +79,8 @@ def extract_error_details(error_message):
return error_code, error_code_string
@shared_rate_limit
def qianwen_long(file_id, user_query, max_retries=2, backoff_factor=1.0):
def qianwen_long(file_id, user_query, max_retries=2, backoff_factor=1.0, need_extra=False):
logger = logging.getLogger('model_log') # 通过日志名字获取记录器
# logger.info(f"Received query: {user_query}")
"""
基于上传的文件 ID 和用户查询生成响应并在失败时自动重试
参数
@ -89,14 +88,12 @@ def qianwen_long(file_id, user_query, max_retries=2, backoff_factor=1.0):
- user_query: 用户查询
- max_retries: 最大重试次数默认 2
- backoff_factor: 指数退避的基础等待时间默认 1.0
- need_extra: 是否需要返回额外数据默认 False
"""
# print("call qianwen_long...")
client = OpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
for attempt in range(1, max_retries + 2): # +1 是为了包括初始调用
try:
# 调用 API
@ -115,15 +112,19 @@ def qianwen_long(file_id, user_query, max_retries=2, backoff_factor=1.0):
],
stream=False
)
token_usage = completion.usage.completion_tokens
# 如果调用成功,返回响应内容
return completion.choices[0].message.content
if need_extra:
return completion.choices[0].message.content, token_usage
else:
return completion.choices[0].message.content
except Exception as exc:
# 提取错误代码
error_code, error_code_string = extract_error_details(str(exc))
logger.error(f"{attempt} 次尝试失败,查询:'{user_query}',错误:{exc}", exc_info=True)
if error_code == 429: #超qps/qpm
if error_code == 429: # qps/qpm
if attempt <= max_retries:
sleep_time = backoff_factor * (2 ** (attempt - 1)) # 指数退避
logger.warning(f"错误代码为 429将在 {sleep_time} 秒后重试...")
@ -131,11 +132,22 @@ def qianwen_long(file_id, user_query, max_retries=2, backoff_factor=1.0):
else:
print(f"查询 '{user_query}' 的所有 {max_retries + 1} 次尝试均失败429 错误)。")
break
elif error_code == 400 and error_code_string in ['data_inspection_failed', 'ResponseTimeout','DataInspectionFailed','response_timeout','request_timeout',"RequestTimeOut"]:
elif error_code == 400 and error_code_string in [
'data_inspection_failed', 'ResponseTimeout', 'DataInspectionFailed',
'response_timeout', 'request_timeout', "RequestTimeOut"
]:
logger.warning(f"错误代码为 400 - {error_code_string},将调用 qianwen_long_stream 执行一次...")
try:
# 超时就调用 qianwen_long_stream
return qianwen_long_stream(file_id, user_query, max_retries=0) # 禁用内部重试
stream_result = qianwen_long_stream(file_id, user_query, max_retries=0) # 禁用内部重试
if need_extra:
if isinstance(stream_result, tuple) and len(stream_result) == 2:
return stream_result[0], stream_result[1] # 返回内容和默认的 token_usage=0
else:
logger.error(f"qianwen_long_stream 返回值不符合预期(需要元组)。返回值: {stream_result}")
return "", 0 # 处理异常返回
else:
return stream_result # need_extra=False直接返回内容
except Exception as stream_exc:
logger.error(f"调用 qianwen_long_stream 时出错:{stream_exc}", exc_info=True)
break # 跳出循环,不再重试
@ -144,12 +156,15 @@ def qianwen_long(file_id, user_query, max_retries=2, backoff_factor=1.0):
logger.error(f"遇到非 429 或非 'data_inspection_failed' 的 400 错误(错误代码:{error_code}),不进行重试。")
break
return ""
# 在所有重试失败的情况下返回
if need_extra:
return "", 0 # 返回默认值和 token_usage = 0
else:
return ""
@shared_rate_limit
def qianwen_long_stream(file_id, user_query, max_retries = 2, backoff_factor = 1.0):
def qianwen_long_stream(file_id, user_query, max_retries=2, backoff_factor=1.0, need_extra=False):
logger = logging.getLogger('model_log') # 通过日志名字获取记录器
# logger.info(f"Received query: {user_query}")
"""
使用之前上传的文件根据用户查询生成响应并实时显示流式输出
参数
@ -157,8 +172,10 @@ def qianwen_long_stream(file_id, user_query, max_retries = 2, backoff_factor = 1
- user_query: 用户查询
- max_retries: 最大重试次数默认 2
- backoff_factor: 指数退避的基础等待时间默认 1.0
- need_extra: 是否需要返回额外数据默认 False
返回:
- Optional[str]: 成功时返回响应内容失败时返回空字符串
- need_extra=False : 返回响应内容 (str)
- need_extra=True : 返回 (响应内容, token_usage)
"""
print("调用 qianwen-long stream...")
@ -166,14 +183,13 @@ def qianwen_long_stream(file_id, user_query, max_retries = 2, backoff_factor = 1
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
for attempt in range(1, max_retries + 2): # +1 是为了包括初始调用
try:
completion_tokens = 0 # 初始化 completion_tokens 为 0
# 生成基于文件ID的响应
completion = client.chat.completions.create(
model="qwen-long",
temperature=0.4,
max_tokens=5000,
messages=[
{
'role': 'system',
@ -184,16 +200,21 @@ def qianwen_long_stream(file_id, user_query, max_retries = 2, backoff_factor = 1
'content': user_query
}
],
stream=True # 启用流式响应
stream=True, # 启用流式响应
stream_options={"include_usage": True}
)
full_response = "" # 用于存储完整的响应内容
for chunk in completion:
print(chunk)
if hasattr(chunk, 'to_dict'):
chunk_data = chunk.to_dict()
else:
chunk_data = json.loads(chunk.model_dump_json())
usage = chunk_data.get('usage')
if usage is not None:
completion_tokens = usage.get('completion_tokens', 0)
choices = chunk_data.get('choices', [])
if not choices:
continue
@ -202,11 +223,15 @@ def qianwen_long_stream(file_id, user_query, max_retries = 2, backoff_factor = 1
content = delta.get('content', '')
if content:
full_response += content
# print(content, end='', flush=True) # 实时打印内容
# 实时打印内容(可以取消注释下面一行以实时输出)
# print(content, end='', flush=True)
if choice.get('finish_reason'):
break
return full_response # 返回完整的响应内容
if need_extra:
return full_response, completion_tokens
else:
return full_response
except Exception as exc:
# 提取错误代码
@ -221,8 +246,10 @@ def qianwen_long_stream(file_id, user_query, max_retries = 2, backoff_factor = 1
else:
logger.error(f"查询 '{user_query}' 的所有 {max_retries + 1} 次尝试均失败429 错误)。")
break
elif error_code == 400 and error_code_string in ['data_inspection_failed', 'ResponseTimeout',
'DataInspectionFailed', 'response_timeout','RequestTimeOut','request_timeout']:
elif error_code == 400 and error_code_string in [
'data_inspection_failed', 'ResponseTimeout', 'DataInspectionFailed',
'response_timeout', 'request_timeout', "RequestTimeOut"
]:
if attempt == 1: # 只重试一次
logger.warning(f"错误代码为 400 - {error_code_string},将立即重试...")
continue # 直接跳到下一次循环(即重试一次)
@ -235,7 +262,10 @@ def qianwen_long_stream(file_id, user_query, max_retries = 2, backoff_factor = 1
break
# 如果所有尝试都失败了,返回空字符串
return ""
if need_extra:
return "", 0
else:
return ""
@shared_rate_limit
def qianwen_long_text(file_id, user_query):
@ -276,8 +306,13 @@ if __name__ == "__main__":
file_path = r"C:\Users\Administrator\Desktop\货物标\截取test\2-招标文件_before.pdf"
file_id = upload_file(file_path)
print(file_id)
user_query1 = "该招标文件前附表中的项目名称是什么请以json格式返回给我"
# res1,res2=qianwen_long_stream(file_id,user_query1,2,1,True)
res1,res2= qianwen_long_stream(file_id, user_query1, 2, 1,True)
print(res1)
print(res2)
#
#
# user_query1 = "该招标文件前附表中的项目名称是什么请以json格式返回给我"
# user_query2 = ("请提供文件中关于资格审查的具体内容和标准。")
# start_time=time.time()
# # First query

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@ import json
import re
from PyPDF2 import PdfReader
import textwrap
from flask_app.general.doubao import read_txt_to_string, pdf2txt
from flask_app.general.doubao import read_txt_to_string, pdf2txt, get_total_tokens
from flask_app.general.json_utils import combine_json_results, clean_json_string
from flask_app.general.model_continue_query import continue_answer, process_continue_answers
from flask_app.general.通义千问long import upload_file, qianwen_long_stream
@ -303,7 +303,7 @@ def get_business_requirements(procurement_path, processed_filepath, model_type):
future = executor.submit(doubao_model, busi_user_query)
else:
# 使用 qianwen_long_stream 并传入 file_id
future = executor.submit(qianwen_long_stream, file_id, busi_user_query, 2, 1)
future = executor.submit(qianwen_long_stream, file_id, busi_user_query, 2, 1,True)
futures.append(future)
future_to_query[future] = busi_user_query # 映射 future 到 busi_user_query
@ -313,24 +313,25 @@ def get_business_requirements(procurement_path, processed_filepath, model_type):
future = executor.submit(doubao_model, tech_user_query)
else:
# 使用 qianwen_long_stream 并传入 file_id
future = executor.submit(qianwen_long_stream, file_id, tech_user_query, 2, 1)
future = executor.submit(qianwen_long_stream, file_id, tech_user_query, 2, 1,True)
futures.append(future)
future_to_query[future] = tech_user_query # 映射 future 到 tech_user_query
# 收集需要继续回答的问题
initial_results = {}
max_tokens = 3900 if model_type == 1 else 5900
# 获取结果
for future in concurrent.futures.as_completed(futures):
original_query = future_to_query[future] # 获取对应的 original_query
try:
result = future.result()
if result: # 确保结果不为空
parsed = clean_json_string(result)
if isinstance(parsed, str): # flag为截断标记如果不能解析且len(response)>5000执行继续问答
questions_to_continue.append((original_query, parsed))
elif isinstance(parsed, dict):
initial_results.update(parsed)
message = result[0]
parsed = clean_json_string(message)
total_tokens = result[1]
if not parsed and total_tokens > max_tokens:
questions_to_continue.append((original_query, message))
else:
print(f"Parsed result is not a dict or str: {parsed}")
initial_results.update(parsed)
except Exception as e:
print(f"An error occurred: {e}")
# 处理需要继续回答的问题

View File

@ -485,20 +485,23 @@ def get_technical_requirements(invalid_path,processed_filepath,model_type=1):
modified_grouped_key, "")
queries.append(new_query)
if model_type:
results = multi_threading(queries, "", "", 3) # 豆包
results = multi_threading(queries, "", "", 3,True) # 豆包
else:
results = multi_threading(queries, "", file_id, 2) # 豆包
results = multi_threading(queries, "", file_id, 2,True) # 豆包
temp_final={}
if not results:
print("errror!未获得大模型的回答!")
else:
# 第一步:收集需要调用 `continue_answer` 的问题和解析结果
questions_to_continue = [] # 存储需要调用 continue_answer 的 (question, parsed)
max_tokens=3900 if model_type==1 else 5900
for question, response in results:
parsed=clean_json_string(response)
if isinstance(parsed, str): #flag为截断标记如果不能解析且len(response)>5000执行继续问答
questions_to_continue.append((question, parsed))
elif isinstance(parsed, dict):
message=response[0]
parsed = clean_json_string(message)
total_tokens=response[1]
if not parsed and total_tokens>max_tokens:
questions_to_continue.append((question, message))
else:
temp_final.update(parsed)
# 第二步:多线程处理需要调用 `continue_answer` 的问题
if questions_to_continue: