资讯动态

英语陪练Agent从零到一:架构、记忆与工具调优实战

发布时间:2026/10/1 19:20:15 来源:尧图企业网站定制
最近被问得最多的问题之一就是“我想做一个英语陪练Agent该从哪开始”。这个问题我前前后后折腾了快两个月从最早只能跑通“你问我答”的Demo到最后整理出一套带记忆、带工具、带多角色切换的英语情景教学Agent中间踩了不少坑也总结出一些可复用的套路。今天把整个从零到一的开发过程完整拆开讲讲我在做这个项目时的真实决策过程希望能给想入手Agent开发的朋友一点参考。很多人一开始会纠结到底是该直接用Coze这类平台拖拉拽还是应该用LangChain/LlamaIndex自己搭框架。我的建议是把两条路都走一遍先用低代码平台把“教学逻辑”验证跑通再用手写代码的方式把业务彻底落地。这篇文章讲的是后者也就是更偏向“大模型应用开发工程师”视角的完整实现路径——从架构设计到模型选型从Prompt工程到工具MCP接入从长期记忆到评测调优我会尽量按我做的时候的顺序来写。1. 整体架构设计与核心拆解1.1 为什么要把Agent拆成四层这个英语情景教学Agent的核心任务很简单用户在任意场景下比如机场问路、餐厅点餐、商务会议开场白用英语和Agent进行自由对话Agent负责扮演场景中的角色如机场工作人员、餐厅服务员、客户并在对话中穿插纠错、提示和知识点讲解。需求听起来不复杂但真正落地时遇到的问题却很现实对话上下文怎么管理、知识点从哪来、学生说错时该怎么纠错才不会打击积极性、多轮对话怎么记住上次的学习进度。这些问题如果全塞在一个系统Prompt里Agent的推理质量会迅速崩溃。所以我最终把系统拆成了四层Retrieval层知识检索层负责从课程知识库、词汇表、语法规则库中检索候选内容。对话管理层维护会话状态、学生画像、上下文窗口。Agent调度层决定当前轮是否需要调工具、是否需要检索知识、是否需要切换角色。技能层封装具体工具比如单词查询、发音评估、句子改写、情景模板加载。这样拆的核心原因在于Agent的每一步推理都可以被记录、被回放、被测试。如果哪一轮回答质量不好我能很快定位是检索出的知识不对还是模型Prompt引导出了问题还是工具返回了脏数据。单体Agent虽然好写但出了问题像在黑洞里捞针几乎没法排查。1.2 Agent怎么想、怎么动手在开发这个项目之前我对“Agent”的理解是停留在概念层的Agent就是能自己调用工具、自己决定下一步做什么的AI。但真正自己实现一遍之后我的体感是——Agent其实就是“一个会思考的循环”学术一点叫ReActReasoning Acting大白话讲就是Think想一想看当前对话和记忆决定下一步要干什么。Act动一动如果判断需要查单词、要加载情景模板就调用一次工具。Observe看一看看工具返回了什么结果结合结果生成回答。重复以上三步直到完成这轮教学任务。我在项目里用LangChain的create_react_agent来搭这个循环模型用的是支持Function Calling的GLM-4-Flash和gpt-4o-mini下文有完整的选型对比。核心代码骨架像这样from langchain.agents import create_react_agent, AgentExecutor from langchain_community.chat_models import ChatZhipuAI from langchain.tools import Tool llm ChatZhipuAI( modelglm-4-flash, api_keyos.getenv(ZHIPU_API_KEY), temperature0.7 ) tools [ Tool(namelookup_word, funclookup_word_func), Tool(nameload_scene_template, funcload_scene_template_func), Tool(nameevaluate_pronunciation, funcevaluate_pronunciation_func) ] agent create_react_agent(llm, tools, system_promptSYSTEM_PROMPT) agent_executor AgentExecutor(agentagent, toolstools, verboseTrue, handle_parsing_errorsTrue)那会儿我第一次跑通这个循环的时候特别兴奋但很快发现一个问题Agent在情景对话中会被“带跑偏”。比如学生扮演在机场迷路的旅客问了一句“Can I smoke here?”Agent马上开始讨论吸烟政策而不是把对话拉回“问路”的主题。原因是模型在生成下一轮Action时没有严格的“任务边界”意识。1.3 先想清楚约束边界再动手这是我在做这个项目时学到的非常重要的一课Agent不是越自由越好边界不清直接导致教学失控。我给Agent加了两条硬约束写进了系统Prompt里任何情况下当前情景未结束时不得主动偏离场景主题超过两轮。英文对话中穿插的中文讲解不得超过全文的30%纠错信息必须放在英文回答之后的“小贴士”区。这些约束在低代码平台里可能通过“工作流节点”实现但在代码Agent里靠的就是Prompt里的强指令加上评测集中对应的测试用例。后面我会在评测模块详细说怎么测这些约束是否真正生效了。2. 底层模型选型与提示词工程2.1 模型选型背后的取舍逻辑做英语教学Agent模型选型有几个特殊要求英文对话要自然流畅、能理解中文指令但输出以英文为主、需要支持Function Calling、响应延迟要低、成本不能太高。我对比了三个候选路线模型优点缺点我的选择理由gpt-4o-mini英文表达最自然Function Calling稳定海外API调用延迟偏高成本稍高主力对话模型负责最终回答生成GLM-4-Flash国内调用延迟低免费额度大复杂指令跟随偶尔不稳定负责工具调用、意图识别、小任务处理本地小模型数据可控、延迟最低英文教学质量不够评测分数明显偏低暂不作为生产方案这里有个关键点同一个项目中可以多个模型各司其职。我不会让一个模型既做意图识别又做知识点讲解而是让GLM-4-Flash这类轻量模型先把“下一步该干嘛”判断出来再让gpt-4o-mini负责真正对用户开口的英文对话。这个做法有点像公司里前台先问清楚你来办什么事再让对应的业务同事来对接——各干各的活整体效率最高。实际测试下来这种“双模型”方案的意图识别准确率基本稳定在92%以上英文回答的语法错误率比单模型下降了约40%。2.2 情景模板、限定性提示词与少样本示例Prompt不是写一段话就行而是要按场景、按功能拆成模块。我把教学Agent的Prompt拆成了三块。第一块是系统总纲管Agent的身份和铁律你是Emma一位有10年经验的英语情景对话教练。 你擅长在真实的场景中引导学生开口说英语。 铁律 1. 始终以英文为主中文只允许出现在“小贴士”部分。 2. 学生犯错时不要在对话中途打断等一个话轮结束后再统一纠正。 3. 纠错时先肯定再示范正确表达最后给一个类似场景的再次练习机会。 4. 如果学生长时间不说英文你可以用温和的提醒拉回。第二块是情景模板每个场景单独一个模板存成JSON动态加载{ scene_id: airport_ask_route, scene_name: 机场问路, roles: { agent: 机场信息台工作人员, user: 一位刚到美国的中国旅客 }, goals: [ 帮助学生完成一次完整的问路对话, 练到至少5个与方向相关的表达 ], key_expressions: [ How do I get to...?, Which terminal...?, Is it far from here? ] }第三块是少样本示例也就是Few-shot Examples。这是我调了七八版Prompt之后才确定的重点。大模型确实能理解“要纠错”这句话但它不知道纠错的语气、程度和呈现方式。所以我在Prompt里硬塞了两组对话示例一组是“学生说得基本正确但不够自然”的场景Agent应该怎么肯定和优化。一组是“学生语法错误明显”的场景Agent应该怎么纠错并给出对比。这两组示例对回答质量的影响巨大。没有示例时Agent经常把纠错写成一长段语法分析读起来像AI批改作业而不是真人陪练加了示例之后输出风格立刻接近“教练在陪练中自然点拨”的感觉。2.3 安全护栏与低风险设计英语教学Agent看起来是一个低风险场景但实际做的时候还是发现了几个必须提前堵上的口子学生可能会故意问一些和英语学习无关的敏感问题。学生可能会在对话中要求Agent“忘掉之前的规则”。学生可能出现情绪化表达比如“I hate this”, “This is stupid”。这些情况如果Agent不加辨别地回应轻则教学失控重则有合规风险。我的做法是在Agent调度层的系统Prompt里加了一条“安全退出机制”如果学生连续两轮表达负面情绪或者主动要求终止对话 请先温和确认学生状态然后建议切换到更简单的情景或结束本次练习。 不要评价学生的性格不要与学生争论。同时在工具层也做了限制发音评估工具只接收纯英文文本如果检测到非英文内容工具直接返回“输入无效”而不是尝试翻译。这个安全设计虽然简单但在实际部署中非常管用。3. 从框架选型到MCP工具落地3.1 主流Agent框架怎么选做Agent开发绕不开框架选型。我同步对比了LangChain、Coze低代码、MetaGPT多Agent和自研Agent框架四条路线。LangChain的优势是生态成熟、文档多、和LangSmith配合调试方便适合我这种需要深度定制的场景。Coze适合快速验证原型但流程编排复杂时反而不如写代码灵活而且平台锁定问题比较明显。MetaGPT这种多Agent框架适合“多个角色协作产出文档”的场景比如自动写PRD、自动写代码但用在实时英语口语对话上太重了多Agent的调度延迟会直接拖垮对话体验。自研框架最灵活但耗时最长我并不建议从零手写Agent内核除非你在做学术研究或深度定制。最终我的选择是“LangChain作为主框架 部分ReAct循环手写 MCP作为工具接入标准”开发效率和后续灵活性的平衡点最好。3.2 测试时计算Test-time Compute与Agent循环控制这个词最近很火但很多人只停留在概念层面。我实际在做的时候体会是Agent和普通单轮Prompt的最大区别就在于“测试时计算”——模型生成最终回答之前多走了几步检索、调用工具、观察结果。我一开始犯的错误是Agent只要看到工具结果就直接生成回答。如果工具返回的内容和模型预期不一致模型会硬着头皮把工具结果编进回答里产生幻觉。后来我加了一个机制工具返回结果必须经过一次“相关性过滤”用相关度判断来决定“是否采纳这条工具结果”。相关度低于阈值时模型会放弃该工具结果改用知识库里的默认内容或者直接如实告诉学生“这些信息我不确定”。这个设计大大降低了工具调用造成的幻觉问题。在实测中加了过滤机制之后Agent回答中出现“虚构航班信息”“编造机场名称”的情况基本清零了。3.3 MCP工具开发实操MCPModel Context Protocol其实是Agent工具的标准协议相当于给Agent配了统一的“USB接口”。在这个项目里我开发了3个核心工具lookup_word查单词释义、音标、例句返回结构化JSON。load_scene_template按场景ID加载情景模板如果没有目标场景就返回默认场景。evaluate_pronunciation接收用户的英文文本做发音/流畅度评估。MCP工具的开发模式很固定定义一个输入Schema实现处理函数然后注册。关键是工具的描述信息description一定要写清楚“什么时候该调用这个工具”。这一点新手特别容易忽略——工具描述写得模棱两可模型就会在错误的时机调用工具。我举个实际例子。最开始我把evaluate_pronunciation这个工具的描述写成了Evaluate user pronunciation.这个描述太模糊导致Agent在任何一轮对话中都有可能调用它连学生说一句“Hello”都触发一次评估把对话节奏切割得稀碎。后来我改成Call this tool ONLY after the user has finished a full sentence or a complete utterance, and you need to provide pronunciation feedback. Do NOT call this tool for short confirmations like OK or Yes.改完之后工具调用准确率肉眼可见地提升。所以工具描述不是写给测试人员看的是写给模型看的——用词要极其明确要告诉模型“什么时候用”“什么时候绝对不要用”。工具返回的数据也不要直接塞给模型就完事要设计好结构。我的返回格式统一是{ status: success, data: { word: terminal, definition: a building at an airport where passengers arrive and leave, example: Please proceed to terminal B., tips: [注意重音在第一个音节] } }统一结构的好处是模型在处理不同工具的返回时模式一致不容易乱。4. 长期记忆与用户画像4.1 分层记忆短期、中期、长期分开管英语教学和闲聊不一样学生上次学到哪、哪个单词已经掌握了、哪类语法错误反复出现——这些信息必须跨会话保留。但如果全塞进上下文字段里窗口很快就被撑爆而且无关历史会干扰模型对当前状态的判断。我采用的是三层记忆体系短期记忆当前会话内的最近10轮对话存在Redis里过期时间30分钟。中期记忆当前学习单元的进度比如“正在进行机场问路场景的第2小节”存在MySQL里。长期记忆用户画像包括掌握词汇表、高频错误类型、学习偏好和情绪反馈记录。短期记忆解决的是对话连贯性中期记忆解决的是学习进度长期记忆解决的是个性化。这三层每层各管各的更新时机也不一样——短期每轮更新中期每次切换场景时更新长期在会话结束后异步更新。4.2 向量检索在记忆召回中的应用长期记忆我用向量库Chroma来存。理由很简单——用户画像不是一条条的结构化字段能描述清楚的“这个学生上次在餐厅点餐场景中对‘rare/medium/well-done’的理解卡了很久”这类信息用向量存最自然。需要召回时我用相似度检索把最相关的那几条历史记录取出来跟当前对话拼在一起喂给模型。初始阶段我没有刻意选重型向量库Chroma这种轻量的就够了。如果数据量过万条再考虑迁移到Milvus或Qdrant。对个人开发者和中小团队来说前期尽量不要在基础设施上花太多时间等业务跑通再升级不迟。4.3 记忆更新的触发时机和防污染机制记忆系统最容易出问题的地方不在于存储而在于“什么时候该写入”。我刚开始时是每轮对话结束后都把整段对话塞进长期记忆很快就发现记忆库里全是噪音——学生随口说的一句“Let me think”也被当作长期特征存下来了。后来我改为“事件驱动”的写入机制只有当如下事件发生时才触发长期记忆更新学生掌握了一个新单词由工具检测到置信度大于阈值。学生同一语法错误出现3次以上。学生主动表达对某个场景的喜好或厌恶。一次教学会话正常结束。这样长期记忆库里的数据质量干净了很多。还有一个坑是“记忆污染”——如果学生在某次对话中乱说一气这些行为被写进长期画像后面Agent会拿这些错误信息去调整教学策略越调越偏。我加了一个简单的校验任何写长期记忆的数据必须经过“是否与当前教学场景一致”的过滤不一致的直接丢弃。宁可记忆少一些也不让错误记忆长期影响用户体验。5. 多Agent协作与评测调优5.1 角色解耦Tutor、Retriever、Critic在项目开发过程中我发现单Agent很难同时做好三件事陪学生聊天、查知识点、评价学生表现。后来我参考多Agent的思路把系统拆成了三个角色English Tutor Agent主对话Agent负责和学生对话引导情景练习。Retriever Agent检索Agent负责从知识库、记忆库中找内容不直接面对学生。Critic Agent评估Agent在后台默默观察每一轮对话对学生的输出做语法、发音、流利度评估生成学习报告。这里的重点是“主对话Agent”和“评估Agent”的分离。如果让同一个模型既陪聊又打分模型很可能为了让学生开心而虚报分数。分拆之后Critic Agent的评估结果会写入中期记忆Tutor在下一轮可以有意设计练习来巩固薄弱点。这个“教师-评估者分离”的思路非常值得做教育类Agent的朋友参考。5.2 评测集构建怎么判断Agent变好了还是变坏了Agent开发最头痛的问题就是“怎么评测”。单轮Prompt可以用蓝V和人工标注但Agent是多轮交互评价维度大不一样。我建了一套自己的评测方式准备30个教学会话场景覆盖9个情景、不同英语水平。每个场景都标注了“教学目标句”和“该场景中应该出现的工具调用”。每次改动Prompt或工具后自动化跑一轮评测记录四个指标目标句命中率、角色保持率、纠错准确率、超出场景率。我建了一个简单的评测脚本跑完自动输出对比表格。这已经成了我的标配动作。没有评测一切调优都是凭感觉。指标说明目标值目标句命中率对话中是否出现目标表达≥80%角色保持率对话是否始终维持在场景内≥90%纠错准确率纠错内容是否语法正确、时机合适≥85%超出场景率话题偏离场景的比例≤10%我强烈建议每个Agent项目都建这样的评测集即使一开始只有10个用例也远胜于没有。因为它让Agent开发从“玄学”变成了可以量化、可以回归的工程。5.3 Prompt迭代时如何防止“按下葫芦浮起瓢”这是我在调优过程中最痛的领悟改一个Prompt可能让目标句命中率提升了5个点但同时“超出场景率”从6%涨到了15%。后来我养成了一个习惯——每次只改一个变量并且只改完就立刻跑全套评测集。宁可一天只迭代三版Prompt也不要一天改二十处结果最后都不知道是哪处起的效果。在做回归评测时我会对比改版前后的所有指标特别关注是否有指标大幅回退超过2个点就要警觉。这个“单变量迭代”的方法论适用于所有Agent类项目不只是在英语教学场景。6. 常见问题与排查实录6.1 工具调用时报错的处理方法开发过程中我遇到过最磨人的问题就是“agent execution terminated due to error”经常是工具调用环节直接让整个链路崩掉。排查了很久之后我发现罪魁祸首往往不是工具本身而是工具的入参校验没做好。模型有时会生成不符合工具Schema的参数比如一个需要scene_id的工具模型传了一个包含中文逗号的JSON。LangChain默认在JSON解析失败时会重试但重试几次后仍然失败就直接终止了。我用的解决方法是给所有工具函数加上一层宽松的入参处理def load_scene_template(scene_id: str default): scene_id scene_id.strip().strip().strip() ...同时把handle_parsing_errors设为True并配置了一个“错误时的兜底回复”让Agent在工具调用失败时输出一句“我暂时没法获取这个场景的详细资料我们可以继续即兴练习”。这样即使工具出错对话也不会中断。6.2 Agent进入死循环怎么办另一个高频坑是Agent反复调用同一个工具不往前走。比如知识库里明明没有某个单词Agent还是会一遍遍调用lookup_word浪费Token也让响应变慢。LangChain的ReAct Agent本身会限制最大迭代轮次我设置的是5步超过就强制输出当前内容。更稳妥的做法是在工具描述里明确写清楚“查不到就返回NOT_FOUND不要重试”。一个标准的工具返回值长这样{ status: not_found, data: null, message: This word is not in the current vocabulary database. }这样模型看到NOT_FOUND之后会自然转入“换一种方式教学”而不是执着于把同一个工具再调一次。这个问题在Agent开发中非常典型值得留意。6.3 学生水平差异大Agent怎么自适应不同用户的英语基础差距很大。同一个机场问路场景对初学者要从“Hello, I need help”开始教对进阶用户可以要求“尽量用间接问句例如Could you tell me how to get to...?”。这本质上又是一个自适应策略的问题。我目前的方案是根据用户画像里的“CEFR级别预估”A1-C2和“最近3次会话的错误率均值”动态调整情景模板里的难度等级。具体实现是在情景模板里给同一场景配了三个难度版本简单版只要求单句问答标准版要求完成完整对话挑战版要求使用特定语法结构和委婉表达。Agent根据记忆层输出的用户当前水平动态选择加载哪个版本。这个机制上线后用户的留存率和练习完成度都有了明显提升。因为学生感受到的是“Agent在顺着我的水平往上推”而不是“一个固定流程的机器在走流程”。6.4 实操中遇到的最隐蔽的三个坑如果说上面那些问题属于“看文档能解决”的下面这三个坑则是真正的经验型知识第一多轮对话中的字面重复。Agent偶尔会原封不动地把用户的句子改个标点又返回去看起来像在复读。原因是模型在上下文较长时倾向于“安全地复述”而不是“积极地推进”。我通过降低temperature到0.7并加入“每一轮都要新增至少一个信息点或一个引导问题”这条约束缓解了这个问题。第二小贴士里出现中英混杂。我本来设计“小贴士”是中文讲解部分但模型偶尔会输出“这个单词的意思是‘航站楼’you can use it like this”。我又不想彻底禁止英文因为对稍高阶段的学生“中英混合的讲解”反而更自然。最后的方案是提示词里明确“小贴士中中文占比不低于60%”从比例上保证了定位。第三记忆串人。多用户并发时如果不小心把用户A的长期记忆带入了用户B的会话教学效果会直接崩掉。我在所有记忆读写操作里都强制带user_id作为隔离维度测试时也专门写了并发用例来验证。这个错误出现一次就够让人刻骨铭心了必须从架构上杜绝。7. 一些想留给后来者的建议这个项目做到现在最大的体会是Agent开发真正的门槛不在“能不能调通”而在“能不能稳定地、可控地、可度量地完成业务目标”。英语教学Agent更是如此——你说错了要纠说得对要鼓励跑偏了要拉回来练完了还要记住下次接着练。这背后没有一项是单纯靠“模型强大”就能搞定的全是工程和设计的功夫。如果你也想动手做一个类似的Agent我给你三条非常实在的建议先把场景收敛到极窄的范围比如只做“机场问路”一个情景把一个场景打磨到令人满意的程度再横向扩到10个场景绝对不要一上来就铺20个场景。从第一天就建评测集哪怕只有10个用例也比没有强。工具MCP类技能优先做查询类工具能解决Agent一半以上的幻觉问题。英语只是这个框架的一个使用场景。换一个行业比如售前咨询、健康陪护、法律科普底层这套“Agent框架记忆分层工具接入评测回归”的套路是完全通用的。我已经用它拓展了第二个项目后续有机会再单独写一篇聊聊。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑