Human LLM Gateway:请求生命周期与身份边界

三套协议入口、Fake Model 身份、人工/LLM/超时接力,以及 first_reply_wins 和伪流式输出的边界。

Human LLM Gateway 专栏 · 01 / 02 目录 ↗

Human LLM Gateway 是自托管的 LLM 身份网关。调用方仍用 OpenAI 或 Anthropic SDK,响应里的 model 始终是请求的 Fake Model;内容来自控制台里的人、用户配置的上游 LLM,或两者中先提交的一方。

请求路径

/v1/* 由 FastAPI 接收,按 OpenAI Chat Completions、OpenAI Responses、Anthropic Messages 三套协议解析。Fake Model 是公开身份,不与真实上游绑定;/v1/models 按 API key 计算可见集合,响应渲染时把 model 重写回 Fake Model。

解析后的请求创建任务,状态进入 WAITING_HUMAN,或直接转发 LLM。控制台和 IM connector 都能看到任务;人的提交、上游的响应、超时 fallback 最终都落到同一条任务记录上,再由 render 层按调用方协议输出。

三种策略

  • human:只等待人工回复。
  • llm:直接把请求转发给用户配置的上游。
  • human_fallback_llm:先等待人工;到达 human_deadline_at 后,claim_fallback 原子地把任务从 WAITING_HUMAN 改为 FORWARDING_LLM,再调用上游。

人的超时范围是 10–1800 秒,默认 300,创建任务时快照。提交通过 first_reply_wins 的 UPDATE ... WHERE state=WAITING_HUMAN AND version=expected_version 完成;晚到的提交返回 409 REPLY_REJECTED_LATE。finalize(allowed_sources) 防止超时后的 LLM 结果覆盖人工答案。

协议与流式

跨协议字段能转就转,不能转直接返回 400 unsupported_parameter,不静默丢弃。Responses 协议还需要展开 previous_response_id 链。

流式不是上游透传。llm 策略先读完上游 SSE、落库,再把完整的 ReplyDraft 切成 200 字符的 frame 输出;每发一帧前重读任务状态。人等待时没有首字节收益,连接看起来是空闲的。预算是 16MiB / 600s 的流、1MiB 单行 SSE、非流式 8MiB。

身份与安全

Fake Model 只负责对外身份,真实上游配置按用户保存。密钥使用 hlg1.<version>.<nonce>.<ciphertext> 的 HKDF-SHA256 + AES-256-GCM envelope,不回显。SSRF 分层拦截云 metadata、loopback、RFC1918、ULA、link-local,每次请求前重解析 DNS;GATEWAY_PUBLIC_HOSTS 防止上游指回网关。

工具调用只校验调用方声明的名字和 JSON Schema,不执行、不沙箱。调用方负责声明和执行工具,也承担执行后果。

边界

单实例部署:一个 FastAPI 进程同时服务 React 控制台和 /v1、/api;多 worker 不支持。每个用户最多 10 个 active task,所有 key 和策略共享这个上限。高频记录保留 7 天,任务和正式回复草稿保留。

human 模式没有进度信号,也不能按请求延长。fallback 只 claim 一次,不重试;上游失败是 FAILED / 500,不是 504。调用方只会看到通用的 Request timed out.。

← 全部文章 阅读时长: 3分钟 写邮件