第 01 步:最小聊天 Agent¶
这一节学什么¶
Agent的最小入口state在jianmu里是什么意思- 一个最基本的 State schema 长什么样
messages / done / final_answer是怎么进入与流出的
你会运行什么¶
示例代码:
examples/getting_started/step_01_minimal_chat.py
运行:
核心概念¶
这一步先建立一个最小心智:
Agent不是一个单独的模型调用函数- 它是一个运行根节点、维护共享状态的运行体
你只要记住:
Agent负责运行一个根节点- State 是 Agent 的共享状态
- 最小聊天链路里,最重要的是
messages、done和final_answer
先说什么是 state¶
在 jianmu 里,state 可以先理解成:
- 当前这棵 Agent 运行树共享的一份结构化工作内存
它不是普通的随手变量集合,而是:
- 有 schema 的
- 能被不同节点共同读取和写入的
- 会随着运行不断演化的
在这个最小聊天例子里,state 里最重要的三个字段是:
messagesdonefinal_answer
它们分别承担:
messages- 保存当前对话消息流
done- 表示这一轮运行是否已经完成
final_answer- 保存这一轮运行产出的最终回答
这个最小 Agent 由什么组成¶
虽然示例代码很短,但它其实已经包含了 4 层东西:
ModelClient¶
ModelClient.resolve() 负责拿到一个可用的模型调用入口。
你可以先把它理解成:
- “帮当前节点连上一个实际可调用的模型 provider”
AgentLLMNode¶
AgentLLMNode 是真正执行一次 LLM 对话的节点。
在这个例子里,它负责:
- 读取 state 里的
messages - 调用模型
- 把回复写回 state
Sequence¶
这里虽然只有一个子节点,外面仍然包了一层 Sequence。
这是因为在 jianmu 里,Agent 运行的是一棵树,而不是单个裸节点函数。
这一节先用最小的树形结构,让你看到:
- 即使最简单的 Agent,本质上也是“一个树在运行”
Agent¶
Agent 负责把这些部分真正装配起来:
- 持有根节点
- 持有 state schema
- 驱动整棵树运行
ChatState 为什么这样写¶
这个例子里的 ChatState 不只是普通的 Pydantic 模型,它还带了一点运行时语义。
messages: Annotated[list[Message], operator.add]¶
这里的重点是 operator.add。
它表示这个字段在运行时更适合用“追加”语义,而不是简单覆盖。
也就是说,当节点往 messages 写新消息时,框架会把它理解成:
- 往现有消息列表后面追加
而不是:
- 整个把旧消息列表替换掉
done: Annotated[bool, Ephemeral(scope=\"run\")]¶
done 是最小运行协议里的完成标志。
在当前实现里,LLM 节点产出最终文本时,会同时:
- 把回复追加到
messages - 写入
final_answer - 把
done置为True
所以这里可以把它理解成:
done负责“这轮该停了”final_answer负责“最终文本结果是什么”
final_answer: Annotated[str | None, Ephemeral(scope=\"run\")]¶
这里的重点是 Ephemeral(scope="run")。
你现在可以先把它理解成:
- 这是一次运行内的临时结果字段
它表达的不是“长期持久业务数据”,而是:
- 当前 run 结束后最想拿出来看的结果
这一节故意还没出现什么¶
这一步是最小聊天主路径,所以它刻意还没有引入:
actionsrounds- tools
ContextBuilder- HITL / guard / execution
也就是说,这一步只回答一件事:
- 一个最小的、没有工具调用的 Agent 是怎么跑起来的
运行后观察什么¶
- 输入用户消息的位置
- 模型回复被追加到
messages - 运行完成时
done会变成True - 最终文本被写入
final_answer - 这个例子里没有
actions,因为它只是最小聊天,不涉及 tool calling
这一步学完后应该会什么¶
你应该能回答:
state在jianmu里是什么Agent和AgentLLMNode分别负责什么- 为什么最小例子里最重要的字段是
messages、done和final_answer
下一步¶
下一节进入真正的 Agent loop: