我其实只是想做一个能自动分析聊天软件上的信息,决定要不要在我打游戏或者睡觉的时候叫醒我的AI。
目前选用的是使用LangGraph/LangChain来进行开发。
虽然其实看不懂写得很笨蛋的Lang文档,但是体感上来说LangGraph应该是包含了Langchain的,至少使用条件,节点这些来判断比用Langchain写一个笨蛋路由要好得多,但为了能看懂笨蛋代码和实在懒得动了让AI自己动手写但自己能看懂,还是先从Langchain看比较好。
这里随手写一下踩到的坑:
1.结构化输出Structured output
Lang提供了两种结构化输出的方式,一种是通过类似工具调用的方式的ToolStrategy,另一种是llm提供方自行支持的ProviderStrategy,后者还没用过,只说前者。
不知道为什么有的模型即便支持工具调用但也做不到结构化输出,例如Qwen3.5 35B A3B,但是Qwen3.0 14B却能非常正确的结构化输出。
如果要进行结构化输出让AI回答问题,比较笨蛋参数比较少的AI会认为结构化输出时前面填表JSON已经把数据填了,从而把用户能看到的字段什么都不写或者只写一点内容,例如
class UserInfo(BaseModel):
"""用于存储用户信息"""
name: str = Field(description="用户名")
age: int = Field(description="用户年龄")
description: str = Field(description="用户描述")
location: str = Field(description="用户地区")
messages: str = Field(description="这里填写所有总结信息和你要对用户展示的信息,只有写在这里的信息能被用户看到")即便这样写了并通过description字段提醒了AI,但有时候AI还是会在messages字段留空,大概是他们无法理解前面的字段用户是看不到的,不过聪明的AI不会有这个问题。
2.流式传输
尽管在官方文档里他使用流式传输的写法是这样的,下面举例一个他官方说明的,获取llm上一刻在做什么的代码
from langchain.agents import create_agent
def get_weather(city: str) -> str:
"""Get weather for a given city."""
return f"It's always sunny in {city}!"
agent = create_agent(
model="gpt-5-nano",
tools=[get_weather],
)
for chunk in agent.stream(
{"messages": [{"role": "user", "content": "What is the weather in SF?"}]},
stream_mode="updates",
version="v2",
):
if chunk["type"] == "updates":
for step, data in chunk["data"].items():
print(f"step: {step}")
print(f"content: {data['messages'][-1].content_blocks}")输出结果应该是
step: model
content: [{'type': 'tool_call', 'name': 'get_weather', 'args': {'city': 'San Francisco'}, 'id': 'call_OW2NYNsNSKhRZpjW0wm2Aszd'}]
step: tools
content: [{'type': 'text', 'text': "It's always sunny in San Francisco!"}]
step: model
content: [{'type': 'text', 'text': 'It's always sunny in San Francisco!'}]尽管代码本身返回结果不会有什么问题,可是stream流式传输返回的是个元组,我也不知道为什么示例代码用键取值,不看返回来的变量到底是个什么真就不知道怎么办了
如果不把langgraph更新到最新版就会有上面的问题,如果版本不对这样写包包错的,更新后就没问题了
不知道后续写些什么,先就写到这里