#100DaysOfAgent Day 5

#100DaysOfAgent Day 5

今天学习了 LangGraph 工具系统进阶,重点掌握了 Reducer 机制、工具错误处理、并行工具调用与循环保护。

收获

1. Reducer 的真正绑定方式

Reducer 是告诉 LangGraph「字段更新时该怎么合并」的函数,必须通过 Annotated 显式绑定才会生效。

python 复制代码
# ❌ 03 的问题:定义了 merge_stats 函数,但没绑定,实际行为还是"覆盖"
task_stats: dict[str, int] = Field(default_factory=dict)

# ✅ 04 的修复:用 Annotated 第二个参数绑定,每次更新都会触发累加
task_stats: Annotated[dict[str, int], merge_stats] = Field(default_factory=dict)

merge_stats 的逻辑是按 key 累加,例如:

复制代码
{"search": 1} + {"search": 2, "weather": 1} => {"search": 3, "weather": 1}

类比 Django 的 aggregate(Sum('views')),把分散的值累加到一起,而不是每次都覆盖。

2. 节点返回 dict vs 返回 State 实例的区别

节点函数有两种返回方式,语义完全不同:

返回方式 语义 类比
返回 dict 部分更新,只更新 dict 里的 key,其他字段保持不变 Django .update({"name": "Alex"})
返回 State 实例 全量替换,其他字段会被默认值覆盖 整条记录覆盖写入

工程上几乎总是返回 dict,避免意外清空其他字段。

3. @tool 装饰器的本质

@tool 不只是普通装饰器,它会把函数替换成一个 StructuredTool 对象:

python 复制代码
@tool
def search_docs(query: str) -> str:
    """Search internal documentation for a query keyword."""
    ...

装饰后 search_docs 拥有 .invoke() / .name / .description 等属性,可以被 model.bind_tools() 识别并传给 LLM 使用。调用时 .invoke(tc["args"]) 会自动把 dict 参数解包成命名参数,并做类型校验。类比 Django 的 @login_required,把原函数包裹成带额外能力的新 callable。

4. 工具错误处理:不让图崩溃

tool_node 对每个工具调用加了 try/except,工具报错时把错误信息作为 ToolMessage 回传给 LLM,让 LLM 自主决定如何应对,而不是让整张图直接崩溃:

python 复制代码
try:
    observation = fn.invoke(tc["args"])
except Exception as e:
    observation = f"Tool error ({type(e).__name__}): {e}"
results.append(ToolMessage(content=str(observation), tool_call_id=tc["id"]))

例如 100 / 0 会触发 ZeroDivisionError,LLM 收到错误提示后会告知用户无法计算,而不是程序崩溃。

5. recursion_limit 循环保护

LLM 有可能陷入「调用工具 → 得到结果 → 继续调用同一工具」的死循环,recursion_limit 是图级别的硬上限:

python 复制代码
config = {
    "configurable": {"thread_id": "demo-04"},
    "recursion_limit": 15,  # 默认值是 25,超过抛 GraphRecursionError
}

类比 Django 的 MAX_REQUEST_SIZE,防止无限资源消耗。工程上通常根据业务复杂度设置,简单问答场景 10-15 步足够。

6. 图的整体结构

复制代码
START
  ↓
llm_call ──有工具调用──→ tool_node
  ↑                          |
  └──────────────────────────┘
  │
  └──无工具调用──→ to_output → END
  • should_continue 是条件路由函数,检查最后一条消息是否有 tool_calls
  • to_output 节点负责从 messages 里提取最终答案,输出给 OutputState
  • OutputState 屏蔽了 messages 字段,外部调用者只看到干净的结构化输出
相关推荐
dozenyaoyida4 分钟前
AI与大模型新闻日报 | 2026-10-17
人工智能·ai·chatgpt·新闻
遇码27 分钟前
流式调用中途断连别直接报错:瞬态故障识别、退避重试与中文根因诊断的搭建方法
大数据·人工智能·ai·rust·数据分析·大模型·agent
信誓旦旦的程序猿33 分钟前
【Python量化实战宝典 #08】可转债与债券接口手册:转股价·溢价率·纯债价值(Python 可跑)
java·python·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
砚底藏山河38 分钟前
python量化:行情数据回溯
java·开发语言·python·金融·maven
今年下半年42 分钟前
AI智能体项目实战记录(02):初始化 Python 项目
开发语言·人工智能·python·fastapi
JXJD20041 小时前
224G PAM4 高速线束:阻抗匹配设计与损耗控制的核心逻辑
大数据·ai
Williamtym1 小时前
PickGo Lab实践:用浏览器、Python和MCP串起机器人搬运仿真
开发语言·python·机器人
misty youth1 小时前
Agent-智能体工程方法论
人工智能·ai·llm·agent·智能体
CS创新实验室1 小时前
Python 对象“死“了之后去了哪?——引用计数与分代垃圾回收
开发语言·jvm·python
CCblandy1 小时前
雪花 ID 四个边界实测:时钟回拨重号 500 个,前端 JSON.parse 直接丢精度
后端·python·算法·性能优化·架构