questionnaire.py 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import json
  2. from typing import TypedDict, Optional
  3. from langgraph.graph import StateGraph, START, END
  4. from langchain_core.messages import HumanMessage
  5. from ..llm.client import get_llm
  6. from ..prompts.questionnaire import PARENT_TEMPLATE, CHILD_TEMPLATE
  7. from ..schemas.questionnaire import Questionnaire, GenerateRequest
  8. class GraphState(TypedDict):
  9. request: GenerateRequest
  10. raw_response: str
  11. questionnaire: Optional[dict]
  12. error: Optional[str]
  13. def build_prompt(state: GraphState) -> GraphState:
  14. req = state["request"]
  15. template = PARENT_TEMPLATE if req.relationship_type == "parent" else CHILD_TEMPLATE
  16. prompt = template.format(member_name=req.member_name)
  17. return {**state, "_prompt": prompt}
  18. def call_llm(state: GraphState) -> GraphState:
  19. llm = get_llm()
  20. messages = [HumanMessage(content=state["_prompt"])]
  21. response = llm.invoke(messages)
  22. return {**state, "raw_response": response.content}
  23. def validate(state: GraphState) -> GraphState:
  24. raw = state["raw_response"]
  25. # 提取 JSON 块
  26. text = raw.strip()
  27. if "```json" in text:
  28. text = text.split("```json")[1].split("```")[0].strip()
  29. elif "```" in text:
  30. text = text.split("```")[1].split("```")[0].strip()
  31. try:
  32. data = json.loads(text)
  33. q = Questionnaire(**data)
  34. if not q.validate_structure():
  35. return {**state, "error": "问卷结构校验失败:至少需要1题且每题有options或scale"}
  36. return {**state, "questionnaire": data, "error": None}
  37. except Exception as e:
  38. return {**state, "error": f"JSON 解析失败: {str(e)}"}
  39. def build_questionnaire_graph():
  40. graph = StateGraph(GraphState)
  41. graph.add_node("build_prompt", build_prompt)
  42. graph.add_node("call_llm", call_llm)
  43. graph.add_node("validate", validate)
  44. graph.add_edge(START, "build_prompt")
  45. graph.add_edge("build_prompt", "call_llm")
  46. graph.add_edge("call_llm", "validate")
  47. graph.add_edge("validate", END)
  48. return graph.compile()
  49. _questionnaire_graph = None
  50. def get_questionnaire_graph():
  51. global _questionnaire_graph
  52. if _questionnaire_graph is None:
  53. _questionnaire_graph = build_questionnaire_graph()
  54. return _questionnaire_graph