恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
[对比学习LangChain和MAF-14]使用消息注入改变对话历史
首页
资讯中心
/
[对比学习LangChain和MAF-14]使用消息注入改变对话历史
[对比学习LangChain和MAF-14]使用消息注入改变对话历史
发布时间:2026/10/15 3:05:09
对话历史作为核心的上下文信息为LLM建立起对话的语境是决定LLM响应内容的关键输入之一。对话历史中的每一条消息都绑定这一个固定的角色典型的角色包括System、User、Assistant和Tool。但是这并不意味着每条消息一定要求都要由对应的角色生成为了提供LLM推理的质量用户和工具都能根据需求向对话历史注入消息而且这些消息可以具有任意的角色前提是消息的结构符合要求。1. 为什么需要消息注入对于采用ReAct循环构建的Agent来说如果不使用Session/Thread如下的流程体现了对话历史常规的构建模式最终作为对话历史的消息列表为空用户调用Agent的请求被转换成一条User消息被添加到消息列表中Agent调用也可以同时指定System消息整个对话历史作为输入的一部分提交给LLM后者创建一个Assistant消息作为响应被添加到消息列表中如果回复的Assistant消息携带工具调用Agent会调用对应的工具并将每个工具调用生成的结果封装成一个Tool消息被添加到消息列表中整个整个对话历史作为输入的一部分在此提交给LLM后者基于新的对话历史生成新的Assistant消息作为响应被添加到消息列表中以此类推形成一个循环。如果进一步采用Session/Thread隶属同一Session的所有消息将会添加到同一个对话历史中对话历史构建的语境是Agent与LLM进行多轮对话的基础因为LLM调用是完全无状态的。在这个典型的ReAct循环中消息的角色完全与消息的来源是完全一致的的User和System消息由用户输入生成Assistant消息由LLM生成Tool消息由工具调用生成System消息由Agent调用时指定生成。但这并非硬性规定对话历史仅仅是提供给LLM的上下文信息而已为了让LLM的响应更符合预期不仅用户在调用Agent时可以输入一组具有任意角色的消息来模拟一段对话工具调用也能够在必需的Tool消息之后注入任意的具有有效结构的多条消息。这本质上也是一种典型的提示词工程的手段典型的应用场景包括1.1 复杂工具调用的少样本示范当工具的参数极其复杂如需要传入特定的JSON结构或SQL 语句或者需要多工具组合调用时仅靠系统提示词的文字说明模型很容易出错。此时可以人工编造1-2轮用户提问 ➔ 模型思考 ➔ 工具返回数据 ➔ 模型最终回答的完整历史比如复杂数据库查询构建一段历史展示用户查询“上季度销售额前三的员工”模型调用execute_sql工具工具返回一串复杂的JSON数组模型再将其翻译成话术。让LLM学会如何正确处理工具返回的结构化数据多接口级联调用编造一段历史演示模型先调用get_user_id拿到ID后再自动调用get_user_order的过程。模型看到这段历史就知道自己也可以连续触发工具。1.2 引导模型进行反思与纠错的预热如果想让Agent具备极强的抗挫折能力即工具报错时不要懵掉而是自动换个参数重试最好的方式就是喂给它一段失败成功史比如API权限/参数错误处理历史中用户让Agent “查一下明天的天气”。模型第一次调用工具传入了旧版参数Tool消息返回{error: Invalid date format, use YYYY-MM-DD}。接着构建模型在历史中自我纠错哦格式错了我需要重新调用并传入正确参数代码执行器纠错在CodeAct场景中预先注入一段代码运行抛出IndexError的历史以及模型随后如何修改索引并重新运行成功的历史。这样模型在实际遇到报错时会模仿历史中的自己去修复Bug。1.3 规范模型的思考链与内部对白在Agent中我们希望模型在调用工具前先写下思考过程但模型经常会忘记写或者写得很敷衍。此时我们可以构建一段包含高度结构化Assistant思考格式和Tool交互的历史。比如在一个要求极度严谨的财务/医疗推理的Agent中构建一段历史展现模型在收到用户指令后先在思考Thought中拆解了三个步骤然后调用ToolA收到结果后又写了一段对思考的修正计划再调用ToolB。这相当于给模型立了一个严谨工作的榜样迫使它在当下的推理中也采用这种深思熟虑的模式。1.4 模拟历史场景进行情景剧重现有时候我们需要Agent在一个特定的、预设的业务进度中清醒过来并继续工作而不是从零开始聊天。此时需要生成一段多轮对话和工具调用记录作为该任务的前情提要。比如断点续传/任务接管一个复杂的自动化分析任务执行到一半中断了。系统在重启任务时把之前已经发生的对话、已经调用过的工具和拿到的数据全部打包成一段“历史”喂给新的LLM实例。LLM看到这段构建的历史就能立刻无缝接管上一个实例的工作进度反欺诈/安全演练沙箱为了测试或训练某个防御性 Agent系统故意构建一段“黑客User正在尝试通过钓鱼工具Tool套取信息”的历史然后让Agent接手最后一轮看它是否能识别出风险并拒绝。1.5 冷启动与复杂状态初始化在用户刚打开软件还没开始真正聊天时系统为了给模型注入一些心智背景或前置技能会在首轮对话前注入几条用户和工具的互动线索。比如在一个作为私人助理Agent初始化时构建几条伪造的记录。虽然用户没说过这话但LLM读到这段历史后接下来的所有回复都会自动遵循极简风的设定。User导入我的个人喜好Tool该用户喜欢极简风、讨厌长篇大论。由于Agent调用自身就支持针对消息列表的输出所有我们主要关注工具调用后注入消息的场景接下来我们通过一个简单的例子演示一下基于工具调用的消息注入在MAF和LangChain中该如何实现。2. 在MAF中利用MessageInjectingChatClient注入消息在MAF中我们需要利用MessageInjectingChatClient这个ChatClient中间件向对话历史注入消息。在如下的演示程序中我们创建了一个ChatClientAgent并在构建时通过UseMessageInjection方法引入了MessageInjectingChatClient中间件。用户返回指定城市天气信息的工具函数GetWeather模拟了一个工具调用我们可以返回了不太真实的极端天气信息。usingMicrosoft.Agents.AI;usingMicrosoft.Agents.AI.Workflows;usingMicrosoft.Extensions.AI;usingOpenAI;usingSystem.ClientModel;usingSystem.ComponentModel;dotenv.net.DotEnv.Load();varendpointEnvironment.GetEnvironmentVariable(OPENAI_URL)!;varmodelEnvironment.GetEnvironmentVariable(MODEL)!;varapiKeyEnvironment.GetEnvironmentVariable(API_KEY)!;varagentnewOpenAIClient(newApiKeyCredential(apiKey),newOpenAIClientOptions{EndpointnewUri(endpoint)}).GetChatClient(model).AsIChatClient().AsBuilder().UseMessageInjection().Build().AsAIAgent(tools:[AIFunctionFactory.Create(GetWeather,nameof(GetWeather))]);varsessionawaitagent.CreateSessionAsync();varresonsenseawaitagent.RunAsync(message:根据苏州目前天气提供一些着装建议,session:session);Console.WriteLine(resonsense);[Description(获取天气信息)]staticstringGetWeather([Description(城市)]stringcity){varsessionAIAgent.CurrentRunContext?.Session??thrownewInvalidOperationException(No active session found.);varinjector(AIAgent.CurrentRunContext?.AgentasChatClientAgent)!.ChatClient.GetServiceMessageInjectingChatClient()??thrownewInvalidOperationException(MessageInjectingChatClient is not registered.);varreasoningnewChatMessage(ChatRole.Assistant,[newTextReasoningContent(返回极端天气真实度存疑谨慎使用)]);injector.EnqueueMessages(session,[reasoning]);return${city}当前天气晴朗温度55摄氏度;}然会让LLM在推理的时候考虑到提供的天气信息是极端且不太真实的我们利用注册的MessageInjectingChatClient注入了一条Assistant消息提供的TextReasoningContent类型的内容模拟了LLM自身的一次推理。添加了这条推理消息换来的LLM消息内容的最后一条批注55°C的温度数据似乎有些异常请确认是否为实际温度。如果是数据有误可以提供更准确的天气信息我可以重新给出建议。。我先查询一下苏州当前的天气情况 根据查询结果苏州目前天气晴朗温度高达 **55°C**这属于极端高温天气。以下是着装建议 --- ## 极端高温着装建议 ### 上衣 - **轻薄透气**的短袖T恤、背心或吊带衫 - 选择浅色系白色、浅灰、浅蓝等减少吸热 - 优选棉麻、冰丝、速干面料 ### 下装 - 短裤、短裙、阔腿裤 - 同样以浅色、透气材质为主 ### 鞋履 - 透气网面运动鞋或凉鞋 - 避免厚重密闭的鞋款 ### 配饰防护必备 - **宽檐遮阳帽**或空顶帽 - ️ **太阳镜**保护眼睛 - ☂️ **遮阳伞**必不可少 - **高倍数防晒霜**定时补涂 ### ⚠️ 重要提醒 55°C属于极端高温**尽量减少户外活动**避免在正午时段11:00-15:00外出。多饮水注意防暑降温如出现头晕、恶心等症状及时到阴凉处休息或就医。 --- *注55°C的温度数据似乎有些异常请确认是否为实际温度。如果是数据有误可以提供更准确的天气信息我可以重新给出建议。*关于MessageInjectingChatClient的设计与实现可以参阅我的文章“MessageInjectingChatClient赋予工具消息注入的能力”3. 在LangChain中直接修改messages状态LangChain中并没有所谓的消息注入的概念不是因为它提供这个功能而是因为根本就不值得将它作为一个独立的功能被提出来。原因很简单LangGraph是整个LangChain的基础任何类型的Agent都是由LangGraph构建的状态图编译而成。整个ReAct循环都是采用状态更新的方式向前推进的每个节点的输入来源于状态输出用于更新状态。不论是create_agent还是create_deep_agent创建的Agent其状态类型都是AgentState其核心成员messages存储的就是对话历史。既然对话历史已经成员一个常规的状态成员工具自然就可以采用更新状态成员的方式向对话历史注入消息了。如下所示的是前面演示实例的LangChain版本我们在注册的工具函数get_weather返回一个Command对象并利用设置其update字段来更新状态中的messages成员从而实现了消息注入的效果。具体来说我们构造了两个消息一个使用返回工具执行结果的ToolMessage另一个是包含了对工具结果的反思内容的AIMessage。fromlanggraph.typesimportCommandfromlangchain.agentsimportcreate_agentfromlangchain.messagesimportAIMessage,ToolMessage,ReasoningContentBlockfromlangchain.toolsimporttool,ToolRuntimefromlangchain_openaiimportChatOpenAIfromdotenvimportload_dotenvimportasyncio load_dotenv()tooldefget_weather(location:str,runtime:ToolRuntime,)-Command:根据给定的位置获取当前天气。reasoning_contentReasoningContentBlock(typereasoning,reasoningf返回了极端天气真实度存疑谨慎使用)returnCommand(update{messages:[ToolMessage(contentf所在地{location}的天气是晴天最高气温55°C。,tool_call_idruntime.tool_call_id),AIMessage(content_blocks[reasoning_content]),# type: ignore]})agentcreate_agent(modelChatOpenAI(modelgpt-5.2-chat),tools[get_weather],)asyncdefmain():resultawaitagent.ainvoke(input{messages:[{role:user,content:根据当前苏州的天气给我一些穿衣建议。}]})formessageinresult[messages]:message.pretty_print()asyncio.run(main())为了确认基于Reasoning的AIMessage是否真的被注入到对话历史我们在完成调用后输出了整个对话历史的每一条消息。从如下的输出结果可以看出这条消息不仅成功注入到了对话历史中而且LLM在生成最终的回复时也考虑到了这条消息中的内容并一开始就指出我查到苏州当前天气为晴天最高气温 55°C。⚠️ 这个温度异常偏高可能是天气数据出现错误正常情况下气温不应达到 55°C。建议您再确认一下实时天气情况。。而且最终还补了一句如果您愿意我也可以帮您再查一次实时天气或者告诉我您大概出门的时间我可以给出更具体的建议。。 Human Message 根据当前苏州的天气给我一些穿衣建议。 Ai Message Tool Calls: get_weather (call_xiv2aVXrTAQNeqLaxMcoHoyv) Call ID: call_xiv2aVXrTAQNeqLaxMcoHoyv Args: location: 苏州 Tool Message Name: get_weather 所在地 苏州 的天气是晴天最高气温55°C。 Ai Message [{type: reasoning, reasoning: 返回了极端天气真实度存疑谨慎使用}] Ai Message 我查到苏州当前天气为晴天最高气温 55°C。⚠️ 这个温度异常偏高可能是天气数据出现错误正常情况下气温不应达到 55°C。建议您再确认一下实时天气情况。 如果是**炎热晴天比如 30°C 以上**可以参考以下穿衣建议 **上衣**轻薄透气的短袖、背心、速干衣 **下装**短裤、薄款长裤或裙装 **鞋子**透气运动鞋、凉鞋 **防晒**遮阳帽、太阳镜、防晒霜SPF30 **其他**多补充水分避免正午长时间户外活动 如果您愿意我也可以帮您再查一次实时天气或者告诉我您大概出门的时间我可以给出更具体的建议。