feat: add persistent chat agent and indexed batch workflows

This commit is contained in:
2026-09-26 19:43:23 +08:00
parent 8bebcdb470
commit d61987c86c
17 changed files with 1758 additions and 180 deletions
+30
View File
@@ -101,6 +101,36 @@ class DeepSeekClient:
time.sleep(min(2 ** attempt, 5))
raise ModelError(f"模型请求或JSON校验失败({last_error}),已重试{self.retries}次")
def tool_call(self, messages: list[dict], tools: list[dict], *, tool_choice="auto"):
"""OpenAI-compatible native tool calls. Credentials and provider bodies never enter logs."""
body = {"model": self.model, "messages": messages, "tools": tools,
"tool_choice": tool_choice, "temperature": 0}
try:
with httpx.Client(timeout=min(self.timeout, 180), transport=self.transport) as client:
response = client.post(self.base_url + "/chat/completions", json=body,
headers={"Authorization": f"Bearer {self.api_key}"})
if response.status_code in (400, 404, 422):
raise ModelError("当前端点或模型不支持原生 tool_calls;请在模型设置中配置支持工具调用的 OpenAI 兼容端点和模型")
response.raise_for_status()
message = response.json()["choices"][0]["message"]
if not isinstance(message, dict) or not isinstance(message.get("tool_calls", []), list):
raise ModelError("模型返回格式不包含有效的 tool_calls 消息")
return {"role": "assistant", "content": message.get("content"), "tool_calls": message.get("tool_calls", [])}
except ModelError:
raise
except (httpx.HTTPError, KeyError, IndexError, ValueError, TypeError) as exc:
raise ModelError(f"对话模型请求失败({type(exc).__name__});请检查端点、模型和网络") from exc
def verify_tool_support(self):
"""Small capability probe without student or course content."""
probe = [{"type": "function", "function": {"name": "wisegrade_ping",
"description": "Return a ping for compatibility verification.",
"parameters": {"type": "object", "properties": {}, "additionalProperties": False}}}]
# Some compatible endpoints implement auto tool selection but reject "required".
response = self.tool_call([{"role": "user", "content": "For compatibility verification, call wisegrade_ping now and do not answer in text."}], probe)
if not any(call.get("function", {}).get("name") == "wisegrade_ping" for call in response["tool_calls"]):
raise ModelError("当前端点或模型未返回原生 tool_calls;请配置支持工具调用的端点和模型")
def validate_score(result: ScoreResult, criterion: dict, chunks: list[dict]):
if result.criterion_id != criterion["criterion_id"] or result.max_score != criterion["max_score"]: