)
摘要本文介绍如何在 LangGraph 中实现 Learning学习与 Adaptation自适应。案例介绍配套 demo 实现一个可反复调教的「自适应技术助手」——用户在命令行提问如「什么是 LangGraph」用自然语言反馈如「太啰嗦了简单点」助手逐轮调整风格。提供main.py交互式命令行与main.ipynb四轮非交互式演示演示中同一问题 同一反馈多轮迭代后回答字数从 3500 降至约 1200风格从冗长专业变为简短口语。技术要点用户反馈由 LLM 解析为各维度调整量±1偏好持久化到 JSON四个维度detail_level、tone、technical_depth、structure各 0–10动态构造 system prompt。不依赖 PPO / DPO仅用「偏好 图结构 持久化 LLM 反馈解析」即可跑通最小闭环并与 SICA、AlphaEvolve 等高级系统在方法论上对齐。关键词Learning AdaptationLangGraph自适应UserPreference自然语言反馈feedback_parser长期记忆system prompt自适应技术助手源代码链接Transformer 12. Learning and Adaptation 案例源代码1. 为什么在 Agent 中要谈「学习与自适应」先用一个生活里的画面来感受这个概念。想象一下你请一个实习生帮忙写技术总结。第一天他照本宣科地把 API 文档翻译成白话你觉得太啰嗦就提醒他「以后简洁一点」。几天之后你会发现他真的开始控制篇幅、突出重点——这就是最朴素的Learning AdaptationLearning学习从你的反馈中抽象出「什么是好答案」Adaptation自适应下次写作时主动调整风格和策略。对智能体Agent来说道理是一样的如果一个 Agent 每次回答都只依赖一段固定的 system prompt而不会因为用户反馈、历史数据、环境变化去更新自己的「习惯」那它本质上还是一个「高级脚本」而不是一个真正会成长的智能体。围绕 Learning Adaptation 这一主题我们可以从几个经典视角来理解「Agent 如何变聪明」强化学习Reinforcement Learning想象一个玩游戏的小孩他一开始乱按按键偶尔赢了几局就会慢慢记住「哪些操作更容易赢」。对 Agent 来说就是在环境中尝试动作Action根据结果拿到奖励Reward或惩罚逐步调整策略Policy。这类方法适合机器人控制、游戏 AI 等需要长期规划、连续决策的场景用 PPO 此类算法稳定更新策略避免「一步走错经验全毁」。在线学习Online Learning如果说「离线训练」像是每年一次体检那么在线学习就更像是「每天戴着手环监控身体状态随时调整作息」。Agent 持续接收新的数据流如日志、行情、传感器数据边用边学使得模型参数或内部策略随着时间不断更新能及时适应分布漂移数据统计规律随时间变化。在推荐系统、风控、行情预测、运维监测等场景里这是非常关键的能力。记忆型学习Memory-Based Learning想象你和一个朋友聊天如果他总是记得你之前提过的兴趣、忌讳、偏好你会觉得「他很懂你」。对 Agent 来说「记忆」也是一种非常实用的 Learning 机制短期记忆当前对话轮次及临时变量中期记忆最近几天 / 几十次交互的摘要长期记忆高度压缩的用户画像、重要事实、偏好。这些信息不一定体现在模型参数里但会影响每次推理前的「上下文」和「工具选择」从而展现出「根据经验做决策」的行为。基于 LLM 的 Few-shot / Zero-shot 学习这是近几年 Agent 最常用的一种「软学习」方式通过几条示例Few-shot或清晰的说明Zero-shot就让模型在新任务上表现得不错如果把「示例 指令」持续记录、整理再喂回给后续调用本质上也形成了一种「上下文级别」的学习和适应。这些方法从不同角度说明了同一件事一个强大的 Agent一定要能根据环境和反馈不断更新自己的内部状态而不是永远停留在「一次性 prompt」的水平。接下来我们会用一个可运行的 LangGraph 示例把「学习与自适应」具体化成一个你可以反复调教的「自适应技术助手」并在后文中再类比到更复杂的系统比如 SICA、AlphaEvolve。2. 示例设定一个会被你「调教」的技术助手我们希望构建这样一个极简场景你在命令行里向助手提问围绕 LLM / LangGraph / Agent 等技术话题助手给出回答后你可以用自然语言表达反馈例如「太啰嗦了简单点」「正式一些」「通俗一点别用那么多术语」「分点说列个清单」系统通过LLM 解析你的反馈得到各维度的调整量±1并更新长期偏好多轮下来助手会逐渐学会在四个维度上微调detail_level更简洁还是更详细tone更口语还是更正式technical_depth更通俗还是更专业structure更自由段落还是更分点编号。也就是说我们不在这里实现完整的 PPO / DPO而是用一个「偏好 图结构 持久化 LLM 反馈解析」的小例子把 Learning Adaptation 的「骨架」跑通接收反馈自然语言——更贴近真实场景用户无需打分用 LLM 将反馈解析为各维度的调整量-1 / 0 / 1把偏好写入 JSON 文件每个维度 0–10 连续可调下次调用前从长期记忆中读取最新偏好动态调整 system prompt形成一个「不断更新内部状态 → 改变后续行为」的闭环。3. 状态与图结构用 LangGraph 表达「学习过程」在代码中我们用一个AgentState来描述图中流转的状态见adaptive_agent_graph.pyclassAgentState(TypedDict):user_id:str# 用户标识question:str# 当前问题messages:List[str]# 简单对话历史preference:UserPreference# 用户长期偏好4 维度各 0-10answer:str# 本轮回答feedback_text:str|None# 用户自然语言反馈可选对应的 LangGraph 结构非常简单START ↓ load_preference # 载入 user_id 对应的长期偏好 ↓ answer_question # 按偏好构造 system prompt调用 LLM 生成回答 ↓ update_preference # 根据用户自然语言反馈用 LLM 解析后更新偏好 ↓ END在build_adaptive_agent()中我们用 LangGraph 把这条链路串起来defbuild_adaptive_agent()-StateGraph:graphStateGraph(AgentState)graph.add_node(load_preference,load_preference_node)graph.add_node(answer_question,answer_question_node)graph.add_node(update_preference,update_preference_node)graph.add_edge(START,load_preference)graph.add_edge(load_preference,answer_question)graph.add_edge(answer_question,update_preference)graph.add_edge(update_preference,END)returngraph这里有三个关键信息状态是显式建模的你能清楚看到有哪些字段会被更新节点是纯函数输入AgentState输出新的AgentState便于测试与复用学习过程是图结构的一部分update_preference节点就是「学习」的载体。4. 长期记忆把偏好写进一个简单的 JSONLearning Adaptation 的一个核心思想是不要把所有「内部状态」都塞在 LLM 的上下文里更适合用专门的数据结构持久化。在adaptive_memory.py中我们用一个极简的 JSON 文件来模拟「长期偏好」文件路径memory_files/adaptive_preferences.json每个user_id对应一个UserPreference四个维度均为 0–10 的整数detail_level0极简5平衡10极详tone0极口语5平衡10极正式technical_depth0大白话5平衡10专业术语structure0自由段落5平衡10分点编号。adaptive_preferences.json里的内容初始化状态下可以是{notebook_demo_user:{user_id:notebook_demo_user,detail_level:6,tone:6,technical_depth:6,structure:6}}加载偏好的逻辑大致如下defload_user_preference(user_id:str)-UserPreference:prefs_load_all_preferences()ifuser_idinprefs:returnprefs[user_id]prefUserPreference(user_iduser_id)prefs[user_id]pref _save_all_preferences(prefs)returnpref而根据自然语言反馈更新偏好的逻辑则借助feedback_parser.py中的 LLM 解析defupdate_preference_from_feedback(user_id:str,feedback_text:str)-UserPreference:deltasparse_feedback_to_deltas(feedback_text)# LLM 解析为 {detail_level: -1, ...}prefload_user_preference(user_id)pref.detail_leveldeltas.get(detail_level,0)pref.tonedeltas.get(tone,0)pref.technical_depthdeltas.get(technical_depth,0)pref.structuredeltas.get(structure,0)pref.clamp()# 限制在 0-10_save_all_preferences(prefs)returnpref你可以把这段逻辑理解成用户说「太啰嗦了简单点」→ LLM 解析为detail_level: -1每次反馈各维度最多 ±1多次迭代后自然收敛到你满意的组合真实场景下用户更习惯用语言表达而非打 1–5 分。5. 自适应的 system prompt让风格真正「用起来」有了长期偏好还需要在实际调用 LLM 时用上它。在adaptive_agent_graph.py里我们通过_build_system_prompt()把四个维度0–10映射成具体的提示词def_value_to_detail_instruction(v:int)-str:ifv2:return尽量用 1-2 句话回答只保留关键结论。ifv4:return回答简短适度展开。ifv6:return在保证结论清晰的前提下适度展开原理与示例。ifv8:return给出分步骤、较详细的推理过程与示例。return给出分步骤、非常详细的推理过程与多个示例。def_value_to_tone_instruction(v:int)-str:ifv2:return语气非常口语、轻松。ifv4:return语气可以更口语、轻松一些。ifv6:return语气适中。ifv8:return整体语气保持专业、正式。return整体语气非常专业、正式适合技术文档。# technical_depth、structure 同理最终拼成完整 system promptanswer_question_node节点则会在调用 LLM 时使用这个 system promptdefanswer_question_node(state:AgentState)-AgentState:使用当前偏好调用 LLM 回答问题。prefstate[preference]system_prompt_build_system_prompt(pref)messages[{role:system,content:system_prompt},{role:user,content:(请用 LangGraph 的视角回答问题并尽量结合图结构、节点、状态的概念。\nf问题{state[question]}),},]completion_client.chat.completions.create(model_llm_config.model,messagesmessages,)answercompletion.choices[0].message.contentorhistorylist(state.get(messages,[]))history.append(fQ:{state[question]})history.append(fA:{answer})state[answer]answer state[messages]historyreturnstatedef_build_system_prompt(pref:UserPreference)-str: 根据长期偏好4 个维度 0-10动态构造 system prompt。 parts[你是一名资深 AI 技术顾问擅长用中文解释大模型与 LangGraph。,_value_to_detail_instruction(pref.detail_level),_value_to_tone_instruction(pref.tone),_value_to_technical_instruction(pref.technical_depth),_value_to_structure_instruction(pref.structure),]return .join(parts)这样每次图执行时都会「读取最新偏好 → 构造对应风格的 system prompt → 生成回答」。学习发生在偏好上自适应体现在 prompt 上。6. 交互入口用命令行感受「越聊越懂你」在main.py中我们用一个简单的命令行循环包装了整个图defrun_cli_session(user_id:strdemo_user)-None:graphbuild_adaptive_agent().compile()history:list[str][]whileTrue:questioninput(\n你的问题).strip()ifquestion.lower()in{exit,quit}:breakstate:AgentState{user_id:user_id,question:question,messages:history,preference:None,answer:,feedback_text:None,}# type: ignore[assignment]resultgraph.invoke(state)answerresult[answer]historyresult[messages]print(\n助手回答)print(answer)feedback_textinput(\n对这次回答有什么反馈直接回车跳过).strip()iffeedback_text:feedback_state:AgentState{user_id:user_id,question:question,messages:history,preference:result[preference],answer:answer,feedback_text:feedback_text,}_graph.invoke(feedback_state)print(已根据反馈更新长期偏好。)运行体验建议如下第一次运行时提一个相同类型的问题例如「什么是 LangGraph它和普通 LangChain 有什么区别」如果你觉得回答太啰嗦可以说「太啰嗦了简单点」再问一次类似的问题你会看到回答逐渐变短你也可以试试「正式一些」「通俗一点」「分点说」等不同维度的反馈。Notebook 演示main.ipynb提供了非交互式演示模拟「同一问题 同一反馈」执行两轮第一轮回答 → 反馈「太啰嗦了简单点」→ 第二轮回答 → 再次反馈 → 第四轮回答。可直观看到detail_level连续下调、回答逐渐变短。这就是一个最小可感知的Learning Adaptation 闭环。我们在main.ipynb中先问了一个问题什么是 LangGraph它和普通 LangChain 有什么区别。初始化情况下UserPreference的四个维度均为 6 detail6, tone6, technical6, structure6。第一轮回答如下“从LangGraph 的视角来看它本质上是一个基于有向图Directed Graph建模的、状态驱动的 LLM 应用编排框架”… 一共3525个字符我们回复“太啰嗦了简单点。而且你说的太专业了我听不懂。”UserPreference的四个维度更新为detail5, tone5, technical5, structure6。大模型回答“从 LangGraph 的视角来看它本质上是一个基于有向图Directed Graph建模的、状态驱动的 LLM 应用编排框架”… 一共3109个字符看起来好像和第一轮回复差别不大。我们再一次回复“太啰嗦了简单点。而且你说的太专业了我听不懂。”UserPreference的四个维度更新为detail4, tone4, technical4, structure6。大模型回答好嘞咱们用「图」的视角来聊聊 LangGraph **LangGraph 是什么** 它本质上是一个**基于有向图Directed Graph的编排框架**专为构建**状态驱动、可循环、带条件分支的 LLM 应用**而生。 核心三要素对应图论结构 ...一共1187个字符。现在我们可以看到这次的回复和上两次明显字数缩短了文字变得更加口语化了。7. 与 SICA / AlphaEvolve 等高级系统的类比像 SICA、AlphaEvolve、OpenEvolve 这样的系统做的事情要复杂得多但可以用同一套思维去理解状态更复杂不只是「detail_level / tone」而是包含完整的代码版本、性能指标、评测日志反馈更丰富不只是 1–5 分而是自动评测脚本、基准测试、人工偏好数据等搜索策略更高级不只是「切换几种风格」而是使用进化算法、自我改写、甚至调用多个子 agent 协同探索。但从 LangGraph 的视角看它们仍然可以抽象成有一个不断被更新的「世界状态」代码、参数、工具集合、偏好等有一条或多条图负责根据当前状态执行动作、收集反馈有专门的节点 / 子图负责根据反馈更新世界状态整个系统通过「图 状态」的组合不断在状态空间中进行搜索和优化。你可以把本节的示例视为这些复杂系统的「玩具版本」我们只在 very small 的状态空间回答风格里做「搜索 / 适应」但架构思路是一致的。8. 小结如何在自己的 Agent 项目中落地 Learning Adaptation如果你想在自己的 Agent 项目中引入 Learning Adaptation可以参考本节示例从最小可行单元做起第一步显式建模状态把「会被更新」的东西偏好、配置、重要的中间结果放进 LangGraph 的状态而不是全部交给 prompt。第二步专门的「学习节点」为「根据反馈更新状态」写一个单独的节点 / 子图哪怕逻辑一开始非常简单。第三步持久化长期记忆先用 JSON / SQLite / 向量库等简单方式把「关键状态」写到磁盘上让系统真正拥有跨会话的记忆。第四步从「调整风格」开始不一定一上来就做 PPO / DPO可以像本示例一样先从「根据偏好调整回答风格 / 展示方式」开始逐步演进到更复杂的策略和算法。当你把这四步跑通后再回头看 SICA、AlphaEvolve就会发现它们做的是更大规模、更高维度的 Learning Adaptation但方法论高度相似。