ErpAiAgent.java 11.9 KB
package com.xly.agent;


import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

/**
 * 优化后:新增场景专属交互规则,大模型仅处理当前场景业务指令
 */
public interface ErpAiAgent {
    @SystemMessage("""
            1. 方法匹配:先精准拆解用户查询的核心业务意图,再自动匹配唯一符合用户问题的工具方法(MethodNo),禁止自创,规则如下;
                1.1 匹配方法时,无需考虑工具描述(@TOOL)中 1.必填参数,2.选填参数,示例,parameters内容 四个部分的内容;
                1.2 匹配方法时,只关注工具描述(@TOOL)中 “当用户” 和 “时,必须调用本工具”两个短语之间的内容;
                1.3 调用工具前,不需要询问用户提供缺失的参数
            2. 参数提取:提取该工具的全部参数,与描述完全一致,严格按标注类型赋值,规则如下:
                2.1 数字无引号,为空时禁止赋值0;
                2.2 如果有空格需要去掉空格后再提取。
            """)
    @UserMessage("用户输入:{{userInput}}")
    String chat(@MemoryId String userId, @V("userInput") String userInput);

    /**
     * 动态表结构:自然语言解释SQL执行结果
     * 入参:用户问题、执行的SQL、表结构、JSON格式结果
     */
    @SystemMessage("""
            你是专业的业务数据分析师,严格遵循以下**通用规则**解释查询结果,适用于所有业务场景:
                1. 解释风格:贴合业务场景,无任何SQL专业术语,用口语化、简洁的商业语言说明,避免技术词汇;
                2. 数据准确:严格按照JSON执行结果解释,不夸大、不遗漏、不编造数据,数值与结果完全一致;
                3. 输出格式:仅返回解释内容,不要列出ID,无多余标题、换行、符号,结果为空时直接返回“未查询到相关数据”
                    3.1. 所有数字格式必须以纯文本形式输出,严禁使用千分位分隔符(即不要出现逗号 ",")示例:正确写法是 1000000,错误写法是 1,000,000,即使数字很大,也请保持连续的数字串,不要打断。
                    3.2  所有日期请转换为 YYYY-MM-DD 格式(例如:2026-03-15),严禁包含时间部分(如小时、分钟、秒)(例如:2026-03-15 00:00:00),也不要包含时区信息。”
                    3.3. 金额,单价,数量 严禁使用千分位分隔符(即不要出现逗号 ",")示例:正确写法是 2400056,错误写法是 2,400,056 即使数字很大,也请保持连续的数字串,不要打断。
                4. 长度控制:单条解释不超过150字,条理清晰,重点突出核心数据/趋势;
                5. 禁止重复:不重复用户问题、不重复执行的SQL语句,仅针对结果做业务解读。
                """)
    @UserMessage("""
            【业务场景表结构信息】
            表结构详情:{{tableStruct}}
            【查询相关信息】
            用户原始查询:{{userInput}}
            执行的MySQL SQL:{{sql}}
            SQL执行结果(JSON格式):{{result}}
            请根据上述信息+通用规则,对查询结果做业务解释:
            """)
    String explainSqlResult(@MemoryId String userId,
                            @V("userInput") String userInput,
                            @V("sql") String sql,
                            @V("tableStruct") String tableStruct,
                            @V("result") String result);

    /**
     * 动态表结构:自然语言解释SQL执行结果
     * 入参:用户问题、执行的SQL、表结构、JSON格式结果
     */
    @SystemMessage("""
            你是专业的业务数据分析师,请分析以下查询结果:
            【用户问题】
            {{userInput}}
            【数据字段说明】
            {{sMilvusFiledDescription}}
            【查询结果数据(JSON格式)】
            {{result}}
            【分析要求】
            1. 解释风格:贴合业务场景,无任何SQL专业术语,用口语化、简洁的商业语言说明,避免技术词汇;
            2. 数据准确:严格按照JSON执行结果解释,不夸大、不遗漏、不编造数据,数值与结果完全一致;
            3. 输出格式:
               3.1. 如果用户要求"表格形式展示",先输出简短文字说明,然后输出Markdown格式的表格
               3.2. 如果用户未要求表格,仅返回解释内容,不要列出ID,无多余标题、换行、符号
               3.3. 结果为空时直接返回"未查询到相关数据"
               3.4. 所有数字格式必须以纯文本形式输出,严禁使用千分位分隔符(即不要出现逗号 ",")
               3.5. 所有日期请转换为 YYYY-MM-DD 格式,严禁包含时间部分
            4. 长度控制:单条解释不超过150字,条理清晰,重点突出核心数据/趋势;
            5. 禁止重复:不重复用户问题、不重复执行的SQL语句,仅针对结果做业务解读。
            """)
    @UserMessage("""
            【用户查询】
            {{userInput}}
            【字段说明】
            {{sMilvusFiledDescription}}
            【查询结果】
            用户原始查询:{{userInput}}
            执行查询向量库后结果(JSON格式):{{result}}
            请根据上述信息+通用规则,对查询结果做业务解释:
            """)
    String explainMilvusResult(@MemoryId String userId,
                               @V("userInput") String userInput,
                               @V("sMilvusFiledDescription") String sMilvusFiledDescription,
                               @V("result") String result);

    @SystemMessage("""
                    你是一个智能查询路由专家。请根据【用户需求】,只返回 true 或 false。
                    
                    【最高优先级规则 - 必须首先判断】
                    如果用户需求包含以下任一关键词,**直接返回 false**,不再进行其他判断:
                    - 明细、详情、详细信息、详细内容、具体内容
                    - 查询...明细、...详情、...记录、...列表、...清单
                    
                    重要:只要出现以上关键词,说明用户需要的是明细数据查询,而非统计分析。
                    
                    【统计类关键词 - 仅在满足最高优先级规则后才判断】
                    只有当用户需求不包含上述明细类关键词时,才检查是否包含以下关键词:
                    统计、求和、汇总、排名、TopN、平均、数量、总额、最高、最低、占比、分组
                    
                    - 如果包含,返回 true
                    - 否则返回 false
                    
                    【判断示例】
                    - \"查询中科精工集团的彩盒类产品的报价单明细\" → false(包含\"明细\")
                    - \"统计各产品销售额\" → true(包含\"统计\",且无明细关键词)
                    - \"查询客户张三信息\" → false(无统计关键词,无明细关键词)
                    - \"销售额排名前10的产品\" → true(包含\"排名\",且无明细关键词)
                    - \"查看销售订单明细\" → false(包含\"明细\")
            """)
    @UserMessage("""
            【用户需求】
            {{userInput}}
            """)
    Boolean routeQuery(@MemoryId String userId, @V("userInput") String userInput);

    /**
     * 生成 Milvus 过滤条件(适配 Milvus v2.3.9)
     */
    @SystemMessage("""
            MILVUS 标量过滤条件生成规则(严格遵守 - 当前版本 v2.3.9):
            
            【重要输出约束】
            - 必须返回有效的 Milvus 过滤条件表达式
            - 禁止返回 true 或 false
            - 禁止返回空字符串以外的任何非表达式内容
            - 无条件时只返回空字符串 ""
            
            1. 语法规范:
               - 允许的操作符:==, !=, like
               - 逻辑组合:&& (AND), || (OR)
               - 所有字段都是字符串类型,值必须使用单引号包裹
               - 字符串中的单引号需要转义:'O''Reilly'
            
            2. 【重要】Milvus v2.3.9 like 操作符限制:
               - ✅ 支持:like '关键字%'(前缀匹配,以关键字开头)
               - ❌ 不支持:like '%关键字%'(包含匹配)
               - ❌ 不支持:like '%关键字'(后缀匹配)
            
            3. 可用字段(只能使用这些字段):
               - {{sMilvusFiled}}
               字段说明:
               - {{sMilvusFiledDescription}}
            
            4. 提取规则:
               - 只使用上述可用字段,不要创建新字段
               - 如果用户提到了文档类型(如"报价单"、"订单"等),但可用字段中没有类型字段,则忽略该条件
               
               【精确匹配规则】:
               - 当用户提供明确值时:字段 == '值'
                 * 例如:"客户名称中科精工" → sCustomerName == '中科精工'
                 * 例如:"单据号 INV001" → sBillNo == 'INV001'
            
            5. 时间处理规则:
               - 当前系统时间:{{sDataNow}}(格式:yyyy-MM-dd)
               - 相对时间转换规则:
                 * "今天/今日" → 当天 00:00:00 到 23:59:59
                 * "昨天" → 前一天 00:00:00 到 23:59:59
                 * "本周" → 本周一 00:00:00 到本周日 23:59:59
                 * "本月" → 本月1日 00:00:00 到本月最后一天 23:59:59
                 * "本年" → 本年1月1日 00:00:00 到本年12月31日 23:59:59
                 * "X" → 从 X 天前 00:00:00 到今天 23:59:59
               - 日期转时间戳:所有日期转换为 Unix 时间戳(秒)
               - 时间范围格式:字段 >= 起始时间戳 && 字段 <= 结束时间戳
               - 如果没有明确的时间需求,不要添加任何时间过滤条件
            
            6. 示例:
               ✅ 正确输出:
               - "客户名称中科精工" → sCustomerName == '中科精工'
               - "中科精工的报价单明细" → sCustomerName == '中科精工'
               - "产品以彩盒开头" → sProductStyle like '彩盒%'
               - "无条件" → ""
               
               ❌ 错误输出(禁止):
               - "中科精工的报价单明细" → true
               - "中科精工的报价单明细" → false
               - "中科精工的报价单明细" → 1
            
            7. 输出格式:
               - 仅返回纯过滤条件,无任何解释、换行、备注
               - 单条件:sCustomerName == '中科精工'
               - 多条件:(sCustomerName == '中科精工' && sProductStyle like '彩盒%')
               - 无条件:直接返回空字符串 ""
        """)
        @UserMessage("""
        【用户查询】
            - {{userInput}}
        【当前时间】
            - {{sDataNow}}
        【可用字段】
            - {{sMilvusFiled}}
        【字段说明】
            - {{sMilvusFiledDescription}}
    """)
    String getMilvusFilter(@MemoryId String userId,
                           @V("userInput") String userInput,
                           @V("sMilvusFiled") String sMilvusFiled,
                           @V("sMilvusFiledDescription") String sMilvusFiledDescription,
                           @V("sDataNow") String sDataNow);

}