StreamingAgentChatResponse
是 LlamaIndex 框架中用于处理流式聊天响应的核心类,特别适用于需要实时生成和传输 AI 回答的场景。
🧱 类定义与核心属性
该类是一个数据类(@dataclass
),其主要属性包括:
response: str
:最终生成的完整回答文本。sources: List[ToolOutput]
:回答中引用的工具输出或文档来源。source_nodes: List[NodeWithScore]
:与回答相关的节点信息,通常用于追踪信息来源。chat_stream
/achat_stream
:同步和异步的聊天响应生成器,用于逐步生成回答内容。queue
/aqueue
:用于存储生成的文本片段(tokens)的队列,实现流式输出。is_function: Optional[bool]
:指示当前消息是否为函数调用。is_done: bool
:标志聊天响应是否已完成。exception: Optional[Exception]
:在生成过程中捕获的异常信息。(docs.llamaindex.ai)
此外,该类还包含用于事件同步的属性,如 new_item_event
和 is_function_false_event
,以支持异步操作中的状态管理。
🔄 异步生成器方法:async_response_gen()
async_response_gen()
是 StreamingAgentChatResponse
类中的一个异步生成器方法,其主要功能是:
- 逐步生成回答内容的文本片段(tokens),实现流式输出。
- 在每次生成新的文本片段时,将其放入异步队列
aqueue
中,并通过事件new_item_event
通知消费者有新数据可用。 - 在生成过程中,如果遇到异常,会将异常信息存储在
exception
属性中,并通过队列传递给消费者。
该方法的设计使得前端可以实时接收和显示 AI 模型生成的内容,提升用户体验。
⚙️ 生成流程示例
以下是一个使用 StreamingAgentChatResponse
进行流式聊天响应的典型流程:
- 用户发送消息,例如:“什么是RAG技术?”
- 调用
chat_engine.astream_chat()
方法,返回一个StreamingAgentChatResponse
对象。 - 通过异步循环
async for token in response.async_response_gen():
获取生成的文本片段。 - 每获取一个文本片段,将其发送给前端进行实时显示。
- 在生成过程中,系统可能还会发送相关事件信息,如检索过程、思考过程等。
- 生成完成后,系统将完整的回答内容存储到聊天历史中,以供后续查询。
这种流式生成机制使得用户可以实时看到 AI 模型的生成过程,提升了交互的流畅性和透明度。
📚 参考资料
通过深入理解 StreamingAgentChatResponse
的结构和工作机制,可以更有效地构建和优化基于 LlamaIndex 的流式聊天应用。
这两个属性:
sources: List[ToolOutput]
source_nodes: List[NodeWithScore]
是 RAG(检索增强生成,Retrieval-Augmented Generation)流程中模型在生成回答之前或同时通过检索系统获取的关键引用信息。下面我用通俗语言 + 时间流程 + 示例来详细解释它们的来源、获取时间和作用。
🧠 简单理解:谁在什么时候找到了这些节点?
- “source_nodes” 是模型在回答前查过的文档内容。
- “sources” 是整理后、格式化好的引用信息,准备发给前端展示的。
🕒 整体流程(带时间线)
我们以 RAG 系统为例,用户问了一个问题:“什么是 RAG?”
步骤 1:用户发出问题
用户通过前端发送问题到后端,触发聊天请求。
response = await chat_engine.astream_chat(user_input, messages)
步骤 2:RAG 检索引擎开始工作
此时 chat_engine
会调用内部的 retrieval 模块,例如:
retrieved_nodes = retriever.retrieve(user_input)
这一步:
- 向向量数据库(如 Chroma、Weaviate、FAISS 等)发出查询。
- 通过问题的 embedding 找出与之最相似的文档片段(也称“节点”)。
✅ 这就是 source_nodes 的来源。
每个节点通常是一个 NodeWithScore
对象,例如:
NodeWithScore(
node=DocumentNode(
text="RAG 是一种结合检索和生成的 AI 技术。",
metadata={"file_name": "rag_paper.pdf"}
),
score=0.92
)
步骤 3:模型开始生成回答
接下来,生成模型(如 GPT)会拿着刚才检索到的这些节点(source_nodes
),作为上下文的一部分进行回答。
步骤 4:生成 sources
在回答快完成时,系统还会对用过的 source_nodes
做一个提炼:
sources = [ToolOutput.from_node(node) for node in source_nodes]
这些 ToolOutput
通常是前端可读、格式良好的结构,如:
{
"type": "sources",
"data": {
"nodes": [
{
"text": "RAG 是一种结合检索和生成的 AI 技术。",
"score": 0.92,
"metadata": {"file_name": "rag_paper.pdf"}
}
]
}
}
✅ 这就是 sources 的生成时机 —— 回答生成过程中或生成完毕前,用于前端展示引用文献。
🔍 举个完整例子
用户提问:
“什么是RAG?”
检索系统检索出两段文档片段:
source_nodes = [
NodeWithScore(
node={"text": "RAG 是一种结合检索与生成的技术。", "metadata": {"file_name": "rag_intro.pdf"}},
score=0.95
),
NodeWithScore(
node={"text": "它将外部知识库与大模型结合,提高了回答的准确性。", "metadata": {"file_name": "rag_paper.pdf"}},
score=0.88
)
]
然后系统将它们传给模型生成:
"RAG 是 Retrieval-Augmented Generation 的简称,是一种结合大语言模型和知识库的技术……"
最后,在返回给前端之前,系统把 source_nodes
转换成 sources
:
{
"type": "sources",
"data": {
"nodes": [
{
"text": "RAG 是一种结合检索与生成的技术。",
"score": 0.95,
"metadata": {"file_name": "rag_intro.pdf"}
},
...
]
}
}
✅ 总结
属性 | 数据来源 | 获取时间 | 作用 |
---|---|---|---|
source_nodes | 从向量数据库检索得到的原始文档节点 | 在调用模型前 | 供模型参考回答 |
sources | 从 source_nodes 生成的可展示引用信息 | 回答生成完成后 | 前端展示引用 |
如你在系统中看到的:
yield cls.convert_data({
"type": "sources",
"data": {"nodes": [SourceNodes.from_source_node(node).model_dump() for node in response.source_nodes]}
})
👉 最终前端就能看到一个 “引用来源” 区块,点击后能看到这段话来自哪里、哪篇文档、相关分数等。