BUSINESS_AGENTS.md 12 KB

多业务智能体与陕西局接入

本服务保留 vent_agent_2.0 执行框架,初期单应用进程运行。主协调 Agent 处理综合聊天,业务 Agent 既可接受委派,也可按名称独立执行。当前仅注册 main_fan;其他业务职责确认后增加扩展,不创建占位智能体。

存储和配置

默认 DB_DIALECT=sqlite、DB_SQLITE_PATH=data/vent_agent.sqlite。业务任务、文件索引、会话、用量及推送回执进入本库;图状态使用 CHECKPOINT_DB_PATH=data/checkpoints.sqlite。SQLite 使用 WAL 和连接锁,保持单进程部署。切换数据库配置不自动迁移 MySQL 历史数据。备份需在停机或使用 SQLite 在线备份机制时同时保存业务库、checkpoint 和 data/workspaces/。

主通风机研判默认开启,配置 MAIN_FAN_ENABLED=0 可关闭。支持双机报告参数、同条件性能数据及切换前后稳定风量比较。completed 表示业务执行完成,具体结论使用 judgment.resultCode。详见 主通风机业务与模拟联调。

增加业务

在 extensions/<业务名>/extension.py 中调用 registry.register_business_agent(...),声明 name、display_name、description、prompt、tools、input_schema、result_schema、max_concurrency。GatewayBinding 声明取数身份,ResultBinding 声明结果平台身份,二者独立。示例见 extensions/main_fan/。

输入和结果使用 Pydantic schema;平台任务结果应继承 runtime.business_models.JudgmentResult。业务工具绑定到专业 Agent,主协调 Agent 经委派使用,保留通用工具。专业 Agent 的独立图分别编译和缓存;全局模型更新失效所有缓存。会话绑定 Agent,不能在已有会话切换业务,否则返回 409,应新建会话。

自主探索业务额外声明 skill_path="/skills/<名称>/SKILL.md"。这类 Agent 不强迫模型再输出结果 schema:由最终提交工具将校验后的正式结果写入 structured_response,SkillCompletionMiddleware 结束调用,结果 validator 和 schema 仍在宿主归档时执行。工具失败返回反馈时不会结束,模型可修正后继续。未声明 skill_path 的业务保留原结构化输出方式。

主协调 Agent 的 task 委派与独立图共用业务定义和启停检查。独立任务额外使用业务级并发上限;全局并发、会话互斥、超时、checkpoint 和计费仍由 runtime 统一处理。

按名称执行

网页新会话选择“矿井主通风机研判智能体”;已有会话沿用绑定的智能体。POST /api/chat 新增可选 multipart 字段 agent_name,缺省为综合助手,新会话填 main_fan 可独立执行。恢复和历史查询自动使用原 Agent。

非 HTTP 脚本可以直接执行:

import asyncio
from db import chat_store
from runtime.environment import RuntimeEnvironment
from runtime.execution import execute

async def main():
    async with RuntimeEnvironment():
        session = chat_store.create_session("report-user", "full")
        result = await execute(
            agent_name="main_fan", user_name="report-user", session_id=session["id"],
            message='输入:{"mine_code":"测试矿井编码","mine_name":"测试煤矿","materials":[]}',
        )
        print(result.status, result.structured_output or result.output)

asyncio.run(main())

持久化任务 API

主网页服务会启动 RuntimeEnvironment(business_jobs=True),独立脚本默认不启动队列。业务 API 服务凭证是自己的 BUSINESS_API_TOKEN,与网关通讯凭证不同;未配置时受保护接口返回 503。该凭证不替代已有聊天 API 的用户鉴权。

方法 路径 用途
GET /api/business-agents 公开业务目录,无凭证
GET /api/business-agents/{name}/schema 输入和结果 schema,无凭证
POST /api/business-agents/{name}/jobs 提交任务,返回 202,需自己的 Bearer 凭证
GET /api/business-agents/{name}/jobs 按 user_name 查询任务,需凭证
GET /api/business-agents/{name}/jobs/{id} 任务详情,需凭证及匹配 user_name
GET /api/business-agents/{name}/jobs/{id}/result 获取与实际推送一致的新格式 JSON,需凭证
POST /api/business-agents/{name}/jobs/{id}/publish 将已保存结果加入独立结果平台队列,需凭证
POST /api/business-agents/{name}/jobs/{id}/retry 重试失败/取消/意外中断任务或失败推送,需凭证
GET /api/business-agents/{name}/status 本地启停状态、业务与推送统计,需凭证
POST /api/business-agents/{name}/manage?action=start\|stop\|restart 单业务逻辑启停,需凭证

任务请求示例(所有矿井值均为测试占位,正式值由平台提供):

{
  "request_id": "main-fan-demo-001",
  "user_name": "default",
  "input": {"mine_code": "test-mine", "mine_name": "测试煤矿", "fan_id": "F1", "materials": []},
  "files": [],
  "publish": false
}

同一业务、用户、来源和 request_id 重复提交返回原任务;改变输入时拒绝。模型成功执行与业务正式研判完成分开记录。任务 API 中,业务 completed 且请求 publish=true 时进入推送队列;网页/工具调用在结果平台启用且 MAIN_FAN_AUTO_PUBLISH=1 时自动入队。结果保存后推送重试不会再次调用模型或识别原件。网络错误和 429/502 等暂时故障退避重试,最多10次;永久错误保留结果及失败状态,可通过 publish/retry 接口重新排队。

意外停机时运行中的任务标为 interrupted,需明确重试,避免重复模型调用;已保存的待推送结果重启后继续推送。等待审批的任务记为 waiting_input,通过现有 /api/chat/resume 恢复(携带会话、user_name 和 interrupt_token);队列执行器同步结果。

连接对方网关

填写以下配置后重启服务:

SHANXI_GATEWAY_ENABLED=1
SHANXI_GATEWAY_URL=对方提供的网关根地址
SHANXI_GATEWAY_TOKEN=对方提供的网关通讯凭证
MAIN_FAN_AGENT_CODE=平台分配的编码

客户端为每个业务显式携带 X-Agent-Code,不共享可变的全局身份。网关用于 JSON 接口转发和下载凭证下发;应用启动时不注册业务、不建立网关 SSE 控制连接,也不向网关上传或推送结果。本地业务启停走自己的 manage API。旧数据库 gateway_online 字段仅为历史兼容,不再作为业务准入条件;单次取数失败仍正常记录为任务失败。旧的 MAIN_FAN_CHECK_TYPE_CODE、MAIN_FAN_TOPICS、MAIN_FAN_SENSOR_TYPES 不再参与运行时接入。

文件获取

文件列表、下载路径、参数和业务触发源由对方提供,当前不预设具体通风接口。SHANXI_FILE_BASE_URL 是文件所属系统根地址。任务 files 示例:

{"file_id":"report-001","version":"v1","filename":"主通风机报告.pdf","path":"/对方提供的下载路径","params":{"id":"report-001"}}

先向网关获取 access_token/client_id,再直连文件系统流式下载,限制大小、不跟随跳转。文件进入会话 /workspace/uploads/ 并记录版本、大小和 SHA256。下载返回 JSON、空文件、凭证不可恢复等会使任务失败,不把错误响应当成文件。401/403 仅在重新取得不同凭证后重试一次;当前网关仅在空 token 时刷新,已过期凭证重复下发需对方解决。

独立结果平台

配置与取数网关完全分开,RESULT_PLATFORM_URL 是完整接收接口地址:

RESULT_PLATFORM_ENABLED=1
RESULT_PLATFORM_URL=http://127.0.0.1:8767/api/judgments
RESULT_PLATFORM_TOKEN=local-result-platform-token
RESULT_PLATFORM_AUTH_HEADER=Authorization
RESULT_PLATFORM_AUTH_SCHEME=Bearer
RESULT_PLATFORM_SUCCESS_FIELD=code
RESULT_PLATFORM_SUCCESS_VALUES=0,200
MAIN_FAN_RESULT_AGENT_CODE=main_fan_equivalence_agent
MAIN_FAN_RESULT_AGENT_NAME=矿井主通风机同等能力研判
MAIN_FAN_AUTO_PUBLISH=1

以上为本地接收平台的接口及凭证。正式环境替换为对方提供的值。自定义 API Key 头可配置 AUTH_HEADER,例如 X-API-Key,并设 AUTH_SCHEME=none;无鉴权接口显式设 AUTH_HEADER=none。接收成功以 HTTP 204,或 HTTP 2xx 且 JSON 中配置的成功字段匹配成功值为准。支持 data.code 等嵌套字段;HTTP 200 的业务失败、HTML 登录页或任务身份不符不计成功。完整回执保存在 receipt_json。

每条报文对应“矿井+同组主备风机+一次研判”,所有叶子字段都是字符串:

字段 内容
agentCode / agentName 结果平台的智能体身份,与网关取数身份分开
taskId 32位任务标识,同次任务重试保持不变
checkedAt 研判完成时间,Asia/Shanghai,yyyy-MM-dd HH:mm:ss
mineCode / mineName 实际输入并校验过的矿井身份
objectDetail 同组两台设备的名称、标识、研判内容
dataDetail 实际参与分析的资料来源、时段、指标和阈值
judgment.resultCode NORMAL / WARNING / ABNORMAL / UNDETERMINED
judgment.result 一句列表结论
judgment.reason 完整整体报告,去除内嵌图片编码和 Markdown 表格标记
judgment.evidenceLink 已部署的外部证据页地址;当前为空字符串

NORMAL 只要求三项通过:两台风机报告基础参数一致(型号、额定功率及共同载明的基础参数)、停机至启动间隔≤10分钟、切换前后稳定风量差≤10%。叶片角度、备用台账可用性、补充曲线/风压指标、普通OCR说明和表图差异不增加否决条件;表图差异在报告中独立说明。明确的一般参数差异、切换间隔超过10分钟或风量差大于10%且小于15%输出 WARNING;有效证据确认风量差达到15%输出 ABNORMAL;关键数据不足或冲突、无法有效比较时输出 UNDETERMINED。10分钟、10%的等于边界仍为通过。规则文件的 severity 分别配置严重风量差、严重切换间隔与严重参数字段,目前风量严重线为15%,另两项留空;严重规则仅针对有有效证据且已不通过的对应项目。ABNORMAL 是业务规则异常,不自动等同于法律上的重大隐患认定。

内部 MainFanResult 保留 analysis_id、workflow_id、证据及计算记录,新格式报文存入 platform_payload。网页继续显示整篇报告;任务的 /result 接口直接返回报文。普通网页研判也可通过 GET /api/business-agents/main_fan/analyses/{analysis_id}/result?session_id=...&user_name=... 查询,使用 BUSINESS_API_TOKEN。模型只能返回工具凭据,服务端从同用户、同会话 SQLite 原件恢复,不能改写编码、数值或结论。

首次入队即冻结报文和接收地址,数据存于 business_jobs.push_payload、business_push_targets。重启和重试沿用同一 taskId、checkedAt、正文及 Idempotency-Key。修改接收地址或智能体身份后,不自动把历史待推送结果改投新平台。原文件和计算记录继续由我们管理,不经网关上传。旧格式历史结果不会被自动改写或重发,需重新执行研判产生新格式结果。

本地接收联调

另开终端运行 .venv/bin/python scripts/mock_result_platform.py,默认端口8767,独立库 data/mock_result_platform.sqlite。取数网关仍在8766,网页仍在8080。浏览器访问 http://127.0.0.1:8767/docs,Authorize 填入上述本地接收凭证,调用 GET /api/judgments 查看收到的原文和回执。重复的 agentCode/taskId 返回相同回执,内容发生变化则409;重启接收服务不会丢记录。可加 --fail-first 1 验证首次503后恢复推送。

验证

运行 .venv/bin/python -m pytest 和 .venv/bin/python scripts/selfcheck.py。测试使用独立 SQLite、假模型、取数网关和独立接收平台,不需要外部访问权限。真实联调还需网关取数信息,以及结果平台的接口地址、鉴权和成功回执约定。