从零搭建英语情景教学Agent:架构设计与实践记录
最近半年我一直在折腾AI Agent手头这个英语情景教学Agent算是其中落地感最强的一个。简单说它不是一个只会回答问题的聊天机器人而是一个能把场景、角色、流程、反馈串起来的“口语陪练”。你告诉它今天想练“机场值机”它就会扮演地勤人员从排队、护照查验到行李托运一路跟你用英语对话然后根据你的表现给出针对性点评。这篇不聊那些悬浮在PPT里的概念只记录我从零开始把Agent跑起来的过程包括架构设计、代码实现、参数调优和踩坑实录。如果你也想做一个教学类Agent或者正在纠结Agent框架怎么选这份笔记应该能帮你少走很多弯路。1. 项目概述这个英语情景教学Agent到底在做什么1.1 一句话说清楚“英语情景教学Agent”的本质它本质上不是又一个聊天机器人而是一个把“英语对话练习”拆成明确步骤的学习系统。传统的英语对话练习怎么做预制对话树。用户选A就走A分支选B就走B分支所有分支都是人力写死的换一种说法、换一个词程序就接不上体验非常生硬。Agent的玩法完全不同。它把“情景”当作动态输入每次练习都会重新生成剧本但始终围绕同一个学习目标。比如今天练“餐厅点餐”Agent会自己生成服务员角色、菜单、价格、特殊菜品甚至能根据用户水平调整语速和用词难度。用户在对话里说的每一句话都会被记录下来用于结束后的纠错点评。它不只是陪你聊还负责把知识点喂给你、把错误揪出来。更关键的是这个Agent有“教学意识”。它会判断当前应该继续推进剧情还是暂时跳出角色讲一个语法点甚至会在用户反复犯错时主动降低难度。这些能力来自Agent架构里的规划模块而不是单靠一个大模型聊天接口硬撑。1.2 为什么是Agent而不是加长System Prompt的ChatBot我一开始也想过偷懒直接写上“你是一个英语老师请跟我进行餐厅点餐对话”然后丢给模型。试完发现效果很糟糕问题主要集中在三个地方。第一个问题是教学节奏完全失控。模型聊着聊着就变成了百科问答角色感很弱用户说一句“I want beef”它可能就开始分析语法而不是先像服务员一样回应一句“Certainly, how would you like it cooked?”。第二个问题是它从来不给你总结反馈练了十分钟用户根本不知道哪里说得不对。第三个问题是情景内容不稳定一会儿在餐厅一会儿又在讨论食物的历史。说白了一个Prompt承担了太多职责模型根本分不清“演员”“导演”“老师”三个身份。Agent的架构价值就在这里它把任务拆分成“生成情景—扮演角色—接收用户回复—判断教学重点—执行纠错反馈”多个明确环节。每个环节可以单独调试单独换模型单独改策略。这正是Agent和普通聊天机器人最本质的区别——有流程控制有状态管理有阶段性目标。1.3 这个方案适合谁参考如果你正在做AI口语陪练产品或者你是教育培训机构的技术负责人再或者你跟我一样在自学Agent开发这篇内容都值得读完。做这个项目之前你不一定需要很深的大模型算法背景但至少要熟悉Python基础语法、懂一点HTTP调用、能自己装依赖。整个MVP我大概花了两周时间核心代码不到五百行。大模型的API费用也很低开发测试阶段每天几块钱人民币就够跑。2. 核心架构设计从“对话机器人”升级为“教学Agent”2.1 Agent的三块基石规划、记忆、工具只要聊Agent就一定绕不开规划Planning、记忆Memory、工具Tools这三个词。我用自己的话解释一遍方便新手建立概念。规划指的是Agent决定下一步做什么的能力。在这个项目里Agent每收到用户一句话要先判断自己是“继续扮演角色推进剧情”还是“跳出角色进行教学解释”又或者“调一个查词工具来确认术语”。这个决策不是写在代码里的硬转换而是让模型根据当前情景输出一个结构化的动作指令代码再去执行。记忆指的是跨多轮对话保留有用信息。最原始的做法就是把所有聊天记录全量塞给模型但这既贵又容易超上下文窗口。所以我单独维护了一个“会话状态对象”把当前场景、用户设定的难度、已经出现的错误类型、最近几轮对话摘要都存成结构化字段。工具则是在模型本身能力之外扩展的接口。我这个Agent接了一个本地单词查询库和一个发音提醒工具后续还可以接外部词典API。工具的意义是让Agent不只会“说”还能“查”“算”“记”这是Agent相对纯对话模型的一大优势。2.2 情景教学的工作循环是怎么转起来的整个系统的核心循环可以拆成五步。第一步用户输入想练的情景和难度比如“我想练酒店入住难度中级”。第二步情景剧本生成器调用大模型产出一份结构化的剧本包括场景背景、角色列表、开场白、核心词汇、目标句型。第三步Agent进入角色用一句英文开场白启动对话。第四步用户回复后Agent先内部判断这轮对话的处理方式是继续接着剧情演还是暂缓剧情插入一次纠错或者暂时不处理错误但记录到错误清单里。第五步在用户主动结束练习或达到指定对话轮数后Agent输出一份完整的评估报告反馈本次对话的优点、错误和推荐练习方向。我特别想说的是第四步这是教学Agent和普通陪聊机器人拉开差距的地方。一开始我让Agent随时纠错结果用户说一句被掐断一次根本练不下去。后来改成“错误分级”致命错误当场打断轻微错误留存到场景结束后统一点拨。这个策略实测下来用户接受度高很多沉浸感也保住了。2.3 多轮对话状态管理让Agent记得住“演到哪一幕”多轮对话是教学Agent最容易翻车的地方。我见过很多Demo前五轮还好到第八轮就开始前后矛盾明明已经在买单了Agent突然又端上一杯水用户明明说过自己不吃牛肉Agent还推荐牛排。我在代码里维护了一个session_state字段包括当前场景名、当前剧情阶段、用户点过的菜品、出现的错误列表、最近一轮历史。每一轮模型调用前我都会把session_state的核心字段转成一小段文本和系统提示词、最近对话一起发给模型。这样模型既知道全局剧情进度又不用读完所有人的完整历史上下文成本大幅下降。这个方案其实就是业界常说的“结构化管理短期记忆”。不用上多复杂的向量数据库一个字典就能解决单会话内的记忆问题。等以后要做跨会话长期记忆再引入外部存储也不迟。3. 技术选型与关键材料准备别一上来就写代码3.1 大模型选型先拆任务再选模型很多人第一步就卡在大模型选型上天天在几个模型之间纠结。我的经验是先看任务再定模型。这个项目里实际上有三个任务情景剧本生成、角色对话、学习反馈评估。它们的侧重点完全不同。情景剧本生成需要创造力和多样性我会用一个平衡速度与质量的通用模型温度参数调到0.8以上让每次生成的剧本都不太一样。角色对话需要强指令遵循和角色扮演稳定性选当时综合能力靠前的主力模型同时把温度调低到0.3左右防止它发挥过头。学习反馈评估其实不需要太强的生成能力反而需要稳定的判断标准。我优先用“硬规则加轻量模型”的组合硬规则负责抓一些低级错误轻量模型负责综合评价。这里想提醒一句不要指望一个模型解决所有问题。你可以用同一个模型厂商的不同档位也可以混用多家服务Agent架构天然支持这种混搭。而且价格上一定要算账把高成本的豪华模型留给关键环节其他环节用便宜模型顶上能省不少钱。3.2 Agent框架选择LangChain、AutoGen还是手写ReAct我去翻了一堆主流Agent框架对比也分别写了点测试代码。LangChain很全内置了很多工具和Agent类型但抽象层太多光搞懂 Chain、Agent、Executor 之间的关系就花了几天。AutoGen适合做多Agent协作拿来做教学流程反而有点大炮打蚊子。最后我先试了手写ReAct循环结果发现非常合适。这里不是否定框架而是想给一个思考角度如果业务逻辑非常固定手写的可控性最好。教学Agent的核心教学顺序是不能乱来的必须“先生成情景再对话最后评估”这个流程如果交给你不熟悉的框架去编排经常会出现莫名其妙的跳转。手写ReAct的代码量不大核心就是前三步让大模型输出Thought想法、Action动作、Action Input动作输入代码解析后执行对应函数再把结果作为Observation观察结果传回去。3.3 Prompt体系设计情景模板、角色设定、反馈规则懂行的人都明白Agent项目大部分效果不是调模型调出来的而是靠Prompt设计和流程拼接。我把Prompt拆成三层。第一层是系统级设定永久不变包括Agent的身份、教学目标、纠错铁律、输出格式规范。第二层是情景级设定每一次练习动态生成包括场景剧本、当前难度、核心词汇、剧情阶段。第三层是临场级信息每次请求都变化包括用户最近几句话、系统刚刚执行完毕的工具结果、当前时间点。下面是一个简化版Prompt模板实际项目里会比这长不少但结构是这个样子。你是英语情景教学Agent名叫Emma。 你正在扮演{role}当前场景是{scene}。 剧情阶段{stage} 核心词汇{vocab_list} 目标句型{target_patterns} 规则 1. 你必须一直扮演角色不要突然变成英语老师。 2. 当你想对用户进行教学讲解时必须先输出[TEACH]再跳出角色。 3. 用户出现轻微语法错误时不要当场打断记录到错误列表。 4. 用户出现无法沟通的严重错误时可以当场给出提示。 对话历史 {history} 用户最新输入 {user_input}这里有一个我反复强调的技巧给模型设定“教学动作信标”比如[TEACH]。这个信标不是一个装饰它是让代码能够稳定识别模型意图的关键。后续做控制流判断时我只要在模型输出里检测有没有这个标签就能决定是继续对话还是进入点评模式。3.4 语音能力取舍MVP阶段先不碰英语情景教学Agent听起来应该带语音但实际上我建议MVP阶段完全不要做语音。原因很简单语音识别会把一个“Agent教学问题”瞬间变成“语音识别问题Agent教学问题”的叠加上一轮语音识别错一个单词很可能导致Agent在后续对话里产生连锁错误。所以我第一版只做纯文本对话。先用文本把教学闭环跑顺验证用户真的能通过这个流程练到英语、拿到有效反馈。后面如果要做语音版本再说接入语音识别和语音合成的事。这个决策帮我省了至少一半的开发时间。4. 实操记录从零搭建英语情景教学Agent4.1 环境准备与依赖安装我的开发环境是Python 3.10用到的核心库只有三个openai库负责调用大模型接口pydantic做数据校验dotenv管理密钥。建一个虚拟环境然后装依赖命令我放在下面。python -m venv venv source venv/bin/activate pip install openai pydantic python-dotenv同时准备一个.env文件里面写模型的API地址和密钥。密钥一定不要写死在代码里。MODEL_API_BASEhttps://your-api-endpoint MODEL_API_KEYyour_secret_key MAIN_MODELgpt-4o-mini LIGHT_MODELgpt-4o-mini这些基础工作做完就可以开始写核心模块了。4.2 核心模块一情景剧本生成器这个模块的职责是把“情景名称”和“难度等级”变成一份结构化剧本。我要求模型输出严格的JSON格式然后用pydantic校验字段。生成出的剧本包括场景名称、角色设定、开场白、核心词汇表、目标句型、剧情里程碑。from pydantic import BaseModel, Field from typing import List import json class ScenarioScript(BaseModel): scene_name: str Field(description场景名称例如餐厅点餐) roles: List[str] Field(description角色列表) opening: str Field(descriptionAgent的开场白) core_vocab: List[str] Field(description核心词汇) target_patterns: List[str] Field(description目标句型) plot_beats: List[str] Field(description剧情里程碑) def generate_scenario(scene: str, level: str) - ScenarioScript: prompt f 你是一个英语情景教学课程设计师。 请为「{scene}」场景设计一份适合{level}学习者的英语对话剧本。 要求 - 台词自然不书面化 - 核心词汇控制在8个以内 - 目标句型必须是口语中使用频率高的表达 - 剧情里程碑按时间顺序给出3到5个节点 只输出JSON不要额外文字。 response client.chat.completions.create( modelMAIN_MODEL, messages[{role: user, content: prompt}], temperature0.8, response_format{type: json_object} ) data json.loads(response.choices[0].message.content) return ScenarioScript(**data)遗嘱很重要的一点如果大模型返回的JSON解析失败整个Agent循环会直接报错。所以我在真实代码里加了两层保险第一层是让API强制返回JSON对象第二层是解析失败时自动重试一次。4.3 核心模块二ReAct风格Agent执行循环执行循环是整个Agent的中枢。它负责接收用户输入把情景、历史、会话状态拼进Prompt调用大模型然后解析模型输出。我这里只保留最核心的ReAct逻辑用一个while循环控制最大轮数避免Agent在逻辑错误时无限循环。class TeachAgent: def __init__(self, system_prompt: str, session_state: dict): self.system_prompt system_prompt self.session_state session_state self.history [] def run(self, user_input: str) - str: max_steps 10 current_input user_input for step in range(max_steps): messages [ {role: system, content: self.system_prompt}, *self.history, {role: user, content: current_input}, ] resp client.chat.completions.create( modelMAIN_MODEL, messagesmessages, temperature0.3, ) output resp.choices[0].message.content if [TEACH] in output: # 讲解模式记录错误并生成点评 teacher_text self._handle_teach(output) self.history.append({role: assistant, content: output}) return teacher_text if ACTION: in output: action self._parse_action(output) result self._execute_action(action) current_input f工具返回结果: {result}请继续对话。 continue else: self.history.append({role: assistant, content: output}) return output return 对话轮数过多请重新发起一次练习。这个代码最核心的设计就是通过解析[TEACH]和ACTION:来控制流程。没有框架没有黑魔法就是一道简单的字符串判断。但就是这道判断让Agent从“无脑聊天”变成了“有教学节奏的陪练”。4.4 核心模块三反馈评估器对话结束后反馈模块开始工作。我先跑一串硬规则检查比如用户每句话的平均长度、错误词汇是否命中、是否使用了目标句型跑完规则后再让模型生成综合评价。我这里把重点放在“可执行的建议”而不是写一段空泛的表扬。def evaluate_session(transcript: list[str], target_patterns: list[str]) - str: low_length_count 0 for line in transcript: if len(line.split()) 3: low_length_count 1 rule_flags [] if low_length_count 5: rule_flags.append(大量句子过短可能缺乏完整表达。) prompt f 你是英语学习评估专家。请根据以下对话记录给出学习反馈。 目标句型{target_patterns} 硬规则检测结果{rule_flags} 要求 1. 先指出优点 2. 再指出最值得改进的2-3个点 3. 给出每个问题的替换表达 4. 最后布置一个30秒可完成的口头练习 对话记录 {chr(10).join(transcript)} response client.chat.completions.create( modelLIGHT_MODEL, messages[{role: user, content: prompt}], temperature0.4, ) return response.choices[0].message.content反馈的质量很大程度上决定了用户是否感受到“教学价值”。空话说再多都没用必须给具体替换表达。比如用户说错“I want eat”反馈里应该写“可以说 I want to eat或者更礼貌的说法是 Id like to eat”。这种反馈才有价值。4.5 主流程串起来一次完整的餐厅点餐演练把上面三个模块接起来实际运行效果大致是这样的。用户输入“我想练餐厅点餐初级”。剧本生成器返回场景数据Agent调用generate_scenario拿到剧本。然后系统Prompt替换成剧本内容。紧接着Agent输出开场白“Welcome to Bella Italia! My name is Marco. Can I get you something to drink while you look at the menu?”用户回一句“Yes, I want a coke.” Agent判断这句话有轻微表达问题但不影响交流于是不打断继续扮演服务员推进剧情“Sure! One coke coming up. Are you ready to order, or do you need a few more minutes?”用户继续回答循环往复。6轮对话结束后用户输入“结束练习”系统调用评估器输出一份带具体替换表达的评价。整个流程非常顺畅而且每一步都能肉眼看到在做什么。5. 运行中踩过的坑常见问题与排查技巧5.1 Agent“卡死”或反复报错怎么办我在开发中最常碰到的报错信息有两类一类是agent execution terminated due to error另一类是agent couldnt generate a response。第一眼看到这些英文报错时容易慌后来发现本质上都是同一个问题模型返回的内容不符合代码的预期格式而解析逻辑没有兜底。比如我要求模型输出JSON但它多输出了一行解释文字json.loads立刻爆炸。或者ReAct循环里模型一直输出ACTION但Action字段里根本没给工具名代码拿不到有效工具就卡死。解决方案其实很朴素解析失败就重试一次同时把大模型调用包在异常捕获里一旦连续三次失败就返回一条兜底回复“我没太听清可以再说一遍吗”。这类问题理论上不可能百分百消除但兜底能保证用户体验不中断。5.2 角色漂移说着说着就变成了英语老师这个坑在很多教学Agent项目里都会出现。模型本来正在认真扮演餐厅服务员用户问一句“这个用英语怎么说”它立刻跳出场景开始讲课把练习节奏全毁了。我一开始靠在系统Prompt里反复强调“不要跳出角色”但效果不稳定于是改为显式的[TEACH]标签机制。只有当用户明确要求讲解或者系统检测到严重表达障碍时Agent才被允许输出[TEACH]并进入教学模式其他情况下必须保持角色对话。这个机制帮我彻底解决了角色漂移问题。它本质上是给了模型一个清晰的动作开关而不是一句模糊的“你别跑题”。所以如果你也在做角色扮演类Agent强烈建议试试这个思路。5.3 上下文太长导致效果下降和费用飙升多轮对话跑了十轮以上如果每次都把全部消息历史传给模型效果和成本都会出问题。历史里包含大量冗余信息真正有用的可能只有最近几轮和会话状态里的关键字段。我的做法是给历史列表加了一个长度上限只保留最近6条消息更早的内容由session_state里的摘要字段兜住。比如前面提到用户点了可乐这个信息不会因为历史被截断而丢失因为它在会话状态里还存着。这个方法见效非常明显模型输出更稳定Token费用直接降了一半多。写代码时注意不要把摘要逻辑放在每轮响应之后可以放在每次用户输入之前集中更新一次。5.4 内容安全与低质量生成别把把关全交给大模型刚开始做的时候我以为只要在System Prompt里写了“不要输出不当内容”就够了。测试之后就发现靠模型自觉远远不够尤其当Agent被诱导跳出角色时生成内容的质量控制会失效。后来我在系统里加了一道轻量拦截层维护一个敏感词表并对最终输出做一次规则校验。一旦命中黑名单或发现输出格式不对就强行替换成安全且中立的回复。同时我还给Agent加了一条“不会的内容就承认”的规则避免它在教学场景里编造不存在的词汇用法。英语教学领域最怕一本正经地胡扯。所以主流模型能力再强外部过滤校验也不可以省略。5.5 成本与限流的平衡调大模型接口一定会遇到限流尤其在开发测试阶段高频调用容易触发并发限制。我的处理方式是给API调用包了一层“指数退避重试”再配合简单的内存缓存。同一个参数组合的请求短时间内直接读缓存减少重复调用。成本控制的思路更简单把任务拆分。剧本生成、角色对话、评估反馈分别使用不同档位的模型剧本生成和评估反馈这类非实时任务可以用更便宜的通用模型实时对话再上更稳的模型。整体费用会变得非常可控个人做项目完全没有压力。下面是我整理的常见问题速查表。问题现象常见原因首选解决方案Agent报错后直接中断模型输出格式不符合解析逻辑加异常捕获失败后自动重试连续失败给兜底回复角色漂移严重Prompt缺乏清晰动作信标引入[TEACH]等显式标签严格限制场景切换多轮后效果骤降上下文过长或关键信息丢失只保留最近几轮会话状态存储结构化摘要生成不相关内容模型被诱导或缺乏规则约束外层加规则校验和黑名单过滤不允许裸奔API经常限流请求频率过高指数退避重试加内存缓存合理调度并发6. 项目后期还能怎么长扩展方向与个人体会6.1 加入长期记忆与知识库目前这个Agent只会在单次会话内保持记忆下次练习它完全不记得用户上次哪里薄弱。想让Agent真正变成一个“了解你的英语老师”就需要引入长期记忆。把每次训练后的错误清单、掌握情况、高频错词写入一个本地向量库下次用户开始时Agent可以先做一次检索把过往错题带进新的情景Prompt。这个方向技术上不复杂核心就是把“会话级记忆”升级为“用户级记忆”。教学产品真正值钱的壁垒也恰恰在这里——不是Agent聊得有多好而是它是否始终记得你的薄弱点。6.2 支持多Agent协作我规划过一版更复杂的系统一个“教师Agent”负责生成情景和推进剧情一个“考官Agent”负责在特定节点发起小测验一个“反馈Agent”专门在对话结束后做细粒度评估。三个Agent各有分工通过一个协调模块交换数据。这种情况下就用得上AutoGen这类多Agent框架了。多Agent的好处是职责隔离每个模型不用同时思考“教学表演评价”角色稳定性和输出质量都会更高缺点是真做好难需要处理Agent之间的通信和冲突。如果你刚入门建议先把单Agent做透再考虑引入多Agent。6.3 语音闭环与真实产品化文本版验证完之后语音接入就是自然下一步。思路是用语音识别把用户口语转成文本Agent按既定流程处理再通过语音合成播报回复。这里还要额外加一道“发音评测”把用户录音的音准、流畅度数据传给评估模块。整体流程就变成了“听—想—说—评”的完整闭环这才算一个真正意义上的口语陪练产品。如果你要走到这一步提醒一句先录音测试别直接用陌生人声安装包。语音链路里任何一个环节的延迟都会直接杀死体验。6.4 一些真心话做这个项目最大的感悟是Agent并没有想象中那么玄乎它本质上还是“流程控制大模型理解”的组合。用ReAct思路写一个不超过二十行的主循环你就能拥有一个最小可用的Agent。真正花时间的不是Agent框架本身也不是模型选型而是你想让它处理的那个业务流程到底梳理清楚没有。我反复重做了三轮才把“什么时候纠错”“什么时候讲题”“什么时候演角色”这几个规则理明白。对英语教学Agent来说教学设计和教学节奏永远比模型参数更重要。最后分享一个自己常用的套路在正式开发前先用思维导图把一次完整练习涉及的所有状态和转换画出来再写任何一行代码。状态图不画清楚写出来的Agent就只是聊天机器人。