LangGraph 12. Learning & Adaptation,用 LangGraph 写一个会「改进自己」的智能体(含代码示例)

摘要 :本文介绍如何在 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 & Adaptation;LangGraph;自适应;UserPreference;自然语言反馈;feedback_parser;长期记忆;system prompt;自适应技术助手

源代码链接:Transformer 12. Learning and Adaptation 案例源代码


1. 为什么在 Agent 中要谈「学习与自适应」?

先用一个生活里的画面来感受这个概念。

想象一下,你请一个实习生帮忙写技术总结。第一天,他照本宣科地把 API 文档翻译成白话;你觉得太啰嗦,就提醒他「以后简洁一点」。几天之后,你会发现他真的开始控制篇幅、突出重点------这就是最朴素的 Learning & Adaptation

  • Learning(学习):从你的反馈中抽象出「什么是好答案」;
  • 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 的「骨架」跑通:

  1. 接收反馈(自然语言)------更贴近真实场景,用户无需打分;
  2. 用 LLM 将反馈解析为各维度的调整量(-1 / 0 / +1);
  3. 把偏好写入 JSON 文件,每个维度 0--10 连续可调;
  4. 下次调用前,从长期记忆中读取最新偏好,动态调整 system prompt;
  5. 形成一个「不断更新内部状态 → 改变后续行为」的闭环。

3. 状态与图结构:用 LangGraph 表达「学习过程」

在代码中,我们用一个 AgentState 来描述图中流转的状态(见 adaptive_agent_graph.py):

python 复制代码
class AgentState(TypedDict):
    user_id: str              # 用户标识
    question: str             # 当前问题
    messages: List[str]       # 简单对话历史
    preference: UserPreference  # 用户长期偏好(4 维度,各 0-10)
    answer: str               # 本轮回答
    feedback_text: str | None  # 用户自然语言反馈(可选)

对应的 LangGraph 结构非常简单:

text 复制代码
START
  ↓
load_preference      # 载入 user_id 对应的长期偏好
  ↓
answer_question      # 按偏好构造 system prompt,调用 LLM 生成回答
  ↓
update_preference    # 根据用户自然语言反馈,用 LLM 解析后更新偏好
  ↓
END

build_adaptive_agent() 中,我们用 LangGraph 把这条链路串起来:

python 复制代码
def build_adaptive_agent() -> StateGraph:
    graph = StateGraph(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)

    return graph

这里有三个关键信息:

  • 状态是显式建模的:你能清楚看到有哪些字段会被更新;
  • 节点是纯函数 :输入 AgentState,输出新的 AgentState,便于测试与复用;
  • 学习过程是图结构的一部分update_preference 节点就是「学习」的载体。

4. 长期记忆:把偏好写进一个简单的 JSON

Learning & Adaptation 的一个核心思想是:不要把所有「内部状态」都塞在 LLM 的上下文里,更适合用专门的数据结构持久化。

adaptive_memory.py 中,我们用一个极简的 JSON 文件来模拟「长期偏好」:

  • 文件路径:memory_files/adaptive_preferences.json
  • 每个 user_id 对应一个 UserPreference四个维度均为 0--10 的整数
    • detail_level:0=极简,5=平衡,10=极详;
    • tone:0=极口语,5=平衡,10=极正式;
    • technical_depth:0=大白话,5=平衡,10=专业术语;
    • structure:0=自由段落,5=平衡,10=分点编号。

adaptive_preferences.json 里的内容初始化状态下可以是:

json 复制代码
{
  "notebook_demo_user": {
    "user_id": "notebook_demo_user",
    "detail_level": 6,
    "tone": 6,
    "technical_depth": 6,
    "structure": 6
  }
}

加载偏好的逻辑大致如下:

python 复制代码
def load_user_preference(user_id: str) -> UserPreference:
    prefs = _load_all_preferences()
    if user_id in prefs:
        return prefs[user_id]
    pref = UserPreference(user_id=user_id) 
    prefs[user_id] = pref
    _save_all_preferences(prefs)
    return pref

而根据自然语言反馈 更新偏好的逻辑,则借助 feedback_parser.py 中的 LLM 解析:

python 复制代码
def update_preference_from_feedback(user_id: str, feedback_text: str) -> UserPreference:
    deltas = parse_feedback_to_deltas(feedback_text)  # LLM 解析为 {"detail_level": -1, ...}
    pref = load_user_preference(user_id)
    pref.detail_level += deltas.get("detail_level", 0)
    pref.tone += deltas.get("tone", 0)
    pref.technical_depth += deltas.get("technical_depth", 0)
    pref.structure += deltas.get("structure", 0)
    pref.clamp()  # 限制在 0-10
    _save_all_preferences(prefs)
    return pref

你可以把这段逻辑理解成:

  • 用户说「太啰嗦了,简单点」→ LLM 解析为 detail_level: -1
  • 每次反馈各维度最多 ±1,多次迭代后自然收敛到你满意的组合;
  • 真实场景下用户更习惯用语言表达,而非打 1--5 分。

5. 自适应的 system prompt:让风格真正「用起来」

有了长期偏好,还需要在实际调用 LLM 时用上它。在 adaptive_agent_graph.py 里,我们通过 _build_system_prompt() 把四个维度(0--10)映射成具体的提示词:

python 复制代码
def _value_to_detail_instruction(v: int) -> str:
    if v <= 2: return "尽量用 1-2 句话回答,只保留关键结论。"
    if v <= 4: return "回答简短,适度展开。"
    if v <= 6: return "在保证结论清晰的前提下,适度展开原理与示例。"
    if v <= 8: return "给出分步骤、较详细的推理过程与示例。"
    return "给出分步骤、非常详细的推理过程与多个示例。"

def _value_to_tone_instruction(v: int) -> str:
    if v <= 2: return "语气非常口语、轻松。"
    if v <= 4: return "语气可以更口语、轻松一些。"
    if v <= 6: return "语气适中。"
    if v <= 8: return "整体语气保持专业、正式。"
    return "整体语气非常专业、正式,适合技术文档。"

# technical_depth、structure 同理,最终拼成完整 system prompt

answer_question_node 节点则会在调用 LLM 时,使用这个 system prompt:

python 复制代码
def answer_question_node(state: AgentState) -> AgentState:
    """使用当前偏好,调用 LLM 回答问题。"""
    pref = state["preference"]
    system_prompt = _build_system_prompt(pref)

    messages = [
        {"role": "system", "content": system_prompt},
        {
            "role": "user",
            "content": (
                "请用 LangGraph 的视角回答问题,并尽量结合图结构、节点、状态的概念。\n"
                f"问题:{state['question']}"
            ),
        },
    ]

    completion = _client.chat.completions.create(
        model=_llm_config.model,
        messages=messages,
    )
    answer = completion.choices[0].message.content or ""

    history = list(state.get("messages", []))
    history.append(f"Q: {state['question']}")
    history.append(f"A: {answer}")

    state["answer"] = answer
    state["messages"] = history
    return state
python 复制代码
def _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 中,我们用一个简单的命令行循环包装了整个图:

python 复制代码
def run_cli_session(user_id: str = "demo_user") -> None:
    graph = build_adaptive_agent().compile()
    history: list[str] = []

    while True:
        question = input("\n你的问题:").strip()
        if question.lower() in {"exit", "quit"}:
            break

        state: AgentState = {
            "user_id": user_id,
            "question": question,
            "messages": history,
            "preference": None,
            "answer": "",
            "feedback_text": None,
        }  # type: ignore[assignment]

        result = graph.invoke(state)
        answer = result["answer"]
        history = result["messages"]

        print("\n助手回答:")
        print(answer)

        feedback_text = input("\n对这次回答有什么反馈?(直接回车跳过):").strip()
        if feedback_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("已根据反馈更新长期偏好。")

运行体验建议如下:

  1. 第一次运行时,提一个相同类型的问题,例如「什么是 LangGraph,它和普通 LangChain 有什么区别?」;
  2. 如果你觉得回答太啰嗦,可以说「太啰嗦了,简单点」;
  3. 再问一次类似的问题,你会看到回答逐渐变短;
  4. 你也可以试试「正式一些」「通俗一点」「分点说」等不同维度的反馈。

Notebook 演示main.ipynb 提供了非交互式演示,模拟「同一问题 + 同一反馈」执行两轮:第一轮回答 → 反馈「太啰嗦了,简单点」→ 第二轮回答 → 再次反馈 → 第四轮回答。可直观看到 detail_level 连续下调、回答逐渐变短。

这就是一个最小可感知的 Learning & Adaptation 闭环

我们在 main.ipynb 中先问了一个问题:什么是 LangGraph,它和普通 LangChain 有什么区别?

初始化情况下,UserPreference 的四个维度均为 6 (detail=6, tone=6, technical=6, structure=6)。第一轮回答如下:"从LangGraph 的视角来看,它本质上是一个基于有向图(Directed Graph)建模的、状态驱动的 LLM 应用编排框架"... 一共3525个字符;

我们回复:"太啰嗦了,简单点。而且你说的太专业了,我听不懂。"

UserPreference 的四个维度更新为:detail=5, tone=5, technical=5, structure=6。大模型回答:"从 LangGraph 的视角来看,它本质上是一个基于有向图(Directed Graph)建模的、状态驱动的 LLM 应用编排框架"... 一共3109个字符;看起来好像和第一轮回复差别不大。

我们再一次回复:"太啰嗦了,简单点。而且你说的太专业了,我听不懂。"

UserPreference 的四个维度更新为:detail=4, tone=4, technical=4, structure=6。大模型回答:

复制代码
好嘞~咱们用「图」的视角来聊聊 LangGraph 👇

🔹 **LangGraph 是什么?**  
它本质上是一个**基于有向图(Directed Graph)的编排框架**,专为构建**状态驱动、可循环、带条件分支的 LLM 应用**而生。  
核心三要素(对应图论结构):
...

一共1187个字符。现在我们可以看到,这次的回复和上两次明显字数缩短了,文字变得更加口语化了。

7. 与 SICA / AlphaEvolve 等高级系统的类比

像 SICA、AlphaEvolve、OpenEvolve 这样的系统,做的事情要复杂得多,但可以用同一套思维去理解:

  • 状态更复杂:不只是「detail_level / tone」,而是包含完整的代码版本、性能指标、评测日志;
  • 反馈更丰富:不只是 1--5 分,而是自动评测脚本、基准测试、人工偏好数据等;
  • 搜索策略更高级:不只是「切换几种风格」,而是使用进化算法、自我改写、甚至调用多个子 agent 协同探索。

但从 LangGraph 的视角看,它们仍然可以抽象成:

  1. 有一个不断被更新的「世界状态」(代码、参数、工具集合、偏好等);
  2. 有一条或多条图,负责根据当前状态执行动作、收集反馈;
  3. 有专门的节点 / 子图,负责根据反馈更新世界状态;
  4. 整个系统通过「图 + 状态」的组合,不断在状态空间中进行搜索和优化。

你可以把本节的示例视为这些复杂系统的「玩具版本」:
我们只在 very small 的状态空间(回答风格)里做「搜索 / 适应」,但架构思路是一致的。

8. 小结:如何在自己的 Agent 项目中落地 Learning & Adaptation

如果你想在自己的 Agent 项目中引入 Learning & Adaptation,可以参考本节示例,从最小可行单元做起:

  • 第一步:显式建模状态

    把「会被更新」的东西(偏好、配置、重要的中间结果)放进 LangGraph 的状态,而不是全部交给 prompt。

  • 第二步:专门的「学习节点」

    为「根据反馈更新状态」写一个单独的节点 / 子图,哪怕逻辑一开始非常简单。

  • 第三步:持久化长期记忆

    先用 JSON / SQLite / 向量库等简单方式把「关键状态」写到磁盘上,让系统真正拥有跨会话的记忆。

  • 第四步:从「调整风格」开始

    不一定一上来就做 PPO / DPO,可以像本示例一样,先从「根据偏好调整回答风格 / 展示方式」开始,逐步演进到更复杂的策略和算法。

当你把这四步跑通后,再回头看 SICA、AlphaEvolve,就会发现:
它们做的是更大规模、更高维度的 Learning & Adaptation,但方法论高度相似。

相关推荐
愈努力俞幸运2 小时前
n8n草履虫教程
人工智能
Once_day2 小时前
AI实践(8)Skills技能
人工智能·ai实践
光锥智能2 小时前
光粒科技多款AI+AR智能运动产品亮相AWE2026
人工智能·科技·ar
智算菩萨2 小时前
大语言模型迈向通用人工智能:基础原理与方法综述——文献精读
人工智能·深度学习·ai·语言模型·自然语言处理
Maryfang132918915512 小时前
应对芯片涨价,光口以太网芯片国产P2P替代
人工智能·网络协议·网络安全·信息与通信
yhdata2 小时前
MTP型光纤连接器发展势头强劲,2032年市场规模锁定276.2亿元新高度
大数据·人工智能
AI4Traffic2 小时前
深度学习中的对数似然损失函数
大数据·人工智能·深度学习
Percent_bigdata2 小时前
百分点科技亮相MWC 2026:以数据智能深耕全球治理
人工智能·科技
arvin_xiaoting2 小时前
AI Agent 实战:用飞书任务卡片让后台任务「可见」
人工智能·自动化·llm·飞书·ai agent·openclaw·任务卡片