فهرست منبع

增加查询销售订单进度工具

longjoedyy 2 روز پیش
والد
کامیت
19c9f132f7
4فایلهای تغییر یافته به همراه117 افزوده شده و 5 حذف شده
  1. 27 1
      config/tool_config.json
  2. 7 3
      core/agent.py
  3. 9 1
      tools/base_tool.py
  4. 74 0
      tools/salebill_tools.py

+ 27 - 1
config/tool_config.json

@@ -48,7 +48,7 @@
             "字段含义": "listname:价格表,currency:币种, mtrlcode:物料编码, mtrlname:物料名称, unit:单位, price:含税价, unit_buy:辅助单位, rate_buy:转换率,price_unit1:辅助单位含税价,saleqty:销售数量下限,saleqty1:销售数量上限"
         },
         "输出格式要求": [
-            "以表格输出",
+            "以表格输出,标题按字段含义显示",
             "币种、物料编码、物料名称:若所有行该列值完全一致,则整列隐藏",
             "辅助单位,含税价辅助单位,转换率,数量区间:若所有行该列值为初始值(如'',0),则整列隐藏",
             "其他列原样显示"
@@ -111,5 +111,31 @@
             "custname,cus_balcamt,currency,scname是汇总信息,不需要在表格中显示"
         ],
         "使用示例": "用户输入:'查询客户A的应收帐情况 或 客户A还有多少款未付 或 查询待收款情况' -> 系统调用此工具获取应收帐数据"
+    },
+    "get_saletask_detail": {
+        "基础描述": "获取指定销售订单的进度",
+        "入参说明": {
+            "backend_url": "后端API地址",
+            "token": "认证令牌",
+            "cusname": "客户名称 或 客户编码, 支持模糊查询",
+            "taskcode": "销售订单编码, 支持模糊查询",
+            "firstdate": "开始日期,格式YYYY-MM-DD,如果不指定,传None",
+            "lastdate": "结束日期,格式YYYY-MM-DD 23:59:59,如果不指定,传None"
+        },
+        "返回值说明": {
+            "格式": "返回多行字符串,每行代表一个销售订单,字段以逗号分隔。每行包含:taskcode(销售订单号)、cusname(客户名称)、taskdate(销售订单日期)、flag_str(单据状态)、mx(JSON字符串,包含物料明细列表)",
+            "mx字段结构": "mx字段是一个JSON字符串列表,每个元素包含:mtrlcode(物料代码)、mtrlname(物料名称)、mtrlmode(规格型号)、unit(单位)、saleqty(销售数量)、consignedqty(发货数量)"
+        },
+        "输出格式要求": [
+            "1. 将返回的多行数据按行拆分为独立的销售订单",
+            "2. 为每个销售订单按以下格式输出:",
+            "   a) 表头信息(以文字描述输出):",
+            "      销售订单:[taskcode]   |    状态:[flag_str]",
+            "      客户:[cusname]   |   下单日期:[taskdate]",
+            "   b) 明细表格(以Markdown表格输出)",
+            "3. 不同销售订单之间要有多个空行分隔",
+            "4. 如果工具返回警告或错误,要直接输出错误信息,不进行格式化"
+        ],
+        "使用示例": "用户输入:'查询客户A的订单进度' -> (只说订单,默认是销售订单)系统调用此工具获取客户A的销售订单进度,如果没有明确日期范围,传None -> 返回结果后,按上述格式要求格式化输出"
     }
 }

+ 7 - 3
core/agent.py

@@ -30,7 +30,7 @@ def create_system_prompt(
     if settings.KNOWLEDGE_BASE_ENABLED:
         # 知识库启用时的提示词
         system_prompt = f"""龙嘉软件助手- 用户:{username} 认证:{auth_status} 服务:{backend_available} 知识库:{knowledge_status}
-职责:ERP数据查询和问题解答,按用户语言回答。所有回答严格按工具提供的数据,不能编造答案。
+职责:ERP数据查询和问题解答,按用户语言回答。
 工作流:
 1. 分析问题意图,提取模块关键词
 2. 如果是数据查询类问题,直接调用相关工具查询数据
@@ -42,6 +42,9 @@ def create_system_prompt(
 - 保护隐私,专业准确,精炼简要
 {"- 后端地址: " + backend_url if backend_url else ""}
 {"- API用户的认证令牌: " + token if token else ""}
+时间:{datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
+数据查询结果尽量以 Markdown 表格格式输出,格式如下:
+| 列名1 | 列名2 | 列名3 |
 | :--- | :--- | :--- |
 | 数据1 | 数据2 | 数据3 |
 | 数据4 | 数据5 | 数据6 |
@@ -49,7 +52,7 @@ def create_system_prompt(
     else:
         # 知识库禁用时的提示词 - 严格限制回答范围
         system_prompt = f"""龙嘉软件助手- 用户:{username} 认证:{auth_status} 服务:{backend_available} 知识库:{knowledge_status}
-职责:仅处理ERP数据查询类问题。
+职责:仅处理ERP数据查询类问题,按用户语言回答
 严格限制:
 - 知识库功能已禁用,无法回答任何非数据查询类问题
 - 禁止回答:疑问解答、操作流程、功能介绍、知识咨询等非数据查询问题
@@ -59,6 +62,7 @@ def create_system_prompt(
 2. 如果是数据查询类问题,直接调用相关工具查询数据
 3. 如果是非数据查询类问题(包括疑问、流程、操作等),必须明确回复:"知识库正在完善,无法回答该问题"
 回答规则:
+- 如用户提出非ERP范围的问题(例如:"你好"等闲聊),明确告知用户自己的职责:仅处理ERP数据查询类问题
 - 非数据查询问题必须回复:"知识库正在完善,无法回答该问题"
 - 禁止尝试回答或提供任何建议
 - 禁止解释原因或提供替代方案
@@ -66,7 +70,7 @@ def create_system_prompt(
 - {"需要个人数据时验证认证状态" if backend_url else "仅提供数据查询支持"}
 {"- 后端地址: " + backend_url if backend_url else ""}
 {"- API用户的认证令牌: " + token if token else ""}
-时间:{datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
+当前时间:{datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
 数据查询结果尽量以 Markdown 表格格式输出,格式如下:
 | 列名1 | 列名2 | 列名3 |
 | :--- | :--- | :--- |

+ 9 - 1
tools/base_tool.py

@@ -222,10 +222,14 @@ def process_api_response(data: Dict[str, Any]) -> str:
         if "err_msg" in inner_data:
             return f"API返回错误: {inner_data['err_msg']}"
 
+        warning_msg = None
+        if "warning_msg" in inner_data:
+            warning_msg = inner_data["warning_msg"]
+
         if "data" in inner_data:
             data_list = inner_data["data"]
             if not data_list:
-                return "NO_DATA"
+                return "没有数据"
 
             if isinstance(data_list[0], dict):
                 headers = list(data_list[0].keys())
@@ -234,6 +238,10 @@ def process_api_response(data: Dict[str, Any]) -> str:
                 for row in data_list:
                     result.append(",".join([str(row.get(h, "")) for h in headers]))
 
+                if warning_msg:
+                    result.append(f"# 警告: {warning_msg}")
+
+                print(result)
                 return "\n".join(result)
 
         return json.dumps(data, ensure_ascii=False)

+ 74 - 0
tools/salebill_tools.py

@@ -0,0 +1,74 @@
+from typing import Optional
+
+from langchain.tools import tool
+from .base_tool import call_csharp_api, get_tool_prompt
+
+
+def get_saletask_detail_config():
+    """get_saletask_detail 工具的默认配置"""
+    return {
+        "get_saletask_detail": {
+            "基础描述": "获取指定销售订单的进度",
+            "入参说明": {
+                "backend_url": "后端API地址",
+                "token": "认证令牌",
+                "cusname": "客户名称 或 客户编码, 支持模糊查询",
+                "taskcode": "销售订单编码, 支持模糊查询",
+                "firstdate": "开始日期,格式YYYY-MM-DD,如果不指定,传None",
+                "lastdate": "结束日期,格式YYYY-MM-DD 23:59:59,如果不指定,传None",
+            },
+            "返回值说明": {
+                "格式": "返回多行字符串,每行代表一个销售订单,字段以逗号分隔。每行包含:taskcode(销售订单号)、cusname(客户名称)、taskdate(销售订单日期)、flag_str(单据状态)、mx(JSON字符串,包含物料明细列表)",
+                "mx字段结构": "mx字段是一个JSON字符串列表,每个元素包含:mtrlcode(物料代码)、mtrlname(物料名称)、mtrlmode(规格型号)、unit(单位)、saleqty(销售数量)、consignedqty(发货数量)",
+            },
+            "输出格式要求": [
+                "1. 将返回的多行数据按行拆分为独立的销售订单",
+                "2. 为每个销售订单按以下格式输出:",
+                "   a) 表头信息(以文字描述输出):",
+                "      销售订单:[taskcode]   |    状态:[flag_str]",
+                "      客户:[cusname]   |   下单日期:[taskdate]",
+                "   b) 明细表格(以Markdown表格输出)",
+                "3. 不同销售订单之间要有多个空行分隔",
+                "4. 如果工具返回警告或错误,要直接输出错误信息,不进行格式化",
+            ],
+            "使用示例": "用户输入:'查询客户A的订单进度' -> (只说订单,默认是销售订单)系统调用此工具获取客户A的销售订单进度,如果没有明确日期范围,传None -> 返回结果后,按上述格式要求格式化输出",
+        }
+    }
+
+
+tool_description = get_tool_prompt("get_saletask_detail", get_saletask_detail_config())
+
+
+def get_saletask_detail_func(
+    backend_url: str,
+    token: str,
+    cusname: str,
+    taskcode: str,
+    firstdate: Optional[str] = None,
+    lastdate: Optional[str] = None,
+) -> str:
+    """实际的函数实现"""
+    print(f"正在获取客户{cusname}的销售订单{taskcode}的进度")
+
+    # 构建参数字典,只包含非 None 的参数
+    params = {
+        "arg_cusname": cusname,
+        "arg_taskcode": taskcode,
+    }
+
+    if firstdate is not None:
+        params["arg_firstdate"] = firstdate
+    if lastdate is not None:
+        params["arg_lastdate"] = lastdate
+
+    return call_csharp_api(
+        backend_url,
+        token,
+        "sale_bill_data_ai",
+        "get_saletask_detail",
+        params,
+    )
+
+
+get_saletask_detail_func.__doc__ = tool_description
+get_saletask_detail = tool(get_saletask_detail_func)