OpenAI Chat
适用场景
- 对接 OpenAI Chat Completions 或兼容代理(如
https://api.openai.com/v1/chat/completions); - 需要标准 function tool 调用、JSON 模式、流式 SSE;
- 希望在请求体中同时发送文本、图片、音频、视频、文件。
OpenAiChatProvider 的 capabilities() 返回:
supports_stream = truesupports_image_input = truesupports_audio_input = truesupports_video_input = false(实现已映射视频输入,但出于谨慎暂不对外宣称)supports_tools = truesupports_structured_output = truesupports_parallel_tool_calls = true
构造方式
#![allow(unused)] fn main() { use kotoba_llm::provider::openai_chat::OpenAiChatProvider; use kotoba_llm::http::reqwest::default_dyn_transport; let transport = default_dyn_transport()?; let provider = OpenAiChatProvider::new(transport, std::env::var("OPENAI_API_KEY")?) .with_base_url("https://api.openai.com") .with_organization("org_123") .with_project("proj_alpha") .with_default_model("gpt-4.1-mini"); }
- 未在
ChatRequest.options.model指定模型时会 fallback 到with_default_model,两者都缺失会抛出LLMError::Validation { message: "model is required for OpenAI Chat" }。 organization与project分别映射到OpenAI-Organization、OpenAI-Projectheader。base_url自动补全/v1/chat/completions,支持自定义代理。
请求映射
request.rs::build_openai_body 把 ChatRequest 映射到 Chat Completions 结构:
messages:逐条转换Message→role/name/content/tool_calls。工具结果只能出现在role = "tool"的消息中,且最多一个ToolResult,否则触发LLMError::Validation。content支持:- 文本 →
{ type: "text", text } - 图片:URL / Base64(自动拼
data:mime;base64,...)/file_id - 音频:
input_audio.data/format - 视频:
input_video.source/format - 文件:
file.file_id - 自定义数据:直接嵌入 JSON
- 文本 →
- 采样参数:
temperature、top_p、max_output_tokens(映射为max_tokens)、presence_penalty、frequency_penalty。 - 工具:仅允许
ToolKind::Function;其他种类直接报LLMError::Validation。工具定义含name、description、parameters。 tool_choice:Auto/Any/None→ 字符串,Tool { name }→ function 对象,Custom完全透传。response_format:Text/JsonObject/JsonSchema/Custom全量支持,分别映射到 OpenAI 的response_format。reasoning:ReasoningOptions转换为reasoning_effort、max_reasoning_tokens及自定义字段。metadata:HashMap → JSON object。options.extra:逐键透传,可用于service_tier、logprobs等未统一的参数。stream:布尔值控制 SSE。
Streaming 与错误
stream_chat使用post_json_stream_with_headers建立 SSE,成功时返回ChatStream;- 若 HTTP 状态码非 2xx,会先收集流 body(
collect_stream_text),再调用parse_openai_error转换为LLMError; - 非流式路径会读取完整响应文本再解析
OpenAiChatResponse,解析失败统一返回LLMError::Provider { provider: "openai_chat", message: ... }。
常见校验
| 触发条件 | 错误 | 排查方式 |
|---|---|---|
ChatRequest 未声明模型且默认模型缺失 | LLMError::Validation | 在配置或请求层确保模型名称填写。 |
role=tool 的消息包含多个 ToolResult | LLMError::Validation { message: "tool role expects a single ToolResult content" } | 将多段工具结果拆分为多条 tool 消息或合并内容。 |
ToolCall.kind 非 Function | LLMError::Validation { message: "OpenAI only supports function tool calls" } | 统一使用 ToolKind::Function,或在业务层做条件判断。 |
extra 建议
ChatOptions.extra["service_tier"] = "default" | "scale":切换服务等级;ChatRequest.metadata:可放 trace id、租户信息,方便调试;- 若代理要求自定义 header,可在构造
HttpTransport时设置。