Spring AI 2.0 OA System: Architecture, RAG & Tool Calling Deep Dive
This article details the design of an AI-powered OA system built with Spring Boot 4, Vue 3, and Spring AI 2.0, covering three AI capabilities (smart leave forms, approval tracking, RAG policy QA), a four-role permission model, two-level approval engine, database schema, API endpoints, and vector retrieval configuration using Redis Stack and Alibaba Qwen models.
Project Overview
The system is an intelligent office automation (OA) platform for small and medium enterprises. On top of traditional OA core flows (leave, expense, approval), it deeply integrates Spring AI 2.0 to embed large model capabilities into real business scenarios, delivering three AI landing capabilities:
AI Smart Leave Form Fill : Employee inputs natural language like "day off next Wednesday"; system auto-calculates dates, determines leave type and days, and prompts annual leave balance and deduction rules. Technical means: Prompt engineering + structured output entity() + Tool Calling.
AI Approval Progress Query : User asks "help me check where last month's expense approval stands"; returns real node, approver, and comments. Technical means: Tool Calling (calls real business Service, not model hallucination).
Enterprise Policy RAG Q&A : Admin uploads policy files (leave, expense, seal); employees ask questions and get answers based on vector retrieval with source citations. Technical means: Tika parsing + token chunking + Redis vector store + QuestionAnswerAdvisor.
System characteristics:
Four-role permission system : ADMIN (system admin), BOSS (general manager), MANAGER (dept manager), EMPLOYEE (staff). Data scope and operation permissions isolated by level.
Two-level approval engine : Leave and expense share one approval model ( t_approval_record unified log). Thresholds on days/amount dynamically decide escalation to BOSS final review.
Four differentiated dashboards : Same /api/home/stats endpoint returns different dashboard data per login role; frontend renders ECharts charts.
Frontend-backend separation : Vue 3 + Element Plus SPA; Spring Boot provides stateless REST APIs; JWT carries login state.
Unified global time format : Date display as 2026-11-02, datetime as 2026-11-02 17:25:17 (backend Jackson unified yyyy-MM-dd HH:mm:ss, frontend utils/format.js fallback).
Business Logic Design
2.1 Role & Permission Matrix
A detailed matrix defines permissions for each role across functions: dashboard, dept management, employee management, leave/expense submission, approval center, knowledge base, announcements, AI assistant, personal center. Permission implementation is three-layered: frontend route guard via meta.roles → backend JwtInterceptor login check → method-level @RequireRole annotation auth; data scope enforced by each Service's applyScope() method assembling MyBatis-Plus query conditions per role.
2.2 User Login & Auth Flow
Diagram illustrates login process: username/password → JWT generation (HMAC-SHA, 24h expiry) → token stored in Pinia → subsequent requests carry Authorization header.
2.3 Leave Business Full Process
Leave is the most complex chain, linking AI form fill, balance check, two-level approval, and balance deduction. Key business rules:
Start node determined by applicant role ; day threshold evaluated only at department manager approval pass ( days > 3 escalates to BOSS).
Department manager's own leave skips manager node , goes directly to BOSS final review.
Admin and BOSS submissions are auto-approved (free pass).
Only PENDING state and own documents can be cancelled (to CANCELLED).
Leave balance deducted only at final approval pass ; marriage leave does not consume balance field.
New employee first balance query triggers EmployeeService.initBalance() to auto-initialize current year record (annual leave default 5 days).
2.4 Expense Business Process
Approval node permission validation ( ApprovalService.checkNodePermission): BOSS node only allow BOSS role; MANAGER node only allow MANAGER role with matching deptId; ADMIN has fallback pass-through for ops handling.
2.5 Knowledge Base Upload & Vectorization Flow
Diagram shows upload → Tika parsing → chunking → embedding via text-embedding-v4 (2048 dim) → Redis Stack HNSW/COSINE index oa-knowledge-index.
2.6 AI Assistant Conversation Flow (RAG + Tool Calling)
Diagram illustrates multi-turn chat with memory (20 messages), RAG retrieval (topK=5, threshold 0.45), and tool calls (LeaveTools, ExpenseTools, EmployeeTools). Anti-hallucination design: system prompt forces "balance and progress must call tools, no fabrication"; "if knowledge base lacks clause, explicitly answer not recorded"; tool internal user ID always from ToolContext / UserContext, preventing model from passing other user IDs for privilege escalation.
2.7 Business Rules Quick Reference
Table summarizing key rules with code locations:
Rule Item Value Code Location
Leave escalate BOSS threshold days > 3 ApprovalService.approveLeave
Expense escalate BOSS threshold amount > 5000 ApprovalService.approveExpense
Document status PENDING / APPROVED / REJECTED / CANCELLED ApprovalStatusEnum
Approval node MANAGER / BOSS / NONE ApprovalService constants
Leave type Annual / Personal / Sick / Compensatory / Marriage t_leave.leave_type
Expense type Travel / Office / Entertainment / Transport / Other t_expense.expense_type
Default password 123456 (MD5: e10adc3949ba59abbe56e057f20f883e) EmployeeService.save / resetPassword
New employee annual leave 5 days EmployeeService.initBalance
Gender Only "Male/Female", default "Male" t_sys_user.gender
Token expiry 24 hours oa.jwt.expire-hours
Upload root dir D:/uploads54, access prefix /uploads oa.upload.*Technology Stack
3.1 Backend Stack
Category Technology Version Purpose
Base Framework Spring Boot 4.0.8 App skeleton, auto-config, embedded container
Web spring-boot-starter-webmvc 4.0.8 REST APIs, interceptors, static resources
Validation spring-boot-starter-validation 4.0.8 Request param validation
AI Framework Spring AI 2.0.1 ChatClient, Advisor, Tool Calling, VectorStore
AI Model Access spring-ai-starter-model-openai 2.0.1 OpenAI-compatible protocol to Alibaba Cloud Bailian
Vector Store spring-ai-starter-vector-store-redis 2.0.1 Redis Stack vector retrieval
RAG spring-ai-vector-store-advisor 2.0.1 QuestionAnswerAdvisor knowledge augmentation
Doc Parsing spring-ai-tika-document-reader 2.0.1 Unified parsing of txt/doc/pdf/markdown
Persistence MyBatis-Plus (Spring Boot 4 Starter) 3.5.17 CRUD, Lambda conditions, pagination
SQL Parsing mybatis-plus-jsqlparser 3.5.17 Pagination plugin dependency
DB Driver mysql-connector-j (Boot) MySQL 8 connection
Cache/Vector spring-boot-starter-data-redis + Jedis Jedis 7.2.0 Redis connection & RediSearch vector index
Auth JJWT 0.12.6 JWT generation & parsing
Runtime JDK 17 Language versionCompatibility Note (Engineering Highlight) : Spring Boot 4 defaults to Lettuce, but Spring AI 2.0.1 Redis vector store depends on Jedis's RedisClient (provided since Jedis 7.2). Project explicitly upgrades Jedis and manually registers RedisVectorStore in RedisVectorStoreConfig (HNSW/COSINE). Meanwhile MyBatis-Plus requires 3.5.17 to adapt to Boot 4.0.8 removed APIs.
3.2 Frontend Stack
Category Technology Version Purpose
Framework Vue 3.5.42 Composition API SPA
Build Vite 8.3.0 Dev server (5173) & production build
UI Components Element Plus 2.11.4 Table, form, dialog; table columns auto-fit browser width
Icons @element-plus/icons-vue 2.3.2 Menu & button icons
State Mgmt Pinia 3.0.3 Login state, user info, roles
Routing Vue Router 4.5.1 Route guards + role menu filtering
HTTP Axios 1.12.2 Request/response interceptors, token injection, unified error toast
Charts ECharts 5.6.0 Dashboard statistics charts3.3 Middleware & External Services
Component Configuration Description
MySQL 8 127.0.0.1:3308 / db_ai_oa / root / 123456 Primary business data store
Redis Stack 7.x 127.0.0.1:6379, requires RediSearch module, index oa-knowledge-index, HNSW + COSINE Vector retrieval
Local File Storage D:/uploads54/{avatar,knowledge,expense}, organized by yyyyMMdd, UUID naming File storage
Alibaba Cloud Bailian .../compatible-mode/v1, chat qwen3.8-27b (temp 0.3), embedding text-embedding-v4 (2048 dim) LLM & embedding via OpenAI-compatible APISystem Architecture Design
4.1 Overall Architecture
Classic frontend-backend separation + layered architecture , 10 layers top-down: User → Frontend Presentation → Frontend Support → Security Access → Controller → Business Service → AI Capability → Data Access → Data Storage → External Services. Layers depend unidirectionally; AI Capability layer and Business Service layer are peers and reuse same Services (ensuring AI answers and page data share same source).
4.2 Request Processing Chain
Diagram shows request flow through filters, interceptors, controllers, services, AI tools, and data layer.
4.3 Backend Package Structure
com.java1234
├── OaApplication.java Startup class
├── ai
│ ├── config AI-related config
│ │ ├── ChatClientConfig ChatClient & ChatMemory (window 20)
│ │ ├── OpenAiCompatibleConfig OpenAI compat adapter + fixed vector dim
│ │ ├── FixedDimensionEmbeddingModel Avoid remote dim detection at startup
│ │ ├── EmbeddingUsageCompatInterceptor Compat missing prompt_tokens in response
│ │ └── RedisVectorStoreConfig Manual RedisVectorStore registration (HNSW/COSINE)
│ ├── service AiChatService / AiLeaveService / KnowledgeService
│ └── tool LeaveTools / ExpenseTools / EmployeeTools (@Tool)
├── common Result, PageResult, RoleEnum, ApprovalStatusEnum, BusinessException, GlobalExceptionHandler, LoginUser, UserContext (ThreadLocal), @RequireRole
├── config JacksonConfig (date format), MybatisPlusConfig (pagination), MetaObjectHandlerConfig (auto-fill), WebMvcConfig (CORS/interceptors/static mapping)
├── controller Auth / Home / Dept / Employee / Leave / Expense / Ai (7 controllers)
├── dto LoginRequest, LoginVO, PasswordDTO, ApprovalDTO, ChatRequest, ChatReplyVO, LeaveParseRequest, LeaveDraftVO
├── entity 10 entities mapping 1:1 to tables (incl. transient display fields)
├── interceptor JwtInterceptor (login + role)
├── mapper 10 BaseMappers + HomeStatMapper (annotation SQL stats)
├── service Auth / Employee / Dept / Leave / Expense / Approval / Home / Notice (8 services)
└── util JwtUtil, Md5Util, FileUtilAll classes and methods have Chinese comments; entity classes do not use Lombok, hand-written getters/setters.
4.4 Frontend Project Structure
client/src
├── main.js / App.vue
├── layout/index.vue Main frame: side menu (role-filtered) + top bar
│ Top-right avatar/name dropdown → Profile / Logout
├── router/index.js Route table + meta.roles guard
├── stores/user.js Pinia: token, user info, role
├── utils/request.js Axios instance with bidirectional interceptors
├── utils/format.js Date 2026-11-02, datetime 2026-11-02 17:25:17
├── components/AiAssistant Global bottom-right floating AI assistant
└── views
├── login Login page
├── home Index dispatches by role → AdminHome / BossHome / ManagerHome / EmployeeHome
├── dept / employee Dept & employee management
├── leave / expense Leave & expense (incl. AI form fill, voucher upload)
├── approval Approval center
├── knowledge / notice Knowledge base & announcements
├── aichat AI assistant full-screen page (session list + message stream + sources)
└── profile Personal center: left avatar upload + info, right password change4.5 Key Technical Implementation Points
Theme Implementation
Stateless Auth JWT carries id/username/realName/role/deptId/avatar, HMAC-SHA signature, 24h expiry
Role Auth Custom annotation @RequireRole, interceptor reads method/class annotation vs role, 403 on fail
Login Context UserContext based on ThreadLocal, cleaned in afterCompletion to avoid thread-pool leakage
Data Scope Isolation Each Service's applyScope(): employee sees self, manager sees dept, BOSS/ADMIN see all pending
Unified Response Result<T>{code,message,data}, pagination PageResult<T>{total,records}
Unified Exception BusinessException + GlobalExceptionHandler, 401/403/500 structured output
Pagination MyBatis-Plus PaginationInnerInterceptor
Time Format Jackson global yyyy-MM-dd HH:mm:ss + timezone Asia/Shanghai
File Upload FileUtil saves to subdir/yyyyMMdd/UUID.ext, returns /uploads/... relative URL, WebMvcConfig maps to disk
CORS Backend addCorsMappings allow; dev also Vite Proxy forwarding /api, /uploads
Password Security MD5 digest storage, change password validates old password and new/confirm match
Home Statistics HomeStatMapper annotation aggregation SQL (leave type pie, 6-month expense bar, dept headcount, status distribution, monthly expense total)AI Capability Architecture
5.1 Three AI Pipelines Comparison
Dimension Smart Leave Fill Smart Assistant (Chat) Knowledge Ingestion
Entry POST /api/ai/leave/parse POST /api/ai/chat POST /api/knowledge/upload
Memory None (single-turn) MessageWindowChatMemory 20 —
Knowledge Enhance None QuestionAnswerAdvisor (topK=5, threshold 0.45) —
Tool Calling LeaveTools LeaveTools / ExpenseTools / EmployeeTools —
Output Form Structured entity(LeaveDraftVO.class) Natural language text + source list Vector write
Fallback fillFallbackTip() with real balance tip Empty answer fallback phrase Failure sets vector_status=FAIL5.2 Tool Calling Tool Catalog
Tool Class Method Parameters Purpose
LeaveTools queryLeaveBalance none (userId from ToolContext) Query current year annual/personal/sick/compensatory quota & used
LeaveTools queryLeaveProgress keyword (optional) Query latest 5 leave requests status & current node
ExpenseTools queryExpenseProgress monthOffset (0/-1), keyword (opt) Query latest 8 expense requests real approval progress, approver, comments
EmployeeTools queryMyInfo none Query name, role, dept, entry date5.3 Vector Retrieval Parameters
Parameter Value
Index name oa-knowledge-index
Key prefix oa:kb:
Vector algorithm/distance HNSW / COSINE
Embedding model/dim text-embedding-v4 / 2048
Chunk size chunkSize=800, min chars 200, min embeddable 50
Retrieval topK/threshold 5 / 0.45
Metadata fields docId (tag), docName (text), fileType (tag)Functional Module Design
Four modules:
Basic Support : Login auth, personal center (avatar upload / info edit / password change, left-right layout), dept management, employee management, password reset, announcement management.
Process Office : Leave submit & cancel, leave balance, expense submit & voucher upload, approval center pending, approve/reject, approval log trace.
AI Intelligence : AI leave form fill, deduction & balance tips, multi-turn chat, session history, policy RAG Q&A with source citation, approval progress tool calls, knowledge base vectorization.
Data Dashboard : Admin global dashboard, manager approval desk, BOSS final review desk, employee personal desk; includes leave type pie, monthly expense bar, dept headcount, latest announcements.
Dashboard data differences per role:
Role Metric Cards Charts List
ADMIN Active staff, dept count, pending leave/expense Leave type dist, 6-mo expense, dept headcount, leave status dist Latest announcements
BOSS Pending final review leave/expense, in-flight count, monthly expense total 6-mo expense, leave status dist Pending final review leave/expense, announcements
MANAGER Dept pending leave/expense, dept headcount, monthly dept expense Dept leave type, dept 6-mo expense Dept pending, announcements
EMPLOYEE My pending leave/expense, approved leave, annual left My leave type, my 6-mo expense, my leave status My recent docs, announcementsDatabase Design
7.1 Design Overview
Database: db_ai_oa, charset utf8mb4 / utf8mb4_unicode_ci, MySQL 8 (port 3308).
All business tables prefixed t_, total 10 tables .
Primary key unified id BIGINT AUTO_INCREMENT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP.
Logical foreign keys (no physical constraints), service layer ensures consistency for sharding/migration ease.
Amount uses DECIMAL(12,2), days uses DECIMAL(6,1) to avoid floating errors.
Script location: server/src/main/resources/db/db_ai_oa.sql.
7.2 Table Catalog
# Table Name Chinese Name Description
1 t_dept Department Dept base info & manager
2 t_sys_user System User Unified account for four roles
3 t_leave_balance Leave Balance Quota per user+year
4 t_leave Leave Request Leave application main table
5 t_expense Expense Request Expense application main table
6 t_approval_record Approval Log Shared approval log for leave & expense
7 t_knowledge_doc Knowledge Doc Policy files & vectorization status
8 t_chat_session AI Session Maps to Spring AI conversationId
9 t_chat_message AI Message Session messages & RAG sources
10 t_notice Announcement System announcements7.3 Table Structure Details
Each table defined with columns, types, lengths, nullability, comments. Key highlights: t_dept: id, dept_name, dept_code, manager_id (logic FK to t_sys_user), parent_id (0=top), sort_num, remark, create_time. t_sys_user: id, username (unique), password (MD5, init 123456), real_name, role (ADMIN/BOSS/MANAGER/EMPLOYEE), dept_id, gender (Male/Female default Male), phone, email, avatar (relative path), entry_date, status (1 enabled/0 disabled), create_time. t_leave_balance: id, user_id, year_num, annual_total (default 10, new employee 5), annual_used, sick_used, personal_used, compensatory_total, compensatory_used. Unique constraint uk_user_year (user_id, year_num). t_leave: id, user_id, dept_id (redundant for dept isolation), leave_type (Annual/Personal/Sick/Compensatory/Marriage), start_date, end_date, days (DECIMAL(6,1), supports 0.5, >3 escalates), reason, status (PENDING/APPROVED/REJECTED/CANCELLED), current_node (MANAGER/BOSS/NONE), ai_generated (1/0), create_time. t_expense: id, user_id, dept_id, expense_type (Travel/Office/Entertainment/Transport/Other), amount (DECIMAL(12,2), >5000 escalates), expense_date, reason, attachment (comma-separated paths), status, current_node, create_time. t_approval_record: id, biz_type (LEAVE/EXPENSE), biz_id, node_name (MANAGER/BOSS), approver_id, approver_role, action_type (APPROVE/REJECT), comment_text, create_time. t_knowledge_doc: id, doc_name (original filename, used as RAG source), file_path, file_type (txt/doc/pdf/md), file_size, chunk_count, vector_status (PENDING/SUCCESS/FAIL), uploader_id, create_time. t_chat_session: id, session_id (UUID no hyphens, unique, maps to Spring AI conversationId), user_id (for ownership check), title (default "New Conversation", auto from first 20 chars), create_time, update_time (ON UPDATE). t_chat_message: id, session_id, role_name (user/assistant), content (MEDIUMTEXT ~16MB), sources_json (comma-separated doc names), create_time. t_notice: id, title, content (TEXT ~64KB), publisher, create_time.
7.4 Indexes & Constraints Summary
Table Constraint/Index Fields Type
All tables PRIMARY KEY id PK, BIGINT auto-inc
t_sys_user UNIQUE username Login account unique
t_leave_balance UNIQUE uk_user_year user_id, year_num Employee yearly balance unique
t_chat_session UNIQUE session_id Session UUID unique7.5 Initialization Test Data
Table Rows Description
t_dept 4 HR, Tech, Finance, Marketing
t_sys_user 16 1 admin + 1 boss + 4 managers + 10 employees, password 123456 (MD5 stored)
t_leave_balance 14 2026 year balances
t_leave 25 Covers 5 leave types, 4 statuses, Apr-Sep 2026
t_expense 20 5 expense types, includes >5000 final review cases & voucher-attached pending
t_approval_record 18 Completed two-level approval logs
t_notice 3 AI assistant enable notice, holiday schedule, expense reminderAPI Design
Unified prefix /api, unified response {"code":200,"message":"操作成功","data":{}}; except /api/auth/login all require Authorization: Bearer <token>.
Key endpoints (module, method, path, permission, description):
Auth POST /api/auth/login Public Username/password login, returns token & user info
Auth GET /api/auth/info Login Current user details (incl dept name, role name)
Profile PUT /api/profile Login Update name, gender, phone, email
Profile PUT /api/profile/password Login Change password (verify old + confirm match)
Profile POST /api/profile/avatar Login Upload avatar
Home GET /api/home/stats Login Returns dashboard data per role
Notice GET /api/notice/page Login Announcement pagination
Notice POST/PUT/DELETE /api/notice ADMIN Announcement CRUD
Dept GET /api/dept/page, /list Login Dept pagination / full list
Dept POST/PUT/DELETE /api/dept ADMIN Dept CRUD
Employee GET /api/employee/page, /{id} ADMIN,MANAGER Employee pagination (manager only own dept), detail
Employee POST/PUT/DELETE /api/employee ADMIN Employee CRUD
Employee POST /api/employee/{id}/resetPassword ADMIN Reset password to 123456
Employee GET /api/employee/managers Login Dept manager candidate list
Leave GET /api/leave/page Login Pagination (status, leaveType, pendingOnly)
Leave GET /api/leave/{id} Login Detail + approval log
Leave POST /api/leave Login Submit leave request
Leave POST /api/leave/{id}/cancel Login Cancel own pending request
Leave POST /api/leave/approve NodeRole Approve / reject
Leave GET /api/leave/balance Login My leave balance
Expense GET /api/expense/page, /{id} Login Pagination, detail
Expense POST /api/expense Login Submit expense request
Expense POST /api/expense/{id}/cancel Login Cancel
Expense POST /api/expense/approve NodeRole Approve / reject
Expense POST /api/expense/attachment Login Upload voucher images
AI POST /api/ai/leave/parse Login Natural language → leave draft
AI POST /api/ai/chat Login Multi-turn chat (RAG + tools)
AI POST /api/ai/session Login New session
AI GET /api/ai/session/list Login Session list
AI GET /api/ai/session/{id}/messages Login Session messages
AI DELETE /api/ai/session/{id} Login Delete session & memory
Knowledge GET /api/knowledge/page ADMIN Document pagination
Knowledge POST /api/knowledge/upload ADMIN Upload & vectorize
Knowledge DELETE /api/knowledge/{id} ADMIN Delete document & vectorsSigned-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
java1234
Former senior programmer at a Fortune Global 500 company, dedicated to sharing Java expertise. Visit Feng's site: Java Knowledge Sharing, www.java1234.com
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
