很多做AI应用的朋友都问过我一个特别实际的问题想做一个“能陪人对话、能指点学习”的Agent应该从哪儿下手我的答案通常是一句话——找一个足够具体的场景先把它做透。这篇文章里我就用“英语情景教学Agent”这个例子完整拆一遍我是怎么从零到一把它做出来的场景怎么拆、Agent怎么设计、提示词怎么写、记忆怎么管、多Agent怎么协作以及一路上踩过的那些坑。如果你是个想上手Agent开发的应用工程师或者想给自己的英语学习工具加一个智能陪练模块这篇应该能帮你省掉不少弯路。我最初的想法并不复杂。市面上背单词App一抓一大把但真正能“开口说”的场景练习很少。很多人背了十几年单词到了机场值机柜台、酒店前台、面试现场还是张不开嘴。原因是传统学习里缺乏一个关键要素——低心理压力的真实情景陪练。与其做一个什么都聊的“大而全”聊天机器人不如做一个只解决“情景口语练习”这件事的教学Agent。这个定位一旦清晰后面的技术选型、架构设计、评估标准就都有了依据。1. 项目概述与整体设计1.1 需求拆解这个Agent到底解决什么问题我从头梳理了一下用户的需求最终提炼出四类核心角色英语基础薄弱的初学者、想备战各类口语考试的人、即将出国需要生活口语的人以及只想找个“不尴尬”陪练的成年人。他们共同的问题不是词汇量不够而是缺乏真实对话场景和即时反馈。场景教学中最重要的不是让Agent像老师一样长篇大论解释语法而是让它像“搭戏的对手演员”一样把用户带入一个具体情境鼓励用户开口并给出温和但精确的纠错。所以我把Agent定位为“情景搭戏伙伴 幕后私教”的双层结构。对话进行时它负责扮演角色比如机场地勤、餐厅服务员、外企面试官不做过多纠错保持对话自然流畅对话结束后它切换成教练模式从语法、词汇、流利度、任务完成度四个维度给反馈。这样分层的好处很明显用户在对话中不会被频繁打断心理压力小纠错集中在演练结束后学习路径清晰。1.2 MVP功能范围与用户路径第一版我没打算做语音识别、虚拟形象这些花哨功能MVP只保留一条最核心的主链路用户选择情景 → Agent扮演角色开场 → 多轮自由对话 → 用户主动结束或到达预设轮次 → 生成表现评估报告 → 对话记录存入记忆库下次能接着练。这个流程走通之后后续再扩展语音输入输出、生词本、学习计划等功能都有明确挂载点。我特别想提醒一点做Agent最怕什么都想塞第一版贪多往往连主链路都做不稳。先用文本把逻辑跑顺再叠加多模态成本低、效果好。2. 技术选型与架构设计2.1 框架选型别一上来就上重型框架开发Agent的第一步就是选“车”。市面上Agent框架不少各有各的定位。我评估过几条路直接用大模型API裸写上手快、可控性强适合MVP用LangChain、LlamaIndex这类通用框架内置了很多组件但抽象层级较多出了问题不好排查用偏重型的多Agent编排框架功能强大但学习曲线和部署复杂度都高。我最后选择的是“裸写核心 轻量自研编排”。理由很朴实情景教学Agent的主流程其实就是一个状态机角色扮演、评估、记忆整理是三个相对独立的阶段完全没有必要为一个中等复杂度的应用引入几十个依赖。自己写不到两百行就能把编排理清楚后续想换模型、换评估策略都很灵活。2.2 模型选择与成本权衡模型选择上我把Agent里的任务分成两类一类是“对话生成”需要自然、稳定、角色感强我选择效果最好的通用模型来扛另一类是“结构化评估”和“记忆摘要”对生成创意要求不高但对格式稳定性要求高这部分我用了更便宜的轻量模型实测效果完全够用。两张表格说明我的取舍逻辑任务类型模型定位选择要点典型候选角色对话主力大模型角色扮演稳定性强、回复口语化通用旗舰/中端模型评估打分轻量模型JSON输出稳定、推理快各家轻量版本记忆摘要轻量模型长文本压缩能力强各家轻量版本优先保证核心对话体验用最好的模型评估和摘要用性价比更高的模型整体API成本能下降一半以上。2.3 系统架构四个模块 一条流水线整个系统我拆成了四个模块情景库写好的剧本数据、对话引擎负责和用户来回聊天、评估模块对话结束后独立打分、记忆模块存放用户画像和历次对话摘要。四个模块之间不直接互相调用而是通过一条流水线顺序衔接。好消息是这套架构天然为后续引入多Agent协作留好了接口——每个模块都能单独替换成一个更独立的Agent。这里有一个容易被新手忽略的设计决策对话引擎和评估模块必须完全隔离。很多第一版Agent把“纠错”直接塞进对话里模型一边演角色一边挑毛病结果角色感全无对话变成了说教。我踩过这个坑后面会在常见问题里细说。3. 核心细节解析与实操要点3.1 情景库设计剧本写不好Agent再聪明也没用很多人以为Agent是万能的只要把系统提示词写清楚就行。实际上在垂直场景里花时间写“剧本”比调提示词更有效。我的情景库是一份JSON数据每个情景都包含场景标题、难度等级、适用人群、角色设定、剧情目标、开场白、可能会用到的核心词汇和表达以及三到五个“挑战点”比如机场改签场景里突然航班延误、餐厅场景里朋友对某种食材过敏。一个虚构但实用的情景结构示例{ id: airport_rebooking, title: 航班延误我要改签, level: intermediate, roles: { agent: 机场值机柜台工作人员礼貌、专业、语速适中, user: 旅客需要改签到最近一趟航班 }, objectives: [ 准确说出原航班号和目的地, 理解并比较两个可选的改签方案, 确认新登机时间和登机口 ], opener: Good morning. I see youre here about flight CA1837 to Shanghai. How can I help you?, challenge_hints: [ 明确表示第一选择起飞太早希望换晚一点的班次, 询问行李是否会自动转运, 确认是否需要额外付费 ], vocabulary: [rebooking, alternative flight, layover, boarding gate] }写情景库时有一条很重要的原则给模型“发挥空间”但不要给“自由发挥的考试题”。这里的区别在于挑战点用“话题”或“意图”描述而不是给完整对话稿。如果预设了逐字台词对话会变得很假两步之后用户说点什么剧本外的话Agent就僵住了。更聪明的做法是只给目标、角色和几个提示点让模型自行发挥。这样每场练习都有变化用户不会觉得是在背课文。3.2 提示词工程角色人设与对话约束怎么平衡情景教学Agent的提示词核心矛盾是“自然”和“教学目标”之间的平衡。如果系统提示词全是“必须纠错”“必须讲解”模型就会变成一个疯狂打断人的老师如果全是“自由对话”模型又会忘了自己的教学任务。我的解法是把约束拆成两层永久约束层和情景注入层。永久约束层写在系统提示词的最前面调节整个Agent的“人格”你是英语情景教学助手在对话阶段只能扮演角色不要打断用户、不要纠错、不要跳出角色解释语法除非用户直接询问。每次回复控制在两三句以内末尾可以自然地抛出一个问题推动对话继续。情景注入层则在每次请求时动态拼上当前剧本内容。我还加了两个小技巧。第一在系统提示词里明确告诉模型“如果你发现用户表达不准确先记住不用声张”。这解决了角色扮演中想做老师的问题。第二要求模型兜底处理“用户用中文回应”的情况——用户在练口语时偶尔词穷说中文此时Agent应该用自然的方式把中文转述成英文并继续对话而不是停下来批评。这样对话不中断学习目标也保住了。3.3 记忆与多轮状态管理不让上下文无限膨胀对话类Agent最经典的坑就是上下文越来越长长到最后不是慢就是贵模型还“忘了”前面的细节。我在这个项目里把记忆拆成了三层第一层是会话级短期记忆整个过程在同一个session上下文里进行记录完整的多轮对话这是工作记忆第二层是用户级长期记忆内容包括用户自称的英语水平、常犯的语法错误类型、练过的情景列表、上次的角色表现总结这是长期画像第三层是情景级记录每个剧本的完成次数和综合评分用于推荐和复习安排。对话进行时短期记忆承载全部上下文但在每轮对话之间我会把用户的上一轮内容做一次“即时摘要”压缩后拼进上下文这样既能保留关键信息又不会让上下文无限膨胀。每次情景练习结束后再用轻量模型把整段对话压缩成一段一百字以内的带错点标注的摘要存进长期画像。3.4 评估模块四维打分是怎么算出来的评估模块是整个Agent的“教学灵魂”如果评分不准用户练了三次就失去了信任。我设了四个维度语法准确性、词汇丰富度、流利度通过语气词数量、停顿次数、句子长度综合判断、内容完成度有没有完成情景目标。为了减少主观偏差我不会让模型只输出一个总分而是让评估模型先输出每个维度的具体观察再输出分数和修改建议。评估模块的返回结构长这样{ evaluations: [ { dimension: grammar, score: 7, observations: 两次使用过去时态出错分别是..., suggestions: 建议复习一般过去时与过去完成时的区别 } ], summary: 整体表现能完成基本沟通目标但过去时态不稳定..., review_expression: 建议下轮重点练习谈论过去经历时的时态选择 }为了让评估更稳定我在提示词里给评估模型准备了两个“范文级”的例子展示什么样的观察算具体、什么样的建议算可执行。这一步的性价比非常高比单纯调温度参数管用得多。4. 实操过程从零到一搭建可运行的最小版本4.1 环境准备与项目结构实操阶段我默认你是Python开发者至少会基本的API调用。环境上不需要额外搭建复杂服务一个Python 3.10环境装两个依赖包就够了。项目目录设计得尽量简洁english-scenario-agent/ ├── scenarios/ # 情景剧本JSON文件 ├── engine/ │ ├── teacher.py # 对话引擎角色扮演 │ ├── assessor.py # 评估模块 │ ├── memory.py # 记忆管理 │ └── pipeline.py # 流水线编排 ├── config.py # 模型配置 └── run.py # 入口这个结构的好处是边界清晰后续做多Agent升级时不需要重构只需要在每个模块内部换实现方式。4.2 对话引擎核心代码对话引擎做的事情不多接收用户输入从情景库取当前角色设定带上最近N轮的上下文摘要调用模型把模型回复返回给用户。关键在“动态上下文拼接”这一段# engine/teacher.py def build_messages(scenario, history, memory, user_input): system f你是{scenario[roles][agent]}。 你在英语情景教学中只负责角色扮演目标是引导用户开口完成{scenario[title]}。 规则 1. 不打断、不纠错、不跳出角色。 2. 每次回复不超过3句话末尾尽量抛出一个问题。 3. 如果用户说中文用英语自然复述其意图并继续对话。 4. 如果用户表示结束回复完成后停止。 情景目标{scenario[objectives]} 可能遇到的情节{scenario[challenge_hints]} user_content { role: user, content: [ f用户历史画像{memory[profile]}\n, f本次练习已发生对话{format_history(history)}\n, f用户刚才说{user_input} ] } return [ {role: system, content: system}, user_content ]这里有一个细节非常关键我把“用户历史画像”和“本轮已发生的对话”放在用户消息里而不是直接拼到系统提示词里。这样模型更容易把这部分当作“待处理的上下文”而不是让它固化行为角色扮演也更自然。实测下来这种少量effort的动态注入比都塞进system效果好不少。4.3 评估模块核心代码评估模块在对话结束之后调用输入整段对话输出结构化的评分结果。为了让模型稳定输出JSON我在提示词里给出了严格的输出格式说明和两个样例并设置response_format为JSON对象如果服务商支持的话。# engine/assessor.py ASSESS_PROMPT 你是英语教学评估专家。请根据下面这段师生对话对学生的英语表现进行评分。 评分维度grammar, vocabulary, fluency, completion。 每个维度输出0-10分并给出具体观察和一条可执行建议。 不要只写“很好”“需要加强”观察必须能对应到原文中的具体句子。 参考示例 维度grammar 分数6 观察在“I go to airport yesterday”中go的时态使用错误应为went。 建议复习一般过去时的规则动词变化。 以下是对话记录和评估要求 {transcript} 顺带说一个容易被忽视的点评估模型也会“睁眼说瞎话”尤其是当它发现用户水平比较差时可能会心软给高分。我后来在提示词末尾加了一句“你是一位严格但不刻薄的考官请基于客观语言能力打分不要因为用户态度好而放宽标准”效果立刻改善。4.4 完整跑通一次情景练习我用“机场改签”场景跑了一轮完整测试下面是节选片段。用户在对话中犯了好几个时态错误但对话过程的体验相当自然没有被打断Agent: Good morning. I see youre here about flight CA1837 to Shanghai. How can I help you?User: My flight is cancelled, I need arrange another flight.Agent: Of course, I understand. Theres another flight at 3 p.m. with one layover in Guangzhou. Would that work for you?User: Yes, but can I get a earlier one? I have a meeting tomorrow.Agent: Im afraid the earlier flight is fully booked. The 3 p.m. option is the earliest available. Shall I check the seat availability for you?User: Okay, please. And how about my luggage? Will it transfer automatically?Agent: Good question. Since the second flight is on the same ticket, your luggage will be transferred automatically. Could you confirm your contact number so I can update the booking?这个片段的质量我很满意。Agent不仅自然推进了情景还主动覆盖了“行李是否会转运”这个挑战点用户也不得不因为“meeting tomorrow”而思考时态安排。整个过程没有一句生硬的说教但用户的错误已经完整体现在对话记录里等待评估阶段被识别。4.5 性能与成本观测跑完一轮大约10轮的对话主力模型的tokens消耗在4000-5000左右评估模型消耗在600-800之间。如果完全不做记忆压缩第二轮对话会直接翻倍一个月练下来费用差距会很明显。所以我强烈建议在第一天就把记忆压缩模块做进去不要等上下文烧钱烧出感觉了再补。5. 多Agent协作与进阶扩展5.1 为什么单体Agent忙不过来当前MVP版本是一个编排函数依次调用模块但当我引入更多功能后发现单个Agent的“人设”很难在多个任务间切换。扮演机场地勤时说话的语调和扮演严厉考官时完全不同混在一个角色里模型总会在某个时刻跳戏。于是我把系统升级为四个分工明确的AgentSceneDirector负责选情景、管理节奏、DialogueActor负责角色扮演、Assessor负责评分反馈、MemoryCurator负责压缩记忆。它们之间不直接聊天而是通过一个标准化的消息协议传递数据。每个Agent有自己的提示词、自己的模型档位、自己的输出JSON格式。5.2 协作协议与执行顺序我定的协议非常简单每个Agent输入和输出都是统一的字典message { agent_id: dialogue_actor, task: continue_dialogue, payload: { scenario: scenario_id, history: [...], user_input: My flight is cancelled... }, request_id: a1b2c3 }每个Agent读取task字段决定自己该干什么输出后把结果写回总线下一个Agent从总线取所需数据。这套协议看起来简陋但它是多Agent协作的骨架。常见的多Agent翻车现场是Agent之间互相传递大段纯文本没有明确消息类型和协议最后谁也不知道该听谁的。协议先行Agent后写是我在多Agent项目里最重要的一条心得。执行顺序是这样的SceneDirector先加载剧本 → DialogueActor进入角色对话循环 → Assessor在对话结束后读取完整记录 → MemoryCurator最后做记忆归档。每个Agent都是无状态的状态全部存在于消息总线和记忆库中这让我能随意调整Agent的模型和提示词而不影响整体流程。5.3 什么时候该引入多Agent什么时候不该我在开发中总结出了一个判断标准如果单Agent的提示词超过600字或者同一个Agent需要在三种以上完全不同的语气/身份之间切换就该拆了。反之如果只是做一个问答机器人强行拆成多Agent只会徒增维护成本。在我这个项目里拆分的收益非常直接DialogueActor的回复变得更自然了因为它不再需要兼顾“考官”角色Assessor的评分也稳定了因为它的输出格式里不再有角色扮演的干扰。多Agent不是炫技它是为了解决“角色混乱”这个实际问题而存在的。6. 常见问题与调试实录6.1 Agent执行中途报错工具调用失败问题开发中我遇到过不止一次“Agent Execution Terminated Due To Error”这类报错。排查后发现多数情况出在模型返回了格式不合法JSON或者模型在尝试调用不存在的工具。我的排查套路是三步走第一步看是不是JSON解析失败给解析函数增加容错逻辑比如从乱串中提取最后一个完整JSON块第二步看是不是模型中途“以为自己在和另一个Agent对话”说明协议消息里有残留的无关字段第三步看是不是上下文截断导致关键指令丢失把上下文压缩模块的阈值调大。6.2 角色扮演时模型“忍不住说教”这个坑我前面提过但在实操里几乎人人都会踩。模型被告知要演机场地勤用户说完“I want eat something”之后Agent突然用老师的口吻说“这里应该是I want to eat something注意to不可省略”。对话体验瞬间就毁了。我的解决方案是双管齐下第一系统提示词里明确写“你在对话阶段不允许纠错可以把错误记在心里”把纠错延迟到评估阶段第二如果确实需要在对话中给出即时反馈我会单独用一个轻量“反馈Agent”在后台分析但只把轻提示返回给用户。对话和纠错是两个不同的Agent任务这句话值得贴在工位上。6.3 用户说中文场景的处理很多用户会在对话中途卡壳突然说中文。一开始我的Agent会直接报中文翻译把情景对话变成翻译课。后来我在系统提示词里加了一条规则当用户说中文时Agent先用英文自然复述用户意图再以角色身份继续推进对话。比如用户说“我的行李会自己到吗”Agent会回复“Youre asking whether your luggage will go straight through. Yes, it will, since both flights are on the same ticket. Shall I confirm your contact number?”这样既照顾了用户卡壳又不脱离情景。实测这个规则的接受度非常高。6.4 评分不准的终极解法样例校准评估模型给分不稳定是最影响信任的问题。我从三个方向做了修正在提示词里引入两到三个不同水平的对话样例让它学会“按锚点打分”多模型并行评分取中位数作为最终分数成本增加但稳定性提升明显定期用人工高分样本微调“评分标准提示词”而不是微调模型权重。这三种方法组合使用后评分和人工评分的一致性提高了很多。6.5 调试技巧给Agent加“行车记录仪”给Agent开发加日志不是可选项是保命项。我在每次请求时都生成一个request_id把完整的prompt、模型返回、token消耗、耗时全部记录到日志文件里。出问题时只要按request_id查日志几秒钟就能定位是提示词问题、模型问题还是数据处理问题。我还写了几组自动化回归用例把典型对话固化下来每次改完提示词跑一遍防止老问题复发。写在最后的小体会这个“英语情景教学Agent”从想法到跑通大概花了两周业余时间。我个人最大的体会是Agent开发和传统后端开发有本质区别传统后端追求确定性Agent必须接受不确定性。你无法让模型百分之百按剧本走但你可以用清晰的情景库、严格的输出协议和稳定的编排流程把不确定性收敛到一个可控范围内。做Agent就像带演员拍戏剧本、场景、角色要备好但真正开拍之后你要接受演员的即兴发挥同时在片场盯着监视器随时准备喊cut。最后给你一个实操建议如果现在想动手做类似的东西先别急着上语音、上虚拟形象、上双Agent。挑一个你自己最熟悉的生活场景把文本对话、四维评分、记忆归档这三个环节跑通把它变成一个每天都能用起来的学习工具。然后在用的过程中不断打磨提示词和剧本逐步再往多模态、多Agent扩。先跑通再优化这句话送给所有跟我一样喜欢边做边学的开发者。