Files
Genarrative/server-rs/crates/platform-llm
lhk229 eb63f44271
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / Backend tests (pull_request) Failing after 12s
Project CI / Frontend tests (pull_request) Failing after 23s
Project CI / Native shell tests (pull_request) Failing after 9m30s
非流式工具参数半截 JSON 改为原样透传
b1ef45fbd 把“arguments 非空必须是完整 JSON”同时应用到流式和非流式,
越界了。两者的“参数不完整”语义不同:流式意味着流被截断,是传输层事实;
非流式的外层 body 已经完整,参数半截只说明模型输出有问题,属于内容层事实。

App 早有更好的处理——工具计划格式修复循环把畸形响应回灌给模型重写,比硬
报错再重跑整轮 Provider 有效得多。平台层拦下来会丢掉修复所需的 call id、
函数名和原始参数,导致 background_agent_runtime_repairs_malformed_native_
function_arguments 直接以 kind=deserialize 失败,第二次 repair 请求不再发出。

按流式与非流式区分该校验。b1ef45fbd 的其余部分不变:禁止静默丢弃、id 与
函数名必填、空参数归一为空对象、三协议共用一份策略。

原用例反转为断言原样透传,并补一条成对的流式用例锁住流式仍然报错。
2026-07-27 07:00:21 +00:00
..
2026-07-27 04:06:26 +00:00
2026-07-27 03:34:39 +00:00

platform-llm 平台适配 crate

日期:2026-07-27

1. crate 职责

platform-llm 是 Rust 工作区里的大模型平台适配 crate,当前已经落地以下能力:

  1. 统一 Ark / DashScope / Anthropic / 其他兼容网关的文本模型配置结构
  2. 统一 OpenAI Chat Completions、OpenAI Responses 和 Anthropic Messages 的文本 / 原生 function tool 请求、非流式响应与 SSE 流式解析
  3. 统一超时、连接失败、上游错误、空响应与重试策略
  4. 为后续 module-aimodule-storymodule-npcmodule-custom-world 提供可直接复用的基础 client

2. 当前能力边界

当前实现只覆盖“文本 run”主链,不提前混入媒体生成和业务编排:

  1. 对外抽象固定为 LlmRunRequest / LlmRunResponse,不再保留旧 LlmTextRequest / LlmTextResponse 类型。
  2. OpenAiChatOpenAiResponsesAnthropic 三类 API kind 都支持 JSON 请求、非流式响应和 SSE 流式响应;默认 API kind 仍为 OpenAiResponses
  3. 三类协议都使用统一的 function_tools / tool_choice 输入和 LlmRunResponse.tool_calls 输出。Anthropic 请求使用顶层 tools[].input_schema 与对象形态 tool_choiceAnthropic URL 默认在 base URL 后拼 /v1/messages,如果 base URL 已以 /v1 结尾则只拼 /messages
  4. Anthropic 当前仍不支持 web_search、图片内容和纯 system 消息;至少需要一条非 system 文本消息。角色动画、图片、视频、资产轮询仍留在其他平台适配和业务模块任务里。
  5. 流式 on_delta 只发送文本增量与完成原因;工具调用增量在 crate 内按 slot 聚合,完整调用只从最终 LlmRunResponse.tool_calls 读取。上下文管理、后台执行和业务状态不写回本 crate。
  6. 支持按 provider 打标签,但不把业务 prompt、SSE 转发和模块状态写回本 crate。
  7. DashScope 当前只通过“调用方显式提供兼容文本网关 base url”的方式接入,不复用图像 API。
  8. 角色动画、图片、视频、资产轮询仍留在后续 platform-llm / platform-oss / 业务模块任务里另行实现。

3. 三协议工具支持矩阵

API kind 请求工具形态 tool_choice 非流式工具响应 流式工具聚合
OpenAiChat tools[].type=function,函数内为 name / description / parameters / strict "auto" / "required" choices[0].message.tool_calls delta.tool_calls[].index;首片提供 id/name,后续拼接 arguments
OpenAiResponses tools[].type=function,函数内为 name / description / parameters / strict "auto" / "required" output[].type=function_call output_indexoutput_item.added 提供身份,function_call_arguments.delta 拼接,.done 覆盖完整参数
Anthropic 顶层 tools[]name / description / input_schema,没有 function 包装层和 strict { "type": "auto" } / { "type": "any" }Required 映射为 any content[].type=tool_useinput 序列化为 arguments content block indexcontent_block_start 提供身份,input_json_delta 拼接参数

Responses 如果只发送 response.completed,解析器会从其中的 response.output[] 恢复 function_call;恢复时使用 output 数组下标作为 slot。三种协议的并行工具调用只在平台层做 slot 聚合,不代表工具会在平台层并发执行。

4. 流式与参数契约

  1. LlmStreamDelta 只包含 accumulated_textdelta_textfinish_reason,工具调用不会进入 on_delta;纯工具响应允许 text 为空。
  2. 工具片段按协议索引聚合:Chat 使用 delta.tool_calls[].indexResponses 使用 output_indexAnthropic 使用 content block index。Responses 的 .doneresponse.completed 完整 arguments 是权威值,可以覆盖之前的分片拼接。
  3. 流结束固化工具调用时,缺少 id 或函数名返回 Deserialize;空参数默认保存为 {};非空参数必须能反序列化为完整 JSON,截断或半截 JSON 不会交给业务层。这里是 JSON 语法完整性检查,不是针对 parameters 的 JSON Schema 业务校验。
  4. 非流式 Anthropic tool_use.input 缺失时同样按 {} 归一;Chat / Responses 非流式响应的 arguments 仍以各自上游字段为准,调用方不能把缺失字段自动假定为统一 schema 校验通过。

5. 错误边界

  1. Deserialize:上游 JSON、SSE 或 UTF-8 无法解析,Chat 非流式缺少 choices[0],流式工具调用缺少 id / name,或流式工具参数不是完整 JSON。
  2. StreamUnavailable:仅用于流式响应已声明 tool_use / tool_calls,但一个工具 slot 都没有聚合出来的协议兼容失败;调用方可以据此回退一次非流式请求,不能把已收到的解说文本当成最终回复。
  3. EmptyResponse:最终文本为空且工具调用也为空。只有文本为空但存在有效工具调用时,响应才是合法的纯工具响应。
  4. 流尾部出现 TimeoutConnectivityTransportDeserialize 时,只有已形成非空文本、完成原因且工具参数完整的响应才会保留;工具参数半截或没有可保留文本时继续返回错误。

6. 核心导出

当前对外导出以下公共类型:

  1. LlmProvider
  2. LlmConfig
  3. LlmMessageRole
  4. LlmMessage
  5. LlmRunRequest
  6. LlmApiKind
  7. LlmStreamDelta
  8. LlmFunctionTool
  9. LlmToolChoice
  10. LlmToolCall
  11. LlmRunResponse
  12. LlmTokenUsage
  13. LlmClient
  14. LlmError

7. 设计文档

当前文档入口

当前长期工程口径已融合到:

  1. ../../../docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md
  2. ../../../docs/【玩法创作】平台入口与玩法链路-2026-05-15.md
  3. ../../../docs/【开发运维】本地开发验证与生产运维-2026-05-15.md

旧阶段设计文档不再作为实现依据。

8. 边界约束

  1. platform-llm 只承接模型平台适配,不承接业务模块状态真相与业务规则。
  2. 业务模块只能依赖这里的统一 client / DTO / 错误模型,不能再把上游请求细节散落回各 crate。
  3. api-server 后续如果需要做 REST/SSE façade,只允许在协议层调用 platform-llm,不能复制一份私有实现。

9. 验收证据边界

  1. cargo test -p platform-llm 的确定性用例把 checked-in SSE fixture 交给 parser,验证归一后的文本、工具调用、slot 聚合、Responses completed-only 恢复、参数 JSON 完整性和错误边界。fixture 可以来源于真实端点抓包,但测试不保存原始 SSE,也不逐事件与端点报文比较,因此不能证明抓包转录无偏差。
  2. tests/live_stream_tool_calls.rs 是默认 #[ignore] 的真实端点工具调用 smoke。它只验证最终归一结果中的工具名、id 和完整参数 JSON;文本增量字符数仅用于打印观测,工具调用不进入 on_delta,也没有原始 SSE 录制或逐事件对比能力。
  3. 因此验收应分别称为“固定 SSE fixture parser 覆盖”和“真实端点归一工具调用 smoke”,不能把后者描述为原始 SSE fidelity 或转录一致性证明。