大模型学习

生成式人工智能服务管理暂行办法

智能体
agent

豆包大模型
盘古大模型
同义千问

ChatModel

@RestController
public class ChatDemoController {
    @Autowired
    private ChatClient chatClient;
    @Autowired
    private ZhiPuAiChatModel chatModel;
    @Autowired
    private OpenAiChatModel openAiChatModel;
    
    /**
     * openAi 聊天
     *
     * @param message
     * @return
     */
    @GetMapping("/ai/openAiChat")
    public Map openAiChat(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        return Map.of("generation", openAiChatModel.call(message));
    }
    /**
     * zhipuAi 聊天
     *
     * @param message
     * @return
     */
    @GetMapping("/ai/generate")
    public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        return Map.of("generation", chatModel.call(message));
    }
    /**
     * ChatClient使用(流式调用)
     * @param message
     * @param voice
     * @return
     */
    @GetMapping("/ai/chatClient")
    Map<String, String> completion(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message, String voice) {
        return Map.of(
                "completion",
                chatClient.prompt()
                        .system(sp -> sp.param("voice", voice))
                        .user(message)
                        .call()
                        .content());
    }
}

FunctionCall 工具调用

大模型是基于历史数据进行训练的,回答我们的问题也是基于历史数据进行回复, 如果你想要大模型具备获取最新消息的能力, 此时,就需要用到工具机制,它能帮助大模型获取最新的数据消息.

工具定义

实现 java.util.function.Function 接口
@Description注解: 注释是可选的,它提供了一个函数描述,帮助模型理解何时调用函数。它是一个重要的属性,可以帮助AI模型确定要调用的客户端函数。

@JsonClassDescription注解: 对方法进行描述.

@JsonPropertyDescription注解: 对参数进行描述.

@Component
@Description("先获取指定地点,再获取当前时间")
public class DateService implements Function<DateService.Request, DateService.Response> {
 
    @JsonClassDescription("地点请求")
    public record Request(@JsonPropertyDescription("地点")String address) { }
 
    public record Response(String date) { }
   
    @Override
    public Response apply(Request request) {
        System.out.println(request.address);
        return new Response(String.format("%s的当前时间是%s", request.address, LocalDateTime.now()));
    }
}

工具调用

@RestController
public class ChatDemoController {
 
    @Autowired
    private OpenAiChatModel openAiChatModel;
    /**
     * 工具调用
     */
    @GetMapping("/ai/function")
    public String function(@RequestParam String message) {
        Prompt prompt = new Prompt(message, OpenAiChatOptions.builder().withFunction("dateService").build());
//        Prompt prompt = new Prompt(message, OpenAiChatOptions.builder().withFunctionCallbacks(
//                List.of(FunctionCallbackWrapper.builder(new DateService())
//                        .withName("dateService")
//                        .withDescription("获取指定地点的当前时间").build())
//        ).build());
        Generation generation = openAiChatModel.call(prompt).getResult();
        return (generation != null) ? generation.getOutput().getContent() : "";
    }
}

Embeddings文本向量化

什么叫向量? 向量可以理解为平面坐标中的一个坐标点(x,y),在编程领域,一个二维向量就是一个大小为float类型的数组。也可以用三维坐标系中的向量表示一个空间中的点. 而文本向量化是指,利用大模型可以把一个字,一个词或一段话映射为一个多维向量.

为什么要向量化? 当我们把所有的文本生成向量后, 就可以利用向量的特点,进行相似度搜索.这种搜索算法比elasticsearch的分词算法更好.

文本读取,解析和存储,SpringAi提供了以下核心概念:

Document

DocumentReader:用来读取TXT、PDF等文件内容
JsonReader:读取JSON格式的文件
TextReader:读取txt文件
PagePdfDocumentReader:使用Apache PdfBox读取PDF文件
TikaDocumentReader:使用Apache Tika来读取PDF, DOC/DOCX, PPT/PPTX, and HTML等文件
DocumentTransformer:用来解析文件内容
tokenTextSplitter:按照token进行解析。

DocumentWriter:用来写入文件内容到向量数据库
VectorStore:DocumentWriter的子类。

文本服务

@Component
public class DocumentService {
 
    @Value("classpath:meituan-qa.txt")
    private Resource resource;
    @Autowired
    private RedisVectorStore vectorStore;
 
    /**
     * 向量存储
     * @return
     */
    public List<Document> loadText() {
        //文本读取
        TextReader textReader = new TextReader(resource);
        textReader.getCustomMetadata().put("filename", "meituan-qa.txt");
        List<Document> documents = textReader.get();
 
        CustomerTextSplitter customerTextSplitter= new CustomerTextSplitter();
        List<Document> list = customerTextSplitter.apply(documents);
        // 把问题存到元数据中
        list.forEach(document -> document.getMetadata().put("question", document.getContent().split("\\n")[0]));
        // 向量存储(文本存储)
        vectorStore.add(list);
        return list;
    }
 
    /**
     * 向量搜索
     * @param message
     * @return
     */
    public List<Document> search(String message) {
        List<Document> documents = vectorStore.similaritySearch(message);
        return documents;
    }
 
    /**
     * 元数据搜索
     * @param message
     * @param question
     * @return
     */
    public List<Document> metadataSearch(String message, String question) {
        return vectorStore.similaritySearch(
                SearchRequest
                        .query(message)
//                        .withTopK(5)
                        .withSimilarityThreshold(0.1)
                        .withFilterExpression(String.format("question in ['%s']", question)));
    }
}

Controller 代码

@RestController
public class ChatDemoController {
 
    @Autowired
    private DocumentService documentService;
    /**
     * 向量存储
     */
    @GetMapping("/ai/vectorStore")
    public Map vectorStore() {
        List<Document> documents = documentService.loadText();
        return Map.of("generation", documents);
    }
    /**
     * 向量搜索
     * @param message
     * @return
     */
    @GetMapping("/ai/documentSearch")
    public List<Document> documentSearch(@RequestParam String message) {
        return documentService.search(message);
    }
    /**
     * 元数据搜索
     * @param message
     * @param question
     * @return
     */
    @GetMapping("/ai/metadataSearch")
    public List<Document> documentMetadataSearch(@RequestParam String message, @RequestParam String question) {
        return documentService.metadataSearch(message, question);
    }
}

Redis 向量库

RAG

RAG 检索增强生成

RAG是什么?检索增强生成又是什么意思?大模型的知识仅限于它所训练的数据,如果你问大模型,你们公司的xxx产品有什么作用,大模型肯定会回答不出来。如果你想让大模型拥有你们公司知识库的数据, 此时就可以用到RAG。 简单的讲,RAG的原理是,根据用户输入的问题,先从你们公司的知识库查询出答案,再把用户输的问题和搜索出来的答案,让大模型根据我们的答案回复用户的问题。 而根据用户问题,从知识库搜索问题,需要用到上面所说的文本向量化。根据文本的相识度,从知识库中搜索出符合用户问题的答案出来。

    RAG的工作原理

    RAG的工作原理可以分为以下几个步骤:
    1.接收请求:首先,系统接收到用户的请求(例如提出一个问题)。
    2.信息检索(R):系统从一个大型文档库中检索出与查询最相关的文档片段。这一步的目标是找到那些可能包含答案或相关信息的文档。
    3.生成增强(A):将检索到的文档片段与原始查询一起输入到大模型(如chatGPT)中,注意使用合适的提示词,比如原始的问题是XXX,检索到的信息是YYY,给大模型的输入应该类似于:请基于YYY回答XXXX。
    4.输出生成(G):大模型基于输入的查询和检索到的文档片段生成最终的文本答案,并返回给用户。

    @RestController
    public class ChatDemoController {
        @Autowired
        private OpenAiChatModel openAiChatModel;
        @Autowired
        private DocumentService documentService;
        /**
         * RAG
         * @param message
         * @return
         */
        @GetMapping("/ai/customerService")
        public String customerService(@RequestParam String message) {
     
            // 向量搜索
            List<Document> documentList = documentService.search(message);
     
            // 提示词模板
            PromptTemplate promptTemplate = new PromptTemplate("{userMessage}\n\n 用以下信息回答问题:\n {contents}");
     
            // 组装提示词
            Prompt prompt = promptTemplate.create(Map.of("userMessage", message, "contents", documentList));
     
            // 调用大模型
            return openAiChatModel.call(prompt).getResult().getOutput().getContent();
        }
    }

    上一篇
    下一篇