Kirish
AI funktsiyalarini xizmatga qo'shganda tezda bunday vaziyatga duch kelasiz. Foydalanuvchi o'zgartirish. Ha, o'zgartirdim.
Boshqaruvchi o'zgartirish boshqaruvchisi matnini tekshirish
Turli funktsiyalarga ko'ra turli ChatModellardan foydalanmoqchiman, qanday boshqarishim kerak?
Sayohat joylarini tavsiya qilish AI xizmatini ishlab chiqish jarayonida bu muammoga duch keldim.
Dastlab, matn asosidagi suhbat modeli yetarli deb o'yladim. Ammo sayohat joyining rasm bermoqda, ushbu rasmani tahlil qilib, rasmning xususiyatlari va tavsifini chiqarishim kerak edi. Bu holatda Matnga asoslangan model faqatgina tasvirlarni tushunishi mumkin emas.
Natijada, quyidagi ikki modelga ehtiyoj paydo bo'ldi.
-
Matn modeli: tez javob berish va uzoq kontekstni qayta ishlash uchun mo'ljallangan muloqotga xos model
-
Ko'p modali model: tasvirlarni qabul qilib, mazmunni tushunishga qodir bo'lgan ko'rish qo'llab-quvvatlash modeli
Bu yerda muammo boshlandi.
Spring Boot + LangChain4J muhitida bir nechta ChatModelni qanday boshqarish kerak?
LangChain4J avtomatik sozlashning chegaralari
LangChain4J Spring Boot avtomatik sozlashni qo'llab-quvvatlaydi. Masalan, application.yml ga quyidagicha sozlangan bo'lsa, ChatModel bean avtomatik ravishda ro'yxatdan o'tkaziladi.
langchain4j:
ollama:
chat-model:
base-url: https://ollama.example.com
model-name: model-name
Lekin bu usulning cheklovlari bor.
Avtomatik sozlash asosanBitta ChatModel bo'shliqni ro'yxatdan o'tkazish usuliyaqin. Shuning uchun turli maqsadlar uchun bir necha model ishlatish zarur bo'lsa, avtomatik sozlashga to'liq tayanish qiyin.
Nihoyat bir necha modelni aniq boshqarish uchun to'g'ridan-to'g'ri @Bean ni aniqlash usuli zarur.
Usullarni taqqoslash
Usul 1. @Qualifier bilan ajratish
Birinchidan, @Qualifier dan foydalanib har bir model bo'shlig'iga nom berish usuli eng ko'p esga olinadi.
@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();
}
}
Foydalanadigan tomonda quyidagicha kiritiladi.
@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;
}
}
Ushbu usul oddiy va intuitivdir. Biroq, model ko'paygan sari @Qualifier satri bir nechta sinflarga tarqaladi.
Matn ga asoslanganligi sababli, xato bo'lsa ham, ularni kompilyatsiya paytida aniqlash qiyin va modelni almashtirish yoki nomni o'zgartirish vaqtida ta'sir doirasi ham kengayadi.
Usul 2. @Qualifier + Proxy sinfini ishlatish
Ikkinchi usul @Qualifier ni to'g'ridan-to'g'ri biznes mantiqiga oshkor qilmasdan, modelga xos Proxy sinflari bilan o'rab olish usulidir.
Hozirgi loyihada ushbu usuldan foydalanilmoqda.
@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) {
// 리스트 형태 응답 파싱
}
}
Rasmiy tahlil uchun maxsus modelni alohida Proxyga ajratish kerak.
@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();
}
}
Bunday hollarda biznes mantiq @Qualifier haqida endi bilishining hojati yo'q.
@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 aniq.
@Qualifier satri faqat Proxy ichida mavjud va xizmat qatlamiga modelning aniq bean nomlarini bilish shart emas. Shuningdek, rasmni yuklab olish, Base64 kodlash, JSONni parselash kabi modelga xos oldindan va keyin ishlov berish mantiqlari ham Proxy ichida kapsüllaşdırilishi mumkin.
Usul 3. Sozlamalarga asoslangan model registridan foydalanish
Agar modellar soni uchdan ortiq bo'lsa yoki faqat sozlamalar orqali modellarni qo'shish yoki almashtirish kerak bo'lsa, registr shablonini ham hisobga olish 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;
}
}
Sozlamalarni 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
Ushbu usul ko'p model mavjud bo'lganda yoki sozlamalar asosida modelni almashtirish kerak bo'lganda foydalidir.
Biroq, kamchiliklari ham bor. Modelga qarab kerakli oldindan tayyorlash mantiqlari farq qilganda, faqatgina Map bilan boshqarish etarli bo'lmaydi.
Masalan, tasvir modeli tasvirni yuklab olish, o'zgartirish, MIME turini aniqlash, Base64 kodlashni talab qiladi. Bunday mantiklar oxir-oqibat ro'yxatdan tashqaridagi alohida xizmatlar yoki Proxy qatlamiga joylashtiriladi.
Shu sababli, model chaqiruv usuli oddiy va bir xil bo'lganda, ro'yxatga olish mos keladi, ammo har bir modelning ishlatish usuli turlicha bo'lsa, Proxy usuli tabiatiga ko'ra qulayroqdir.
Hozirgi loyihada tanlangan usul
Hozirgi loyihada @Qualifier + Proxy sinfi usulitanlashni tanladi.
|
element |
baholash |
|
@Qualifier matnning ko'rsatish doirasi |
Proxy klassining ichki qismiga izolyatsiya |
|
Modelga xos oldindan ishlov berish mantiqini ajratish |
Rasmni o'lchamlash, kodlash logikasini ImageChatModelProxy'ga kapsül qilish |
|
Matn modeli qo'shimcha funktsiyalari |
JSONni parslash, ro'yxat javoblarini parslashni ChatModelProxyga jamlash |
|
Biznes kodining birikma darajasi |
Xizmat faqat Proxy turiga bog'liq |
Ikkita modelning roli aniq farq qiladi.
Matn modeli odatiy suhbat, JSON javobini tahlil qilish kabi vazifalar uchun ishlatiladi. Buning o'rniga, rasm modeli rasm kiritish uchun alohida oldindan qayta ishlash jarayonini talab qiladi.
Shuning uchun, ikkita modelni majburan bitta interfeysga birlashtirishdan ko'ra, har biri o'z mas'uliyatlariga ega bo'lgan Proxy orqali ajratish tabiiyroqdir.
Albatta, model 3 tadan ortiq bo'lsa yoki runtime-da modelni tanlash talabi yuzaga kelsa, registr modelini ham ko'rib chiqish mumkin.
Xulosa qilib
-
LangChain4J avtomatik sozlash bilan bir necha ChatModelni aniq boshqarish qiyin.
-
Agar bir nechta modellardan foydalanish kerak bo'lsa, to'g'ridan-to'g'ri @Bean ni aniqlash va @Qualifier bilan ajratish mumkin.
-
Proxydan foydalanish orqali modelga xos oldingi va keyingi ishlov berish mantiqlarini kapsulalashtirish mumkin va biznes mantiq modelning bo'sh nomini bilmasligi mumkin.
-
Model soni ko'payganda yoki sozlamalarga asoslangan almashtirish muhim bo'lganda registratsiya naqshidan foydalanishni ko'rib chiqish mumkin.
Shaxsiy fikrim, bu vaziyatda Proxy usuli eng maqbul tanlovdirshunday deb hisoblanadi.
Matn modeli va rasm modeli faqat “ChatModelning ikkita” ekanligi bilan cheklanmaydi, balki ularni ishlatish usuli va javobgarliklari ham boshqacha. Shuning uchun umumiy interfeys yoki ro'yxatga olishdan oldin, modellar bo'yicha javobgarliklarni aniq ko'rsatadigan Proxy'ni joylashtirish, saqlash nuqtai nazaridan yaxshiroqdir.
Ted