fix(v2): 修复预审模型字段表三处缺陷并留出工具预算余量
- 补 8 个标准字段(还款来源/涉诉/增信/保证金/保险/客户名称),对齐原生方法文档声明的 inputs - 字段守卫改为比对标准字段表,不再把"标准字段但本次无数据"误判为未知字段 - 向模型下发 standard_fields 并在提示词约束字段名,避免自造派生指标 - 补 insurance./deposit. 维度前缀;方案预算 12→18、120s→180s,版本升 1.1.0 实测(临时库 + DeepSeek):模型类技能由 failed 转为 partial(部分 unknown 属如实标注), 降级记录为空,工具调用 11 次。字段表三处为代码层改动,对既有库即时生效。 验证:scripts/verify.py 11/11 PASS,531 项单测。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ from langchain_openai import ChatOpenAI
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
|
||||
from graph.agent import agent_manager
|
||||
from services.assistant_materials import FIELDS
|
||||
|
||||
|
||||
class ModelCheck(BaseModel):
|
||||
@@ -82,6 +83,8 @@ PROMPT = """你是兴邦项目核查助手,必须通过受限工具读取本
|
||||
必须读取 read_project_snapshot、read_checks;每个选中方法都用 read_method 读取。
|
||||
输出一个JSON对象,只含 findings 和 requirement_response。findings 每项字段为 code(稳定英文码)、title、result
|
||||
(pass/issue/unknown/not_applicable)、evidence_ids(真实证据ID数组)、fields(标准字段数组)、suggested_action。
|
||||
fields 每项必须**逐字**取自本次任务给出的 standard_fields 列表;不得自造字段名,也不得使用派生指标名
|
||||
(如负债率、流动比率);派生值只能引用程序已计算的 metrics.* 。清单里没有的字段,说明该项无法核查。
|
||||
没有依据不得判定pass/issue。缺失资料标unknown,证据只能引用冻结快照。不得引用其他项目经验中的客户信息。
|
||||
requirement_response必须是一个普通字符串,不得输出对象或数组;逐项说明是否完成用户要求,无法验证要明确说明。
|
||||
示例顶层结构:{"findings": [], "requirement_response": "已读取授权事实并完成核查。"}。不要Markdown围栏。"""
|
||||
@@ -134,6 +137,7 @@ def invoke(skill, snapshot, checks, rules, requirement, experiences, model_confi
|
||||
available = [read_project_snapshot, read_document, read_checks, read_method, read_experiences]
|
||||
selected = [t for t in available if t.name in skill["allowed_tools"]]
|
||||
task = {"instructions": skill.get("instructions"), "requirement": requirement, "methods": list(skill.get("methods", {})),
|
||||
"standard_fields": sorted(FIELDS.values()),
|
||||
"documents": [{"id": d["id"], "name": d["name"]} for d in snapshot["documents"]]}
|
||||
prompt = PROMPT
|
||||
if feedback:
|
||||
@@ -153,7 +157,6 @@ def invoke(skill, snapshot, checks, rules, requirement, experiences, model_confi
|
||||
if feedback and parsed.experience_proposal is None:
|
||||
raise ValueError("模型未返回结构化经验草稿")
|
||||
if parsed.experience_proposal:
|
||||
from services.assistant_materials import FIELDS
|
||||
proposal = parsed.experience_proposal
|
||||
if not proposal.conditions or set(proposal.conditions) - set(FIELDS.values()) or proposal.required_field not in FIELDS.values() or proposal.exception_field not in FIELDS.values() or proposal.required_field in proposal.conditions:
|
||||
raise ValueError("经验草稿的触发条件或执行字段无效")
|
||||
@@ -168,7 +171,11 @@ def invoke(skill, snapshot, checks, rules, requirement, experiences, model_confi
|
||||
raise ValueError("模型结论缺少证据")
|
||||
if any("document:" + document_evidence[e] not in reads for e in finding.evidence_ids if e in document_evidence):
|
||||
raise ValueError("模型引用了尚未读取的材料片段")
|
||||
if set(finding.fields) - set(snapshot["values"]):
|
||||
raise ValueError("模型引用未知字段")
|
||||
# 白名单比的是**标准字段表**,不是"当前恰好有值的字段":
|
||||
# 后者会把"标准字段但本次无数据"误判成未知字段,与提示词"缺失资料标 unknown"相矛盾。
|
||||
# 仍是封闭白名单——表外字段一样被拒,模型不能自造指标。
|
||||
unknown = sorted(set(finding.fields) - set(FIELDS.values()))
|
||||
if unknown:
|
||||
raise ValueError("模型引用未知字段:" + ",".join(unknown))
|
||||
seen.add(finding.code)
|
||||
return parsed.model_dump(), {"engine": result["engine"], "tool_calls": count[0], "tools_read": sorted(reads), "model": model_config["name"]}
|
||||
|
||||
Reference in New Issue
Block a user