聊天模型接口（ChatModel）支持：

* 同步调用（call），一次性返回结果
* 支流式调用（stream，基于 reactivestreams 规范）。通过 `sse` 或 `x-ndjson` 流式返回结果。
* Tool Call（或 Function Call） 与本地数据互动（需要 llm 支持）
* 提示语多消息输入输出（记忆体）
* 带图片消息
* 与 solon-flow 结合使用


### 1、聊天模型的构建

* 配置方式构建

```yaml
solon.ai.chat:
  demo:
    apiUrl: "http://127.0.0.1:11434/api/chat" # 使用完整地址（而不是 api_base）
    provider: "ollama" # 使用 ollama 服务时，需要配置 provider
    model: "llama3.2"
    headers:
      x-demo: "demo1"
```


```java
import org.noear.solon.ai.chat.ChatConfig;
import org.noear.solon.ai.chat.ChatModel;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;

@Configuration
public class DemoConfig {
    @Bean
    public ChatModel build(@Inject("${solon.ai.chat.demo}") ChatConfig config) {
        return ChatModel.of(config).build();
    }
}
```

* 手动方式构建


```java
@Configuration
public class DemoConfig {
    @Bean
    public ChatModel build() {
        return ChatModel.of("http://127.0.0.1:11434/api/chat") //使用完整地址（而不是 api_base）
                .headerSet("x-demo", "demo1")
                .provider("ollama")
                .model("llama3.2")
                .modelOptions(o->o.optionSet("stream_options", Utils.asMap("include_usage", true))) //v3.8.4 之后
                //.defaultOptionAdd("stream_options", Utils.asMap("include_usage", true)) //v3.8.4 之前
                .build();
    }
}
```



### 2、同步调用（call）


```java
public void case1() throws IOException {
    ChatResponse resp = chatModel.prompt("hello").call();

    //打印消息
    log.info("{}", resp.getMessage());
}
```

### 3、异步流式或响应式调用（stream）

流式返回为 `reactor.core.publisher.Flux`（reactor 规范）

```java
public void case2() throws IOException {
    Flux<ChatResponse> publisher = chatModel.prompt("hello").stream();

    //return publisher; //使用 solon-web-rx 时可直接返回；或者对接 solon-web-sse 或 websocket

    publisher.doOnNext(resp -> {
                log.info("{}", resp.getMessage());
            }).doOnComplete(() -> {
                log.debug("::完成!");
            }).doOnError(err -> {
                log.error("{}", err);
            })
            .subscribe();
}
```

可以直接订阅消费（如上）。也可对接各种流行的响应式框架，比如 mutiny、rxjava 或 reactor：


```java
@Produces(MimeType.TEXT_EVENT_STREAM_UTF8_VALUE)
@Mapping("case2")
public Flux<SseEvent> case2(String prompt) throws IOException {
    return chatModel.prompt(prompt).stream()
                .map(resp -> resp.getMessage())
                .map(msg -> new SseEvent().data(msg.getContent()))
                .doOnError(err->{
                    log.error("{}", err);
                });
}
```

### 4、模型日志

内部默认会打印 llm 请求与响应的日志，分别以 `llm-request:` 和 `llm-response: ` 开头。日志级别为：DEBUG。
