بهار Ai و Ollama – ساخت یک چت بابات منبع باز

ما از تازه منتشر شده استفاده خواهیم کرد بهار ai 1.0 ga نسخه ، آماده برای تولید، برای ساختن یک برنامه چت با Spring AI ، Ollama ، Docker و ارائه مدیریت حافظه چت جعبه.
بگذارید توسعه دهندگان جاوا بتوانند به سرعت و به راحتی هوش مصنوعی را به پروژه های خود اضافه کنند.
وابستگی ها:
- جاوا 21
- وب بهار
- اولاما
- پایگاه داده H2
- مخزن حافظه چت JDBC
- محرک بوت بهار
چرا بهار ai + ollama؟
چشم انداز مهندسی هوش مصنوعی دیگر فقط پایتون محور نیست. با بهار شما، توسعه دهندگان جاوا اکنون می توانند با استفاده از مدل های منبع باز مانند Llama 3 ، Gemma ، Deepseek-R1 و موارد دیگر ، برنامه های با قدرت AI بسازند!
و بهترین قسمت این است: شما می توانید از طریق آنها میزبانی محلی را شروع کنید اولامابشر
در این مقاله ، چگونه یاد می گیرید:
- Ollama را به عنوان سرور محلی LLM خود (Docker) تنظیم کنید.
- آن را با AI بهار به عنوان یک چارچوب مهندسی AI مستقر در جاوا ادغام کنید.
- با سابقه مکالمه یک جلسه چند کاربره ایجاد کنید
- ساخت جریان چت بابات با استفاده از رویدادهای سرور SENT (SSE) و یک جبهه آسان (HTML/CSS/JS).
- dockerizing برای توسعه محلی و استفاده
بیایید شیرجه بزنیم!
1. تنظیم مدل های Ollama و بارگیری
ما می توانیم استفاده از مدل های جمع و جور را با پارامترهای کم و بیش 1B شروع کنیم. برای کارهای ایجاد شده در متن ، مدل های کوچک انتخاب خوبی برای شروع کار هستند.
اولاما به شما امکان می دهد LLM های منبع باز را به صورت محلی اجرا کنید. در اینجا نحوه شروع کار آورده شده است:
نصب Ollama (از طریق Docker)
docker run -d -v ./ollama/ollama-server:/root/.ollama -p 11434:11434 --name ollama ollama/ollama
بارگیری مدل ها (انتخاب یک یا چند)
docker exec ollama ollama pull llama3.2:1b # Meta's Llama 3
docker exec ollama ollama pull gemma3:1b # Google's Gemma
docker exec ollama ollama pull deepseek-r1:1.5b # Deepseek's R1
تأیید کنید که در حال اجرا است:
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2:1b",
"prompt": "Hello, world!"
}'
2. مهندسی AI 101: فراتر از پایتون
در حالی که پایتون بر ابزار AI حاکم است ، جاوا در حال جلب توجه است با چارچوب هایی مانند بهار هوش مصنوعی.
مفاهیم کلیدی:
مدلهای پایه: LLMS از قبل آموزش دیده (به عنوان مثال ، لاما 3) که می توانید تنظیم کنید.
API های استنباط: ابزارهایی مانند Ollama به شما امکان می دهد این مدل ها را بصورت محلی اجرا کنید.
مهندسی هوش مصنوعی: هنر ادغام LLM ها در برنامه های دنیای واقعی (به عنوان مثال ، چت بابات ، سیستم های RAG).
3. بهار AI + Ollama: Java با LLMS ملاقات می کند
بهار هوش مصنوعی بهترین انتخاب برای آوردن قابلیت های هوش مصنوعی به اکوسیستم بهار است. در اینجا نحوه اتصال آن به اولاما آورده شده است:
- مرحله 3.1: AI بهار را به پروژه خود اضافه کنید
org.springframework.ai
spring-ai-starter-model-ollama
org.springframework.ai
spring-ai-starter-model-chat-memory-repository-jdbc
com.h2database
h2
runtime
- مرحله 3.2: اولاما را در پیکربندی کنید
application.yml
spring:
application:
name: demo-chatbot
ai:
ollama:
base-url: http://localhost:11434
chat:
model: llama3.2:1b # deepseek-r1:1.5b, gemma3:1b
chat:
memory:
repository:
jdbc:
# https://docs.spring.io/spring-ai/reference/1.0/api/chat-memory.html#_schema_initialization
initialize-schema: always
schema: classpath:sql/schema-h2.sql
datasource:
url: jdbc:h2:mem:~/demo-chatbot
driverClassName: org.h2.Driver
username: sa
password: password
h2:
console:
enabled: true
path: /h2
- مرحله 3.3: با LLM از جاوا تماس بگیرید
در ChatClient
یک API مسلط برای برقراری ارتباط با یک مدل هوش مصنوعی ارائه می دهد.
در Default System Prompt
یک الگوی سریع ساده ایجاد می کند و لحن را برای پاسخ ها تنظیم می کند.
در Advisors API
یک روش انعطاف پذیر برای رهگیری ، اصلاح و تقویت تعامل با یک مدل فراهم می کند.
(LLMS) بدون تابعیت هستند ، به این معنی که آنها اطلاعات مربوط به تعامل قبلی را حفظ نمی کنند.
بهار ai خودکار پیکربندی ChatMemory
لوبیا که به شما امکان می دهد پیام ها را در چندین تعامل ذخیره و بازیابی کنید. برای H2 شما باید طرح را ایجاد کنید. آن را درون آن قرار دهید: src/main/resources/sql/schema-h2.sql
CREATE TABLE IF NOT EXISTS SPRING_AI_CHAT_MEMORY (
conversation_id VARCHAR(36) NOT NULL,
content TEXT NOT NULL,
type VARCHAR(10) NOT NULL CHECK (type IN ('USER', 'ASSISTANT', 'SYSTEM', 'TOOL')),
"timestamp" TIMESTAMP NOT NULL
);
CREATE INDEX IF NOT EXISTS SPRING_AI_CHAT_MEMORY_CONVERSATION_ID_TIMESTAMP_IDX
ON SPRING_AI_CHAT_MEMORY(conversation_id, "timestamp");
@Configuration
public class ChatConfig {
@Bean
public ChatClient chatClient(ChatClient.Builder builder, ChatMemory chatMemory) {
String defaultSystemPrompt = """
Your are a useful AI assistant, your responsibility is provide users questions
about a variety of topics.
When answering a question, always greet first and state your name as JavaChat
When unsure about the answer, simply state that you don´t know.
""";
return builder
.defaultSystem(defaultSystemPrompt)
.defaultAdvisors(
new SimpleLoggerAdvisor(), //simply logs requests and responses with a Model
new PromptChatMemoryAdvisor(chatMemory) //let Spring AI manage long term memory in the DB
)
.build();
}
}
@RequestMapping("/api/chat")
@RestController
public class ChatController {
@Autowired
private ChatClient chatClient;
@GetMapping
public String chat(@RequestParam String question, @RequestParam String chatId) {
return chatClient
.prompt()
.user(question)
.advisors(advisor -> advisor
.param(ChatMemory.CONVERSATION_ID, chatId))
.call()
.content();
}
}
آن را امتحان کنید: curl "http://localhost:8080/api/chat?question=Tell%20me%20a%20joke"
4. گفتگوی چت با رویدادهای سرور (SSE)
SSE یک پروتکل سبک برای در زمان واقعیبا جریان یک طرفه از سرور به مشتری (مناسب برای chatbots). بر خلاف WebSockets (دو طرفه) ، SSE برای مواردی مانند پخش LLM ساده تر است.
SSE همچنین UX بهتری را برای کاربران نهایی فراهم می کند ، زیرا پاسخ ها به محض آماده شدن منتشر می شوند (برخی از پاسخ های پیچیده می توانند یک دقیقه یا بیشتر طول بکشد). بیایید پاسخ ها را با استفاده از SSE پخش کنیم:
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ChunkResponseDTO> streamChat(@RequestParam String question, @RequestParam String chatId) {
return chatClient
.prompt()
.user(question)
.advisors(advisor -> advisor
.param(ChatMemory.CONVERSATION_ID, chatId))
.stream()
.content()
.map(chunk -> new ChunkResponseDTO(chunk));
}
جزئیات کلیدی:
-
text_event_stream_value: هدر
text/event-stream
SSE را فعال می کند. -
قالب SSE: هر پیام باید به پایان برسد
\n\n
بشر پیشوند باdata:
برای انطباق -
جریان های واکنشی:
Flux
(از پروژه راکتور) جریان جریان ناهمزمان را انجام می دهد.
public record ChunkResponseDTO(String value) {}
محدودیت با HTTP/1.1
محدودیت های اتصال:
- مرورگرها فقط 6 اتصال همزمان HTTP/1.1 را در هر دامنه مجاز می کنند.
- SSE یک اتصال در هر جریان مصرف می کند ، که می تواند درخواست های دیگر را مسدود کند.
ارتقاء به HTTP/2 برای عملکرد
HTTP/2 تنگناهای SSE را با:
چند برابر: چندین جریان بیش از یک اتصال TCP. حداکثر تعداد جریانهای HTTP همزمان بین سرور و مشتری مذاکره می شود (پیش فرض تا 100)
نحوه فعال کردن HTTP/2 در بوت بهار
- مرحله 4.1: پیکربندی HTTP/2 در
application.yml
server:
http2:
enabled: true
ssl:
enabled: true
key-store: classpath:keystore.p12
key-store-password: yourpassword
- مرحله 4.2: یک گواهینامه خود امضا کنید (فقط برای آزمایش):
keytool -genkeypair -alias mydomain -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 365
تأیید کنید HTTP/2 فعال است (-k برای اعتماد به گواهینامه خود امضا شده)
curl --head -k https://localhost:8080/actuator/health
Frontend:
شروع با JavaScript:
const chatStream = (question) => {
const eventSource = new EventSource(`https://localhost:8080/api/chat/stream?chatId=1&question=${encodeURIComponent(question)}`);
eventSource.onmessage = (e) => {
console.log('New message:', JSON.parse(e.data).value);
// Append to UI (e.g., a chat div)
document.getElementById('messages').innerHTML += JSON.parse(e.data).value;
};
eventSource.onerror = (e) => {
console.error('SSE error:', e);
eventSource.close();
};
};
// Usage
chatStream("Tell me about Java");
جزئیات کلیدی:
EventSource
: API مرورگر بومی برای SSE (هیچ کتابخانه ای لازم نیست).
اتصال مجدد خودکار: اگر اتصال کاهش یابد ، منطق آزمایش مجدد داخلی.
رندر جلو برای خروجی LLM
پاسخ های LLM اغلب شامل Markdown یا HTML است (به عنوان مثال ، **bold**
با ), which can lead to
XSS vulnerabilities
if rendered naively.
Here’s how to secure your frontend:
- Step 4.3: Sanitize Markdown/HTML (Critical!) Use DOMPurify to sanitize raw LLM output before rendering:
"https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.6/purify.min.js">
eventSource.onmessage = (e) => {
const chunkResponse = JSON.parse(e.data).value);
console.log('New message:', chunkResponse);
const sanitized = DOMPurify.sanitize(chunkResponse); // Strips malicious scripts
// Append to UI (e.g., a chat div)
document.getElementById('messages').innerHTML += sanitized;
};
- مرحله 4.4: برای پشتیبانی از علامت گذاری (اختیاری)
اگر می خواهید با خیال راحت علامت گذاری را ارائه دهید، از کتابخانه ای مانند Marked + Dompurify استفاده کنید:
"https://cdn.jsdelivr.net/npm/marked/marked.min.js">
let chunkResponses = '';
eventSource.onmessage = (e) => {
chunkResponses += JSON.parse(e.data).value;
// Sanitize all chunks received so far.
DOMPurify.sanitize(chunkResponses);
// Check if the output was insecure.
if (DOMPurify.removed.length) {
// If the output was insecure, immediately stop what you were doing.
// Reset the parser and flush the remaining Markdown.
chunkResponses = '';
return;
}
// Append to UI (e.g., a chat div)
document.getElementById('messages').innerHTML = marked.parse(chunkResponses);
};
ملاحظات امنیتی کلیدی: هرگز به خروجی LLM اعتماد نکنید (و نه ورودی کاربر)
- فرض کنید تمام پاسخ های LLM ممکن است حاوی کد مخرب (حتی ناخواسته) باشد.
- فرض کنید کاربران سعی می کنند کد شما را بشکنند و امنیت شما را آزمایش کنند.
- حمله مثال: سلام
محدودیت با API EventSource
حتی اگر استفاده از SSE در سمت مشتری آسان باشد ، API EventSource محدودیت هایی دارد:
- بدون هدر درخواست سفارشی: هدرهای درخواست سفارشی مجاز نیستند.
- http فقط دریافت کنید: هیچ راهی برای مشخص کردن روش HTTP دیگر وجود ندارد.
- بدون بدنه درخواست: تمام پیام های گپ باید در URL باشد که در اکثر مرورگرها به 2000 کاراکتر محدود می شود.
- کتابخانه های پسوند را برای EventSource و SSE بررسی کنید: Fetch Source ، Fetch API + getReader ()
- مرحله 4.5: شروع ساختار HTML
در اینجا ساختار HTML وجود دارد که شامل یک فرم برای ورودی کاربر ، یک ظرف برای نمایش داده های پخش شده و یک نوار جانبی برای تاریخچه پیام است.
lang="en">
Spring AI Chat
rel="stylesheet" href="layout.css">
id="sidebar">
Chat History
id="chat-container">
id="messages">
"main.js">
"https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.6/purify.min.js">
"https://cdn.jsdelivr.net/npm/marked/marked.min.js">
HTML را در src/main/resources/static/index.html
جاوا اسکریپت را در src/main/resources/static/js/main.js
5. بهار AI + Ollama Chatbot خود را با Docker مستقر کنید
- مرحله 5.1 Docker Compose Setup
ایجاد کردن ollama-docker-compose.yaml
(PS اگر دستگاه شما از GPU پشتیبانی می کند ، می توانید شتاب GPU را در داخل ظروف Docker فعال کنید. اسناد تصویر Ollama)
services:
# Ollama LLM inference server
ollama:
volumes: # Ollama with persistent storage (no redownloading models).
- ./ollama/ollama-server:/root/.ollama
container_name: ollama
pull_policy: always
tty: true
restart: unless-stopped
image: docker.io/ollama/ollama:latest
ports:
- 11434:11434
environment:
- OLLAMA_KEEP_ALIVE=24h
# Enable GPU support
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
# Spring AI Backend
chat-app:
build:
context: . # Dockerfile in the root folder
container_name: chat-app
ports:
- "8080:8080"
environment:
- SPRING_AI_OLLAMA_BASE_URL=http://ollama:11434
depends_on:
- ollama
- مرحله 5.2 Boot Boot Dockerfile
# Maven build stage
FROM maven:3.9.9-eclipse-temurin-21-alpine as build
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src/ ./src/
RUN mvn clean package
# Spring Boot package stage
FROM eclipse-temurin:21-jre-alpine
COPY --from=build app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
- همه چیز را با استفاده از
docker-compose build && docker-compose up -d
- حرکت به:
https://localhost:8080
و جلسه چت خود را شروع کنید
- اگر می خواهید ببینید که چگونه پیام ها در پایگاه داده ذخیره می شوند ، به کنسول H2 بروید
https://localhost:8080/h2
نتیجه گیری: آینده هوش مصنوعی جاوا شما
معماری نهایی
شما فقط یک میزبان محلی ، چت بابات منبع باز با بهار AI و Ollama ، هیچ هزینه API OpenAi یا پایتون لازم نیست!
SSE + http/2 + بهار ai = جریان LLM مقیاس پذیر و در زمان واقعیبشر
کجا برویم؟
- کد کامل را پرداخت کنید
- آزمایش کردن RAG (نسل بازیابی-آمریكا) با استفاده از API مدل تعبیه شده AI بهار AI و پایگاه داده های بردار.
چه چیزی می سازید؟ افکار خود را در نظرات به اشتراک بگذارید! 👇
(PS من را برای آموزش بیشتر Java + AI دنبال کنید!)