落地并存测服全端:智能体 Graph/路由、后台切 8180、主账与部署脚本齐备,便于线上重发与验收。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
linmianxun
2026-09-13 21:15:58 +08:00
co-authored by Cursor
parent 0eb1adecc8
commit 8103b3b651
143 changed files with 8968 additions and 277 deletions
+127
View File
@@ -0,0 +1,127 @@
"""
LLM 网关骨架:入队 Redis Stream,不在回调线程等完整结果。
本文件职责:校验 mode、短幂等、XADD;真实模型 HTTP 后续按 mode 实现。
禁止:wait_result 堵在请求线程;禁止本包维护工单六态。
"""
from __future__ import annotations
import logging
from dataclasses import dataclass
from typing import Any, Optional
from agent.config import Settings, get_settings
from agent.llm.modes import LlmMode
from agent.redis_coord import get_redis_runtime, try_acquire_idempotency
from agent.redis_coord.runtime import RedisRuntime
logger = logging.getLogger(__name__)
@dataclass
class LlmEnqueueResult:
"""入队结果。"""
accepted: bool
entry_id: str = ""
reason: str = ""
@dataclass
class LlmGateway:
"""
LLM 网关。
调用:HTTP/Handler 只 enqueue;Worker 槽 claim 后调 invoke_stub/未来真调用。
"""
settings: Settings
redis: RedisRuntime
@classmethod
def from_settings(cls, settings: Optional[Settings] = None) -> "LlmGateway":
cfg = settings or get_settings()
return cls(settings=cfg, redis=get_redis_runtime(cfg))
def enqueue(
self,
*,
mode: LlmMode | str,
payload: dict[str, Any],
idempotency_key: str = "",
) -> LlmEnqueueResult:
"""
将任务写入 LLM Stream。
重复 idempotency_key(TTL 内)返回 accepted=False。
副作用:可能写 Redis;不调外部模型。
"""
mode_val = mode.value if isinstance(mode, LlmMode) else str(mode)
try:
LlmMode(mode_val)
except ValueError:
return LlmEnqueueResult(accepted=False, reason=f"unknown_mode:{mode_val}")
if idempotency_key:
ok = try_acquire_idempotency(
self.redis.client,
scope=f"llm:{mode_val}",
idempotency_key=idempotency_key,
ttl_seconds=300,
)
if not ok:
return LlmEnqueueResult(accepted=False, reason="duplicate_idempotency_key")
body = {"mode": mode_val, "payload": payload}
entry_id = self.redis.llm_stream.enqueue(
payload=body,
idempotency_key=idempotency_key,
)
logger.info("llm.enqueue mode=%s id=%s", mode_val, entry_id)
return LlmEnqueueResult(accepted=True, entry_id=entry_id)
def invoke_stub(self, *, mode: LlmMode | str, payload: dict[str, Any]) -> dict[str, Any]:
"""
模型调用占位:返回固定结构,不访问外网。
正式实现按 mode 调 DeepSeek/千问;本方法仅供骨架与单测。
"""
mode_val = mode.value if isinstance(mode, LlmMode) else str(mode)
if mode_val != LlmMode.ORDERED_ACTIONS.value:
from agent.llm.mode_registry import invoke_mode_shell
return invoke_mode_shell(mode_val, payload=payload)
return {
"ok": True,
"stub": True,
"mode": mode_val,
"echo_keys": sorted(payload.keys()),
"note": "骨架不调用真实模型",
}
def invoke(
self,
*,
mode: LlmMode | str,
messages: list[dict[str, Any]],
allow_network: bool = False,
) -> dict[str, Any]:
"""
Worker 槽内调用模型。
allow_network=False:走 stub(默认,防误打费)。
allow_network=True:走 LlmHttpClient(需已配 API Key)。
"""
if not allow_network:
return self.invoke_stub(mode=mode, payload={"messages": len(messages)})
from agent.llm.http_client import LlmHttpClient
result = LlmHttpClient.from_settings(self.settings).chat(mode=mode, messages=messages)
return {
"ok": result.ok,
"stub": False,
"provider": result.provider,
"content": result.content,
"error": result.error,
}