feat: 添加 Action 协议
This commit is contained in:
@@ -43,6 +43,7 @@ class InputNode(BaseNode):
|
||||
"intent_decision": None,
|
||||
"intent": None,
|
||||
"requirement": None,
|
||||
"change_scope": None,
|
||||
"clarification": None,
|
||||
"answer": None,
|
||||
"status": "running",
|
||||
|
||||
@@ -21,20 +21,17 @@ class RequirementNode(BaseNode):
|
||||
"intent": intent,
|
||||
"input_context": context.model_dump(mode="json", exclude_unset=True),
|
||||
}
|
||||
llm = get_llm(Requirement)
|
||||
result = await llm.ainvoke(
|
||||
llm_client = get_llm(Requirement)
|
||||
llm_res = await llm_client.ainvoke(
|
||||
[
|
||||
SystemMessage(content=REQUIREMENT_SYSTEM_PROMPT),
|
||||
HumanMessage(content=json.dumps(payload, ensure_ascii=False)),
|
||||
]
|
||||
)
|
||||
|
||||
print(f"LLM 返回的需求: {result}")
|
||||
print("=" * 66)
|
||||
|
||||
# 沿用门控后的意图,合并后重新校验字段一致性
|
||||
requirement = Requirement.model_validate(
|
||||
{**result.model_dump(), "intent": intent}
|
||||
{**llm_res.model_dump(), "intent": intent}
|
||||
)
|
||||
node_ids = {node.id for node in context.screen.nodes}
|
||||
for change in requirement.changes:
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
"""判断需求涉及的范围、规划和资源需求"""
|
||||
|
||||
import json
|
||||
|
||||
from langchain_core.messages import HumanMessage, SystemMessage
|
||||
|
||||
from app.clients.llm import get_llm
|
||||
from app.processor.base import BaseNode
|
||||
from app.processor.state import QueryState
|
||||
from app.prompt.scope import SCOPE_SYSTEM_PROMPT
|
||||
from app.schemas.change_scope import ChangeScope
|
||||
|
||||
|
||||
class ScopeNode(BaseNode):
|
||||
name = "scope_node"
|
||||
|
||||
async def process(self, state: QueryState) -> QueryState:
|
||||
requirement = state["requirement"]
|
||||
if requirement.needs_clarification or requirement.intent not in (
|
||||
"create_screen",
|
||||
"modify_screen",
|
||||
):
|
||||
raise ValueError("ScopeNode 只处理信息完整的新建或修改需求")
|
||||
context = state["input_context"]
|
||||
llm_client = get_llm(ChangeScope)
|
||||
scope = await llm_client.ainvoke(
|
||||
[
|
||||
SystemMessage(content=SCOPE_SYSTEM_PROMPT),
|
||||
HumanMessage(
|
||||
content=json.dumps(
|
||||
{
|
||||
"requirement": requirement.model_dump(mode="json"),
|
||||
"input_context": context.model_dump(
|
||||
mode="json", exclude_unset=True
|
||||
),
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
),
|
||||
]
|
||||
)
|
||||
existing_ids = {node.id for node in context.screen.nodes}
|
||||
if unknown_ids := set(scope.target_ids) - existing_ids:
|
||||
raise ValueError(f"范围引用了不存在的节点: {sorted(unknown_ids)}")
|
||||
required_ids = {
|
||||
node_id for change in requirement.changes for node_id in change.target_ids
|
||||
}
|
||||
if missing_ids := required_ids - set(scope.target_ids):
|
||||
raise ValueError(f"范围遗漏了需求中的节点: {sorted(missing_ids)}")
|
||||
return {**state, "change_scope": scope}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import asyncio
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.processor.nodes.input_node import InputNode
|
||||
from app.schemas.requirement import Requirement
|
||||
|
||||
async def main():
|
||||
# 直接提供已理解的需求,单独测试范围判断,仅需 LLM 配置
|
||||
state: QueryState = {
|
||||
"request": {
|
||||
"prompt": "把销售额统计向右移动 50px,其他不变",
|
||||
"screen": {
|
||||
"canvas": {"width": 1920, "height": 1080},
|
||||
"nodes": [
|
||||
{
|
||||
"id": "sales-chart",
|
||||
"type": "bar-chart",
|
||||
"name": "销售额统计",
|
||||
"layout": {"x": 26, "y": 34.8, "width": 400, "height": 260},
|
||||
}
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
state = InputNode().process(state)
|
||||
state["requirement"] = Requirement(
|
||||
intent="modify_screen",
|
||||
goal="销售额统计向右移动 50px",
|
||||
changes=[
|
||||
{
|
||||
"target_scope": "nodes",
|
||||
"target_ids": ["sales-chart"],
|
||||
"operation": "move",
|
||||
"parameters": {"delta_x": 50},
|
||||
}
|
||||
],
|
||||
needs_clarification=False,
|
||||
constraints=["其他不变"],
|
||||
)
|
||||
node = ScopeNode()
|
||||
final_state = await node.process(state)
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
key: value.model_dump(mode="json")
|
||||
if isinstance(value, BaseModel)
|
||||
else value
|
||||
for key, value in final_state.items()
|
||||
},
|
||||
ensure_ascii=False,
|
||||
indent=2,
|
||||
)
|
||||
)
|
||||
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user