智能体大模型接口全面切换 + 新增视觉智能体

- 全部 AI Worker 切换到 deepseek/deepseek-v4-flash(api.deepseek.com,实测757ms/次,成本降40倍)
- 团队模板默认 provider/model 同步改为 deepseek/deepseek-v4-flash
- 新增视觉智能体「视觉分析师」:autodl/qwen3.6-plus 多模态
- llm_gateway: chat_vision 多模态调用(URL/base64) + 空content自动重试 + 聚合后端路由容错
- engine: 任务描述支持 ![图](url) 图片注入(视觉任务直接派活)
- API: POST /api/workers/<id>/vision_test;前端 Worker 页新增🖼️视觉测试按钮
- 实测: 截图结构化分析  雪羊图片识别  辩论模式DeepSeek 55秒完成
This commit is contained in:
2026-08-12 13:22:56 +08:00
parent 8bae953d7d
commit dc49864af4
6 changed files with 138 additions and 10 deletions
+56 -2
View File
@@ -30,7 +30,12 @@ def calc_cost(model, prompt_tokens, completion_tokens):
def chat(provider, model, messages, temperature=0.7, max_tokens=None,
base_url=None, api_key=None, timeout=None, retries=None):
"""调用 OpenAI 兼容 chat/completions,返回 {text, usage, cost, model}"""
"""调用 OpenAI 兼容 chat/completions,返回 {text, usage, cost, model}
messages 支持两种格式:
- 纯文本:[{'role':'user','content':'...'}]
- 多模态:[{'role':'user','content':[{'type':'text','text':'...'},
{'type':'image_url','image_url':{'url':'...'}}]}]
"""
cfg = get_provider_cfg(provider)
url = (base_url or cfg['base_url']).rstrip('/') + '/chat/completions'
key = api_key or cfg['api_key']
@@ -56,7 +61,14 @@ def chat(provider, model, messages, temperature=0.7, max_tokens=None,
resp = requests.post(url, json=payload, headers=headers, timeout=timeout)
if resp.status_code == 200:
data = resp.json()
text = data['choices'][0]['message']['content'] or ''
msg = data['choices'][0]['message']
text = msg.get('content') or ''
if not text:
# 推理模型偶发 content 为空:用 reasoning_content 兜底
text = msg.get('reasoning_content') or ''
if not text:
last_err = LLMError('模型返回空内容,重试中…')
continue
usage = data.get('usage', {})
pt = usage.get('prompt_tokens', 0)
ct = usage.get('completion_tokens', 0)
@@ -84,6 +96,48 @@ def chat(provider, model, messages, temperature=0.7, max_tokens=None,
raise last_err or LLMError('未知错误')
def chat_vision(provider, model, text, image_url=None, image_path=None,
temperature=0.4, max_tokens=2000, base_url=None, api_key=None,
retries=3):
"""多模态视觉调用:文本 + 图片(URL 或本地路径/base64)。
返回与 chat() 相同结构。
容错:聚合 API 偶发路由到纯文本后端(不认识 image_url),自动重试。"""
import base64 as _b64
import time as _time
content = [{'type': 'text', 'text': text}]
img_url = image_url
if image_path:
with open(image_path, 'rb') as f:
raw = f.read()
mime = 'image/png'
if image_path.lower().endswith(('.jpg', '.jpeg')):
mime = 'image/jpeg'
elif image_path.lower().endswith('.gif'):
mime = 'image/gif'
elif image_path.lower().endswith('.webp'):
mime = 'image/webp'
img_url = f'data:{mime};base64,{_b64.b64encode(raw).decode()}'
if img_url:
content.append({'type': 'image_url', 'image_url': {'url': img_url}})
messages = [{'role': 'user', 'content': content}]
last_err = None
for attempt in range(max(1, retries)):
try:
return chat(provider, model, messages,
temperature=temperature, max_tokens=max_tokens,
base_url=base_url, api_key=api_key)
except LLMError as e:
last_err = e
msg = str(e)
# 仅对“多模态格式不被支持/图片无效”类错误重试(聚合后端路由问题)
if any(k in msg for k in ('image_url', 'InvalidParameter', 'invalid_parameter',
'does not appear to be valid', 'image')):
_time.sleep(2 * (attempt + 1))
continue
raise
raise last_err or LLMError('视觉调用失败')
def test_connection(provider, model, base_url=None, api_key=None):
"""连通性测试:发一条最小请求"""
t0 = time.time()