elksmmx 1 день назад
Родитель
Сommit
0130e8b25a

+ 12 - 9
examples/process_pipeline/prompts/apply_to_grounding.prompt

@@ -1,24 +1,27 @@
-你是内容树映射助手。现在是 Stage 2:把 apply_to_draft 映射为精确 apply_to,并为每个条目生成 ideal_path。
+你是内容树映射助手。现在是 Stage 2:把 apply_to_draft 映射为精确 apply_to,并为每个 fragment/query 生成一个 ideal_path。
 
 # 绝对规则
 
 - 不要调用任何工具,不要查树;只能使用本 prompt 中给出的完整内容树。
 - 只处理:fragments 数组中的每一条 fragment。
-- **只输出 apply_to 字段**,不要回显 inputs、outputs、action、body、effects、stage、tools、criterion、unstructured_what 等字段。
+- **只输出 apply_to 和 ideal_path 字段**,不要回显 inputs、outputs、action、body、effects、stage、tools、criterion、unstructured_what 等字段。
 - apply_to.实质 只能选择 source_type=实质 的节点;apply_to.形式 只能选择 source_type=形式 的节点。
 - category_id 和 category_path 必须逐字来自内容树里的 id/path。
 - element 只有在该节点 elements 中逐字存在时才能填写;否则省略 element 或填 null。
 - 每侧 1-3 项即可。优先选择最贴近 apply_to_draft 的节点;不确定时选较粗分类,不要编造。
 - rationale 用一句话说明 draft 短语为何落在该节点。
-- **每个 apply_to 条目必须包含 ideal_path**,不得省略
+- **每个 fragment/query 必须包含且只能包含一个 ideal_path**,不得在 apply_to 条目内输出 ideal_path
 
 # ideal_path 规则
 
-每个 apply_to 条目必须输出 ideal_path,表示该描述"理想上应该挂在哪个路径"(即使树上不存在):
-- 从根往下逐层检查 category_path 的每一层,判断该层是否仍然准确描述了 draft 的语义。
+每个 fragment/query 必须输出一个 ideal_path,表示该 query 的整体描述"理想上应该挂在哪个路径"(即使树上不存在):
+- 先完成 apply_to.实质 和 apply_to.形式 的真实树节点映射。
+- 综合 apply_to_draft 的语义,以及你选出的真实 category_path,判断这个 query 最理想的单一路径。
+- 优先以最能代表 query 核心语义的真实 category_path 为基准;如果实质和形式都存在,通常优先以实质路径为基准,形式路径只作为命名和细化参考。
+- 从根往下逐层检查基准 category_path 的每一层,判断该层是否仍然准确描述了 query 的语义。
 - 找到第一个"不够精确或有偏差"的层级,从该层级开始续写(替换该层及其后的所有层)。续写的风格应当与路径中的其他层级相符合,至少词性应当一致。
-- 如果 category_path 所有层级都准确,且 draft 没有更细的信息,则 ideal_path = category_path。
-- 如果 category_path 所有层级都准确,但 draft 还有更细的信息未体现,则在末尾续写 1-3 个层级。
+- 如果基准 category_path 所有层级都准确,且 query 没有更细的信息,则 ideal_path = 基准 category_path。
+- 如果基准 category_path 所有层级都准确,但 query 还有更细的信息未体现,则在末尾续写 1-3 个层级。
 - 续写部分命名风格参考下方"邻近路径参考"(两字名词、层级粒度保持一致)。
 - 续写部分可以是树上不存在的节点,这正是 ideal_path 的意义。
 
@@ -36,12 +39,12 @@
 
 # 输出格式
 
-输出 `{ "fragments": [ { "fragment_id": "f_s1_0", "apply_to": {...} } ] }`
+输出 `{ "fragments": [ { "fragment_id": "f_s1_0", "apply_to": {...}, "ideal_path": "..." } ] }`
 
 - fragments 数组长度和输入 fragments 保持一致。
 - 每个输出项必须带原输入的 fragment_id,逐字照抄。
 
-每个 apply_to 条目格式:`{ "category_id": 123, "category_path": "...", "ideal_path": "...", "element": null, "rationale": "..." }`
+每个 apply_to 条目格式:`{ "category_id": 123, "category_path": "...", "element": null, "rationale": "..." }`
 
 # 输出硬规则
 

+ 9 - 5
examples/process_pipeline/prompts/apply_to_grounding_fragment.schema.json

@@ -3,27 +3,31 @@
   "title": "apply_to_grounding_fragment_output",
   "type": "object",
   "required": ["fragments"],
+  "additionalProperties": false,
   "properties": {
     "fragments": {
       "type": "array",
       "items": {
         "type": "object",
-        "required": ["fragment_id", "apply_to"],
+        "required": ["fragment_id", "apply_to", "ideal_path"],
+        "additionalProperties": false,
         "properties": {
           "fragment_id": { "type": "string", "minLength": 1 },
+          "ideal_path": { "type": "string", "minLength": 1 },
           "apply_to": {
             "type": "object",
             "required": ["实质", "形式"],
+            "additionalProperties": false,
             "properties": {
               "实质": {
                 "type": "array",
                 "items": {
                   "type": "object",
-                  "required": ["category_id", "category_path", "ideal_path", "rationale"],
+                  "required": ["category_id", "category_path", "rationale"],
+                  "additionalProperties": false,
                   "properties": {
                     "category_id": { "type": "integer" },
                     "category_path": { "type": "string", "minLength": 1 },
-                    "ideal_path": { "type": "string", "minLength": 1 },
                     "element": { "type": ["string", "null"] },
                     "rationale": { "type": "string", "minLength": 1 }
                   }
@@ -33,11 +37,11 @@
                 "type": "array",
                 "items": {
                   "type": "object",
-                  "required": ["category_id", "category_path", "ideal_path", "rationale"],
+                  "required": ["category_id", "category_path", "rationale"],
+                  "additionalProperties": false,
                   "properties": {
                     "category_id": { "type": "integer" },
                     "category_path": { "type": "string", "minLength": 1 },
-                    "ideal_path": { "type": "string", "minLength": 1 },
                     "element": { "type": ["string", "null"] },
                     "rationale": { "type": "string", "minLength": 1 }
                   }

+ 9 - 2
examples/process_pipeline/script/apply_to_grounding.py

@@ -24,7 +24,7 @@ load_dotenv(PROJECT_ROOT / ".env")
 
 # 搜索 API 配置
 SEARCH_API = os.getenv("SEARCH_API", "http://8.147.104.190:8001").rstrip("/")
-FRAGMENT_GROUNDING_BATCH_SIZE = int(os.getenv("FRAGMENT_GROUNDING_BATCH_SIZE", "5"))
+FRAGMENT_GROUNDING_BATCH_SIZE = int(os.getenv("FRAGMENT_GROUNDING_BATCH_SIZE", "8"))
 
 # 本地文件路径(作为回退方案)
 EXTRACT_DIR = Path(__file__).resolve().parent / "resource"
@@ -330,8 +330,15 @@ async def ground_single_case(
             if frag_idx is None or frag_idx in used_indices:
                 continue
             apply_to = grounded_frag.get("apply_to")
-            if apply_to is not None and isinstance(updated_fragments[frag_idx], dict):
+            ideal_path = grounded_frag.get("ideal_path")
+            if (
+                apply_to is not None
+                and isinstance(ideal_path, str)
+                and ideal_path.strip()
+                and isinstance(updated_fragments[frag_idx], dict)
+            ):
                 updated_fragments[frag_idx]["apply_to"] = apply_to
+                updated_fragments[frag_idx]["ideal_path"] = ideal_path.strip()
                 updated_fragments[frag_idx].pop("apply_to_draft", None)
                 used_indices.add(frag_idx)