简单来说:它本质上就是一个普通的 Python 字典(dict),但它在代码编写和静态检查阶段,具有像类(Class)一样的键名(Key)和键值(Value)类型约束。
1. 为什么需要 TypedDict?
在没有 TypedDict 之前,如果你给一个字典加类型提示:
user: <span>dict</span>[<span>str</span>, <span>str</span>] = {<span>"name"</span>: <span>"Alice"</span>, <span>"role"</span>: <span>"admin"</span>}
问题在于:
- 它只能规定所有的 Key 是
str,所有的 Value 是str。 - 它无法规定这个字典必须包含哪些特定的键(比如必须有
"name"和"age")。 - 如果 Value 类型不一致(比如
name是str,age是int),你只能写dict[str, Any],这样就彻底丢失了类型检查和 IDE 的自动补全。
2. TypedDict 长什么样?
使用 TypedDict,你可以像定义类一样定义字典的“形状”(Schema):
<span>from</span> typing <span>import</span> TypedDict
<span># 定义字典的数据结构</span>
<span>class</span> <span>UserState</span>(<span>TypedDict</span>):
user_id: <span>int</span>
user_name: <span>str</span>
is_active: <span>bool</span>
<span># 实例化:它本质上就是一个标准 dict!</span>
user: UserState = {<span>"user_id"</span>: <span>101</span>, <span>"user_name"</span>: <span>"Alice"</span>, <span>"is_active"</span>: <span>True</span>}
<span># 运行时检验:</span>
<span>print</span>(<span>type</span>(user)) <span># 输出: <class 'dict'>,没有任何类实例化的额外开销!</span>
它的好处:
- IDE 代码自动补全:当你输入
user["时,编辑器会直接提示补全user_id、user_name等。 - 静态类型检查(MyPy / Pyright):如果你写错拼写(例如
user["username"])或者传入了错误类型(user["user_id"] = "abc"),静态类型检查器和 VSCode/PyCharm 会直接标红报错。
3. 它与 LangGraph / 前文上下文的关系
在 LangGraph 中,图(Graph)在节点之间传递的数据载体就叫做 State(状态)。
LangGraph 官方标准做法就是用 TypedDict 来定义这个 State:
<span>from</span> typing <span>import</span> TypedDict
<span>from</span> langgraph.graph <span>import</span> END, START, StateGraph
<span># 1. 用 TypedDict 约束图里流动的数据结构</span>
<span>class</span> <span>TranslationState</span>(<span>TypedDict</span>):
input_text: <span>str</span>
target_language: <span>str</span>
translated_text: <span>str</span> <span># 后续节点会填入这个字段</span>
<span># 2. 定义图节点</span>
<span>def</span> <span>translate_node</span>(<span>state: TranslationState</span>) -> <span>dict</span>:
<span># 这里能享受 IDE 的完美补全和类型保护</span>
text = state[<span>"input_text"</span>]
target = state[<span>"target_language"</span>]
<span># ... 调用 LLM ...</span>
<span>return</span> {<span>"translated_text"</span>: <span>"你好,世界"</span>}
<span># 3. 构建图</span>
builder = StateGraph(TranslationState)
builder.add_node(<span>"translate"</span>, translate_node)
builder.add_edge(START, <span>"translate"</span>)
builder.add_edge(<span>"translate"</span>, END)
graph = builder.<span>compile</span>()
4. 它和 Pydantic 的区别(为什么前文两者都提到了?)
前文提到:“with typed state in and a typed Pydantic result out”(输入是强类型的 TypedDict 状态,输出是强类型的 Pydantic 结果)。它们的分工是不同的:
| 特性 | `TypedDict` | `Pydantic` (BaseModel) |
|---|---|---|
| **底层本质** | 就是普通 Python 原生字典 `dict` | 一个独立的自定义类实例(Class Object) |
| **运行时验证** | **无**(只在写代码和静态检查时起作用,运行几乎零性能损耗) | **有**(运行时会进行严格的数据解析、类型转换和校验) |
| **常见用途** | 框架内部管线传参(如 LangGraph 的状态流转) | 接口入参校验、LLM 结构化输出(让模型吐出合法 JSON) |
**总结:**前文作者的意思是:LangGraph 内部流转的状态数据用了 TypedDict(既有类型提示与补全规范,又像普通字典一样轻量零开销);而让 LLM 输出的结构化数据则用 Pydantic 进行严格的运行时格式校验。
一文讲清 TypedDict 与 Pydantic 的边界:轻量类型提示用于内部状态流转,严格运行时校验用于外部数据与模型输出。适合写 LangGraph、LLM 应用及类型注解实践者参考。