Spaces:
Sleeping
Sleeping
| import os | |
| import gradio as gr | |
| import dashscope | |
| from dashscope import Generation | |
| from http import HTTPStatus | |
| # ====== 1. 配置区域 ====== | |
| dashscope.api_key = os.getenv("DASHSCOPE_API_KEY", "") | |
| MODEL_TUTOR = "qwen-turbo" | |
| MODEL_PROFESSOR = "qwen-plus" | |
| TEXTBOOK_PATH = "textbook.txt" | |
| # ====== 2. 教材加载 ====== | |
| def load_textbook(path=TEXTBOOK_PATH, max_chars=8000): | |
| if not os.path.exists(path): | |
| return "(未找到教材文件,系统将基于通用知识运行,严谨性可能会下降)" | |
| try: | |
| with open(path, "r", encoding="utf-8") as f: | |
| text = f.read() | |
| except UnicodeDecodeError: | |
| with open(path, "r", encoding="gbk") as f: | |
| text = f.read() | |
| if len(text) > max_chars: | |
| text = text[:max_chars] + "\n...(教材内容过长,已截断)" | |
| return text | |
| TEXTBOOK_CONTENT = load_textbook() | |
| # ====== 3. 模型调用 ====== | |
| def call_llm(messages, model_name): | |
| resp = Generation.call(model=model_name, messages=messages, result_format="message") | |
| if resp.status_code == HTTPStatus.OK: | |
| return resp.output["choices"][0]["message"]["content"].strip() | |
| return f"API Error: {resp.code} - {resp.message}" | |
| # ====== 4. Agent 逻辑(完全保留) ====== | |
| def answer_agent(question): | |
| """ | |
| 生成第一版答案:直接回答 + 详细讲解 + 教材例子 | |
| """ | |
| system_prompt = f"""你是一个专业、耐心、循循善诱的教学助手,专门帮助学生理解教材内容。 | |
| ## 你的角色和任务: | |
| 你是问题回答者智能体,负责生成第一版答案,是整个系统的主要输出来源。 | |
| 你必须严格基于提供的教材内容进行回答,不得编造教材外的知识。 | |
| ## 教材内容参考: | |
| {TEXTBOOK_CONTENT} | |
| ## 核心能力要求: | |
| 1. **生成解答**:首先直接、清晰地回答学生的问题 | |
| 2. **讲解内容**:分点展开,详细解释相关概念和原理 | |
| 3. **举例说明**:必须基于上述教材内容进行举例说明 | |
| 4. **追问学生**:最后提出一个相关的思考问题引导学生进一步思考 | |
| ## 回答结构建议: | |
| ### 直接解答 | |
| 先用简洁明了的语言回答问题的核心 | |
| ### 详细讲解 | |
| - 将复杂概念分解成易于理解的要点 | |
| - 使用分点方式展开说明 | |
| - 确保逻辑清晰,层次分明 | |
| ### 教材示例 | |
| 明确引用教材中的具体内容,可以使用"如教材中所述..."或"教材中提到..."等表述 | |
| ### 启发思考 | |
| 提出一个与问题相关的思考题,帮助学生深化理解 | |
| ## 语言风格: | |
| - 面向初学者,语言亲切易懂 | |
| - 温柔指导式,避免过于学术化 | |
| - 使用鼓励性语言,激发学习兴趣 | |
| - 保持耐心和教学友好度 | |
| ## 重要提醒: | |
| - 所有回答必须严格基于提供的教材内容 | |
| - 如果教材中没有相关内容,请如实告知学生 | |
| - 确保回答的准确性和教学价值 | |
| - 你的目标是帮助学生真正理解概念,而不仅仅是给出答案""" | |
| user_prompt = f"""请基于教材内容回答以下问题: | |
| 问题:{question} | |
| 请按照以下要求组织回答: | |
| 1. 首先给出直接答案 | |
| 2. 然后进行分点详细讲解 | |
| 3. 必须基于教材内容举例说明 | |
| 4. 最后提出一个启发性的思考问题 | |
| 5. 使用面向初学者的友好教学语言 | |
| 请开始你的回答:""" | |
| messages = [ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": user_prompt} | |
| ] | |
| return call_llm(messages, MODEL_TUTOR) | |
| def checker_agent(question, draft): | |
| """ | |
| 审查助教的回答:检查概念准确性、完整性、严谨性 | |
| """ | |
| # === 分支 A:初稿为空或过短 === | |
| if not draft or len(draft.strip()) < 50: | |
| system_prompt = f""" | |
| 你是一名严谨负责的AI课程助教,核心任务是对照教材审查回答者的初稿质量。 | |
| 当前初稿为空或内容过短,无法满足回答要求,请按以下框架反馈: | |
| ### 检查依据(唯一参考,不得脱离) | |
| {TEXTBOOK_CONTENT} | |
| ### 输出要求(结构化呈现) | |
| 1. 【学生问题复盘】:简要重复学生问题(确保理解核心诉求) | |
| 2. 【初稿质量评估】: | |
| - 优点:无(初稿未满足基础长度要求) | |
| - 不足:初稿为空或内容过短(少于50字),未覆盖“直接回答+详细讲解+教材例子”的基础结构,无法判断知识点准确性 | |
| 3. 【针对性修改建议】: | |
| - 第一步:先给出“直接回答”(用1-2句话概括问题结论,基于教材) | |
| - 第二步:补充“详细讲解”(分点解释核心概念,如定义、分类等,对应教材内容) | |
| - 第三步:添加“教材例子”(引用教材中的具体案例) | |
| 4. 【修订后的参考答案】:按上述三步,基于教材完整撰写回答,格式清晰 | |
| 5. 【学生水平预判】:未形成有效回答,暂无法判断,建议先掌握“基础回答结构+教材核心概念” | |
| ### 注意事项 | |
| - 修订答案需严格基于教材,不添加额外扩展内容 | |
| - 语气友好,体现助教的指导属性 | |
| """ | |
| # === 分支 B:正常审查 === | |
| else: | |
| system_prompt = f""" | |
| 你是一名严谨负责的AI课程教授,核心任务是对照教材,全面审查回答者的初稿质量,确保内容准确、完整、贴合教材。 | |
| ### 检查依据(唯一参考,不得脱离) | |
| {TEXTBOOK_CONTENT} | |
| ### 检查维度(必须逐一覆盖,不遗漏,每个维度需对应教材依据) | |
| 1. 概念准确性:是否存在与教材冲突的错误?需引用教材原文对比。 | |
| 2. 内容完整性:是否遗漏教材中与问题相关的核心知识点? | |
| 3. 表达严谨性:是否有模糊/歧义表述? | |
| 4. 扩展合理性:若初稿有教材外内容,是否标注“扩展补充”且不超过总内容的20%? | |
| 5. 格式规范性:是否符合“直接回答 + 详细讲解 + 教材相关例子”三部分? | |
| ### 输出要求(结构化呈现,清晰易懂,语言专业且友好) | |
| 请严格按以下框架组织反馈,每个部分需具体、可落地: | |
| 1. 【学生问题复盘】:1-2句话重复学生问题。 | |
| 2. 【初稿质量评估】: | |
| - 优点:分点列出初稿的亮点。 | |
| - 不足:分点列出具体问题,每个问题需包含「初稿原文」+「教材依据」。 | |
| 3. 【针对性修改建议】:对每个“不足”给出唯一对应的修改方案。 | |
| 4. 【修订后的参考答案】: | |
| - 保留初稿中正确的部分,仅修正错误、补充遗漏。 | |
| - 严格按“直接回答+详细讲解+教材例子”结构撰写。 | |
| - 格式清晰:可用小标题分点。 | |
| 5. 【学生水平预判】:基于初稿质量判断(如“基础概念掌握准确,但细节记忆偏差”)。 | |
| ### 注意事项 | |
| - 若初稿完全符合教材且无任何问题:“不足”写“无”,“修改建议”写“无需修改”。 | |
| - 修订答案不得添加教材外知识(除非是通俗化解释)。 | |
| - 反馈语气像助教指导学生,避免生硬批评。 | |
| """ | |
| messages = [ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": f"学生问题:{question}\n\n回答者初稿:\n{draft}"} | |
| ] | |
| return call_llm(messages, MODEL_PROFESSOR) | |
| # ====== 5. 对话式交互逻辑(核心修改点) ====== | |
| def run_chat(question, history): | |
| if not question: | |
| return history, history | |
| history += f"\n\n---\n\n👤 **学生:** {question}\n" | |
| tutor_answer = answer_agent(question) | |
| history += f"\n🤖 **实习助教:**\n{tutor_answer}\n" | |
| professor_answer = checker_agent(question, tutor_answer) | |
| history += f"\n👨🏫 **严谨教授:**\n{professor_answer}\n" | |
| return history, history | |
| # ====== 6. UI ====== | |
| APPLE_UI_CSS = """ | |
| body { background: #F5F5F7; font-family: -apple-system; } | |
| .card { background: white; border-radius: 16px; padding: 24px; margin-bottom: 20px; } | |
| .output-card { height: 600px; overflow-y: auto; } | |
| """ | |
| with gr.Blocks(title="双师课堂 AI") as demo: | |
| gr.Markdown(f"<style>{APPLE_UI_CSS}</style>") | |
| gr.Markdown("# 🎓 双师课堂:对话式教学问答") | |
| chat_history = gr.State("") | |
| with gr.Column(elem_classes=["card"]): | |
| inp = gr.Textbox( | |
| placeholder="请输入你的问题,例如:什么是加速度?", | |
| show_label=False | |
| ) | |
| btn = gr.Button("发送") | |
| with gr.Column(elem_classes=["card", "output-card"]): | |
| chat_display = gr.Markdown("等待提问...") | |
| btn.click( | |
| fn=run_chat, | |
| inputs=[inp, chat_history], | |
| outputs=[chat_display, chat_history] | |
| ) | |
| inp.submit( | |
| fn=run_chat, | |
| inputs=[inp, chat_history], | |
| outputs=[chat_display, chat_history] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |