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