pipeline-llm/README.md

9.8 KiB
Raw Blame History

pipeline-llm — 产线平台模型治理模块

产线平台的模型层:供应商/账号/模型治理 + 组织容错策略 + 限额限流 + 双维度记账。 所有表 llm_ 前缀建在宿主应用库pipeline

模块定位

解决五类问题:

  1. 供给侧治理:供应商协议+全球端点目录、账号(钱包)、模型注册、适配模板
  2. 容量治理:供应商限流 → 多账号轮转;多供应商 → 主备模型容错
  3. 需求侧治理:组织级模型容错策略、组织限额限流、个人限额限流
  4. 计费:双维度记账(成本侧记账号、消费侧记组织/个人),模型挂定价 pricing_program.ppid
  5. 端点选择端点目录配在供应商下全球配置一次账号选用端点客户按区域偏好prefer/must

数据表8 张)

说明
llm_vendor 供应商(端点目录 JSON2026-09-05 起不存协议字段,请求形态归模型挂的适配模板)
llm_account 供应商账号(钱包:余额/充值/选端点api_key AES 加密;模型可绑定账号 account_id 收窄候选池)
llm_model 模型注册(能力分类/挂定价 ppid/sync_mode/query_profile_idsname 唯一2026-09 起不存单价,定价走 ppid
llm_api_profile 适配模板(提交模板按协议×能力×形态指纹去重复用,见 _tpl_fingerprintdata/response 模板全 Jinja2含媒体转换函数method 独立列2026-09-06 起不塞 request_template
llm_org_policy 组织容错策略(主备模型 + 辅助模型 utility_model_id + 端点偏好)
llm_org_quota 组织限额限流(池余额 + QPM
llm_user_quota 个人限额限流(额度上限 + QPM
llm_usage 用量流水双维度记账事实表status 统一枚举 SUCCEEDED/FAILED/PENDING/RUNNING/rechargeaccounting_status 仅 SUCCEEDED 行有意义否则 NULLusages 字段存非 token 计价因子 JSON

调用门禁链

① 个人限流 → ② 组织限流 → ③ 个人额度 → ④ 组织池(预授权)
→ ⑤ 组织策略选模型(主→备) → ⑥ 账号×端点候选池(偏好过滤+余额加权+冷却避让)
→ ⑦ 调用 → ⑧ 结算(实际用量,多退少补,双维度记账)

任何一级不过:快速失败 + 明确中文原因(不挂起、不静默)。

集成方式(复用不改建)

模块只提供治理引擎与配置管理;实际 LLM 转发仍由宿主已有的 pipeline_service.llm_bridge / llm_proxy 承担,在两处挂钩子:

  • llm_bridge._get_model_config:治理启用时前置解析(主备容错+端点选择)
  • llm_proxy.proxy_chat_completion:调用前后接门禁与结算(运行环境 token 路径)

机构未配置治理(无策略、无新模型)→ 返回 __LEGACY__,调用方回退旧 llm 表,向后兼容。

宿主接入清单

  1. app/pipeline_app.py init() 加 load_pipeline_llm()try/except ImportError 兜底;规范名 load_<模块名>,旧名 load_llm 保留为别名)
  2. build.shclone 枚举 + pip install 枚举 + CRUD 生成枚举 + wwwroot 符号链接枚举
  3. scripts/create_tables.pyIDE 幂等建表枚举加 pipeline-llm(或执行本模块 mysql.ddl.sql
  4. scripts/import_init.pyINIT_MODULES 加本模块 init/data.jsonappcodes 字典)
  5. conf/rp.json/pipeline-llm/** 注册到 logined;运行 scripts/load_path.py
  6. wwwroot/index.ui 主菜单加「模型治理」项URL /pipeline-llm
  7. restart-pipeline.sh 重启(.py 变更必须重启;api_key 有缓存,改 key 也须重启)

关键约定

  • api_key 用 AES 单层加密appPublic.aes.aes_encode_b64password_key 做密钥)。 ⚠️ 不用 RC4password()/unpassword() 盐不对称,加密后永久不可解。
  • 限流用 Redis 分钟窗口原子计数db4与会话 db3 隔离Redis 故障时限流放行fail-open 余额仍由 DB 条件 UPDATE 守住。
  • 429 → (账号,端点)对冷却 60s;账号级冷却用 * 通配键。
  • status 统一枚举 + 记账三态2026-09-05 定夺2026-09-06 补 NULL 语义m0012 llm_usage.status 各家模型归一为 SUCCEEDED/FAILED/PENDING/RUNNING其他=recharge 充值对账行)。 accounting_status 只有三个值——created(待记账)→ accounted(记账成功)/ failed(记账失败); 只有 status='SUCCEEDED' 才有记账意义:仅成功行写 created非 SUCCEEDED 行保持 NULL (不冒充待记账)。出账循环扫 accounting_status='created' AND status='SUCCEEDED'。 自用 vs 跨机构分流由产品层 product_accounting_generic 的 is_self_use 决定(自用只记 PAY* 采购成本, 跨机构另记 PAY 客户应付)。流水 usages 存非 token 计价因子(视频时长/ 分辨率等),异步出账循环(独立进程,需 load_appbase 提供 get_business_date 读入定价引擎。未挂 ppid 的模型出账置 failed 并写明原因(不静默)。
  • method 独立列2026-09-06 用户定夺m0012llm_api_profile.methodGET/POST 默认 POST不塞 request_template JSON运行时读该列决定 HTTP 动词,存量行由迁移 从 request_template 的 $.method 回填,查询步骤兼容回退解析。
  • 媒体转换铁律2026-09-06 三数组契约,对齐 sage/llmage:生成类模型适配模板 data 用 b64media2url(request, _f) 逐元素转公网 URL、response 用 downloadfile2url(request, url)(生成物落地本地,上游 URL 仅 24 小时); 上行媒体统一三数组参数 image_files/audio_files/video_files(字符串或数组 均可Jinja is string 动态判断),变长输入用 {% for %} 按文档示例组装。
  • 异步模型执行器sync_mode=async 时走提交→按 query_profile_ids 轮询→ 取结果;等待预算默认 600 秒,_timeout 可覆盖(上限 900
  • 会话 agent 模型选择收窄为对话能力2026-09-06 用户定夺) selection.CHAT_CAPS = ('t2t','i2t','m2t') 是会话形态能力白名单的唯一事实源—— 所有会话 agent 模型下拉agent_model_options / cockpit_model_options / get_model_options 角色配置)传 capabilities='chat' 过滤;持久化入口 set_agent_model 个人默认 / cockpit_agent 角色模型 / pipeline_service gateway._resolve_and_persist_model 项目模型)同样只接受对话能力,防绕过下拉。 chat_inference 同步门禁从「只认 t2t」放宽到 CHAT_CAPS实测根因测试库 机构策略主模型 qwen3.8-max 能力是 i2t旧门禁直接 FAILED 「capability mismatch: i2t != t2t」会话 agent 选它必挂)。 存量模型 capability 空串按 t2t 语义归一COALESCE+NULLIF。 embedding/rerank/图视频生成等非对话模型各有专属入口list_models 按能力分栏)。
  • m2t多媒体生文入能力字典四处同步m0013:种子 init/data.json + 端点注释 api/v1/models.dspy + docs/design-spec.md §6 + 提取提示词 pipeline_platform.platform_ability._EXTRACT_PROMPT,判定表补 「多媒体输入→文本 ⇒ m2t」「仅图像→文本 ⇒ i2t」「仅文本→文本 ⇒ t2t」 且 r2v 判定加「输出为视频」限定防误吸文本输出模型); _MEDIA_INPUT_CAPS 加 m2t模板生成按输入媒体处理

治理页面弹窗化2026-09-07 用户定夺)

wwwroot/index.ui 顶部统计条llm_dashboard_widget+ 7 张功能卡片。 每张卡片点击后弹窗处理PopupWindow 85%×85%),不再在页面下方 llm_content 容器展示

  • api/card_popup.dspytarget 白名单llm_vendor/llm_model/llm_api_profile/llm_org_policy/ llm_org_quota/llm_user_quota/llm_usage→ 弹窗内嵌对应 CRUD 页 urlwidget 非白名单 target 返回「无效的功能入口」提示(不拼 URL
  • 模型注册弹窗target=llm_model顶部额外两个按钮
    • 🤖 自动配置api/auto_config_popup.dspy:输入 API 文档与定价信息的链接或正文, 「开始自动配置」按钮 script 组装指令后驱动弹窗内嵌 AgentIO pipeline_id=platform_general弹窗级独立 session_idspec 锚定会话隔离天然成立), 内部助手全链完成(抓取/提取/落库/定价/测试/记账检查)后汇报模型状态。
    • 上线检查api/online_check_popup.dspy:模型下拉 api/get_llm_online_check_models.dspyvalue=模型名test_model_call 按名调用)+ 「上线检查」按钮 → 内部助手按模型配置后的测试过程处理test_model_call 真实调用 → check_model_accounting 记账检查 → platform_llm_status 状态复核),最后明确告知通过/不通过。
  • 驱动 AgentIO 的机制:io.inputw.textw.setValue(指令) + io.inputw.input_finished() AgentInput 原生方法 dispatch('inputed') → AgentIO POST 流),零自定义 JS 文件。
  • 权限:新 dspy 都在 /pipeline-llm/** logined 通配内,无需新增 RBAC 内部助手工具本身有 owner 角色代码层硬门禁pipeline-platform

API 文档端点2026-09-05

/pipeline-llm/api/v1/docs/RBAC 授权 any公开文档照 sage /bricks/docs 先例):

  • index.ui_lang 参数分发 ApiDoc 组件zh/en/ja/ko 四语言,带白名单回落 zh
  • api_{zh,en,ja,ko}.md 四语言文档chat/completions + models 端点、异步模型参数、 媒体转换约定、token 认证、计费说明)
  • 依赖宿主 conf/config.json 的 processors 注册 [".md","md"]MarkdownProcessor

文档

  • docs/design-spec.md — 完整设计规范(架构/表/机制/功能点/分期)
  • docs/test-cases.md — 测试用例30 例,部署后全部执行)

开发日志

docs/work-log-2026-09-01.md