introductory
Okay, let's continue our chat about Spring AI today. In October, I used Spring AI to build a simple version of the personal assistant system, and the overall effect is still very good. Through this attempt, I have a clearer understanding and practice of the exploration of the combination of business systems and AI. Although the current function is still relatively simple, the overall system also lacks more operable interactions, especially in the database operation, the function is more basic, and at present mainly realizes a simple query function.
But right at the end of October, Spring AI received a major update, which not only enhanced the ability of function calls, but also introduced the concept of global parameters. These two new features bring a huge boost to the scalability and playability of the system, opening up even more possibilities.
So, today we'll take advantage of this global parameter feature to implement a database plugin. Specifically, we will implement a complete add, delete, change, and retrieve (CRUD) operation. For the current intelligent body system, database operation has been a crucial feature, especially in the business system, the intelligent body can interact with the database, which not only improves the flexibility and intelligence of the system, but also greatly enhances the efficiency of business processing. Therefore, our goal today is to realize a set of basic database operation framework through the powerful features of Spring AI, and complete the four functional modules of add, delete, change and check.
Special attention should be paid to the fact that here we are only through a simple use case to analyze and explain, of course, this does not mean that it can only be limited to this, in fact, for most business scenarios, such a database operation is sufficient to meet the demand, and can be based on specific business needs to further expand and optimize functionality.
If any of you are still not quite sure how to use Spring AI to build your own intelligent body system, or you don't know much about the basic functions of Spring AI, you are welcome to check out the related articles we have shared before to learn more about it:/guoxiaoyu/p/18453559
Personal Assistant Major Optimization
First, let's take a look at the personal assistant features we plan to implement. At present, we have already realized the travel tips and weather query function. Today, we will add a "personal to-do" function on this basis. Due to the large and complex database module, we will explain this part in detail separately. The following is the general realization of the function and the related process diagram:
Demonstration
First, let's take a look at the demo of the effect after half a day of tweaking. After a period of optimization and debugging, the final presentation basically meets my expectations.
Here only demonstrated the next to-do additions, deletions and changes, and did not demonstrate the weather query and travel tips, you can see the previous section of the demo.
Start optimization
clue
Of course, our optimization work starts from the entrance part, first of all, the design of the prompt word is indispensable. Looking back to the previous section, we did not do too much modification to the prompt words as there were fewer features at that time, so the overall interaction and model responses were relatively simple. However, with this addition of new features, the model responses may become more disorganized.
Therefore, in order to ensure that the output of the model can be more accurate and organized, we prepared and generated detailed cue words in advance in this optimization.
String conversation_id = "123";
OpenAiChatOptions openAiChatOptions = ()
.withModel("hunyuan-pro").withTemperature(0.5)
.build(); String systemPrompt = ""; String systemPrompt = "".
String systemPrompt = """"
- Role: Personal Assistant
- Background: The user needs a multi-functional AI assistant that can provide real-time weather information, detailed travel tips and help record to-do lists.
- Profile: You are a professional travel weather assistant with strong information retrieval and data processing capabilities, able to provide users with accurate weather information, detailed travel tips, and help manage daily to-do lists.
- Skills: You have strong web searching, data processing and user interaction skills to provide users with the information they need quickly and accurately.
- Goals: Provide accurate weather information, create detailed travel guides with flight, hotel, and train information, and help users record and manage their to-do lists.
- Constrains: The information provided must be accurate, the travel tips should be detailed and practical, and the to-do list management should be simple and efficient.
- OutputFormat: A friendly, conversational response that contains the necessary details and formatted data.
- Workflow.
1. Receive user's weather query request and provide accurate weather information. 2.
2. according to the user's travel destination, search and provide travel tips including flights, hotels, trains.
3. receive user's to-do list and provide concise record and reminder service.
""";
ChatMemory chatMemory1 = ();
String content =
.prompt()
.system(systemPrompt)
.user(userInput)
.options(openAiChatOptions)
.advisors(messageChatMemoryAdvisor,myLoggerAdvisor,promptChatKnowledageAdvisor,promptChatDateAdvisor)
.advisors(advisor -> ("chat_memory_conversation_id", conversation_id)
.param("chat_memory_response_size", 100))
.functions("CurrentWeather", "TravelPlanning", "toDoListFunctionWithContext")
.toolContext(("sessionId", conversation_id, "userMemory", chatMemory1, "client",chatClient))
.call()
.call(); .content().
("content: {}", content);
ChatDataPO chatDataPO = ().code("text").data(().text(content).build()).build();
return chatDataPO;
Okay, we've just added some new parameters, I'll now explain in detail what each parameter does and the usage scenarios:
-
: This is the parameter used to individually modify our default enhancer (Enhanced Advisor). It is similar to the above mentioned
Advisor
class associated with it, allowing the user to customize and adjust the behavior and configuration of the enhancer without modifying the core code. -
toolContent: This parameter is a global parameter that we introduced when we added the function callback feature, and is mainly used to handle the various instrumented contents of the callback. In the function callback, the
toolContent
Different instrumentation data can be passed to ensure that the callback process is executed correctly. -
sessionId: This parameter is used to identify each individual session, and it helps us control the state of each user's session. By assigning each session a unique
sessionId
, we can ensure that each function call is specific to a particular user and not shared global data. For example, our to-do list is personalized so that only the corresponding user can see and manipulate their own to-do list. Here, for the sake of demonstration, we'llsessionId
Set as a fixed value, did not access the login interface, the actual application should be dynamically generated according to the user's identity. - userMemory: This parameter is used to pass the user's historical context, allowing the callback function to use a record of previous conversations or actions. For example, in to-do list management, we may need to determine if a task has been completed based on historical data.
-
chatClient: This parameter connects the to-do function to a large model with which to generate SQL queries or other complex operations.
chatClient
responsible for interacting with the larger model and generating the required SQL, while the outer thinking model focuses on invoking the interface and handling the business logic.
Okay, once again, if some of you haven't touched anything related to intelligences before, I suggest you go through my first post before to understand the basics and add relevant background information, so that it will be easier to understand the next content.
So, let's move on to what's related to the to-do list.
data sheet
The purpose of personal to-do list is very clear, mainly for the to-do list table to add, delete, change, check and other basic operations. In order to ensure the efficiency and simplicity of the system, we are designing the database with very simple and intuitive data fields. This is our table construction statement:
create table todo_info(
id int(11) auto_increment primary key,
todo_info varchar(1000) not null,
todo_Date date not null,
done boolean not null default false
)
After generating this table building statement, be sure to save it properly for subsequent reference to the larger model.
function callback
First, we need to make it clear that callbacks for pending functions must be able to support four basic operations: add, delete, change, and check. In addition, the callback function needs to have the ability to generate SQL statements and to execute those SQL statements in order to interact with the database. Only after these operations are successfully completed can we return the final resultant data to the outer thinking model for further processing and analysis.
Based on these requirements, we can now begin to flesh out and step-by-step implement the required functionality.
Okay, let's take it one step at a time.
to-do function
Based on the above information, we need to design a function that contains an entry parameter and a return parameter. The main purpose of the input parameter is to pass an identifier that uniquely identifies an operation, while the return parameter is a string-type return value that provides the caller with the appropriate result or status information.
public class ToDoListInfoService implements BiFunction<, ToolContext, > {
private JdbcTemplate jdbcTemplate;
public ToDoListInfoService(JdbcTemplate jdbcTemplate) {
= jdbcTemplate;
}
@JsonClassDescription("crud:c Increased representation;r:Delegate inquiries,u:Delegate Updates,d:Delete on behalf of")
public record ToDoRequest(String crud) {}
public record ToDoResponse(String message) {}
@Override
public ToDoResponse apply( request, ToolContext toolContext) {}
}
It can be observed that here we are using theBiFunction
interface instead of the previously usedFunction
interface because we need to use ToolContext.
It's important to note that although here we use the
JsonClassDescription
, but its main purpose is to improve the readability and maintainability of the code and to make it easier for developers to understand and view the structure. In practice, the big model does not depend on theJsonClassDescription
to determine or parse the specific parameters passed.
Bean Assembly
Since we are using theJdbcTemplate
To perform database operations, it is necessary to introduce the appropriate Maven dependencies into the project.
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
I still choose to use the Bean assembly approach here, mainly because it can provide higher flexibility and maintainability. In addition, maintaining the definition and configuration of the input parameters can also provide an effective reference and support for the larger model in subsequent development.
@Bean
public FunctionCallback toDoListFunctionWithContext(JdbcTemplate jdbcTemplate) {
return (new ToDoListInfoService(jdbcTemplate))
.withName("toDoListFunctionWithContext") // (1) function name
.withDescription("Add to-do,crud:c Increased representation;r:Delegate inquiries,u:Delegate Updates,d:Delete on behalf of") // (2) function description
.build();
}
Next, we will work on implementing the specific methods inside the function.
contextual information
defaultMessageChatMemoryAdvisor
class does not support getting the history chat log directly. Therefore, we need to customize a class to implement this feature. For ease of use, the following code will integrate this functionality and expose an interface to be called.
@Slf4j
public class MyMessageChatMemoryAdvisor extends MessageChatMemoryAdvisor {
private ChatMemory chatMemory;
public MyMessageChatMemoryAdvisor(ChatMemory chatMemory) {
super(chatMemory);
= chatMemory;
}
public MyMessageChatMemoryAdvisor(ChatMemory chatMemory, String defaultConversationId, int chatHistoryWindowSize) {
super(chatMemory, defaultConversationId, chatHistoryWindowSize);
= chatMemory;
}
public MyMessageChatMemoryAdvisor(ChatMemory chatMemory, String defaultConversationId, int chatHistoryWindowSize, int order) {
super(chatMemory, defaultConversationId, chatHistoryWindowSize, order);
= chatMemory;
}
public ChatMemory getChatMemory() {
return chatMemory;
}
}
In order to be able to access the history chats smoothly, we have written a special method which will return the history context object. In this way, we can easily get the complete chat information in the subsequent operations, so as to realize the normal access and processing of the content of the history conversation.
database operation
Next, we will perform database operations, but in doing so, we must rely on the help of the big model to generate SQL statements. The reason for this is that the outer layer of the big model has the powerful ability to accurately analyze and understand the requirements in order to determine whether the specific type of operation is an add, delete, change, or lookup. Next, we will describe in detail how to realize this process.
public ToDoResponse apply( request, ToolContext toolContext) {
String tableinfo = """
- Role: SQL Statement Generation Expert
- Background: Users need to generate accurate MySQL query or modification statements based on specific table structure and parameter information to automate and efficient database operations.
- Profile: You are an experienced database administrator and SQL expert who is proficient in all kinds of query and modification statements of MySQL database, and can quickly generate correct SQL statements based on table structure and parameter information provided by users.
- Skills: You have deep knowledge of database theory and rich practical experience, and can understand complex table structures, accurately grasp the user's needs, and generate efficient and accurate SQL statements accordingly.
- Goals: Based on the table structure and parameter information provided by the user, you will generate MySQL query or modification statements that can be executed directly, ensuring the correctness of the statements and the success rate of their execution.
- Constrains: Generate SQL statements that conform to MySQL syntax rules, can be executed directly in MySQL database, and do not contain any additional information or hints.
- OutputFormat: Plain SQL text statements with standardized formatting and no extra information. Markdown formatting is prohibited.
- Workflow.
1. Analyze the table structure and parameter information provided by the user. 2.
2. Based on the analysis results, determine the type of database operation to be performed (query, insert, update or delete). 3.
3. Combine the operation type and user-supplied information to generate a SQL statement that conforms to MySQL syntax.
-example.
q.Create a to-do for me: remind me to read at 9:00 tomorrow. Today's date is 2024-11-07 20:20:11
a: INSERT INTO todo_info (todo_info, todo_date) VALUES ('Read tomorrow at 8', '2024-11-08 08:00:00');
- tableinfo:
create table todo_info(
id int(11) auto_increment primary key,
todo_info varchar(1000) not null,
todo_info varchar(1000) not null, todo_Date date not null, done boolean not null default
done boolean not null default false
)
""" ;
String crud = ;
ChatMemory chatMemory = (ChatMemory)().get("userMemory");
String conversation_id = (String)().get("sessionId");
ChatClient client = (ChatClient)().get("client");
List<Message> messages = (conversation_id, 1); var userqa = (0); var userqa = (0); var userqa = (0)
var userqa = (0).getContent();
String jsonString = "Successful execution";
String content = ()
.system(tableinfo)
.user("Please generate the corresponding SQL text according to the current problem can be, prohibit the generation of content other than SQL:" + userqa + ", today's date is:" + ())
.call().content();
try {
if (("r")) {
jsonString = "Querying the pending content as follows:" + ((content));
} else {
(content);
}
}catch (Exception e){
("ToDoListInfoService:{}", ()); }
jsonString = "Execution failed.";
}
("ToDoListInfoService:{}", content);
return new ToDoResponse(jsonString);
The implementation of this code relies entirely on information passed through global parameters to better handle historical context. Traditional callback function approaches have significant limitations in dealing with historical context across multiple rounds of conversations, and are not able to efficiently track the context in a session, making it difficult to solve such problems. In this case, we are able to work across multiple interactions by means of global parameter passing, ensuring that the most recent context information is accessible at each step.
Let's briefly explain the flow of this code:
- Get user questions in the current session: We fetch the most recent user-asked question from the current session to make sure we don't mistakenly fetch the context of another session.
- Submit the problem to the big model to generate SQL: We pass the user's question to the big model and utilize its capabilities to help us generate appropriate SQL query statements.
- Determine if it is a query request: We check whether the generated SQL statement is a query operation. If it is a query, the query is executed and the result is returned to the user.
- Handling of other operations: If it's not a query request, then the user's instruction may be an update or execution type of operation, in which case we return an "Executed Successfully" response.
As you can see, the cue word in thetableinfo
I hardcoded it to death. In fact, we can design it as a passable parameter, which not only improves the flexibility and reusability of the plugin, but also makes the plugin is no longer only limited to the use of the to-do list scenarios, but can be used as a general database operation plugin to adapt to different needs and application scenarios.
In order to be able to show the effect in the demo process, at present I will do some parts of the temporary hardcoding processing. This is just to provide you with a preliminary idea and reference framework, I will gradually improve these features.
Next, let's take a look at the results we get during debugging. Below is a screenshot of what I got during debugging:
Next, we will check if the database has successfully stored and updated the data properly.
Next, I'll show the query in action, along with the generated SQL statement, which is quite good and meets the query requirements efficiently.
As you can see, here has successfully returned data or results to the front-end normally, the system is running in good condition.
summarize
In this article, we delve into how to utilize theSpring AI The new features, especially global parameters and enhanced function call capabilities, to build an intelligent personal assistant system. With this system, we implement basic add, delete, change, and check (CRUD) functionality, with a special focus on database interaction and to-do list management. We show how to incorporateSpring AI Integrate into actual business processes and generate SQL query statements through the model to enhance the automation and flexibility of database operations.
First, we introduced theSpring AI How to simplify and extend the business logic processing after the feature update, especially the advantages in dealing with multi-round conversations, user history data and complex database operations. With global parameters, the system is able to more accurately capture user needs and perform related operations at the database level, truly realizing intelligent interactions and automated business processes.
We also designed a to-do list management function, in which the addition, deletion and checking operations of the to-do function are made more efficient and accurate through well-designed prompt words and model optimization.
To summarize, this time based onSpring AI The system optimization of the system not only provides us with a powerful framework for intelligent assistants, but also provides a learnable solution for intelligent systems in actual business. In the future, we can further expand the functions based on this to create more intelligent and personalized business solutions.
I'm Rain, a Java server-side coder, studying the mysteries of AI technology. I love technical communication and sharing, and I am passionate about open source community. I am also a Tencent Cloud Creative Star, Ali Cloud Expert Blogger, Huawei Cloud Enjoyment Expert, and Nuggets Excellent Author.
💡 I won't be shy about sharing my personal explorations and experiences on the path of technology, in the hope that I can bring some inspiration and help to your learning and growth.
🌟 Welcome to the effortless drizzle! 🌟