1-Intro

高层服务. 专注于业务逻辑,而不是低层细节. 类似 Spring Data JPA, Retrofit 这样的框架.

  • 采用声明式的接口 来定义 ;
  • 使用代理的模式实现接口 ;
  • 作为服务层的一个组件 ;

同时支持 LLM 的常见升天, Chat Memory, Tools, RAG 这种。

原理,就是用反射创建一个 动态实现, 属于初级使用.

graph LR
    A[用户接口定义] --> B[AiServices创建代理]
    B --> C[代理对象]
    C --> D[输入转换]
    D --> E[调用模型]
    E --> F[输出转换]
    F --> G[返回结果]

2-Quick start

1)-组装

@Bean  
open fun chatLanguageModel(llmConfigProps: LlmConfigProps): ChatLanguageModel {  
    val supplierType = llmConfigProps.active  
    return when (supplierType) {  
        LlmSupplierType.AZURE -> AzureOpenAiChatModel.builder()  
            .apiKey(llmConfigProps.activeConfig.appKey)  
            .endpoint(llmConfigProps.activeConfig.endpoint)  
            .deploymentName(llmConfigProps.activeConfig.modelName)  
            .logRequestsAndResponses(true)  
            .build()  
  
        else -> throw IllegalArgumentException("Unknown LLM supplier type: $supplierType")  
    }  
}  
  
@Bean  
open fun assistant(  
    chatLanguageModel: ChatLanguageModel,  
    chatSessionDao: IChatSessionDao,  
    redisChatMemoryStore: RedisChatMemoryStore  
): Assistant {  
    return AiServices.builder(Assistant::class.java)  
        .systemMessageProvider {  
            chatSessionDao.findById(it.toString().toInt()).map(ChatSession::systemMessage).orElse(null)  
        }.chatMemoryProvider {  
            MessageWindowChatMemory.builder()  
                .id(it)  
                .maxMessages(30)  
                .chatMemoryStore(redisChatMemoryStore)  
                .build()  
        }  
        .chatLanguageModel(chatLanguageModel)  
        .build()  
}

2)-定义基本的 chat 函数

  
interface Assistant {  
  
    fun chat(@MemoryId memoryId: Int, @UserMessage userMessage: String): String  
}

3)-实现 redis chat memory

@Component  
open class RedisChatMemoryStore(  
    private val redisTemplate: RedisTemplate<String, String>,  
    @Value("\${chat.memory.prefix}")  
    private val prefix: String  
) : ChatMemoryStore, ILogging {  
  
    fun key(memoryId: Any): String {  
        return "$prefix$memoryId"  
    }  
  
    override fun getMessages(memoryId: Any): List<ChatMessage> {  
        val key = key(memoryId)  
        logger.info("Retrieving messages from Redis, key:{}", key)  
        val json = redisTemplate.opsForValue().get(key)  
        return ChatMessageDeserializer.messagesFromJson(json)  
    }  
  
    override fun updateMessages(  
        memoryId: Any,  
        messages: List<ChatMessage>  
    ) {  
        val key = key(memoryId)  
        logger.info("Updating messages in Redis, key: {}, size:{}", key, messages.size)  
        val json = ChatMessageSerializer.messagesToJson(messages)  
        /*默认保留30天*/  
        redisTemplate.opsForValue().set(key, json, 30L, TimeUnit.DAYS)  
    }  
  
    override fun deleteMessages(memoryId: Any) {  
        val key = key(memoryId)  
        logger.info("Deleting messages from Redis, key : {}", key)  
        redisTemplate.opsForValue().getOperations().delete(key)  
    }  
}

refer