文章目录
langchain1.2的又一大新特性。
监听事件要点
1、要用.astream_event()方法来调用。
2、循环要用asycn for来循环 # 否则捕捉不到event
示例
新建python文件event_demo,代码:
python
import asyncio
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
import os
API_KEY = os.getenv("DASHSCOPE_API_KEY", "YOUR API KEY")
print(f"🔍 代码读取到的API_KEY:{API_KEY}")
llm = ChatOpenAI(
api_key=API_KEY, # 替换为你的实际 Key (sk-...)
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
model="qwen-plus"
)
prompt = ChatPromptTemplate.from_template("讲一个关于{topic}的短笑话")
parser = StrOutputParser()
# 2. 构建链 (LCEL)
chain = prompt | llm | parser
# 3. 定义异步主函数
async def main():
print("🚀 开始流式监听事件...\n")
# astream_events 是核心方法
# version="v2" 是 LangChain 1.0+ 推荐的事件流版本
async for event in chain.astream_events({"topic": "程序员"}, version="v2"):
# 事件类型 (kind) 决定了当前发生了什么
kind = event["event"]
# --- 场景 A: 模型开始生成内容 (流式打字机效果) ---
if kind == "on_chat_model_stream":
# 获取模型生成的文字片段
content = event["data"]["chunk"].content
# 实时打印,end="" 防止换行,flush=True 确保立即显示
print(content, end="", flush=True)
# --- 场景 B: 链/工具开始执行 (用于显示状态) ---
elif kind == "on_chain_start":
name = event.get("name")
if name:
print(f"\n\n🔍 [系统] 开始执行: {name}")
# --- 场景 C: 链/工具执行结束 ---
elif kind == "on_chain_end":
print(f"\n✅ [系统] 执行完毕")
# 4. 运行
if __name__ == "__main__":
asyncio.run(main())
输出结果:
python
🔍 代码读取到的API_KEY:sk-e49bdf8d737549ffb6269b63bcff8a7a
🚀 开始流式监听事件...
🔍 [系统] 开始执行: RunnableSequence
当然可以!😄
**笑话:**
程序员去咖啡馆点单。
服务员:"您好,请问要什么?"
程序员:"我要一杯咖啡,不加糖,不加奶,不加冰,不加盖,不加吸管......等等,先别下单------我得先 `git status` 一下,确认自己没在 `develop` 分支上点单。"
服务员:"......您确定要的是咖啡,不是 `coffee.exe` 的调试日志?"
(停顿两秒)
程序员叹了口气:"算了,还是 `git checkout -- coffee_order` 吧......我刚刚好像把'加糖'改成了'删糖'。"
☕️
*------毕竟,人生最大的 bug,往往不是逻辑错误,而是需求没写清楚。*
需要再来一个(比如 Python 版/前端版/摸鱼版)? 😄
✅ [系统] 执行完毕
解读:
支持哪些事件
也可以从chain.astream_events()这个方法跟代码跟进去查看,往下滑几行就是。
如下图:
事件名称 (event) |
触发时机 | 关键数据 (event["data"]) |
典型用途 |
|---|---|---|---|
on_chat_model_start |
模型接收到请求,准备开始推理时 | input: 包含消息列表 (messages) |
记录请求参数,统计 Token 消耗前的准备 |
on_chat_model_stream |
模型生成新 Token 时 (高频触发) | chunk: 包含新生成的文本片段 (AIMessageChunk) |
打字机效果,实时显示 AI 回答 |
on_chat_model_end |
模型完成所有推理,返回最终结果时 | output: 完整的 AI 回复对象 |
统计总耗时,获取完整的回复内容 |
on_tool_start |
Agent 决定调用某个工具时 | input: 工具调用的参数 (JSON) |
显示"正在调用搜索工具...",展示工具参数 |
on_tool_end |
工具执行完毕,返回结果给 Agent 时 | output: 工具返回的原始数据 |
显示工具执行结果,调试工具调用逻辑 |
on_chain_start |
任意链 (Chain) 或自定义组件开始时 | input: 输入数据 |
追踪复杂链的执行进度 |
on_chain_stream |
链中的组件产生流式输出时 | chunk: 中间产生的数据块 |
监听中间步骤的流式数据 |
on_chain_end |
链或组件执行结束时 | output: 该步骤的最终输出 |
确认步骤完成,获取中间结果 |
on_retriever_start |
检索器 (RAG) 开始查找文档时 | input: 查询语句 (query) |
显示"正在知识库中搜索..." |
on_retriever_end |
检索器返回文档列表时 | output: 找到的文档列表 (Documents) |
展示参考来源,调试检索质量 |
on_prompt_start |
提示词模板开始填充变量时 | input: 原始变量值 |
调试 Prompt 模板是否正确接收了变量 |
on_prompt_end |
提示词构建完成,准备发给模型时 | output: 构建好的 Prompt 对象 |
查看最终发送给 LLM 的完整 Prompt |
astream_event()方法为什么没有return呢?
好问题,就是没有return,因为它不是一个常规方法,而是一个生成器。