v0.21 alpha add research brief and compressed findings
This commit is contained in:
+130
-8
@@ -63,6 +63,14 @@ class TaskCard:
|
||||
preferred_model_role: str = "dr_analyst"
|
||||
status: str = "pending"
|
||||
dependencies: list[str] = field(default_factory=list)
|
||||
research_goal: str = ""
|
||||
research_method: str = ""
|
||||
prompt_brief: str = ""
|
||||
required_skills: list[str] = field(default_factory=list)
|
||||
allowed_materials: list[str] = field(default_factory=list)
|
||||
expected_evidence: dict[str, Any] = field(default_factory=dict)
|
||||
stop_conditions: list[str] = field(default_factory=list)
|
||||
model_hint: str = ""
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return asdict(self)
|
||||
@@ -105,6 +113,66 @@ def _questions_for_axis(chapter: Chapter, axis: str) -> list[str]:
|
||||
]
|
||||
|
||||
|
||||
def _default_required_skills(axis: str) -> list[str]:
|
||||
skills = ["search-gateway", "search-strategy", "source-quality", "evidence-table"]
|
||||
if axis == "counter":
|
||||
skills.append("mckinsey-method")
|
||||
return skills
|
||||
|
||||
|
||||
def _default_expected_evidence(axis: str) -> dict[str, Any]:
|
||||
return {
|
||||
"min_tier_1_2_sources": 2,
|
||||
"must_include_counter_evidence": True,
|
||||
"must_include_source_metadata": True,
|
||||
"preferred_evidence_types": [
|
||||
"regulatory_or_best_practice_requirement",
|
||||
"site_or_material_finding",
|
||||
"quantitative_fact_or_record",
|
||||
"implementation_or_verification_evidence",
|
||||
],
|
||||
"axis": axis,
|
||||
}
|
||||
|
||||
|
||||
def _default_stop_conditions() -> list[str]:
|
||||
return [
|
||||
"已形成至少 3 条可追溯 evidence_items,且每条关键 claim 有 source_id。",
|
||||
"已主动记录 counter_evidence 或明确说明未找到反方证据的检索路径。",
|
||||
"candidate_sources 不足以支撑结论时停止写作,并把缺口写入 open_questions。",
|
||||
]
|
||||
|
||||
|
||||
def _task_card_for_chapter_axis(
|
||||
*,
|
||||
chapter: Chapter,
|
||||
axis: str,
|
||||
routes: list[str],
|
||||
method_key: str,
|
||||
required_skills: list[str] | None = None,
|
||||
allowed_materials: list[str] | None = None,
|
||||
prompt_brief: str | None = None,
|
||||
stop_conditions: list[str] | None = None,
|
||||
) -> TaskCard:
|
||||
return TaskCard(
|
||||
task_id=f"{chapter.chapter_id}-{axis}",
|
||||
chapter_ids=[chapter.chapter_id],
|
||||
topic_axis=axis,
|
||||
questions=_questions_for_axis(chapter, axis),
|
||||
search_routes=routes,
|
||||
output_packet=f"phase2/packets/{chapter.chapter_id}-{axis}.json",
|
||||
preferred_model_role="dr_verifier" if axis == "counter" else "dr_analyst",
|
||||
research_goal=f"为《{chapter.title}》收集并验证 {axis} 轴证据,形成可写入章节的具体判断与证据落点。",
|
||||
research_method=method_key,
|
||||
prompt_brief=prompt_brief or f"围绕《{chapter.title}》的 {axis} 轴,优先形成可证伪、可引用、可落地的证据包。",
|
||||
required_skills=required_skills or _default_required_skills(axis),
|
||||
allowed_materials=allowed_materials or [],
|
||||
expected_evidence=_default_expected_evidence(axis),
|
||||
stop_conditions=stop_conditions or _default_stop_conditions(),
|
||||
model_hint="use_cross_model_verifier" if axis == "counter" else "use_cost_effective_research_worker",
|
||||
)
|
||||
|
||||
|
||||
def generate_task_cards(
|
||||
slug: str,
|
||||
framework_text: str,
|
||||
@@ -120,14 +188,56 @@ def generate_task_cards(
|
||||
for axis in selected_axes:
|
||||
routes = AXIS_ROUTES.get(axis, ["general"])
|
||||
cards.append(
|
||||
TaskCard(
|
||||
task_id=f"{chapter.chapter_id}-{axis}",
|
||||
chapter_ids=[chapter.chapter_id],
|
||||
topic_axis=axis,
|
||||
questions=_questions_for_axis(chapter, axis),
|
||||
search_routes=routes,
|
||||
output_packet=f"phase2/packets/{chapter.chapter_id}-{axis}.json",
|
||||
preferred_model_role="dr_verifier" if axis == "counter" else "dr_analyst",
|
||||
_task_card_for_chapter_axis(
|
||||
chapter=chapter,
|
||||
axis=axis,
|
||||
routes=routes,
|
||||
method_key=method.key if method else "",
|
||||
)
|
||||
)
|
||||
validate_task_cards(cards)
|
||||
return cards
|
||||
|
||||
|
||||
def generate_task_cards_from_research_brief(
|
||||
slug: str,
|
||||
framework_text: str,
|
||||
research_brief: dict[str, Any],
|
||||
*,
|
||||
axes: list[str] | None = None,
|
||||
method: ResearchMethod | None = None,
|
||||
) -> list[TaskCard]:
|
||||
del slug
|
||||
chapters = parse_framework_chapters(framework_text)
|
||||
planning = research_brief.get("task_planning") or {}
|
||||
method_key = research_brief.get("research_method") or (method.key if method else "")
|
||||
selected_axes = axes or (method.task_axes if method else None) or list(planning.get("search_routes_by_axis") or []) or DEFAULT_AXES
|
||||
routes_by_axis = planning.get("search_routes_by_axis") or {}
|
||||
prompt_by_axis = planning.get("axis_prompt_briefs") or {}
|
||||
base_skills = list(planning.get("required_skills") or [])
|
||||
stop_conditions = list(planning.get("stop_conditions") or [])
|
||||
allowed_materials = [
|
||||
str(item.get("path"))
|
||||
for item in research_brief.get("materials", [])
|
||||
if item.get("path")
|
||||
]
|
||||
cards: list[TaskCard] = []
|
||||
for chapter in chapters:
|
||||
for axis in selected_axes:
|
||||
routes = list(routes_by_axis.get(axis) or AXIS_ROUTES.get(axis, ["general"]))
|
||||
skills = base_skills or _default_required_skills(axis)
|
||||
if "search-gateway" not in skills:
|
||||
skills = ["search-gateway", *skills]
|
||||
cards.append(
|
||||
_task_card_for_chapter_axis(
|
||||
chapter=chapter,
|
||||
axis=axis,
|
||||
routes=routes,
|
||||
method_key=method_key,
|
||||
required_skills=skills,
|
||||
allowed_materials=allowed_materials,
|
||||
prompt_brief=prompt_by_axis.get(axis),
|
||||
stop_conditions=stop_conditions or None,
|
||||
)
|
||||
)
|
||||
validate_task_cards(cards)
|
||||
@@ -157,6 +267,18 @@ def detect_dependency_cycles(cards: list[TaskCard]) -> None:
|
||||
def validate_task_cards(cards: list[TaskCard]) -> None:
|
||||
seen: set[str] = set()
|
||||
for card in cards:
|
||||
if not card.research_goal:
|
||||
card.research_goal = f"围绕 {card.topic_axis} 轴收集并验证结构化证据。"
|
||||
if not card.prompt_brief:
|
||||
card.prompt_brief = f"按 {card.topic_axis} 轴形成证据包,避免泛泛结论。"
|
||||
if not card.required_skills:
|
||||
card.required_skills = _default_required_skills(card.topic_axis)
|
||||
if "search-gateway" not in card.required_skills:
|
||||
card.required_skills = ["search-gateway", *card.required_skills]
|
||||
if not card.expected_evidence:
|
||||
card.expected_evidence = _default_expected_evidence(card.topic_axis)
|
||||
if not card.stop_conditions:
|
||||
card.stop_conditions = _default_stop_conditions()
|
||||
if card.task_id in seen:
|
||||
raise ValueError(f"duplicate task_id: {card.task_id}")
|
||||
seen.add(card.task_id)
|
||||
|
||||
Reference in New Issue
Block a user