feat(llm): profile表补path/headers自含字段;model表补query_profile_ids后续步骤模板链(异步模型提交→查询→[下载]);CRUD接helper+placeholder说明

This commit is contained in:
yumoqing 2026-09-04 14:00:15 +08:00
parent 4b6b4a2c95
commit d5dd9f4be2
9 changed files with 74 additions and 4 deletions

View File

@ -6,6 +6,7 @@
"browserfields": {
"exclouded": [
"id",
"headers",
"request_template",
"response_template",
"param_schema"
@ -28,6 +29,12 @@
"dataurl": "{{entire_url('../api/get_llm_status_options.dspy')}}",
"valueField": "value",
"textField": "text"
},
"path": {
"placeholder": "请求路径相对端点base_url如 /chat/completions"
},
"headers": {
"placeholder": "请求头JSON如 {\"Authorization\": \"Bearer {{api_key}}\", \"Content-Type\": \"application/json\"}"
}
}
},

View File

@ -5,7 +5,8 @@
"sortby": "name",
"browserfields": {
"exclouded": [
"id"
"id",
"query_profile_ids"
],
"alters": {
"vendor_id": {
@ -37,6 +38,16 @@
"dataurl": "{{entire_url('../api/get_llm_ppid_options.dspy')}}",
"valueField": "value",
"textField": "text"
},
"sync_mode": {
"uitype": "code",
"data": [
{"value": "sync", "text": "同步"},
{"value": "async", "text": "异步(提交后轮询)"}
]
},
"query_profile_ids": {
"placeholder": "后续步骤模板ID的JSON数组异步模型提交后顺序执行 查询→[下载]),如 [\"模板ID1\",\"模板ID2\"]"
}
}
},
@ -46,9 +57,9 @@
"updated_at"
],
"editable": {
"new_data_url": "{{entire_url('./add_llm_model.dspy')}}",
"update_data_url": "{{entire_url('./update_llm_model.dspy')}}",
"delete_data_url": "{{entire_url('./delete_llm_model.dspy')}}"
"new_data_url": "{{entire_url('../api/add_llm_model.dspy')}}",
"update_data_url": "{{entire_url('../api/update_llm_model.dspy')}}",
"delete_data_url": "{{entire_url('../api/delete_llm_model.dspy')}}"
}
}
}

View File

@ -39,6 +39,17 @@
"nullable": "no",
"default": "'t2t'"
},
{
"name": "path",
"title": "请求路径",
"type": "str",
"length": 200
},
{
"name": "headers",
"title": "请求头(JSON)",
"type": "text"
},
{
"name": "request_template",
"title": "请求模板(Jinja2)",

View File

@ -65,6 +65,11 @@
"type": "str",
"length": 32
},
{
"name": "query_profile_ids",
"title": "后续步骤模板链(JSON)",
"type": "text"
},
{
"name": "ppid",
"title": "定价项目ID",

View File

@ -41,6 +41,7 @@ CREATE TABLE IF NOT EXISTS llm_model (
`capability` varchar(20) NOT NULL DEFAULT 't2t' comment '能力类型',
`sync_mode` varchar(10) NOT NULL DEFAULT 'sync' comment '同步性',
`profile_id` varchar(32) comment '适配模板ID',
`query_profile_ids` text comment '后续步骤模板链(JSON数组,异步模型提交后顺序执行:查询/下载)',
`ppid` varchar(32) comment '定价项目ID(pricing_program)',
`price_input` decimal(12,6) NOT NULL DEFAULT 0 comment '输入单价(元/千token)',
`price_output` decimal(12,6) NOT NULL DEFAULT 0 comment '输出单价(元/千token)',
@ -62,6 +63,8 @@ CREATE TABLE IF NOT EXISTS llm_api_profile (
`name` varchar(100) NOT NULL comment '模板名称',
`protocol` varchar(20) NOT NULL comment '协议类型',
`capability` varchar(20) NOT NULL DEFAULT 't2t' comment '能力类型',
`path` varchar(200) comment '请求路径(相对端点base_url,如/chat/completions)',
`headers` text comment '请求头(JSON,含认证头模板)',
`request_template` text comment '请求模板(Jinja2)',
`response_template` text comment '响应模板(Jinja2)',
`param_schema` text comment '参数Schema(bricks input_fields)',

View File

@ -277,6 +277,15 @@ async def create_llm_model(params_kw):
if dp.strip():
json.loads(dp) # 校验合法
data['default_params'] = dp
# 后续步骤模板链JSON 数组校验
qp = data.get('query_profile_ids', '') or ''
if isinstance(qp, (list, dict)):
qp = json.dumps(qp, ensure_ascii=False)
if qp.strip():
ql = json.loads(qp)
if not isinstance(ql, list):
raise ValueError('query_profile_ids 必须是 JSON 数组')
data['query_profile_ids'] = qp
data['id'] = getID()
db, dbname = _get_sor()
async with db.sqlorContext(dbname) as sor:
@ -303,6 +312,15 @@ async def update_llm_model(params_kw):
if dp.strip():
json.loads(dp)
data['default_params'] = dp
if 'query_profile_ids' in data:
qp = data.get('query_profile_ids', '') or ''
if isinstance(qp, (list, dict)):
qp = json.dumps(qp, ensure_ascii=False)
if qp.strip():
ql = json.loads(qp)
if not isinstance(ql, list):
raise ValueError('query_profile_ids 必须是 JSON 数组')
data['query_profile_ids'] = qp
db, dbname = _get_sor()
async with db.sqlorContext(dbname) as sor:
await sor.U('llm_model', data)

View File

@ -0,0 +1,5 @@
# add_llm_model.dspy — 薄封装:走模块 helper注册名唯一+JSON字段校验
r = json.loads(await create_llm_model(dict(params_kw or {})))
if r.get('success'):
return {"widgettype": "Message", "options": {"title": "Success", "message": r.get('message') or 'ok', "timeout": 3, "cwidth": 16, "cheight": 9}}
return {"widgettype": "Error", "options": {"title": "Error", "message": r.get('message') or 'failed', "timeout": 3, "cwidth": 16, "cheight": 9}}

View File

@ -0,0 +1,5 @@
# delete_llm_model.dspy — 薄封装:走模块 helper被组织策略引用时禁止删除
r = json.loads(await delete_llm_model(dict(params_kw or {})))
if r.get('success'):
return {"widgettype": "Message", "options": {"title": "Success", "message": r.get('message') or 'ok', "timeout": 3, "cwidth": 16, "cheight": 9}}
return {"widgettype": "Error", "options": {"title": "Error", "message": r.get('message') or 'failed', "timeout": 3, "cwidth": 16, "cheight": 9}}

View File

@ -0,0 +1,5 @@
# update_llm_model.dspy — 薄封装:走模块 helperJSON字段校验
r = json.loads(await update_llm_model(dict(params_kw or {})))
if r.get('success'):
return {"widgettype": "Message", "options": {"title": "Success", "message": r.get('message') or 'ok', "timeout": 3, "cwidth": 16, "cheight": 9}}
return {"widgettype": "Error", "options": {"title": "Error", "message": r.get('message') or 'failed', "timeout": 3, "cwidth": 16, "cheight": 9}}