ClareCourseWare / api /teacher_agent.py
claudqunwang's picture
添加持续对话功能:支持每个功能模块与AI进行多轮对话和互动
6a91b07
# api/teacher_agent.py
"""
教师端 AI Agent:基于与 Clare 相同的 Weaviate(GenAICourses)与 OpenAI,为教师提供:
- 课程描述生成
- 课程文档内容建议
- 作业和题库生成建议
- 学生学习评估分析
"""
from typing import Optional
from .config import client, DEFAULT_MODEL, USE_WEAVIATE
from .weaviate_retrieve import retrieve_from_weaviate
TEACHER_SYSTEM = """你是一位面向高校教师的 AI 助教,擅长课程设计、教学材料建议与学习评估分析。
你与 Clare 共用同一套 GENAI 课程知识库(Weaviate)。回答时请优先依据提供的「课程知识库摘录」,
并结合通用教学经验,给出简洁、可操作的建议。若未提供知识库摘录,则基于通用教育学与学科知识回答。"""
def _lang_instruction(reply_language: Optional[str]) -> str:
if reply_language == "en" or reply_language == "english":
return "You must reply in English only."
if reply_language == "zh" or reply_language == "中文" or not reply_language:
return "请务必仅用中文回答。"
return ""
def _call_llm(
user_content: str,
system_extra: str = "",
reply_language: Optional[str] = None,
max_tokens: int = 1500,
history: Optional[list] = None,
) -> str:
"""
history: List of tuples [(user_msg, assistant_msg), ...] for conversation context
"""
system = TEACHER_SYSTEM
lang = _lang_instruction(reply_language)
if lang:
system = system + "\n\n" + lang
if system_extra:
system = system + "\n\n" + system_extra
messages = [{"role": "system", "content": system}]
# Add conversation history if provided
if history:
for user_msg, assistant_msg in history[-10:]: # Keep last 10 turns
if user_msg:
messages.append({"role": "user", "content": user_msg})
if assistant_msg:
messages.append({"role": "assistant", "content": assistant_msg})
messages.append({"role": "user", "content": user_content})
try:
resp = client.chat.completions.create(
model=DEFAULT_MODEL,
messages=messages,
temperature=0.6,
max_tokens=max_tokens,
timeout=60,
)
return (resp.choices[0].message.content or "").strip()
except Exception as e:
print(f"[teacher_agent] LLM error: {repr(e)}")
return f"生成时出错:{repr(e)}。请稍后重试。"
def generate_course_description(
topic: str,
outline_hint: Optional[str] = None,
reply_language: Optional[str] = None,
history: Optional[list] = None,
user_message: Optional[str] = None,
) -> str:
"""
课程描述生成:根据课程主题(及可选大纲要点)生成一段可用于课程介绍/选课页的描述。
reply_language: "en" | "zh" | None(默认中文)
user_message: 持续对话时的用户消息(可选)
"""
rag = retrieve_from_weaviate(topic, top_k=6) if USE_WEAVIATE else ""
if user_message:
# 持续对话模式:直接使用用户消息
user = user_message
if rag:
user = f"**参考知识库摘录:**\n{rag[:4000]}\n\n---\n\n{user}"
else:
# 初始提交模式:使用表单字段
user = f"请根据以下信息,生成一段简洁的**课程描述**(约 150–250 字),适合放在课程介绍或选课页面。\n\n"
user += f"**课程主题/名称:** {topic}\n\n"
if outline_hint:
user += f"**大纲或要点(可选):**\n{outline_hint}\n\n"
if rag:
user += "**参考知识库摘录(请据此保持与现有课程内容一致):**\n" + rag[:4000] + "\n\n"
user += "请直接输出课程描述正文,无需重复题目。"
return _call_llm(user, reply_language=reply_language, max_tokens=800, history=history)
def suggest_course_doc_content(
topic: str,
current_doc_excerpt: Optional[str] = None,
doc_type: str = "讲义/课件",
reply_language: Optional[str] = None,
history: Optional[list] = None,
) -> str:
"""
课程文档内容建议:针对某一主题或现有文档片段,给出可写入讲义/课件的内容建议。
"""
rag = retrieve_from_weaviate(topic, top_k=8) if USE_WEAVIATE else ""
user = f"请针对以下**课程文档**(类型:{doc_type})给出**内容建议**:结构要点、关键概念、可选的例子或习题方向。\n\n"
user += f"**主题或章节:** {topic}\n\n"
if current_doc_excerpt:
user += f"**当前已有内容(片段):**\n{current_doc_excerpt[:2000]}\n\n"
if rag:
user += "**参考知识库摘录:**\n" + rag[:5000] + "\n\n"
user += "请用分点或短段落给出建议,便于教师直接采纳或改写。"
return _call_llm(user, reply_language=reply_language, max_tokens=1200, history=history)
def suggest_assignments_questions(
topic: str,
week_or_module: Optional[str] = None,
question_type: str = "混合",
reply_language: Optional[str] = None,
history: Optional[list] = None,
) -> str:
"""
作业和题库生成建议:根据主题(及可选周次/模块)给出作业题、练习题或考试题建议。
question_type 可为:选择题、简答题、开放题、混合 等。
"""
rag = retrieve_from_weaviate(topic, top_k=8) if USE_WEAVIATE else ""
user = f"请根据以下课程信息,给出**作业与题库**的生成建议:包含题目类型、难度分布、2–3 道示例题(含参考答案要点)。\n\n"
user += f"**主题:** {topic}\n\n"
if week_or_module:
user += f"**周次/模块:** {week_or_module}\n\n"
user += f"**题型偏好:** {question_type}\n\n"
if rag:
user += "**参考知识库摘录:**\n" + rag[:5000] + "\n\n"
user += "请直接给出建议与示例题,便于教师录入题库或布置作业。"
return _call_llm(user, reply_language=reply_language, max_tokens=1500, history=history)
def analyze_student_assessment(
assessment_summary: str,
course_topic_hint: Optional[str] = None,
reply_language: Optional[str] = None,
history: Optional[list] = None,
) -> str:
"""
学生学习评估分析:根据教师提供的学生表现摘要(如作业/测验得分、常见错误、参与度等),
给出简要分析结论与教学改进建议。
"""
rag = ""
if course_topic_hint and USE_WEAVIATE:
rag = retrieve_from_weaviate(course_topic_hint, top_k=4)
user = "请根据以下**学生学习评估信息**,给出简要的**分析结论**与**教学改进建议**(分点、可操作)。\n\n"
user += f"**评估摘要:**\n{assessment_summary}\n\n"
if course_topic_hint:
user += f"**相关课程主题:** {course_topic_hint}\n\n"
if rag:
user += "**参考知识库摘录(可选,用于对齐课程目标):**\n" + rag[:3000] + "\n\n"
user += "控制在 300–500 字。"
return _call_llm(user, reply_language=reply_language, max_tokens=800, history=history)