ChatClient 对话客户端
概述
ChatClient 是模型协议的传输与响应处理层。BaseChatModel 先完成 Prompt、Options、拦截器和请求 Body 构建,再把最终 Body 交给 Client:
ChatModel -> ChatInterceptor -> RequestSpecBuilder
-> ChatClient -> HTTP/SSE -> AiMessageParser普通业务只调用 ChatModel,不需要直接创建 Client。只有接入新协议、替换网络实现或编写模型适配器时才使用本篇 API。
适用场景
- 服务端不是 OpenAI 兼容协议,需要自定义传输与错误解析。
- 需要使用公司统一的 HTTP Client、代理、证书和网络观测。
- 流式协议是 NDJSON、WebSocket,而不是 SSE。
- 响应 JSON 结构不同,需要注入自定义
AiMessageParser。
只需修改 URL、Header 或 Body 时,优先扩展 ChatRequestSpecBuilder 或使用 ChatInterceptor。
快速开始
OpenAI 兼容模型已经由 OpenAIChatClient 处理,通常只需通过 ChatModel 调用:
OpenAIChatModel model = new OpenAIChatModel(config);
AiMessageResponse response = model.chat(new SimplePrompt("你好"));要替换同步网络实现,可在模型创建后注入:
OpenAIChatClient client = new OpenAIChatClient(model);
client.setHttpClient(new AgentsFlexHttpClient(customOkHttpClient));
model.setChatClient(client);核心接口
public abstract class ChatClient {
public abstract AiMessageResponse chat(String body);
public abstract void chatStream(
String body,
StreamResponseListener listener
);
}Client 不持有请求级 ChatContext。实现类在调用期间通过 ChatContextHolder.currentContext() 读取 URL、Header、重试参数和 Prompt;因此方法必须由 BaseChatModel 的上下文范围内调用。
OpenAIChatClient
同步路径使用 AgentsFlexHttpClient.post(...),解析 JSON 错误或成功响应;流式路径每次调用新建 SseClient,并由 BaseStreamClientListener 聚合增量消息。
- 空同步响应返回 error
AiMessageResponse。 - 非法 JSON 返回
invalid json response错误响应。 - 响应含
error对象时保留 message、type 和 code。 - 成功时使用
AiMessageParser,并补充本地 Token 估算。
可以注入解析器:
OpenAIChatClient client = new OpenAIChatClient(model);
client.setAiMessageParser(customParser);
model.setChatClient(client);getStreamClient() 当前每次返回新的 SseClient。若要支持其他流协议,应继承 Client 并覆盖该方法或实现完整的 chatStream(...)。
自定义 Client
public class MyChatClient extends ChatClient {
public MyChatClient(BaseChatModel<?> model) {
super(model);
}
@Override
public AiMessageResponse chat(String body) {
ChatContext context = ChatContextHolder.currentContext();
ChatRequestSpec spec = context.getRequestSpec();
String raw = myTransport.post(spec.getUrl(), spec.getHeaders(), body);
return parse(raw, context);
}
@Override
public void chatStream(String body, StreamResponseListener listener) {
// 连接流、解析分片,并完整转发 onMessage/onStop/onFailure。
}
}自定义实现必须把协议错误转换为一致的错误响应或 Listener 失败事件,并确保网络资源在正常结束、异常和主动停止时都能关闭。
生产建议
- Client 实例会被模型复用,字段必须线程安全;请求状态放在
ChatContext或局部变量中。 - 不要在 Client 中再次序列化 Prompt,Body 已由责任链末端构建。
- 对同步与流式路径分别测试 2xx、4xx、5xx、空响应、非法 JSON 和中途断流。
- 日志中不要输出 Authorization 和未经脱敏的完整 Body。
常见问题
为什么直接调用 client.chat(body) 报上下文错误?
Client 依赖 ChatContextHolder,应由 ChatModel 调用。如果你需要独立 HTTP Client,请直接使用传输层 API。
可以在一个 Client 中保存当前 Context 吗?
不应这样做。模型可能被并发调用,请求级 Context 不能保存在共享字段。