生成式人工智能服务管理暂行办法
智能体
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();
}
}