LangGraph:官方文档 Custom SQL agent 示例的小bug

5 阅读3分钟

本示例来自官方文档 Build a custom SQL agent - Docs by LangChain

主要问题出在了Implement human-in-the-loop review 一节。问题不是逻辑处理部分,而是输出逻辑。主要症状是没有如预期般打印出INTERRUPTED:开头的日志。

请先观察大模型调用的输出逻辑:

import json

config = {"configurable": {"thread_id": "1"}}

question = "Which genre on average has the longest tracks?"

for step in agent.stream(
    {"messages": [{"role": "user", "content": question}]},
    config,
    stream_mode="values",
):
    if "messages" in step:
        step["messages"][-1].pretty_print()
    elif "__interrupt__" in step:
        action = step["__interrupt__"][0]
        print("INTERRUPTED:")
        for request in action.value:
            print(json.dumps(request, indent=2))
    else:
        pass

看起来没啥问题,但是呢,代码中第16行,就是没有正常打印INTERRUPTED

排查过程

一开始就怀疑是否自己示例代码抄错了,由于这部分示例是基于前几步的代码改造来的,于是就认真的检查了一下代码,还真给检查出来两点:

  1. 新方法run_query_tool_with_interrupt 构造了新的 node,用来代替之前的 sql_db_query node。这一步本来不会有什么问题,因为对象会被覆盖,为了保险一些,还是把它注掉了。
  2. 当检查构建graph的步骤时发现,由 check_queryrun_query 的边没有了。但是官方文档并没有给出删除的指示。

除了这些其他都一模一样了,于是就信心满满的继续运行。

还是出意外了,依然没有打印出预期中的INTERRUPTED

到这里基本进入死胡同了,唯一可以怀疑的就是,是否是这种中断写法有问题。

刚好文档中给出了中断参考链接 Interrupts - Docs by LangChain

排查中断写法

这种怀疑确实有些大胆,但是呢,死马当活马医吧。

于是就硬着头皮看吧,看了老半天,并且把其中的几个示例跑了一遍。

还好,这几个示例没有问题,都正常跑了。

最后,得出结论:中断的写法没问题。

最后的办法

实在没办法了,还是调试看看具体是怎么输出的吧。这么一调试,终于发现了其中的猫腻。原来是在输出的判断逻辑上。

原因

step对象有 message 时,不一定有 __interrupt__,而发生了中断时,有__interrupt__时,仍然有 message。就导致了,发生中断时,走不到elif分支。

不仅如此,而且还会导致 message 重复打印,比如下面这样,可以看到 id是相同的,都是 6c6a5c6169654fcabe9de3467aea8540

================================== Ai Message ==================================
Tool Calls:
  sql_db_query (chatcmpl-tool-6c6a5c6169654fcabe9de3467aea8540)
 Call ID: chatcmpl-tool-6c6a5c6169654fcabe9de3467aea8540
  Args:
    query: SELECT Genre.Name, AVG(Track.Milliseconds) AS AvgLength FROM Track JOIN Genre ON Track.GenreId = Genre.GenreId GROUP BY Genre.GenreId ORDER BY AvgLength DESC LIMIT 5;
================================== Ai Message ==================================
Tool Calls:
  sql_db_query (chatcmpl-tool-6c6a5c6169654fcabe9de3467aea8540)
 Call ID: chatcmpl-tool-6c6a5c6169654fcabe9de3467aea8540
  Args:
    query: SELECT Genre.Name, AVG(Track.Milliseconds) AS AvgLength FROM Track JOIN Genre ON Track.GenreId = Genre.GenreId GROUP BY Genre.GenreId ORDER BY AvgLength DESC LIMIT 5;

解决

找到了原因,解决就很好办,调整一下判断的先后顺序即可。代码就不贴出来了。

解决了这个问题后,从中断恢复的示例也正常执行了。到此,这个Custom SQL agent示例就跑通了。

参考

Build a custom SQL agent - Docs by LangChain

Interrupts - Docs by LangChain