初始化提交
This commit is contained in:
commit
887c1f449e
963 files changed
+166869
No files matched your search
@@ -0,0 +1,166 @@
|
||||
"""洛书枢 deliberative 规划器领域模块。
|
||||
|
||||
纯数据结构和纯函数(禁止 IO),定义显式计划的数据模型与解析逻辑。
|
||||
IO 相关编排在 ``app/application/planning/`` 中完成。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
|
||||
@dataclass
|
||||
class PlanStep:
|
||||
"""计划步骤。"""
|
||||
|
||||
id: int
|
||||
title: str
|
||||
description: str
|
||||
tool: str | None = None
|
||||
risk_level: str = "L2"
|
||||
|
||||
|
||||
@dataclass
|
||||
class DeliberativePlan:
|
||||
"""显式计划。"""
|
||||
|
||||
title: str
|
||||
steps: list[PlanStep]
|
||||
assumptions: list[str] = field(default_factory=list)
|
||||
risks: list[str] = field(default_factory=list)
|
||||
|
||||
|
||||
def parse_plan(raw: str) -> DeliberativePlan | None:
|
||||
"""解析 LLM 返回的 JSON 计划文本。
|
||||
|
||||
Args:
|
||||
raw: LLM 原始输出(可能含 ```json 围栏)。
|
||||
|
||||
Returns:
|
||||
解析成功的 DeliberativePlan,失败返回 None。
|
||||
"""
|
||||
text = raw.strip()
|
||||
matched = re.search(r"```(?:json)?\s*(\{.*?\})\s*```", text, re.DOTALL)
|
||||
if matched:
|
||||
text = matched.group(1)
|
||||
else:
|
||||
brace_start = text.find("{")
|
||||
brace_end = text.rfind("}")
|
||||
if brace_start != -1 and brace_end > brace_start:
|
||||
text = text[brace_start : brace_end + 1]
|
||||
try:
|
||||
data = json.loads(text)
|
||||
except json.JSONDecodeError:
|
||||
return None
|
||||
if not isinstance(data, dict):
|
||||
return None
|
||||
title = str(data.get("title", "")).strip()
|
||||
raw_steps = data.get("steps", [])
|
||||
if not title or not isinstance(raw_steps, list) or not raw_steps:
|
||||
return None
|
||||
steps: list[PlanStep] = []
|
||||
for i, s in enumerate(raw_steps):
|
||||
if not isinstance(s, dict):
|
||||
continue
|
||||
step_title = str(s.get("title", "")).strip()
|
||||
if not step_title:
|
||||
continue
|
||||
tool_raw = str(s.get("tool", "")).strip()
|
||||
tool = tool_raw if tool_raw and tool_raw != "None" else None
|
||||
steps.append(
|
||||
PlanStep(
|
||||
id=s.get("id", i + 1),
|
||||
title=step_title,
|
||||
description=str(s.get("description", "")).strip(),
|
||||
tool=tool,
|
||||
risk_level=str(s.get("risk_level", "L2")).upper(),
|
||||
)
|
||||
)
|
||||
if not steps:
|
||||
return None
|
||||
return DeliberativePlan(
|
||||
title=title,
|
||||
steps=steps,
|
||||
assumptions=[str(a).strip() for a in data.get("assumptions", []) if a],
|
||||
risks=[str(r).strip() for r in data.get("risks", []) if r],
|
||||
)
|
||||
|
||||
|
||||
def build_planning_prompt(
|
||||
request: str,
|
||||
*,
|
||||
goal_directive: str = "",
|
||||
available_tools: list[str] | None = None,
|
||||
memory_context: str = "",
|
||||
) -> str:
|
||||
"""构建规划 prompt。
|
||||
|
||||
当请求明显需要多步骤(调用多个工具、查询多处信息等)时,
|
||||
要求 LLM 先生成一个显式计划,再按计划逐步执行。
|
||||
|
||||
Args:
|
||||
request: 用户请求文本。
|
||||
goal_directive: 当前活跃目标描述。
|
||||
available_tools: 可用工具列表。
|
||||
memory_context: 相关记忆上下文。
|
||||
|
||||
Returns:
|
||||
规划 prompt 文本。
|
||||
"""
|
||||
tools_str = ""
|
||||
if available_tools:
|
||||
tools_str = "\n可用工具:\n" + "\n".join(f"- {t}" for t in available_tools)
|
||||
return (
|
||||
"请判断以下用户请求是否需要多步计划。如果需要,请输出 JSON 格式的计划。\n\n"
|
||||
f"用户请求:{request}\n"
|
||||
f"{f'当前目标:{goal_directive}' if goal_directive else ''}"
|
||||
f"{tools_str}"
|
||||
f"{f'\n上下文记忆:{memory_context}' if memory_context else ''}"
|
||||
"\n\n"
|
||||
"输出格式(如需多步计划):\n"
|
||||
'```json\n{\n "title": "计划标题",\n'
|
||||
' "assumptions": ["假设1", "假设2"],\n'
|
||||
' "risks": ["风险1", "风险2"],\n'
|
||||
' "steps": [\n'
|
||||
' {"id": 1, "title": "步骤1", "description": "说明", '
|
||||
'"tool": "工具名(可选)", "risk_level": "L2"}\n'
|
||||
" ]\n"
|
||||
"}\n```\n\n"
|
||||
"如果不需要多步计划(简单问题),只回复:NO_PLAN_NEEDED"
|
||||
)
|
||||
|
||||
|
||||
def format_plan_for_prompt(plan: DeliberativePlan) -> str:
|
||||
"""将计划格式化为 system prompt 可用文本。"""
|
||||
lines = [f"## 计划:{plan.title}\n"]
|
||||
if plan.assumptions:
|
||||
lines.append("假设:")
|
||||
lines.extend(f"- {a}" for a in plan.assumptions)
|
||||
lines.append("")
|
||||
if plan.risks:
|
||||
lines.append("风险:")
|
||||
lines.extend(f"- {r}" for r in plan.risks)
|
||||
lines.append("")
|
||||
lines.append("执行步骤:")
|
||||
for step in plan.steps:
|
||||
tool_info = f" [工具:{step.tool}]" if step.tool else ""
|
||||
lines.append(f"{step.id}. {step.title}{tool_info}")
|
||||
if step.description:
|
||||
lines.append(f" {step.description}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def should_plan(request: str) -> bool:
|
||||
"""判断请求是否需要多步计划。
|
||||
|
||||
简单规则:包含需要多工具的关键词时返回 True。
|
||||
"""
|
||||
triggers = [
|
||||
"搜索", "查找", "研究", "调研", "分析", "比较",
|
||||
"整理", "总结", "汇总", "规划", "安排", "计划",
|
||||
"search", "research", "analyze", "compare",
|
||||
"summarize", "plan", "organize",
|
||||
]
|
||||
return any(t in request for t in triggers)
|
||||
Reference in new issue
Block a user