完善整体效果
This commit is contained in:
+16
-10
@@ -39,7 +39,7 @@ class CodeExecutor:
|
||||
|
||||
def execute_code(self, code_str):
|
||||
"""封装代码执行逻辑"""
|
||||
logger.debug(f"开始执行代码: {code_str[:50]}...")
|
||||
logger.debug(f"开始执行代码: {code_str}")
|
||||
try:
|
||||
namespace = {
|
||||
"ProjectBuilder": ProjectBuilder,
|
||||
@@ -54,10 +54,10 @@ class CodeExecutor:
|
||||
exec(code_str, namespace)
|
||||
|
||||
# 确保neo4j_find_function存在
|
||||
if "neo4j_find_function" not in namespace:
|
||||
raise ValueError("代码中未定义neo4j_find_function函数")
|
||||
if "project_get_calculate_function" not in namespace:
|
||||
raise ValueError("代码中未定义project_get_calculate_function函数")
|
||||
|
||||
result_tuple = namespace["neo4j_find_function"]()
|
||||
result_tuple = namespace["project_get_calculate_function"]()
|
||||
|
||||
sys.stdout = old_stdout
|
||||
output = redirected_output.getvalue().strip()
|
||||
@@ -92,23 +92,29 @@ class CodeExecutor:
|
||||
|
||||
def generate_and_run_code(self, user_request: str, context: str = "", bowei_api_docs: str = "") -> str:
|
||||
code = self.generate_code(user_request, context, bowei_api_docs)
|
||||
pre_code = code.content
|
||||
logger.info("开始执行生成的代码")
|
||||
|
||||
pre_code = ""
|
||||
error_msg = ""
|
||||
prev_happend_error = False
|
||||
for attempt in range(self.max_retries):
|
||||
try:
|
||||
if prev_happend_error:
|
||||
logger.error(f"代码执行失败,尝试第 {attempt+1} 次修复。错误信息:{error_msg}")
|
||||
code = self.fix_code(pre_code, error_msg)
|
||||
|
||||
import re
|
||||
pre_code = re.sub(r'^```python\s*|\s*```$', '', code.content, flags=re.MULTILINE)
|
||||
result = self.execute_code(pre_code)
|
||||
if result["status"] == "success":
|
||||
logger.info(f"代码执行成功,返回结果长度:{len(result['data'])}")
|
||||
logger.info(f"代码执行成功,结果: {result['data']}")
|
||||
return result["data"]
|
||||
else:
|
||||
error_msg = result.get("error", "未知错误")
|
||||
logger.error(f"代码执行失败,尝试第 {attempt+1} 次修复。错误信息:{error_msg}")
|
||||
pre_code = self.fix_code(pre_code, error_msg)
|
||||
prev_happend_error = True
|
||||
except Exception as e:
|
||||
error_msg = str(e)
|
||||
logger.error(f"代码执行异常,尝试第 {attempt+1} 次修复。异常信息:{error_msg}")
|
||||
pre_code = self.fix_code(pre_code, error_msg)
|
||||
prev_happend_error = True
|
||||
|
||||
logger.error(f"代码执行失败,超过最大重试次数 {self.max_retries}")
|
||||
return f"代码执行失败,超过最大重试次数 {self.max_retries}。\n最后一次错误信息:\n{error_msg}"
|
||||
|
||||
@@ -51,6 +51,8 @@ class DialogManager:
|
||||
messages = prompt.to_messages()
|
||||
messages.append(HumanMessage(content=user_input))
|
||||
|
||||
logger.debug(f"重写提示词:{messages}")
|
||||
|
||||
result = ""
|
||||
async for chunk in self.llm_client.stream(messages):
|
||||
print(chunk.content, end="", flush=True)
|
||||
@@ -78,14 +80,14 @@ class DialogManager:
|
||||
messages = prompt.to_messages()
|
||||
result = ""
|
||||
async for chunk in self.llm_client.stream(messages):
|
||||
print(chunk.content, end="", flush=True)
|
||||
#print(chunk.content, end="", flush=True)
|
||||
result += chunk.content
|
||||
print()
|
||||
#print()
|
||||
return [(result.strip(), "")]
|
||||
|
||||
rewritten_list = []
|
||||
for idx, doc in enumerate(docs, start=1):
|
||||
print(f"\n第{idx}条相关文档改写结果(流式):")
|
||||
logger.debug(f"\n第{idx}条相关文档改写结果(流式):")
|
||||
rewritten = await self.rewrite_question_with_query_result(user_input, doc.page_content)
|
||||
rewritten_list.append((rewritten, doc.page_content))
|
||||
return rewritten_list
|
||||
|
||||
+56
-24
@@ -23,7 +23,7 @@ class PromptManager:
|
||||
"""
|
||||
你是一名电力造价业务专家,请基于以下工程文件业务结构,将用户自然语言问题改写成专业查询语句:
|
||||
|
||||
**工程文件业务结构**:
|
||||
**工程文件业务结构(示例,请勿当真实数据)**:
|
||||
{business_structure}
|
||||
|
||||
**改写规则**:
|
||||
@@ -55,10 +55,10 @@ class PromptManager:
|
||||
# 工作流程
|
||||
1. 从用户问题中提取关键信息(节点路径、节点类型、节点名称等)
|
||||
2. 根据"用户问题"和"上下文信息"选择最匹配的"工程数据访问库"中的方法
|
||||
3. 生成可直接执行的Python代码
|
||||
3. 只能生成一个可直接执行的Python函数代码
|
||||
|
||||
# 代码模板(必须严格遵循)
|
||||
def neo4j_find_function():
|
||||
# 输出格式(必须严格遵循)
|
||||
def project_get_calculate_function():
|
||||
project = ProjectBuilder.build()
|
||||
status, data, error, helper_info = project.[SELECTED_METHOD]([PARAMETERS])
|
||||
return status, data, error, helper_info
|
||||
@@ -66,14 +66,7 @@ def neo4j_find_function():
|
||||
# 执行规则
|
||||
- 参数必须从用户问题或上下文信息中提取
|
||||
- 必须确保生成的代码可以直接执行
|
||||
- 禁止修改代码模板结构
|
||||
- 禁止添加任何注释或解释
|
||||
|
||||
# 输出格式
|
||||
def neo4j_find_function():
|
||||
project = ProjectBuilder.build()
|
||||
status, data, error, helper_info = project.[SELECTED_METHOD]([PARAMETERS])
|
||||
return status, data, error, helper_info
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -82,8 +75,14 @@ def neo4j_find_function():
|
||||
|
||||
你是一个专业的Python工程师。我会给你一段错误python代码和错误信息,你需要帮我修复这段出错的代码
|
||||
|
||||
已执行代码:
|
||||
{code}
|
||||
|
||||
代码执行报错信息:
|
||||
{error}
|
||||
|
||||
你的任务是:
|
||||
1. 根据需要修改的代码{original_code}和代码的错误信息{error_info}来对代码和参数进行修改
|
||||
1. 根据"已执行代码"和"代码执行报错信息"来对“已执行代码”和函数调用参数进行修改,修复执行错误
|
||||
2. 如果错误信息中是代码的逻辑出现错误,那么就需要对代码本身整体结构进行修改
|
||||
3. 如果是代码中参数出现问题了,那么就需要结合错误信息中的帮助信息(helper_info)来对代码总的参数进行修改
|
||||
4. 修复后的代码应该完整,可以直接执行,并且能够返回查询结果
|
||||
@@ -102,29 +101,62 @@ def neo4j_find_function():
|
||||
)
|
||||
|
||||
rewrite_prompt_template = ChatPromptTemplate.from_template(
|
||||
"""你是一个专业的工程业务助理,结合以下工程业务结构信息和相关知识:
|
||||
{business_structure}
|
||||
"""
|
||||
你是一个AI助手,负责将模糊的用户问题改写成明确的查询。给定一个模糊的用户问题、一条从知识库获取的具体上下文知识以及相关业务背景信息,你需要执行以下任务:
|
||||
|
||||
相关知识内容:
|
||||
{context}
|
||||
1. **理解输入**:
|
||||
- 原始问题:用户输入的模糊性问题(字符串)
|
||||
- 上下文知识:从知识库查询获取的一条具体知识(字符串)
|
||||
- 业务背景:当前问题所属的业务场景信息(字符串,如行业、产品类型、业务规则等)
|
||||
|
||||
请根据用户的问题,结合上述信息,理解并改写成一个针对工程数据的访问请求(简洁明了的描述)。
|
||||
请只输出改写后的访问请求文本,不要多余解释。"""
|
||||
)
|
||||
2. **改写要求**:
|
||||
- 基于**上下文知识**和**业务背景**,将原始问题改写成针对该知识的明确性问题
|
||||
- 严格保留原始问题的核心语义(意图和关键信息不变)
|
||||
- 输出应是一个完整的自然语言问题,需同时满足:
|
||||
✅ 如果是一个查找语句则改写成一个获取语句
|
||||
✅ 直接关联上下文知识的具体内容
|
||||
✅ 符合业务背景的专业表述(如使用行业术语)
|
||||
- 禁止添加原始问题未提及的额外假设
|
||||
|
||||
3. **输出格式**:
|
||||
- 仅输出改写后的明确性问题(单个字符串)
|
||||
|
||||
4. **示例**:
|
||||
用户输入:查找名称中包含“工程”的项目划分项,并返回其人工费乘以1000的值。
|
||||
上下文知识: <Node element_id='4:f0ca7d86-42db-43e9-87d5-8b942b8972a9:1080' labels=frozenset({{'ProjectDivisionItem'}}) properties={{'序号': '1.1', '专业类型': '线路', 'GUID': '{{3CA66E10-EBB1-41E4-8B9B-23EFEA1B0E98}}', '取费表': '线路取费表', '颜色标记': '标记:16777215;', '资源库名称': '预算 第四册 架空输电线路工程(2018年版)', 'type': '项目划分', '最小资源库编码': '10', 'path': '安装/架空输电线路本体工程/基础工程/基础工程材料工地运输', '合价含税': '250340.309025', '取费表id': '3_1', 'name': '基础工程材料工地运输', 'notCheck': '1', '费率': '0'}}>
|
||||
改写输出:获取[安装/架空输电线路本体工程/基础工程/基础工程材料工地运输]项目划分项的人工费,并乘以1000的值
|
||||
|
||||
现在请处理以下输入:
|
||||
- 上下文知识:"{context}"
|
||||
- 业务背景(示例,请勿当真实数据):"{business_structure}"
|
||||
""")
|
||||
|
||||
cypher_conversion_prompt = ChatPromptTemplate.from_template(
|
||||
"""
|
||||
你是一个Neo4j专家。请将用户的自然语言问题转换成一个有效的Cypher查询语句,查询知识图谱中相关信息。
|
||||
只返回Cypher语句,不要任何解释,最多返回5条。
|
||||
你是一名电力造价业务专家,负责将用户自然语言问题中需要访问的对象识别出来,并生成针对该对象的NEO4J知识图谱的Cypher查询语句,获取该对象的全部信息。知识图谱基于以下工程文件业务结构构建。
|
||||
|
||||
业务结构信息:
|
||||
业务结构(示例,请勿当真实数据):
|
||||
{business_structure}
|
||||
|
||||
改写规则:
|
||||
识别目标对象:从业务结构中识别用户问题中需要获取的核心对象类型(如 ProjectDivisionItem、ProjectQuantity、Fee、FeeCollection 等)。对象类型必须精确映射到结构中的节点标签(例如,使用 ProjectDivisionItem 而非“项目划分项”)。
|
||||
提取查询条件:从用户输入中解析关键条件(如名称、量、类型、值、层级等),条件应基于对象属性(如 name、quantity、type)。
|
||||
如果用户指定层级(如“叶节点”),需在条件中体现(例如,添加 WHERE item.isLeaf = true)。
|
||||
忽略任何计算、转换或后处理要求(如“乘以1000”),只关注获取原始数据对象或属性。
|
||||
构建Cypher查询:生成一个Cypher查询语句,格式为:
|
||||
|
||||
MATCH 子句:匹配目标对象节点,并应用条件,不带变量。
|
||||
WHERE 子句:包含提取的条件(使用变量或具体值)。
|
||||
RETURN 子句:必须返回对象(如 RETURN item),不能包含对象属性、函数(如乘法、SUM)。
|
||||
LIMIT 子句: 最多返回5条。
|
||||
使用业务术语在节点标签和属性中(例如,ProjectDivisionItem 而不是“项目”)。
|
||||
查询应简洁,只获取数据,不执行计算。
|
||||
输出格式:直接输出最终Cypher查询语句,不添加解释或额外文本。
|
||||
|
||||
用户问题:
|
||||
{user_input}
|
||||
Cypher查询语句:
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
return CodeExecutorPrompts(
|
||||
understand_prompt=understand_prompt,
|
||||
|
||||
Reference in New Issue
Block a user