当前位置: 首页 > article >正文

第5章:在LangChain中如何使用AI Services

这篇文章详细介绍了 LangChain4j 中的 AI Services 概念,展示了如何通过高层次的抽象来简化与大语言模型(LLM)的交互。AI Services 的核心思想是隐藏底层复杂性,让开发者专注于业务逻辑,同时支持聊天记忆、工具调用和 RAG 等高级功能。通过示例和代码片段,文章展示了如何定义和使用 AI Services,以及如何将它们组合起来构建复杂的 LLM 驱动的应用程

AI Services | LangChain4j

引言

到目前为止,我们已经介绍了低层次的组件,例如 ChatLanguageModel、ChatMessage 和 ChatMemory 等。在这一层次上工作非常灵活,给你完全的自由,但这也迫使你编写大量的样板代码(boilerplate code)。由于基于 LLM 的应用程序通常不仅需要单个组件,而是多个组件协同工作(例如,提示词模板、聊天记忆、LLM、输出解析器、RAG 组件:嵌入模型和存储),并且通常涉及多次交互,因此协调它们变得更加繁琐。

解决方案

我们希望你专注于业务逻辑,而不是底层实现细节。因此,LangChain4j 提出了两个高层次的概念来帮助实现这一点:AI Services 和 Chains。

  1. Chains(已废弃)
    Chains 的概念源自 Python 的 LangChain(在引入 LCEL 之前)。其想法是为每个常见用例提供一个 Chain,例如聊天机器人、RAG 等。Chains 结合了多个低层次组件,并协调它们之间的交互。然而,它们的主要问题是,如果你需要自定义某些内容,它们会显得过于僵化。LangChain4j 目前只实现了两个 Chains(ConversationalChain 和 ConversationalRetrievalChain),并且目前不计划添加更多。
  2. AI Services
    我们提出了另一种解决方案,称为 AI Services,专为 Java 设计。其想法是将与 LLM 和其他组件交互的复杂性隐藏在一个简单的 API 后面。
    这种方法类似于 Spring Data JPA 或 Retrofit:你声明性地定义一个接口,指定所需的 API,而 LangChain4j 提供一个实现该接口的对象(代理)。你可以将 AI Service 视为应用程序服务层的一个组件,它提供 AI 服务,因此得名。

AI Services 处理最常见的操作:

  • 为 LLM 格式化输入。
  • 解析 LLM 的输出。
    它们还支持更高级的功能:
  • 聊天记忆(Chat Memory)。
  • 工具(Tools)。
  • RAG(Retrieval-Augmented Generation,检索增强生成)。

AI Services 可以用于构建支持来回交互的状态化聊天机器人,也可以用于自动化每个 LLM 调用都是独立的流程。

AI Service初探

最简单的 AI Service 示例

首先,我们定义一个接口,其中包含一个名为 chat 的方法,该方法接受一个 String 类型的输入并返回一个 String 类型的输出:

interface Assistant {
    String chat(String userMessage);
}

然后,我们创建低层次组件。这些组件将在 AI Service 的底层使用。在这个例子中,我们只需要 ChatLanguageModel:

ChatLanguageModel model = OpenAiChatModel.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .modelName(GPT_4_O_MINI)
    .build();

最后,我们使用 AiServices 类创建 AI Service 的实例:

Assistant assistant = AiServices.create(Assistant.class, model);

注意:在 Quarkus 和 Spring Boot 应用程序中,自动配置会处理 Assistant 的创建。这意味着你不需要调用 AiServices.create(…),只需在需要的地方注入/自动装配 Assistant 即可。
现在我们可以使用 Assistant:

String answer = assistant.chat("Hello");
System.out.println(answer); // 输出:Hello, how can I help you?

工作原理

你将接口的 Class 和低层次组件提供给 AiServices,AiServices 会创建一个实现该接口的代理对象。目前,它使用反射实现,但我们也在考虑其他替代方案。这个代理对象处理所有输入和输出的转换。在这个例子中,输入是一个单独的 String,但我们使用的是接受 ChatMessage 作为输入的 ChatLanguageModel。因此,AiService 会自动将其转换为 UserMessage 并调用 ChatLanguageModel。由于 chat 方法的输出类型是 String,因此在从 chat 方法返回之前,ChatLanguageModel 返回的 AiMessage 将被转换为 String。

在 Quarkus 和 Spring Boot 应用程序中使用 AI Services

LangChain4j 提供了 Quarkus 扩展和 Spring Boot 启动器,极大地简化了在这些框架中使用 AI Services 的过程。

@SystemMessage

现在,我们来看一个更复杂的例子。我们将强制 LLM 使用俚语回答。这通常是通过在

SystemMessage 中提供指令来实现的:
interface Friend {
    @SystemMessage("You are a good friend of mine. Answer using slang.")
    String chat(String userMessage);
}
Friend friend = AiServices.create(Friend.class, model);
String answer = friend.chat("Hello"); // 输出:Hey! What's up?

在这个例子中,我们添加了 @SystemMessage 注解,并指定了我们想要使用的系统提示模板。这将在后台被转换为 SystemMessage,并与 UserMessage 一起发送给 LLM。
@SystemMessage 也可以从资源文件中加载提示模板:

@SystemMessage(fromResource = "my-prompt-template.txt")

系统消息提供者(System Message Provider)

系统消息也可以通过系统消息提供者动态定义:

Friend friend = AiServices.builder(Friend.class)
    .chatLanguageModel(model)
    .systemMessageProvider(chatMemoryId -> "You are a good friend of mine. Answer using slang.")
    .build();

你可以根据聊天记忆 ID(用户或对话)提供不同的系统消息。

@UserMessage

假设我们使用的模型不支持系统消息,或者我们只想使用 UserMessage 来实现:

interface Friend {
    @UserMessage("You are a good friend of mine. Answer using slang. {{it}}")
    String chat(String userMessage);
}
Friend friend = AiServices.create(Friend.class, model);
String answer = friend.chat("Hello"); // 输出:Hey! What's shakin'?

我们将 @SystemMessage 替换为 @UserMessage,并指定了一个包含变量 it 的提示模板,该变量指向方法的唯一参数。
你也可以使用 @V 注解为提示模板变量指定自定义名称:

interface Friend {
    @UserMessage("You are a good friend of mine. Answer using slang. {{message}}")
    String chat(@V("message") String userMessage);
}

注意:在使用 LangChain4j 的 Quarkus 或 Spring Boot 应用程序中,@V 注解不是必需的。只有在 Java 编译时未启用 -parameters 选项时,才需要使用它。
@UserMessage 也可以从资源文件中加载提示模板:

@UserMessage(fromResource = "my-prompt-template.txt")

有效的 AI Service 方法示例

以下是一些有效的 AI Service 方法示例:

使用 UserMessage

String chat(String userMessage);

String chat(@UserMessage String userMessage);

String chat(@UserMessage String userMessage, @V("country") String country); // userMessage 包含 "{{country}}" 模板变量

@UserMessage("What is the capital of Germany?")
String chat();

@UserMessage("What is the capital of {{it}}?")
String chat(String country);

@UserMessage("What is the capital of {{country}}?")
String chat(@V("country") String country);

@UserMessage("What is the {{something}} of {{country}}?")
String chat(@V("something") String something, @V("country") String country);

@UserMessage("What is the capital of {{country}}?")
String chat(String country); // 仅在 Quarkus 和 Spring Boot 应用程序中有效

结合 SystemMessage 和 UserMessage

@SystemMessage("Given a name of a country, answer with a name of its capital")
String chat(String userMessage);

@SystemMessage("Given a name of a country, answer with a name of its capital")
String chat(@UserMessage String userMessage);

@SystemMessage("Given a name of a country, {{answerInstructions}}")
String chat(@V("answerInstructions") String answerInstructions, @UserMessage String userMessage);

@SystemMessage("Given a name of a country, answer with a name of its capital")
String chat(@UserMessage String userMessage, @V("country") String country); // userMessage 包含 "{{country}}" 模板变量

@SystemMessage("Given a name of a country, answer with a name of its capital")
@UserMessage("Germany")
String chat();

@SystemMessage("Given a name of a country, {{answerInstructions}}")
@UserMessage("Germany")
String chat(@V("answerInstructions") String answerInstructions);

@SystemMessage("Given a name of a country, answer with a name of its capital")
@UserMessage("Germany")
String chat();

@SystemMessage("Given a name of a country, {{answerInstructions}}")
@UserMessage("Germany")
String chat(@V("answerInstructions") String answerInstructions);

@SystemMessage("Given a name of a country, answer with a name of its capital")
@UserMessage("{{country}}")
String chat(@V("country") String country);

@SystemMessage("Given a name of a country, {{answerInstructions}}")
@UserMessage("{{country}}")
String chat(@V("answerInstructions") String answerInstructions, @V("country") String country);

多模态(Multimodality)

目前,AI Services 不支持多模态功能,需要使用基础的套件和 API 实现。

结构化输出(Structured Outputs)

如果你希望从 LLM 中获取结构化输出,可以将 AI Service 方法的返回类型从 String 改为其他类型。目前,AI Services 支持以下返回类型:

  • String
  • AiMessage
  • 任意自定义 POJO(Plain Old Java Object)
  • 任意 Enum 或 List 或 Set(用于对文本进行分类,例如情感分析、用户意图等)
  • boolean/Boolean(用于获取“是”或“否”的回答)
  • byte/short/int/BigInteger/long/float/double/BigDecimal
  • Date/LocalDate/LocalTime/LocalDateTime
  • List/Set(用于以项目符号列表的形式返回答案)
  • Map<K, V>
  • Result(如果需要访问 TokenUsage、FinishReason、来源(RAG 中检索到的内容)和执行的工具,除了 T,T 可以是上述任意类型。例如:Result、Result)

除非返回类型是 String、AiMessage 或 Map<K, V>,AI Service 会自动在 UserMessage 的末尾附加指示 LLM 应该如何响应的指令。在方法返回之前,AI Service 会将 LLM 的输出解析为所需的类型。
你可以通过启用日志记录来观察附加的指令。

注意:某些 LLM 提供商(例如 OpenAI 和 Google Gemini)允许为期望的输出指定 JSON 模式。如果此功能被支持且启用,自由格式的文本指令不会被附加到 UserMessage 的末尾。在这种情况下,将从你的 POJO 自动生成 JSON 模式并传递给 LLM,从而确保 LLM 遵循该 JSON 模式。

现在,让我们来看一些示例。

1. 返回类型为 boolean 的示例

interface SentimentAnalyzer {
    @UserMessage("Does {{it}} have a positive sentiment?")
    boolean isPositive(String text);
}

SentimentAnalyzer sentimentAnalyzer = AiServices.create(SentimentAnalyzer.class, model);

boolean positive = sentimentAnalyzer.isPositive("It's wonderful!");
// 输出:true

2. 返回类型为 Enum 的示例

enum Priority {
    @Description("Critical issues such as payment gateway failures or security breaches.")
    CRITICAL,

    @Description("High-priority issues like major feature malfunctions or widespread outages.")
    HIGH,

    @Description("Low-priority issues such as minor bugs or cosmetic problems.")
    LOW
}

interface PriorityAnalyzer {
    @UserMessage("Analyze the priority of the following issue: {{it}}")
    Priority analyzePriority(String issueDescription);
}

PriorityAnalyzer priorityAnalyzer = AiServices.create(PriorityAnalyzer.class, model);

Priority priority = priorityAnalyzer.analyzePriority("The main payment gateway is down, and customers cannot process transactions.");
// 输出:CRITICAL

注意:@Description 注解是可选的。当枚举名称不够直观时,建议使用它来帮助 LLM 更好地理解。

3. 返回类型为 POJO 的示例

class Person {
    @Description("first name of a person") // 可选描述,帮助 LLM 更好地理解
    String firstName;
    String lastName;
    LocalDate birthDate;
    Address address;
}

@Description("an address") // 可选描述,帮助 LLM 更好地理解
class Address {
    String street;
    Integer streetNumber;
    String city;
}

interface PersonExtractor {
    @UserMessage("Extract information about a person from {{it}}")
    Person extractPersonFrom(String text);
}

PersonExtractor personExtractor = AiServices.create(PersonExtractor.class, model);

String text = """
            In 1968, amidst the fading echoes of Independence Day,
            a child named John arrived under the calm evening sky.
            This newborn, bearing the surname Doe, marked the start of a new journey.
            He was welcomed into the world at 345 Whispering Pines Avenue
            a quaint street nestled in the heart of Springfield
            an abode that echoed with the gentle hum of suburban dreams and aspirations.
            """;

Person person = personExtractor.extractPersonFrom(text);

System.out.println(person); 
// 输出:Person { firstName = "John", lastName = "Doe", birthDate = 1968-07-04, address = Address { ... } }

JSON 模式(JSON Mode)

当提取自定义 POJO(实际上是 JSON,然后解析为 POJO)时,建议在模型配置中启用“JSON 模式”。这样,LLM 将被强制以有效的 JSON 格式响应。

注意:JSON 模式和工具/函数调用是类似的功能,但它们有不同的 API,并且用于不同的目的。

  • JSON 模式:当你总是需要 LLM 以结构化格式(有效的 JSON)响应时非常有用。此外,通常不要状态/记忆,因此每次与 LLM 的交互都是独立的。例如,你可能希望从文本中提取信息,例如文本中提到的人的列表,或者将自由格式的产品评论转换为具有字段(如 String productName、Sentiment sentiment、List claimedProblems 等)的结构化形式。
  • 工具/函数调用:当 LLM 应该能够执行某些操作时(例如查询数据库、搜索网络、取消用户的预订等),此功能非常有用。在这种情况下,向 LLM 提供一组工具及其期望的 JSON 模式,LLM 将自主决定是否调用其中的任何一个来满足用户请求。
    以前,函数调用常用于结构化数据提取,但现在我们有了 JSON 模式功能,它更适合此目的。

以下是启用 JSON 模式的方法:

OpenAI

  • 对于支持结构化输出的较新模型(例如 gpt-4o-mini、gpt-4o-2024-08-06)
OpenAiChatModel.builder()
    ...
    .responseFormat("json_schema")
    .strictJsonSchema(true)
    .build();
  • 对于较旧的模型(例如 gpt-3.5-turbo、gpt-4):
OpenAiChatModel.builder()
    ...
    .responseFormat("json_object")
    .build();

Azure OpenAI

AzureOpenAiChatModel.builder()
    ...
    .responseFormat(new ChatCompletionsJsonResponseFormat())
    .build();

Vertex AI Gemini

VertexAiGeminiChatModel.builder()
    ...
    .responseMimeType("application/json")
    .build();

或者通过指定一个 Java 类的显式模式:

GoogleAiGeminiChatModel.builder()
    ...
    .responseFormat(ResponseFormat.builder()
        .type(JSON)
        .jsonSchema(JsonSchemas.jsonSchemaFrom(Person.class).get())
        .build())
    .build();

或者通过指定一个 JSON 模式:

GoogleAiGeminiChatModel.builder()
    ...
    .responseFormat(ResponseFormat.builder()
        .type(JSON)
        .jsonSchema(JsonSchema.builder()...build())
        .build())
    .build();

Mistral AI

MistralAiChatModel.builder()
    ...
    .responseFormat(MistralAiResponseFormatType.JSON_OBJECT)
    .build();

Ollama

OllamaChatModel.builder()
    ...
    .responseFormat(JSON)
    .build();

其他模型提供商

如果底层模型提供商不支持 JSON 模式,提示工程(Prompt Engineering)是你的最佳选择。此外,尝试降低 temperature 参数以获得更确定性的结果。

流式响应(Streaming)

AI Service 可以通过使用 TokenStream 返回类型逐个流式传输响应令牌:

interface Assistant {
    TokenStream chat(String message);
}

StreamingChatLanguageModel model = OpenAiStreamingChatModel.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .modelName(GPT_4_O_MINI)
    .build();

Assistant assistant = AiServices.create(Assistant.class, model);

TokenStream tokenStream = assistant.chat("Tell me a joke");

tokenStream.onNext((String token) -> System.out.println(token))
    .onRetrieved((List<Content> contents) -> System.out.println(contents))
    .onToolExecuted((ToolExecution toolExecution) -> System.out.println(toolExecution))
    .onComplete((Response<AiMessage> response) -> System.out.println(response))
    .onError((Throwable error) -> error.printStackTrace())
    .start();

使用 Flux

你也可以使用 Flux 替代 TokenStream。为此,请导入 langchain4j-reactor 模块:

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-reactor</artifactId>
    <version>1.0.0-beta1</version>
</dependency>

代码示例

interface Assistant {
    Flux<String> chat(String message);
}

聊天记忆(Chat Memory)

AI Service 可以使用聊天记忆来“记住”之前的交互:

Assistant assistant = AiServices.builder(Assistant.class)
    .chatLanguageModel(model)
    .chatMemory(MessageWindowChatMemory.withMaxMessages(10))
    .build();

在这种情况下,相同的 ChatMemory 实例将用于所有 AI Service 的调用。然而,这种方法在有多个用户时将无法工作,因为每个用户都需要自己的 ChatMemory 实例来维护各自的对话。
解决这个问题的方法是使用 ChatMemoryProvider:

interface Assistant {
    String chat(@MemoryId int memoryId, @UserMessage String message);
}

Assistant assistant = AiServices.builder(Assistant.class)
    .chatLanguageModel(model)
    .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
    .build();

String answerToKlaus = assistant.chat(1, "Hello, my name is Klaus");
String answerToFrancine = assistant.chat(2, "Hello, my name is Francine");

在这种情况下,ChatMemoryProvider 将为每个内存 ID 提供两个不同的 ChatMemory 实例。

注意

  1. 如果 AI Service 方法没有带有 @MemoryId 注解的参数,则 ChatMemoryProvider 中的 memoryId 默认值为字符串 “default”。
  2. 目前,AI Service 不支持对同一个 @MemoryId 的并发调用,因为这可能导致 ChatMemory 被破坏。AI Service 目前没有实现任何机制来防止对同一个 @MemoryId 的并发调用。

工具(Tools)

AI Service 可以配置工具,LLM 可以使用这些工具:

class Tools {
    @Tool
    int add(int a, int b) {
        return a + b;
    }

    @Tool
    int multiply(int a, int b) {
        return a * b;
    }
}

Assistant assistant = AiServices.builder(Assistant.class)
    .chatLanguageModel(model)
    .tools(new Tools())
    .build();

String answer = assistant.chat("What is 1+2 and 3*4?");

在这种情况下,LLM 将请求执行 add(1, 2) 和 multiply(3, 4) 方法,然后才提供最终答案。LangChain4j 将自动执行这些方法。

关于工具的更多信息可以参考 LangChain4j 文档。

RAG(检索增强生成)

AI Service 可以配置 ContentRetriever 来启用简单的 RAG:

EmbeddingStore embeddingStore = ...;
EmbeddingModel embeddingModel = ...;

ContentRetriever contentRetriever = new EmbeddingStoreContentRetriever(embeddingStore, embeddingModel);

Assistant assistant = AiServices.builder(Assistant.class)
    .chatLanguageModel(model)
    .contentRetriever(contentRetriever)
    .build();

配置 RetrievalAugmentor 可以提供更大的灵活性,启用高级的 RAG 功能,例如查询转换、重新排序等:

RetrievalAugmentor retrievalAugmentor = DefaultRetrievalAugmentor.builder()
        .queryTransformer(...)
        .queryRouter(...)
        .contentAggregator(...)
        .contentInjector(...)
        .executor(...)
        .build();

Assistant assistant = AiServices.builder(Assistant.class)
    .chatLanguageModel(model)
    .retrievalAugmentor(retrievalAugmentor)
    .build();

关于 RAG 的更多信息可以参考 LangChain4j 文档。

自动审核(Auto-Moderation)

(示例略)

链接多个 AI Services

随着你的 LLM 驱动应用程序的逻辑变得越来越复杂,将其分解为更小的部分变得至关重要,这在软件开发中是一种常见的实践。

例如,将大量指令塞入系统提示中以涵盖所有可能的场景,容易出错且效率低下。如果指令过多,LLM 可能会忽略一些。此外,指令的呈现顺序也很重要,这使得整个过程更加复杂。

这一原则也适用于工具、RAG 和模型参数(例如 temperature、maxTokens 等)。
你的聊天机器人可能并不需要在所有情况下都了解你所有的工具。例如,当用户仅仅是问候聊天机器人或说再见时,让 LLM 访问数十个甚至数百个工具(每个工具都会消耗大量的 token)是成本高昂的,有时甚至是危险的,可能会导致意外的结果(LLM 可能会幻觉或被操纵以调用工具并输入意外的内容)。

关于 RAG:同样,有时需要为 LLM 提供一些上下文,但并非总是如此,因为这会增加额外的成本(更多上下文 = 更多 token)并增加响应时间(更多上下文 = 更高的延迟)。

关于模型参数:在某些情况下,你可能需要 LLM 高度确定性,因此你会设置较低的 temperature。在其他情况下,你可能会选择较高的 temperature,依此类推。

要点是,更小且更具体的组件更容易、更便宜开发、测试、维护和理解。

另一个需要考虑的方面是两个极端:

  • 你是否希望你的应用程序高度确定性,其中应用程序控制流程,LLM 只是其中一个组件?
  • 或者你希望 LLM 完全自主并驱动你的应用程序?

或许根据情况,两者都有?所有这些选项都可以通过将你的应用程序分解为更小、更易于管理的部分来实现。

AI Services 可以作为常规(确定性)软件组件使用,并与其他组件结合:

  • 你可以依次调用一个 AI Service(即链式调用)。
  • 你可以使用确定性和基于 LLM 的 if/else 语句(AI Services 可以返回 boolean)。
  • 你可以使用确定性和基于 LLM 的 switch 语句(AI Services 可以返回 enum)。
  • 你可以使用确定性和基于 LLM 的 for/while 循环(AI Services 可以返回 int 和其他数值类型)。
  • 你可以模拟 AI Service(因为它是一个接口)以进行单元测试。
  • 你可以单独集成测试每个 AI Service。
  • 你可以分别评估每个 AI Service 并找到每个子任务的最优参数。
    等等。
    让我们考虑一个简单的例子。我想为我的公司构建一个聊天机器人。如果用户问候聊天机器人,我希望它用预定义的问候语回答,而不依赖 LLM 生成问候语。如果用户提问,我希望 LLM 使用公司的内部知识库生成回答(即 RAG)。
    以下是如何将此任务分解为两个独立的 AI Services:
interface GreetingExpert {
    @UserMessage("Is the following text a greeting? Text: {{it}}")
    boolean isGreeting(String text);
}

interface ChatBot {
    @SystemMessage("You are a polite chatbot of a company called Miles of Smiles.")
    String reply(String userMessage);
}

class MilesOfSmiles {
    private final GreetingExpert greetingExpert;
    private final ChatBot chatBot;

    public MilesOfSmiles(GreetingExpert greetingExpert, ChatBot chatBot) {
        this.greetingExpert = greetingExpert;
        this.chatBot = chatBot;
    }

    public String handle(String userMessage) {
        if (greetingExpert.isGreeting(userMessage)) {
            return "Greetings from Miles of Smiles! How can I make your day better?";
        } else {
            return chatBot.reply(userMessage);
        }
    }
}

GreetingExpert greetingExpert = AiServices.create(GreetingExpert.class, llama2);

ChatBot chatBot = AiServices.builder(ChatBot.class)
    .chatLanguageModel(gpt4)
    .contentRetriever(milesOfSmilesContentRetriever)
    .build();

MilesOfSmiles milesOfSmiles = new MilesOfSmiles(greetingExpert, chatBot);

String greeting = milesOfSmiles.handle("Hello");
System.out.println(greeting); // 输出:Greetings from Miles of Smiles! How can I make your day better?

String answer = milesOfSmiles.handle("Which services do you provide?");
System.out.println(answer); // 输出:At Miles of Smiles, we provide a wide range of services ...

注意我们如何使用较便宜的 Llama2 来完成简单的问候识别任务,而使用更昂贵的 GPT-4(带有内容检索器,即 RAG)来完成更复杂的任务。

这是一个非常简单且有些幼稚的例子,但希望它能说明这个想法。
现在,我可以分别模拟 GreetingExpert 和 ChatBot,并独立测试 MilesOfSmiles。此外,我还可以分别集成测试 GreetingExpert 和 ChatBot,分别评估它们,并为每个子任务找到最优化的参数,甚至在长期内为每个特定任务微调一个小的专用模型。

总结

这篇文章详细介绍了 LangChain4j 中的 AI Services 概念,展示了如何通过高层次的抽象来简化与大语言模型(LLM)的交互。AI Services 的核心思想是隐藏底层复杂性,让开发者专注于业务逻辑,同时支持聊天记忆、工具调用和 RAG 等高级功能。通过示例和代码片段,文章展示了如何定义和使用 AI Services,以及如何将它们组合起来构建复杂的 LLM 驱动的应用程序。


http://www.kler.cn/a/554244.html

相关文章:

  • 微软Win11新动态:官方“换机助手”曝光,PC数据迁移或迎全新体验
  • 自动化之ansible(二)
  • Day6 25/2/19 WED
  • RedisTemplate存储含有特殊字符解决
  • 【Pandas】pandas Series rename
  • 51单片机学习之旅——C语言小知识
  • 在WPF中实现窗口拖拽功能:打造自定义交互体验
  • C#项目04——递归求和
  • ubuntu下安装TFTP服务器
  • vue中将当前视频播放进度转换为整数
  • 科技快讯 | DeepSeek推出NSA加速长上下文训练,xAI Grok系列将陆续开源,月之暗面发布Kimi Latest新模型
  • Mobaxterm: Local port forwarding Remote port forwarding
  • 解码 NLP:从萌芽到蓬勃的技术蜕变之旅
  • Docker 镜像加速器配置指南
  • 大量请求,数据库连接不足,会导致什么问题,最大连接数一般设置多大
  • pptx文档提取信息
  • UDP通信开发
  • 深研究:与Dify建立研究自动化应用
  • Rust编程语言入门教程(四)猜数游戏:一次猜测
  • Git环境搭建指南