""" 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)