@roll-agent/octopus-agent
v0.3.1
Published
Octopus Agent:编排 Sponge MCP Server 的 NL2SQL 查询链路
Readme
Octopus Agent
Octopus Agent 是 Node.js 实现的轻量 NL2SQL(自然语言转 SQL)调用客户端。正常查询调用 query_sponge(查询 Sponge),SQL 修复由 Sponge 主流程内部完成;查询成功后根据 Sponge 返回的能力契约,可继续调用 analyze_query_result(分析查询结果)或 export_query_csv(导出全部数据)。丸子不负责图表生成。
询问能力、没有可识别的查询对象或查询动作、闲聊、无关问题或要求增删改业务数据时,由 LLM(大语言模型)调用 get_query_guidance(获取查询引导);程序不使用字符串或正则匹配用户原话。查询引导只是动态示例,不是能力白名单;明确业务查询即使重复提出、未出现在引导中或仅缺少筛选条件具体值,也必须调用 query,由 Sponge 判断是否追问。用户要求使用、启动或检查丸子 Agent 时,仅通过 GET /mcp/health 执行健康检查,不尝试简单业务查询。
上一轮 query 返回 clarifying(等待补充条件)或成功结果展示『猜你想查』后,用户选择编号或追加其他要求时,下一次 query.question(查询问题)仍逐字传入用户本轮原话,例如 2,并分析;禁止在 Octopus 中替换为选项正文,选项解析和历史继承由 Sponge 统一处理。
本地运行
要求 Node.js 22.6 或更高版本。query 使用 @roll-agent/sdk 的 defineTool(定义工具)和 Zod(输入校验)声明入参;现有 MCP 响应适配层继续负责标准答案和结构化内容。
npm install
npm test
npm startRoll Agent 接入
roll agent add .
roll run octopus-agent query --json \
--input-json '{"question":"查询本月各门店销售额","isNewConversation":true}'上层平台必须明确传递 isNewConversation(是否新对话)。当前上层对话第一次调用丸子 Agent 时传 true;后续调用传 false。后续调用可以回传上一次结果中的 structuredContent.contextId,实现精确续接;没有回传时,Agent 会从该访问令牌最近 5 个上下文中进行语义选择。
query(自然语言查询)入参:
| 字段 | 必填 | 中文说明 |
|-|-|-|
| question | 是 | 用户原始问题,不得改写 |
| isNewConversation | 是 | 是否为当前上层对话第一次调用丸子 Agent;新对话传 true,后续传 false |
| contextId | 否 | 上一次返回的上下文 ID;isNewConversation=false 时用于精确续接 |
| resultFormat | 否 | 结果格式,支持 text/json/yaml/md/markdown/html,默认 markdown(Markdown 格式) |
同一上层对话的后续调用示例:
roll run octopus-agent query --json \
--input-json '{"question":"其中肯德基有多少个岗位","isNewConversation":false,"contextId":"ctx_a1b2"}'isNewConversation=true 时禁止同时传入 contextId,避免新对话误接旧上下文。
上层模型调用时使用 --json(完整 JSON),只读取 content[0].text(最终文本)及 structuredContent.contextId(结构化内容中的上下文 ID)等必要字段。
export_query_csv(导出全部数据)接收必填的 queryId(查询编号)和可选的 analysisRequest(分析要求)。仅当上一条结果的 structuredContent.availableActions(可用动作)包含 export_query_csv 时,用户追问“导出 CSV”“导出全部”“把刚才结果导出”等纯导出诉求才直接沿用该查询编号。同一上层对话存在多次成功查询时,新查询覆盖此前的默认续接目标;用户未明确指定更早对象或查询编号时,只能使用时间上最后一次成功 query 返回的 queryId。用户要求“导出并分析”时只调用本工具,将本轮原话逐字传入 analysisRequest,禁止随后调用只分析页面快照的 analyze_query_result;只要求导出时省略。不再次调用 query,也不改写上一条问题。Sponge MCP Server 基于实际导出的最多 1000 条数据生成分析,并将同一份分析统一写入 answer(答案)和 CSV,octopus-agent 原样展示,不自行生成或补充分析。用户同时修改筛选条件时才发起新的 query。
纯图表要求不属于丸子能力,由独立 Chart Agent(图表智能体)处理。用户同时要求查询和生成图表时,Roll 先通过 Octopus 完成查询并导出 CSV,再将 CSV 临时地址和用户原始制图要求交给 Chart Agent;Octopus 不识别图型、不生成 HTML,也不为制图重新查询。
analyze_query_result(分析查询结果)接收必填的 queryId 和 analysisRequest(分析要求)。仅当上一条结果的 availableActions 包含 analyze_query_result,且用户只要求分析、没有同时要求导出时调用;查询当轮待分析时沿用 Sponge 返回的分析要求,用户后续追问分析时逐字传入本轮要求,不重新查询。
get_query_guidance(获取查询引导)接收必填的 showQueryOnlyNotice(是否展示仅支持查询提示)和可选的 role(角色),角色支持 operation(运营)、personal(个人)和 supplier(供应商)。能力询问传 false;闲聊、无关问题、没有可识别的查询对象或查询动作、增删改请求传 true。仅缺少筛选条件具体值时调用 query。Tool 返回 Sponge 内存快照中的本周热门、推荐问题、标准示例和可选筛选条件。
query 的结构化结果包含 resultKind(结果类型)、availableActions、pendingActions(待执行动作)及可能存在的 exportResult(自动导出结果)。pendingActions 非空时 terminal=false(当前调用链未结束),上层按顺序调用对应工具;全部完成后再统一展示每次工具返回的 content[0].text。resultKind=report(报表)且动作列表为空时,不显示查询编号,也不允许套用普通查询的导出或分析动作。
health(健康检查)无入参,返回 Sponge MCP Server 及业务库、权限库、审计库的 UP(正常)或 DOWN(异常)状态。
环境变量
| 环境变量 | 必填 | 中文说明 | 默认值 |
|-|-|-|-|
| SPONGE_MCP_BASE_URL | 是 | Sponge MCP Server 地址 | https://sponge-mcp.duliday.com |
| SPONGE_MCP_ACCESS_TOKEN | 是 | 身份透传 Token(令牌) | 无 |
Agent 内置单次请求超时 58 秒、query(查询)总超时 59 秒、网络重试 2 次,无需额外配置。每个新问题生成新的 requestId(请求编号),仅网络重试复用该编号。总超时低于当前 Roll 的 60 秒固定限制。
最终答案的“此次查询耗时”使用 Agent 记录的 agentDurationSeconds(Agent 总耗时),计算范围为 octopus-agent 收到 query 请求到生成可交给平台渲染的 content[0].text,包含上下文处理、网络传输、服务端处理和答案组装,精确到 3 位小数。MCP Server 不再计算或返回总耗时;平台收到 Tool 结果后的 UI(用户界面)绘制耗时不在 Agent 可观测范围内。
isNewConversation=true 时 octopus-agent 直接生成全局唯一 contextId(上下文 ID),不读取历史。isNewConversation=false 且传入 contextId 时精确续接;未传入时从 MCP Server 获取当前访问令牌最近 5 个上下文及每个上下文最近 5 轮问答,再由 Roll Core LLM(大语言模型)选择 continue(继续上下文)或 new(新话题)。多个候选同样合理时保守新建,避免并行聊天串线。MCP Server 在生成 SQL 时根据最终 ID 独立加载最近 5 轮;禁止 Server 自行切换 ID。requestId(请求编号)仍由 octopus-agent 每次请求重新生成。
Sponge Server 返回的 steps(阶段数据)仅用于内部审计,不再透传给上层 Agent;完整步骤通过现有 PostgreSQL 审计记录查看。
查询成功后,octopus-agent 直接使用 Sponge MCP Server 返回的 answer(答案),不校验是否包含数据分析,不调用 Roll Core Sampling(采样调用),也不使用程序重新生成分析。普通可续接查询追加 Agent 查询耗时和查询编号;报表等无后续动作结果不追加查询编号。最终内容放在 result.content[0].text;result.content[1] 只要求上层 Agent 逐字复制并在需要时继续执行 pendingActions,不要求外层模型分析或重建表格。查询返回的 resultAnalysis(结果分析信息)和 steps(阶段数据)不再透传;contextId、contextAction(上下文动作)和 contextReason(判断原因)保留在 result.structuredContent(结构化内容)中。
接口名称:export_query_csv(导出全部数据)
接口说明:重新校验并执行原查询 SQL,最多导出 1000 条;传入 analysisRequest 时基于实际导出数据生成分析,并把同一份分析写入页面答案和 CSV。
入参:
| 字段 | 必填 | 中文说明 |
|-|-|-|
| queryId | 是 | 原查询编号,必须来自上一条可导出的查询结果 |
| analysisRequest | 否 | 用户本轮逐字提出的分析要求;只导出时省略 |
回参:
| 字段 | 中文说明 |
|-|-|
| queryId | 原查询编号 |
| rowCount | 实际导出条数 |
| url | CSV 下载地址 |
| expiresAt | 下载地址过期时间 |
| answer | 下载信息,以及按需生成的完整导出数据分析 |
| resultAnalysis | 按需返回的分析文本、状态和导出统计摘要 |
curl -X POST 'http://localhost:3001/mcp/tools/export_query_csv' \
-H 'Authorization: Bearer <访问令牌>' \
-H 'Content-Type: application/json' \
-d '{"queryId":"qry_a1b2","analysisRequest":"分析多次上岗人员和门店分布"}'{
"queryId": "qry_a1b2",
"rowCount": 1000,
"url": "http://localhost:3001/mcp/exports/example",
"expiresAt": "2026-08-26T10:00:00.000Z",
"answer": "## 导出结果\n已生成 CSV,共 1000 条。\n\n## 数据分析\n以下结论基于本次实际导出的 1000 条数据。",
"resultAnalysis": {
"status": "llm",
"text": "以下结论基于本次实际导出的 1000 条数据。",
"summary": {
"rowCount": 1000,
"exportLimit": 1000,
"exportLimitReached": true
}
}
}MCP Server 内部接口
接口名称:get_query_guidance(获取查询引导)
接口说明:读取 Sponge 已聚合的内存快照,可按角色筛选推荐内容。
入参:
| 字段 | 必填 | 中文说明 |
|-|-|-|
| role | 否 | 角色:operation(运营)、personal(个人)、supplier(供应商) |
回参:
| 字段 | 中文说明 |
|-|-|
| snapshot | 快照时间范围、生成时间及下次刷新时间 |
| weeklyHotQuestions | 本周热门问题 |
| recommendedQuestions | 推荐问题 |
| blueprintGroups | 可复用查询蓝图分组 |
curl -X POST 'http://localhost:3001/mcp/tools/get_query_guidance' \
-H 'Authorization: Bearer <访问令牌>' \
-H 'Content-Type: application/json' \
-d '{"role":"supplier"}'{
"snapshot": {
"timezone": "Asia/Shanghai",
"weekStart": "2026-08-24T00:00:00+08:00",
"weekEndExclusive": "2026-08-31T00:00:00+08:00",
"generatedAt": "2026-08-25T09:00:00+08:00",
"nextRefreshAt": "2026-08-25T12:30:00+08:00"
},
"weeklyHotQuestions": [],
"recommendedQuestions": [],
"blueprintGroups": []
}接口名称:analyze_query_result(分析查询结果)
接口说明:基于已成功查询的服务端留存结果执行专项分析,不重新生成或执行 SQL。
入参:
| 字段 | 必填 | 中文说明 |
|-|-|-|
| queryId | 是 | 原查询编号,必须来自上一条结果 |
| analysisRequest | 否 | 分析要求;不传时复用原查询已保存的明确要求,但最终必须存在非空要求 |
回参:
| 字段 | 中文说明 |
|-|-|
| queryId | 原查询编号 |
| status | 分析状态 |
| analysisRequest | 本次分析要求 |
| answer | 已渲染的分析正文 |
| analysis | 分析内容 |
| analysisStatus | 模型分析状态 |
| cached | 是否复用已有分析 |
curl -X POST 'http://localhost:3001/mcp/tools/analyze_query_result' \
-H 'Authorization: Bearer <访问令牌>' \
-H 'Content-Type: application/json' \
-d '{"queryId":"qry_a1b2","analysisRequest":"比较供应商高低"}'{
"queryId": "qry_a1b2",
"status": "succeeded",
"analysisRequest": "比较供应商高低",
"answer": "## 数据分析\n甲供应商高于乙供应商。",
"analysis": "甲供应商高于乙供应商。",
"analysisStatus": "llm",
"cached": false
}接口名称:get_context_candidates(获取候选上下文)
接口说明:根据鉴权访问令牌返回最近 5 个成功上下文,每个上下文包含最近 5 轮成功问答。无业务入参,访问令牌 ID 由 MCP Server 鉴权获得。
返回字段:
| 字段 | 中文说明 |
|-|-|
| candidates | 候选上下文数组,最多 5 个 |
| candidates[].contextId | 上下文 ID |
| candidates[].lastActiveAt | 上下文最后成功查询时间 |
| candidates[].history | 最近成功问答数组,最多 5 条 |
| history[].question | 用户原始问题 |
| history[].answer | 对应查询答案 |
curl -X POST 'http://localhost:3001/mcp/tools/get_context_candidates' \
-H 'Authorization: Bearer <访问令牌>' \
-H 'Content-Type: application/json' \
-d '{}'{
"candidates": [
{
"contextId": "ctx_a1b2",
"lastActiveAt": "2026-07-17T10:00:00.000Z",
"history": [
{ "question": "上海有多少品牌", "answer": "上海共有 391 个品牌" }
]
}
]
}安全边界
- 正常查询只调用一次
query_sponge;SQL 生成、校验和最多两次自动修复都由 Sponge 主流程完成。 - 上一条查询的
availableActions包含export_query_csv时,纯导出追问才沿用queryId调用该工具;禁止重新调用query_sponge。导出仍由 Sponge MCP Server 去掉展示上限、应用导出上限并重新执行安全与权限校验。 - 上一条查询的
availableActions包含analyze_query_result时,才可沿用queryId做专项分析;查询当轮待分析时沿用服务端要求,后续追问时逐字传入用户本轮要求,禁止自行改写或重跑查询。 - 查询已自动导出全部数据时,保留 Sponge 返回的
exportResult,直接展示下载与分析正文。 - 导出成功时,Sponge MCP Server 返回的
answer已包含 CSV 下载信息和完整导出数据分析;octopus-agent 与上层 Agent 只能原样展示。 - 查询返回
failed(失败)时原样展示服务端错误并结束,禁止追问或自行补充查询条件。 - 查询返回
clarifying(等待补充条件)时原样展示服务端追问;用户下一轮补充条件后使用原contextId继续调用query。 - 查询成功或失败都使用
renderMode=verbatim_markdown(原样 Markdown)或renderMode=verbatim(原样文本)。octopus-agent 不校验或补充 Sponge MCP Server 返回的answer;上层 Agent 只能逐字展示content[0].text。terminal=false时按pendingActions顺序继续调用,不重新查询;terminal=true且nextAction=stop时结束调用链。 - 使用或检查 Agent 时只调用
health,禁止通过query做连接测试。 - 非明确查询场景调用
get_query_guidance;能力询问直接展示动态引导,其他场景先说明目前只支持查询。 - 未经用户明确确认,不调用
export_query_csv。 - Agent 不接收或传入任意 SQL。
- Agent 不读取 Schema,不生成 SQL,也不生成数据分析;Roll Core LLM 仅用于上下文语义判断,不使用正则或硬编码业务判断。
- 认证 Token 仅用于身份透传,数据权限由 Sponge MCP Server 校验。
- 不新建数据库。MCP Server 使用现有
mcp_query_run持久化完整问答,并按访问令牌提供最近 5 个上下文。上下文恢复不依赖 Agent 进程内存。
