From eb8d73b6da95a4120b94d8bdad55360a394e11c7 Mon Sep 17 00:00:00 2001 From: ThearchyHelios Date: Wed, 14 Oct 2026 14:07:15 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A8=E5=8A=A9=E6=89=8B=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E6=8A=8A=E6=95=B0=E6=8D=AE=E6=BA=90=E7=9A=84=E8=B5=B7=E8=8D=89?= =?UTF-8?q?=E8=A6=81=E6=B1=82=E5=BD=93=E6=88=90=E4=BD=BF=E7=94=A8=E8=80=85?= =?UTF-8?q?=E7=9A=84=E5=8E=9F=E8=AF=9D=EF=BC=9A=E4=BA=A4=E7=BB=99=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E7=9A=84=E8=83=8C=E6=99=AF=E9=87=8C=E8=B5=B7=E8=8D=89?= =?UTF-8?q?=E8=A6=81=E6=B1=82=E6=A0=87=E6=98=8E=E3=80=8C=E4=B8=8D=E6=98=AF?= =?UTF-8?q?=E8=BF=99=E6=AC=A1=E5=AF=B9=E8=AF=9D=E9=87=8C=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E8=80=85=E8=AF=B4=E7=9A=84=E8=AF=9D=E3=80=8D=EF=BC=8C=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E6=8F=90=E7=A4=BA=E8=AF=8D=E5=92=8C=20propose=5Fchang?= =?UTF-8?q?es=20=E7=9A=84=E8=AF=B4=E6=98=8E=E5=86=99=E6=B8=85=20reason=20?= =?UTF-8?q?=E9=87=8C=E5=BC=95=E7=94=A8=E7=9A=84=E5=8E=9F=E8=AF=9D=E5=8F=AA?= =?UTF-8?q?=E8=83=BD=E6=98=AF=E8=BF=99=E6=AC=A1=E5=AF=B9=E8=AF=9D=E9=87=8C?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E8=80=85=E7=9A=84=E6=B6=88=E6=81=AF=EF=BC=8C?= =?UTF-8?q?=E4=BE=9D=E6=8D=AE=E6=9D=A5=E8=87=AA=E8=B5=B7=E8=8D=89=E8=A6=81?= =?UTF-8?q?=E6=B1=82=E6=97=B6=E5=86=99=E3=80=8C=E8=B5=B7=E8=8D=89=E8=A6=81?= =?UTF-8?q?=E6=B1=82=E5=86=99=E7=9D=80=EF=BC=9A=E2=80=A6=E2=80=A6=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/data/catalog_assistant.py | 16 ++++++++++++---- backend/tests/test_catalog_assistant.py | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/backend/app/data/catalog_assistant.py b/backend/app/data/catalog_assistant.py index 27d848f5..6f1c378e 100644 --- a/backend/app/data/catalog_assistant.py +++ b/backend/app/data/catalog_assistant.py @@ -3,7 +3,11 @@ **为什么要有它。** 模型起草只看表结构,缩写列名、状态码的意思常常拿不准而留空;审阅时人知道答案,却要一项一项填。表助手 把这张表的结构、目录现状(每项的来源和状态)、关联关系、剖析结果、起草要求、使用次数、上次起草留空的列交给模型,让它主动 问拿不准的地方;使用者说出一条业务事实,它整理成成批的修改提案(形状同助手流里的 catalog_patch),使用者在界面上逐项看过、 -一次保存(PATCH /catalog/{table}/patch,记为人工确认)。 +一次保存(PATCH /catalog/{table}/patch,记为人工确认,每项的 reason 作为依据进这一项的备注)。 + +**依据只引用这次对话。** 数据源的起草要求是以前写在数据源上的背景,背景里标明「不是这次对话里使用者说的话」;提示词要求 +reason 里的原话只引用这次对话里使用者的消息,依据来自起草要求的写「起草要求写着:……」。验收时模型把起草要求写成了 +「使用者说:……」,保存之后看起来像是使用者亲口确认过。 **只改目录、不改业务库。** 模型只有两个工具: - propose_changes:一批修改提案。按 catalog.plan_patch 核对(取值格式、列名必须在表结构里、公式不收),遮罩列不给码值,已经 @@ -123,7 +127,9 @@ ASSISTANT_SYSTEM = """你是 AgentLab 的「表助手」,和使用者一起完 - 拿不准就问,不要猜。一次只问一两件最要紧的事,问得具体(例如「status 为 9 的行是不是作废的单子?」)。目录里留空的列、\ 标着「推断」的项是最值得问的。 - 使用者说出一条业务事实时,用 propose_changes 把它整理成修改提案,reason 里引用使用者的原话(例如「使用者说:9 是作废」)。\ -一次可以提多项。提案只是建议:使用者在界面上看过、保存之后才写进数据目录,记为人工确认。 +reason 里引用使用者原话只能引用这次对话里使用者的消息;依据来自下面背景里的数据源起草要求时写「起草要求写着:……」,\ +不要写成「使用者说」。一次可以提多项。提案只是建议:使用者在界面上看过、保存之后才写进数据目录,记为人工确认,\ +reason 会作为这一项的依据一起保存。 - 表名、列名照原样写,只能用下面表结构里有的列。 - 标着「已确认」的项由人工确认过,使用者没有明确要改就不要提修改;标着「已驳回」的项使用者驳回过,不要再提。 - 「界面上还没保存的修改」是使用者已经接受、还没保存的提案:不要重复提;要改其中一项就再提一次,写完整的新值。 @@ -162,7 +168,7 @@ ASSISTANT_PROMPT_LABELS = { "usage": "这张表被 {runs} 次运行用到(查询 {n} 次)。", "usage_none": "这张表还没有被运行用到过。", "description": "数据源说明:{text}", - "guidance": "数据源的起草要求(使用者补充的背景和要求):{text}", + "guidance": "数据源的起草要求(不是这次对话里使用者说的话):{text}", "structure": "表结构:", "column": "- {name} {type}{marks}", "pk": "主键", @@ -238,7 +244,9 @@ PROPOSE_TOOL_PROMPT: dict[str, Any] = { "properties": { "path": {"type": "string", "description": "要改的项,写法见系统提示"}, "value": {"description": "新的值:文字、列名列表、码值对照或关联关系"}, - "reason": {"type": "string", "description": "一句话依据,引用使用者的原话"}, + "reason": {"type": "string", + "description": "一句话依据:引用这次对话里使用者的原话(「使用者说:……」);" + "来自数据源起草要求的写「起草要求写着:……」"}, }, "required": ["path", "value", "reason"], }, diff --git a/backend/tests/test_catalog_assistant.py b/backend/tests/test_catalog_assistant.py index 2e143421..6ec473fa 100644 --- a/backend/tests/test_catalog_assistant.py +++ b/backend/tests/test_catalog_assistant.py @@ -353,6 +353,23 @@ async def test_background_has_structure_catalog_and_hides_masked_values(client, assert "没开剖析" not in system +async def test_the_draft_guidance_is_not_what_the_user_said(client, tmp_path, monkeypatch): + """数据源的起草要求是以前写在数据源上的背景,不是这次对话里使用者说的话:背景里标明白;系统提示词写清 reason 里引用的 + 原话只能是这次对话里使用者的消息,依据来自起草要求时写「起草要求写着:……」。验收时模型把起草要求写成了 + 「使用者说:……」,保存之后看起来像是使用者亲口确认过。""" + sid = await _source(client, tmp_path, guidance="pay_type:1=现金,2=刷卡") + model = Scripted([Turn(text=["好。"])]) + use(monkeypatch, model) + await _talk(client, sid, _ask("看看还缺什么")) + system = model.seen[0][0].content + assert "数据源的起草要求(不是这次对话里使用者说的话):pay_type:1=现金,2=刷卡" in system + assert "使用者补充的背景和要求" not in system + assert "只能引用这次对话里使用者的消息" in system and "起草要求写着:" in system + reason = (catalog_assistant.PROPOSE_TOOL_PROMPT["function"]["parameters"]["properties"]["changes"]["items"] + ["properties"]["reason"]["description"]) + assert "这次对话里使用者" in reason and "起草要求写着" in reason + + async def test_background_says_how_many_runs_used_the_table(client, tmp_path, monkeypatch): """使用次数的口径同审阅队列:被几次运行用到(同「用过这张表的运行」的 total),查询几次(同目录清单的「使用 N 次」)。""" from app.db.models import Artifact, Run