feat: 新增需求理解并实现human in loop

This commit is contained in:
2026-09-23 11:20:02 +08:00
parent 006112600a
commit dd7138598d
11 changed files with 167 additions and 35 deletions
+20 -18
View File
@@ -1,5 +1,7 @@
"""整理澄清问题,等待用户补充"""
import json
from langchain_core.messages import HumanMessage, SystemMessage
from app.clients.llm import get_llm
@@ -16,23 +18,20 @@ class ClarifyNode(BaseNode):
intent = state["intent"]
print(intent)
print("=================")
if intent == "unclear":
llm = get_llm(Clarification)
clarification = await llm.ainvoke(
[
SystemMessage(content=CLARIFY_SYSTEM_PROMPT),
HumanMessage(
content=state["input_context"].model_dump_json(
exclude_unset=True
)
),
]
)
else:
# 需求理解已经给出问题,直接复用
clarification = Clarification(
question=state["requirement"].clarification_question
)
payload = {
"intent": intent,
"input_context": state["input_context"].model_dump(mode="json"),
}
if intent != "unclear":
# 以需求节点的问题为依据补齐选项,不重新判断意图
payload["requirement"] = state["requirement"].model_dump(mode="json")
llm = get_llm(Clarification)
clarification = await llm.ainvoke(
[
SystemMessage(content=CLARIFY_SYSTEM_PROMPT),
HumanMessage(content=json.dumps(payload, ensure_ascii=False)),
]
)
return {**state, "clarification": clarification}
@@ -54,7 +53,9 @@ if __name__ == "__main__":
}
}
try:
final_state = await query_app.ainvoke(state)
final_state = await query_app.ainvoke(
state, config={"configurable": {"thread_id": "clarify-test"}}
)
finally:
await close_decision_engine()
print(
@@ -67,6 +68,7 @@ if __name__ == "__main__":
},
ensure_ascii=False,
indent=2,
default=str,
)
)
+35
View File
@@ -11,6 +11,41 @@ class InputNode(BaseNode):
name = "input_node"
def process(self, state: QueryState) -> QueryState:
reply = state.get("clarification_reply")
if reply is not None:
data = state["input_context"].model_dump(mode="json")
turn = {
"question": state["clarification"].question,
"answer": reply.answer,
}
if reply.option_id is not None:
option = next(
option
for option in state["clarification"].options
if option.id == reply.option_id
)
turn["selected_option"] = option.model_dump(mode="json")
data["clarification_history"].append(turn)
if reply.screen is not None:
data["screen"] = reply.screen.model_dump(mode="json")
# 新快照不沿用可能已经失效的选中节点
if reply.context is None:
data["context"]["selected_node_ids"] = []
data["context"]["screen_revision"] = None
if reply.context is not None:
data["context"] = reply.context.model_dump(mode="json")
context = InputContext.model_validate(data)
# 显式清空旧推导结果,LangGraph 的状态合并不会删除省略字段
return {
**state,
"input_context": context,
"clarification_reply": None,
"intent_decision": None,
"intent": None,
"requirement": None,
"clarification": None,
"status": "running",
}
# 深拷贝隔离原始请求,后续修改上下文不会改变提交时的快照
context = InputContext.model_validate(state["request"]).model_copy(deep=True)
updated_state: QueryState = {**state, "input_context": context}
+1
View File
@@ -38,6 +38,7 @@ class IntentNode(BaseNode):
)
return {
"prompt": context.prompt,
"clarification_history": context.clarification_history,
"context": context.context.model_dump(mode="json", exclude_unset=True),
"screen_summary": {
"canvas": {