以下基于1.0.0

多层次记忆架构

记忆多=聪明, 记忆多会触发token上限
要知道, 无论你用什么存储对话以及, 也只能保证服务端的存储性能。
但是一旦聊天记录多了依然会超过token上限, 但是有时候我们依然希望存储更多的聊天记录,这样才能保证整个对话更像“人”。

  • 近期记忆:保留在上下文窗口中的最近几轮对话,每轮对话完成后立即存储(可通过ChatMemory); 10 条
  • 中期记忆:通过RAG检索的相关历史对话(每轮对话完成后,异步将对话内容转换为向量并存入向量数据库) 5条
  • 长期记忆:关键信息的固化总结
    • 方式一:定时批处理
      • 通过定时任务(如每天或每周)对积累的对话进行总结和提炼
      • 提取关键信息、用户偏好、重要事实等
      • 批处理方式降低计算成本,适合大规模处理
    • 方式二:关键点实时处理
      • 在对话中识别出关键信息点时立即提取并存储
      • 例如,当用户明确表达偏好、提供个人信息或设置持久性指令时
      • 采用"写入触发器"机制,在特定条件下自动更新长期记忆

结构化输出大模型回答

基础数据类型

这里以boolean为例

@SpringBootTest(classes = QuickStartApplication.class)
public class BaseStructTest {

    ChatClient chatClient;
    @BeforeEach
    public  void init(@Autowired
                      OpenAiChatModel chatModel) {
        chatClient = ChatClient.builder(chatModel).build();
    }
    @Test
    public void testBoolOut() {
        Boolean isComplain = chatClient
                .prompt()
                .advisors(new SimpleLoggerAdvisor())
                .system("""
            请判断用户信息是否表达了投诉意图?
            只能用 true 或 false 回答,不要输出多余内容
            """)
                .user("你们家的快递迟迟不到,我要退货!")
                .call()
                .entity(Boolean.class);

        // 分支逻辑
        if (Boolean.TRUE.equals(isComplain)) {
            System.out.println("用户是投诉,转接人工客服!");
        } else {
            System.out.println("用户不是投诉,自动流转客服机器人。");
            // todo 继续调用 客服ChatClient进行对话
        }
    }
}

输出指定POJO

这里以解析收货地址为例:

@SpringBootTest(classes = QuickStartApplication.class)
public class PojoStructTest {

    ChatClient chatClient;
    @BeforeEach
    public  void init(@Autowired
                      OpenAiChatModel chatModel) {
        chatClient = ChatClient.builder(chatModel).build();
    }

    @Test
    public void testEntityOut() {
        Address address = chatClient.prompt()
                .system("""
                        请从下面这条文本中提取收货信息
                        """)
                .user("收货人:张三,电话13588888888,地址:浙江省杭州市西湖区文一西路100号8幢202室")
                .call()
                .entity(Address.class);
        System.out.println(address);
    }
}

pojo对象

public record Address(
    String name,        // 收件人姓名
    String phone,       // 联系电话
    String province,    // 省
    String city,        // 市
    String district,    // 区/县
    String detail       // 详细地址
) {}

结果返回
在这里插入图片描述

原理

在这里插入图片描述

function-call

在这里插入图片描述
tool calling也可以直接叫tool(也称为function-call), 主要用于提供大模型不具备的信息和能力:

    1. 信息检索:可用于从外部源(如数据库、Web 服务、文件系统或 Web 搜索引擎)检索信息。目标是增强模型的知识,使其能够回答无法回答的问题。例如,工具可用于检索给定位置的当前天气、检索最新的新闻文章或查询数据库以获取特定记录。 这也是一种检索增强方式。
    1. 采取行动:例如发送电子邮件、在数据库中创建新记录、提交表单或触发工作流。目标是自动执行原本需要人工干预或显式编程的任务。例如,可以使用工具为与聊天机器人交互的客户预订航班,在网页上填写表单等。

怎么使用 在这里插入图片描述

声明tools类
@Service
class NameCountsTools {

    @Tool(description = "长沙有多少名字的数量")
    String LocationNameCounts(
            @ToolParam(description = "名字")
            String name) {
        return "10个";
    }

}
调用tool
@RestController
@RequestMapping("/tool")
public class ToolController {
    @Autowired
    private ToolService toolService;

    private final ChatClient chatClient;

    public ToolController(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder
                .build();
    }
    @GetMapping(value = "/call")
    public String call() {
        String content = chatClient.prompt()
                .advisors(new SimpleLoggerAdvisor())
                .tools(toolService)
                .user("全国有多少个叫张三的人")
                .call()
                .content();
        return content;
    }
}

tool原理

在这里插入图片描述

tool注意事情

参数或者返回值不支持

以下类型目前不支持工具使用的方法参数或者返回类型

  • Optional
  • 异步类型(CompletableFuture,例如:Future)
  • 响应类型(例如:Flow、Mono、Flux)
  • 功能类型(例如:Function、Supplier、Consumer)
    推荐使用:POJO、record、Java基础类型、list、map
Tool参数无法自动推算问题
  • 温度(即模型随机性)太低,AI可能缺少自由度会变得比较拘谨(从一定程度上可以解决,不推荐)
  • 可以通过描述更加明确
  @Tool(description = "获取指定位置天气,根据位置自动推算经纬度")
    public String getAirQuality(@ToolParam(description = "纬度") double latitude,
                                @ToolParam(description = "经度") double longitude) {
        return "天晴";
    }
Tool参数的幻觉问题,大模型“强行适配”
  • 加强参数描述,可能解决
@Parameter(description = "真实人名(必填,必须为人的真实姓名,严禁用其他信息代替;如缺失请传null)")
String name
  • 后端代码加强校和验兜底保护(比如执行更新操作前,先查询一次保证数据存在)
  • 系统Prompt设定限制
“严禁随意补全或猜测工具调用参数。
参数如缺失或语义不准,请不要补充或随意传递,请直接放弃本次工具调用。”
工具暴露的接口名、方法名、参数名要可读、业务化
  • AI是“看”你的签名和注释来决定用不用工具的;
  • 尽量避免乱码、缩写等,使用语义明确的英文
方法参数数量不宜过多
  • 建议每个工具方法尽量少于5个参数,否则AI提示会变复杂、出错率高。
工具方法不适合做超耗时操作, 更长的耗时意味着用户延迟响应时间变长
  • 性能优化 能异步处理就异步处理、 查询数据 redis
关于Tools的权限控制
  • 1.可以利用SpringSecurity限制
    @Tool(description = "退票")
    //此处是权限判定
    @PreAuthorize("hasRole('ADMIN')")
    public String cancel(
            // @ToolParam告诉大模型参数的描述
      @ToolParam(description = "预定号,可以是纯数字") String ticketNumber,
      @ToolParam(description = "真实人名(必填,必须为人的真实姓名,严禁用其他信息代替;如缺失请传null)") String name
           ) {
        // 当前登录用户名
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        // 先查询 --->先校验
        ticketService.cancel(ticketNumber, name);
        return username+"退票成功!";
    }
  • 2.将tools和权限资源一起存储, 然后动态设置tools
.defaultToolCallbacks(toolService.getToolCallList(toolService))

根据当前用户读取当前用户所属角色的所有tools

public List<ToolCallback> getToolCallList(ToolService toolService) {
   	//从数据库中读取-相应的方法
       Method method = ReflectionUtils.findMethod(ToolService.class, "cancel",String.class,String.class);
       ToolDefinition build = ToolDefinition.builder()
               .name("cancel")
               .description("退票")
               .inputSchema("""
                       {
                         "type": "object",
                         "properties": {
                           "ticketNumber": {
                             "type": "string",
                             "description": "预定号,可以是纯数字"
                           },
                           "name": {
                             "type": "string",
                             "description": "真实人名"
                           }
                         },
                         "required": ["ticketNumber", "name"]
                       }
                       """)
               .build();
       ToolCallback toolCallback = MethodToolCallback.builder()
               .toolDefinition(build)
               .toolMethod(method)
               .toolObject(toolService)
               .build();

       return List.of(toolCallback);
   }
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐