19b6cdcbd8
- Remove redundant status steps (understanding, preparing, generating) from SSE stream — only emit retrieved docs and reasoning content - ThinkingProcess: only show when there's actual reasoning or docs - Collapse header shows concise state: thinking count or doc count - Clean up unused icon imports Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
135 lines
4.6 KiB
Python
135 lines
4.6 KiB
Python
"""
|
||
LangChain 1.0 对话链(Normal Mode)
|
||
"""
|
||
from typing import List, Dict, Any, Optional
|
||
from langchain_core.runnables import RunnablePassthrough
|
||
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
||
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
|
||
from langchain_core.output_parsers import StrOutputParser
|
||
|
||
from ..llm.siliconflow import get_llm_client
|
||
|
||
|
||
class ConversationChain:
|
||
"""标准对话链(LangChain 1.0)"""
|
||
|
||
def __init__(
|
||
self,
|
||
system_prompt: Optional[str] = None,
|
||
model: Optional[str] = None
|
||
):
|
||
"""初始化对话链
|
||
|
||
Args:
|
||
system_prompt: 系统提示词
|
||
model: 可选的模型名称,如 deepseek-ai/DeepSeek-V3, Qwen/QwQ-32B
|
||
"""
|
||
_sf_client = get_llm_client(model=model)
|
||
self.llm = _sf_client.llm
|
||
self.client = _sf_client
|
||
self.system_prompt = system_prompt or "你是一个专业的国土空间规划知识问答助手。请基于你的知识回答用户的问题。"
|
||
|
||
# 创建带历史的Prompt模板
|
||
self.prompt = ChatPromptTemplate.from_messages([
|
||
SystemMessage(content=self.system_prompt),
|
||
MessagesPlaceholder(variable_name="chat_history"),
|
||
("human", "{question}")
|
||
])
|
||
|
||
# 创建对话链
|
||
self.chain = self._create_chain()
|
||
|
||
def _create_chain(self):
|
||
"""创建对话链"""
|
||
return (
|
||
self.prompt
|
||
| self.llm
|
||
| StrOutputParser()
|
||
)
|
||
|
||
def invoke(self, question: str, chat_history: List[Dict] = None) -> Dict[str, Any]:
|
||
"""同步调用"""
|
||
history_messages = self._format_history(chat_history or [])
|
||
answer = self.chain.invoke({
|
||
"question": question,
|
||
"chat_history": history_messages
|
||
})
|
||
|
||
return {
|
||
"answer": answer,
|
||
"sources": [],
|
||
"metadata": {
|
||
"mode": "normal",
|
||
"has_history": bool(chat_history)
|
||
}
|
||
}
|
||
|
||
async def ainvoke(self, question: str, chat_history: List[Dict] = None) -> Dict[str, Any]:
|
||
"""异步调用"""
|
||
history_messages = self._format_history(chat_history or [])
|
||
answer = await self.chain.ainvoke({
|
||
"question": question,
|
||
"chat_history": history_messages
|
||
})
|
||
|
||
return {
|
||
"answer": answer,
|
||
"sources": [],
|
||
"metadata": {
|
||
"mode": "normal",
|
||
"has_history": bool(chat_history)
|
||
}
|
||
}
|
||
|
||
async def astream_with_thinking(self, question: str, chat_history: List[Dict] = None):
|
||
"""流式调用(包含思考过程,捕获推理模型的真实推理内容)"""
|
||
import time
|
||
|
||
start_time = time.time()
|
||
history_messages = self._format_history(chat_history or [])
|
||
|
||
# 直接使用原始 OpenAI SDK 捕获推理内容
|
||
prompt_value = await self.prompt.ainvoke({
|
||
"question": question,
|
||
"chat_history": history_messages
|
||
})
|
||
prompt_messages = prompt_value.to_messages()
|
||
|
||
content_started = False
|
||
async for event_type, content in self.client.stream_with_reasoning(prompt_messages):
|
||
if event_type == "reasoning":
|
||
yield {"type": "thinking", "stage": "reasoning", "message": content}
|
||
elif event_type == "content":
|
||
if not content_started:
|
||
content_started = True
|
||
yield {"type": "chunk", "content": content}
|
||
|
||
# 完成
|
||
total_time = time.time() - start_time
|
||
yield {
|
||
"type": "complete",
|
||
"metadata": {
|
||
"total_time": round(total_time, 2)
|
||
}
|
||
}
|
||
|
||
def _format_history(self, chat_history: List[Dict]) -> List:
|
||
"""格式化聊天历史为LangChain消息格式"""
|
||
messages = []
|
||
for msg in chat_history:
|
||
if msg["role"] == "user":
|
||
messages.append(HumanMessage(content=msg["content"]))
|
||
elif msg["role"] == "assistant":
|
||
messages.append(AIMessage(content=msg["content"]))
|
||
return messages
|
||
|
||
|
||
def create_conversation_chain(system_prompt: Optional[str] = None, model: Optional[str] = None) -> ConversationChain:
|
||
"""创建对话链实例
|
||
|
||
Args:
|
||
system_prompt: 系统提示词
|
||
model: 可选的模型名称,如 deepseek-ai/DeepSeek-V3, Qwen/QwQ-32B
|
||
"""
|
||
return ConversationChain(system_prompt=system_prompt, model=model)
|