Files
AgentLab/backend/tests/fixtures/copilot_answer_ops_baseline.json
T
ThearchyHelios 6b68961c65 助手把操作写成工具调用格式时照操作读;一个能落地的操作都没有时当场纠正一次;报错按诊断照实说
部署上画布助手连着几轮报「助手本轮未完成:模型没有给出任何修改,也没有说明原因」,又试了一次才成。本地用同一网关、同一模型、同一底图和需求重放复现:模型思考里写着「先输出 look」,正文却是一段 DeepSeek 的 DSML 工具调用(invoke name="look",参数 need、targets),意图和参数都对,只是不是约定的单行 JSON。读流只认 JSON 和原生工具调用,于是一个操作都没认出、整轮报错;画布不处理 next=retry,点重试原样再发,几率不变。提示词里「输出这一行就停下,系统把结果交回来」很像工具调用,却从没说这里没有工具调用接口。

- engine/toolcalls:take_leaked_calls 读写成文字的工具调用(DSML 竖线一到两个、带不带空格,<function_calls><invoke>,<tool_call>{name, arguments},DeepSeek 特殊 token 两种排法),按出现先后交出已写完的调用和没写完的那一段;final 时参数写完整、只差结尾的补上结尾再读,写到一半的不硬读。_MARKUP 补认 DSML 结尾标签和 function_calls / tool_calls 包装(agent 节点的识别跟着受益)。has_markup 只认标记本身
- copilot_gen._iter_ops:从有标记的那一行起攒,一次调用写完就按名字读成操作(名字是操作名的才认,规矩同原生工具调用 _call_op;op 写在最前,接着写时交回模型的是约定写法),读到 look 照样停下去查看;读不出的记「工具调用标记的名字不认识 / 参数解析不了 / 没写完」;raw 交出正文开头一段
- Generation:起草时一次调用读完、到这时还没有能落地的操作(plan、look 不算——查看完接着写什么都没认出的整轮照样是空的),把原话交回去、附 StreamDiagnosis.correction 那句纠正,当场重写一次(FORMAT_NUDGE_PROMPT,每轮一次);什么都没写的把纠正接在最后那条消息后面。诊断按次收(absorb),记 nudged。写成标记被读出、当场纠正都打 info 日志
- 报错说法:Generation.empty 默认用 StreamDiagnosis.headline(写成工具调用格式 / 只写了思考 / 什么都没有输出 / 格式不对 / 只说了打算),不再一律「也没有说明原因」;摘要注明当场纠正过
- 提示词:look 用法(四个入口共用)和画布、应用、蓝图的输出格式都写明这里没有工具调用接口
- 问数据失败原因 meta.cause(kind=copilot)带上 code、diagnostics

验证:本地真模型重放,修后 DSML 没再出现、都正常交付;把第一次调用换成读不出的 DSML 后交给真模型,都被当场纠正救回来(先 look 再出操作);原先抓到的真实 DSML 原文离线读成 look。测试:新增 tests/test_copilot_markup_ops.py(各写法、流式切碎、和 JSON 行混写、读不出的诊断、DSML look 驱动真查看、说明文字 / 只写思考 / 只写 plan / 查看后空续写的纠正、只纠正一次、画布流不报错、报错说法、提示词);空生成相关的旧测试按「一次生成先纠正一次」更新(基线夹具 no_ops 的说法)。后端全量通过。
2026-10-19 22:48:23 +08:00

1031 lines
18 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"graph_ok": [
{
"op": "model",
"model": "mock-fast"
},
{
"op": "plan",
"summary": "数一数"
},
{
"op": "add_node",
"node": {
"id": "start",
"type": "input",
"label": "start",
"config": {
"fields": [
{
"name": "question"
}
]
}
}
},
{
"op": "add_node",
"node": {
"id": "init",
"type": "transform",
"label": "init",
"config": {
"mode": "expression",
"expression": "[1, 2]",
"assign_to": "items"
}
}
},
{
"op": "add_edge",
"edge": {
"source": "start",
"target": "init"
}
},
{
"op": "add_node",
"node": {
"id": "lp",
"type": "loop",
"label": "lp",
"config": {
"mode": "while",
"condition": "len(vars.items) > 5",
"max_iterations": 2
}
}
},
{
"op": "add_edge",
"edge": {
"source": "init",
"target": "lp"
}
},
{
"op": "add_node",
"node": {
"id": "body",
"type": "transform",
"label": "body",
"config": {
"mode": "expression",
"expression": "1"
}
}
},
{
"op": "add_edge",
"edge": {
"source": "lp",
"target": "body",
"sourceHandle": "body"
}
},
{
"op": "add_edge",
"edge": {
"source": "body",
"target": "lp"
}
},
{
"op": "add_node",
"node": {
"id": "out",
"type": "output",
"label": "out",
"config": {
"fields": [
{
"name": "结果",
"value": "{{ vars.items }}"
}
]
}
}
},
{
"op": "add_edge",
"edge": {
"source": "lp",
"target": "out",
"sourceHandle": "done"
}
},
{
"op": "done",
"explanation": "数一数",
"run": true
},
{
"op": "check",
"status": "passed",
"repaired": 0,
"warnings": []
},
{
"op": "final",
"graph": {
"nodes": [
{
"id": "start",
"type": "input",
"position": {
"x": 80.0,
"y": 0.0
},
"data": {
"label": "start",
"description": "",
"config": {
"fields": [
{
"name": "question"
}
]
}
}
},
{
"id": "init",
"type": "transform",
"position": {
"x": 414.0,
"y": 0.0
},
"data": {
"label": "init",
"description": "",
"config": {
"mode": "expression",
"expression": "[1, 2]",
"assign_to": "items"
}
}
},
{
"id": "lp",
"type": "loop",
"position": {
"x": 748.0,
"y": 0.0
},
"data": {
"label": "lp",
"description": "",
"config": {
"mode": "while",
"condition": "len(vars.items) > 5",
"max_iterations": 2
}
}
},
{
"id": "body",
"type": "transform",
"position": {
"x": 1082.0,
"y": -66.0
},
"data": {
"label": "body",
"description": "",
"config": {
"mode": "expression",
"expression": "1"
}
}
},
{
"id": "out",
"type": "output",
"position": {
"x": 1082.0,
"y": 66.0
},
"data": {
"label": "out",
"description": "",
"config": {
"fields": [
{
"name": "结果",
"value": "{{ vars.items }}"
}
]
}
}
}
],
"edges": [
{
"id": "start:->init",
"source": "start",
"target": "init",
"sourceHandle": null,
"targetHandle": null,
"label": ""
},
{
"id": "init:->lp",
"source": "init",
"target": "lp",
"sourceHandle": null,
"targetHandle": null,
"label": ""
},
{
"id": "lp:body->body",
"source": "lp",
"target": "body",
"sourceHandle": "body",
"targetHandle": null,
"label": ""
},
{
"id": "body:->lp",
"source": "body",
"target": "lp",
"sourceHandle": null,
"targetHandle": null,
"label": ""
},
{
"id": "lp:done->out",
"source": "lp",
"target": "out",
"sourceHandle": "done",
"targetHandle": null,
"label": ""
}
],
"viewport": {},
"defaults": {}
},
"issues": [],
"explanation": "数一数",
"autorun": true,
"layout": {
"mode": "full",
"placed": [
"start",
"init",
"lp",
"body",
"out"
]
},
"tool_changes": []
}
],
"graph_fixed": [
{
"op": "model",
"model": "mock-fast"
},
{
"op": "plan",
"summary": "数一数"
},
{
"op": "add_node",
"node": {
"id": "start",
"type": "input",
"label": "start",
"config": {
"fields": [
{
"name": "question"
}
]
}
}
},
{
"op": "add_node",
"node": {
"id": "init",
"type": "transform",
"label": "init",
"config": {
"mode": "expression",
"expression": "[1, 2]",
"assign_to": "items"
}
}
},
{
"op": "add_edge",
"edge": {
"source": "start",
"target": "init"
}
},
{
"op": "add_node",
"node": {
"id": "lp",
"type": "loop",
"label": "lp",
"config": {
"mode": "while",
"condition": "{{ vars.items | length }} > 5",
"max_iterations": 2
}
}
},
{
"op": "add_edge",
"edge": {
"source": "init",
"target": "lp"
}
},
{
"op": "add_node",
"node": {
"id": "body",
"type": "transform",
"label": "body",
"config": {
"mode": "expression",
"expression": "1"
}
}
},
{
"op": "add_edge",
"edge": {
"source": "lp",
"target": "body",
"sourceHandle": "body"
}
},
{
"op": "add_edge",
"edge": {
"source": "body",
"target": "lp"
}
},
{
"op": "add_node",
"node": {
"id": "out",
"type": "output",
"label": "out",
"config": {
"fields": [
{
"name": "结果",
"value": "{{ vars.items }}"
}
]
}
}
},
{
"op": "add_edge",
"edge": {
"source": "lp",
"target": "out",
"sourceHandle": "done"
}
},
{
"op": "done",
"explanation": "数一数",
"run": true
},
{
"op": "check",
"status": "repairing",
"round": 1,
"issues": [
{
"level": "error",
"node_id": "lp",
"edge_id": null,
"message": "循环条件有误:表达式中不支持 | 过滤器(那是模板的写法):取长度请写 len(x),转换大小写请写 upper(x) / lower(x)(原文:{{ vars.items | length }} > 5)",
"field": "condition",
"code": null,
"fix": null
}
]
},
{
"op": "update_node",
"id": "lp",
"config": {
"mode": "while",
"condition": "len(vars.items) > 5",
"max_iterations": 2
}
},
{
"op": "check",
"status": "passed",
"repaired": 1,
"warnings": []
},
{
"op": "final",
"graph": {
"nodes": [
{
"id": "start",
"type": "input",
"position": {
"x": 80.0,
"y": 0.0
},
"data": {
"label": "start",
"description": "",
"config": {
"fields": [
{
"name": "question"
}
]
}
}
},
{
"id": "init",
"type": "transform",
"position": {
"x": 414.0,
"y": 0.0
},
"data": {
"label": "init",
"description": "",
"config": {
"mode": "expression",
"expression": "[1, 2]",
"assign_to": "items"
}
}
},
{
"id": "lp",
"type": "loop",
"position": {
"x": 748.0,
"y": 0.0
},
"data": {
"label": "lp",
"description": "",
"config": {
"mode": "while",
"condition": "len(vars.items) > 5",
"max_iterations": 2
}
}
},
{
"id": "body",
"type": "transform",
"position": {
"x": 1082.0,
"y": -66.0
},
"data": {
"label": "body",
"description": "",
"config": {
"mode": "expression",
"expression": "1"
}
}
},
{
"id": "out",
"type": "output",
"position": {
"x": 1082.0,
"y": 66.0
},
"data": {
"label": "out",
"description": "",
"config": {
"fields": [
{
"name": "结果",
"value": "{{ vars.items }}"
}
]
}
}
}
],
"edges": [
{
"id": "start:->init",
"source": "start",
"target": "init",
"sourceHandle": null,
"targetHandle": null,
"label": ""
},
{
"id": "init:->lp",
"source": "init",
"target": "lp",
"sourceHandle": null,
"targetHandle": null,
"label": ""
},
{
"id": "lp:body->body",
"source": "lp",
"target": "body",
"sourceHandle": "body",
"targetHandle": null,
"label": ""
},
{
"id": "body:->lp",
"source": "body",
"target": "lp",
"sourceHandle": null,
"targetHandle": null,
"label": ""
},
{
"id": "lp:done->out",
"source": "lp",
"target": "out",
"sourceHandle": "done",
"targetHandle": null,
"label": ""
}
],
"viewport": {},
"defaults": {}
},
"issues": [],
"explanation": "数一数",
"autorun": true,
"layout": {
"mode": "full",
"placed": [
"start",
"init",
"lp",
"body",
"out"
]
},
"tool_changes": []
}
],
"check_failed": [
{
"op": "model",
"model": "mock-fast"
},
{
"op": "plan",
"summary": "数一数"
},
{
"op": "add_node",
"node": {
"id": "start",
"type": "input",
"label": "start",
"config": {
"fields": [
{
"name": "question"
}
]
}
}
},
{
"op": "add_node",
"node": {
"id": "init",
"type": "transform",
"label": "init",
"config": {
"mode": "expression",
"expression": "[1, 2]",
"assign_to": "items"
}
}
},
{
"op": "add_edge",
"edge": {
"source": "start",
"target": "init"
}
},
{
"op": "add_node",
"node": {
"id": "lp",
"type": "loop",
"label": "lp",
"config": {
"mode": "while",
"condition": "foo(vars.items)",
"max_iterations": 2
}
}
},
{
"op": "add_edge",
"edge": {
"source": "init",
"target": "lp"
}
},
{
"op": "add_node",
"node": {
"id": "body",
"type": "transform",
"label": "body",
"config": {
"mode": "expression",
"expression": "1"
}
}
},
{
"op": "add_edge",
"edge": {
"source": "lp",
"target": "body",
"sourceHandle": "body"
}
},
{
"op": "add_edge",
"edge": {
"source": "body",
"target": "lp"
}
},
{
"op": "add_node",
"node": {
"id": "out",
"type": "output",
"label": "out",
"config": {
"fields": [
{
"name": "结果",
"value": "{{ vars.items }}"
}
]
}
}
},
{
"op": "add_edge",
"edge": {
"source": "lp",
"target": "out",
"sourceHandle": "done"
}
},
{
"op": "done",
"explanation": "数一数",
"run": true
},
{
"op": "check",
"status": "repairing",
"round": 1,
"issues": [
{
"level": "error",
"node_id": "lp",
"edge_id": null,
"message": "循环条件有误:不支持函数 foo(),可用的函数:len、str、int、float、bool、abs、min、max、sum、round、sorted、any、all、lower、upper、contains、startswith、endswith、matches、get、cell(原文:foo(vars.items))",
"field": "condition",
"code": null,
"fix": null
}
]
},
{
"op": "update_node",
"id": "lp",
"config": {
"mode": "while",
"condition": "bar(vars.items)",
"max_iterations": 2
}
},
{
"op": "check",
"status": "repairing",
"round": 2,
"issues": [
{
"level": "error",
"node_id": "lp",
"edge_id": null,
"message": "循环条件有误:不支持函数 bar(),可用的函数:len、str、int、float、bool、abs、min、max、sum、round、sorted、any、all、lower、upper、contains、startswith、endswith、matches、get、cell(原文:bar(vars.items))",
"field": "condition",
"code": null,
"fix": null
}
]
},
{
"op": "update_node",
"id": "lp",
"config": {
"mode": "while",
"condition": "bar(vars.items)",
"max_iterations": 2
}
},
{
"op": "check",
"status": "failed",
"issues": [
{
"level": "error",
"node_id": "lp",
"edge_id": null,
"message": "循环条件有误:不支持函数 bar(),可用的函数:len、str、int、float、bool、abs、min、max、sum、round、sorted、any、all、lower、upper、contains、startswith、endswith、matches、get、cell(原文:bar(vars.items))",
"field": "condition",
"code": null,
"fix": null
}
],
"warnings": []
},
{
"op": "final",
"graph": {
"nodes": [
{
"id": "start",
"type": "input",
"position": {
"x": 80.0,
"y": 0.0
},
"data": {
"label": "start",
"description": "",
"config": {
"fields": [
{
"name": "question"
}
]
}
}
},
{
"id": "init",
"type": "transform",
"position": {
"x": 414.0,
"y": 0.0
},
"data": {
"label": "init",
"description": "",
"config": {
"mode": "expression",
"expression": "[1, 2]",
"assign_to": "items"
}
}
},
{
"id": "lp",
"type": "loop",
"position": {
"x": 748.0,
"y": 0.0
},
"data": {
"label": "lp",
"description": "",
"config": {
"mode": "while",
"condition": "bar(vars.items)",
"max_iterations": 2
}
}
},
{
"id": "body",
"type": "transform",
"position": {
"x": 1082.0,
"y": -66.0
},
"data": {
"label": "body",
"description": "",
"config": {
"mode": "expression",
"expression": "1"
}
}
},
{
"id": "out",
"type": "output",
"position": {
"x": 1082.0,
"y": 66.0
},
"data": {
"label": "out",
"description": "",
"config": {
"fields": [
{
"name": "结果",
"value": "{{ vars.items }}"
}
]
}
}
}
],
"edges": [
{
"id": "start:->init",
"source": "start",
"target": "init",
"sourceHandle": null,
"targetHandle": null,
"label": ""
},
{
"id": "init:->lp",
"source": "init",
"target": "lp",
"sourceHandle": null,
"targetHandle": null,
"label": ""
},
{
"id": "lp:body->body",
"source": "lp",
"target": "body",
"sourceHandle": "body",
"targetHandle": null,
"label": ""
},
{
"id": "body:->lp",
"source": "body",
"target": "lp",
"sourceHandle": null,
"targetHandle": null,
"label": ""
},
{
"id": "lp:done->out",
"source": "lp",
"target": "out",
"sourceHandle": "done",
"targetHandle": null,
"label": ""
}
],
"viewport": {},
"defaults": {}
},
"issues": [
{
"level": "error",
"node_id": "lp",
"edge_id": null,
"message": "循环条件有误:不支持函数 bar(),可用的函数:len、str、int、float、bool、abs、min、max、sum、round、sorted、any、all、lower、upper、contains、startswith、endswith、matches、get、cell(原文:bar(vars.items))",
"field": "condition",
"code": null,
"fix": null
}
],
"explanation": "数一数",
"autorun": false,
"layout": {
"mode": "full",
"placed": [
"start",
"init",
"lp",
"body",
"out"
]
},
"tool_changes": []
}
],
"reply": [
{
"op": "model",
"model": "mock-fast"
},
{
"op": "reply",
"text": "上一轮已经查过了:一共 3 家门店。"
}
],
"ask_only": [
{
"op": "model",
"model": "mock-fast"
},
{
"op": "plan",
"summary": "先问清楚"
},
{
"op": "ask",
"question": "要看哪个月的?",
"options": [
"九月",
"十月"
]
},
{
"op": "final",
"graph": {
"nodes": [],
"edges": []
},
"issues": [],
"explanation": "",
"autorun": false,
"layout": {
"mode": "keep",
"placed": []
},
"tool_changes": [],
"asked": {
"question": "要看哪个月的?",
"options": [
"九月",
"十月"
]
}
}
],
"error": [
{
"op": "model",
"model": "mock-fast"
},
{
"op": "error",
"message": "助手本轮未完成:接入返回了 502",
"hint": "",
"detail": "RuntimeError: 接入返回了 502"
}
],
"no_ops": [
{
"op": "model",
"model": "mock-fast"
},
{
"op": "error",
"message": "助手本轮未完成:模型的输出格式不对,没有一行能认出的操作",
"hint": "画布未修改。可以重试,或把需求描述得更具体",
"detail": ""
}
],
"truncated": [
{
"op": "model",
"model": "mock-fast"
},
{
"op": "plan",
"summary": "想了很久"
},
{
"op": "error",
"message": "助手本轮未完成:模型的输出超出了长度上限,修改没有写完",
"hint": "画布未修改。可以重试,或把需求拆成几步分别提出",
"detail": "finish_reason=length"
}
]
}