Browse Source

feat: 新增文章答题出题 graph

Sisyphus 1 month ago
parent
commit
484c6e4896
1 changed files with 58 additions and 0 deletions
  1. 58 0
      cfc-langgraph/app/graphs/article_quiz_graph.py

+ 58 - 0
cfc-langgraph/app/graphs/article_quiz_graph.py

@@ -0,0 +1,58 @@
+from langchain_openai import ChatOpenAI
+from langchain_core.messages import SystemMessage, HumanMessage
+from app.config import settings
+from app.monitoring import monitor_agent
+from app.prompt_service import get_prompt
+import json
+import logging
+
+logger = logging.getLogger(__name__)
+
+SYSTEM_PROMPT = """你是一位家庭教育出题助手。根据给定的文章内容,为读者生成 3 道单项选择题。
+
+要求:
+1. 每题 4 个选项,选项以 "A. "、"B. "、"C. "、"D. " 开头
+2. 题目考察文章核心内容的理解,适合青少年读者
+3. 每题标注所属五维(body/mind/wisdom/action/wealth),缺省为 wisdom
+4. 以 JSON 数组格式返回,不要返回其他文字,只返回 JSON 数组
+
+输出格式:
+[
+  {"question": "问题", "options": ["A. xxx", "B. xxx", "C. xxx", "D. xxx"], "answer": "A", "dimension": "wisdom", "explanation": "解析"}
+]
+"""
+
+
+class ArticleQuizAgent:
+    def __init__(self):
+        self.llm = ChatOpenAI(
+            model=settings.llm_model,
+            api_key=settings.llm_api_key,
+            base_url=settings.llm_base_url,
+            temperature=settings.llm_temperature,
+        )
+
+    @monitor_agent("article_quiz")
+    async def run(self, article_title: str, article_content: str, profile_summary: str = "") -> dict:
+        """根据文章内容生成 3 道选择题,失败返回空 questions"""
+        try:
+            human = f"文章标题:{article_title}\n文章内容:{article_content}"
+            if profile_summary:
+                human += f"\n用户画像摘要:{profile_summary}"
+            messages = [
+                SystemMessage(content=await get_prompt("article_quiz") or SYSTEM_PROMPT),
+                HumanMessage(content=human),
+            ]
+            response = await self.llm.ainvoke(messages)
+            content = response.content.strip()
+            if "```json" in content:
+                content = content.split("```json")[1].split("```")[0].strip()
+            elif "```" in content:
+                content = content.split("```")[1].split("```")[0].strip()
+            questions = json.loads(content)
+            if not isinstance(questions, list):
+                return {"questions": [], "fallback_used": True}
+            return {"questions": questions, "fallback_used": False}
+        except Exception as e:
+            logger.warning("文章出题生成失败: %s", e)
+            return {"questions": [], "fallback_used": True}