Kirish
AI funksiyalarini xizmatlarga qo‘shganda tezda bunday vaziyatga duch kelasiz.
Xususiyatlariga qarab bir-biridan farq qiluvchi ChatModelni ishlatmoqchiman, buni qanday boshqarishim kerak?
Sayyohlik joylarini tavsiya qiluvchi AI xizmatini ishlab chiqish jarayonida aslida bunday muammoga duch keldim.
Dastlab men faqat matn asosidagi muloqot modelidan yetarli deb o'yladim. Ammo sayyohlik joyining tasviri kiritilganda, ushbu tasvirni tahlil qilib, tasvirning xususiyatlari va tavsifini chiqarishim kerak edi. Bunday holatda Matn asosidagi modellardan foydalanib, rasmni tushunib bo'lmaydi되었습니다.
Nihoyat, ikkita model kerak bo'ldi.
Matn modeli: tezkor javoblar va uzun kontekstni qayta ishlashga mos keladigan muloqotga ixtisoslashgan model
Ko'p modalli model: tasvirlarni qabul qilib, mazmunini tushunadigan ko'rsatma yordam beruvchi model
Bu erda muammo boshlanadi.
Spring Boot + LangChain4J muhitida bir nechta ChatModelni qanday boshqarish kerak?
LangChain4J avtomatik sozlashning cheklovlari
LangChain4J Spring Boot avtomatik sozlashni qo'llab-quvvatlaydi. Masalan, application.yml faylida quyidagicha sozlash qilsangiz, ChatModel obyekti avtomatik ravishda ro'yxatga olinadi.
langchain4j:
ollama:
chat-model:
base-url: https://ollama.example.com
model-name: model-name
Ammo bu usulda cheklovlar mavjud.
Avtomatik sozlash asosan bitta ChatModel bo'shligini ro'yxatga olish usuliyaqin emas. Shuning uchun turli maqsadlar uchun bir nechta modellardan foydalanish zarur bo'lsa, avtomatik sozlamalarga to'liq bog'lanish qiyin.
Natijada, bir nechta modellarning boshqarilishini aniq amalga oshirish uchun to'g'ridan-to'g'ri @Bean ni aniqlash usuli kerak.
Usullarni taqqoslash
Usul 1. @Qualifier bilan farqlash
Eng birinchi o'ylab ko'rish mumkin bo'lgan usul - bu @Qualifier ni har bir model binosiga nom berish uchun ishlatishdir.
@Configuration
public class ModelConfig {
@Primary
@Bean
@Qualifier("textChatModel")
public ChatModel textChatModel() {
return OllamaChatModel.builder()
.baseUrl("https://ollama.example.com")
.modelName("chat-model-name")
.build();
}
@Bean
@Qualifier("imageChatModel")
public ChatModel imageChatModel() {
return OllamaChatModel.builder()
.baseUrl("https://ollama.example.com")
.modelName("multi-modal-model-name")
.build();
}
}
Foydalanish tomoni quyidagicha inject qilinadi.
@Service
public class SomeService {
private final ChatModel textModel;
private final ChatModel imageModel;
public SomeService(
@Qualifier("textChatModel") ChatModel textModel,
@Qualifier("imageChatModel") ChatModel imageModel
) {
this.textModel = textModel;
this.imageModel = imageModel;
}
}
Bu usul oddiy va intuitivdir. Ammo model ko'paygani sayin @Qualifier qatori bir nechta sinflarga tarqaladi.
Qator asosida bo'lgani uchun xatolar paydo bo'lsa, ular kompilyatsiya paytida aniqlanmaydi va modelni almashtirish yoki nomni o'zgartirish holatlarida ta'sir doirasi kengayadi.
2-usul. @Qualifier + Proxy klassini ishlatish
Ikkinchi usul @Qualifier ni to'g'ridan-to'g'ri biznes mantiqiga oshkor qilmasdan, modelga qarab Proxy klasslarini o'rab olish usulidir.
Hozirgi loyihada ushbu usul ishlatilmoqda.
@Service
public class ChatModelProxy {
private final ChatModel chatModel;
private final ObjectMapper objectMapper;
public ChatModelProxy(
@Qualifier("textChatModel") ChatModel chatModel,
ObjectMapper objectMapper
) {
this.chatModel = chatModel;
this.objectMapper = objectMapper;
}
public String chat(Prompt prompt) {
// 텍스트 모델 호출
}
public T chat(Prompt prompt, Class clazz) {
// 응답 JSON 파싱
}
public List chatAnswerInList(Prompt prompt, Class
clazz) { // 리스트 형태 응답 파싱 } }
Rasmni tahlil qilish uchun mo'ljallangan model alohida Proxy-ga ajratiladi.
@Service
public class ImageChatModelProxy {
private final ChatModel chatModel;
public ImageChatModelProxy(
@Qualifier("imageChatModel") ChatModel chatModel
) {
this.chatModel = chatModel;
}
public String chatWithImage(String imageUrl, String textPrompt) {
String base64 = fetchAsResizedBase64(imageUrl);
String mimeType = detectMimeType(imageUrl);
UserMessage message = UserMessage.from(
ImageContent.from(base64, mimeType, ImageContent.DetailLevel.AUTO),
TextContent.from(textPrompt)
);
return chatModel.chat(message).aiMessage().text();
}
}
Shunday qilib, biznes mantiq @Qualifier bilan bog'liq bo'lishi shart emas.
@Service
public class ChatTask {
private final ChatModelProxy chatModelProxy;
private final ImageChatModelProxy imageChatModelProxy;
public ChatTask(
ChatModelProxy chatModelProxy,
ImageChatModelProxy imageChatModelProxy
) {
this.chatModelProxy = chatModelProxy;
this.imageChatModelProxy = imageChatModelProxy;
}
}
Ushbu usulning afzalliklari aniqdir.
@Qualifier satri Proxyning ichida mavjud bo'lib, xizmat qatlamlari har bir modelning aniq bo'sh nomlarini bilmasligi mumkin. Shuningdek, tasvirni yuklab olish, Base64 kodlash, JSON parsi kabi modelga xos oldingi va keyingi ishlov berish mantiqlari ham Proxyning ichida kapsulalash mumkin.
Usul 3. Sozlamalar asosidagi model ro'yxatini ishlatish
Model uchtadan ortiq bo'lsa yoki faqat sozlash orqali model qo'shish yoki almashtirish kerak bo'lsa, registry naqshini ham ko'rib chiqishingiz mumkin.
@Configuration
public class ModelRegistryConfig {
@Bean
public Map chatModelRegistry(ModelProperties props) {
Map registry = new HashMap<>();
props.getModels().forEach((name, config) -> {
ChatModel model = OllamaChatModel.builder()
.baseUrl(config.getBaseUrl())
.modelName(config.getModelName())
.build();
registry.put(name, model);
});
return registry;
}
}
Sozlashni quyidagicha boshqarish mumkin.
my-service:
models:
text:
base-url: https://ollama.example.com
model-name: text-model-name
timeout: 10m
image:
base-url: https://ollama.example.com
model-name: multi-modal-model-name
timeout: 30m
Bu usul, ko'plab modellarning mavjudligi yoki modelni sozlash asosida almashtirish kerak bo'lganda foydalidir.
Biroq, kamchiliklari ham bor. Modellarga qarab zarur bo'lgan oldindan qayta ishlash natijalari farq qilganda, oddiygina Map
Masalan, rasm modeliga rasm yuklash, o'lchamni o'zgartirish, MIME turini aniqlash va Base64 kodlash talab etiladi. Bunday mantiq oxir-oqibat ro'yxatdan tashqari alohida xizmat yoki Proxy qatlamiga joylashtiriladi.
Shu sababli, model chaqiruv usuli oddiy va bir xil bo'lsa, registr yaxshi, lekin modeldan modelga foydalanish usuli farq qilsa, Proxy usuli tabiiyroq hisoblanadi.
Hozirgi loyiha uchun tanlangan usul
Hozirgi loyiha davomida @Qualifier + Proxy sinfi usuliSiz tanladingiz.
|
element |
Baholash |
|
@Qualifier matnining ko'rsatish doirasi |
Proxy sinfi ichida izolyatsiya |
|
Modelga xos oldindan ishlov berish mantiqini ajratish |
Rasmni qayta o'lchash, kodlash mantiqini ImageChatModelProxy ga kapsulalash |
|
Matn modeli qo'shimchalari |
JSON parsi, ro'yxat javoblarini parsi qilish kabi narsalarni ChatModelProxy'da jamlash |
|
Biznes kodining birikkanligi |
Xizmat faqat Proxy turidan bog'liq |
Ikkita modelning roli aniq farq qiladi.
Matn modeli oddiy suhbat, JSON javobni tahlil qilish kabi ishlarda foydalaniladi. Boshqa tomondan, tasvir modeli tasvirlarni qabul qilish uchun alohida oldindan ishlov berish jarayoniga muhtoj.
Shuning uchun, ikkita modelni majburan bitta interfeysga birlashtirish o'rniga, har biri o'z mas'uliyatiga ega bo'lgan Proxy sifatida ajratish yaxshiroq bo'ladi.
Albatta, model 3 tadan ko'proq bo'lsa yoki ishlash vaqtida modelni tanlash talabi paydo bo'lsa, ro'yxatga olish usulini ko'rib chiqishimiz mumkin.
Xulosa qilib
LangChain4J avtomatik sozlash orqali bir nechta ChatModelni aniq boshqarish qiyin.
Agar bir nechta modeldan foydalanishingiz kerak bo'lsa, to'g'ridan-to'g'ri @Beanni belgilab, @Qualifier yordamida farqlashingiz mumkin.
Proxy yordamida modelga xos oldingi va keyingi ishlov berish logikasini kapsül qilish mumkin, biznes logikasi modelning bo'sh nomini bilmasligi shart emas.
Model soni ko'payganda yoki sozlamalar asosida almashtirish muhim bo'lganda, registrlar naqshidan foydalanishni o'ylab ko'rish mumkin.
Shaxsiy ravishda, bu holatda Proxy usuli eng mos tanlovdeb hisoblayman.
Matn modeli va tasvir modeli oddiygina "ChatModel ikkita" emas, balki foydalanish usuli va mas'uliyat o'ziga xosdir. Shuning uchun umumiy interfeys yoki ro'yxatga olishdan oldin avval modelga xos mas'uliyatlarni aniq ko'rsatadigan Proxy qo'yish, texnik xizmat ko'rsatish jihatidan yaxshiroqdir.
Ted