基于LangChain框架搭建对话式表单系统(附源码)

1. 背景与需求分析

在智能化服务日益普及的今天,传统的表单填写方式已难以满足用户对交互体验的高要求。对话式表单系统通过自然语言交互,能够显著提升用户体验,尤其适用于:

  • 复杂表单的逐步引导填写
  • 移动端受限场景下的数据采集
  • 老年人或儿童友好型交互界面
  • 客户服务中的信息收集场景

LangChain框架凭借其强大的链式调用能力和多模型集成特性,为构建对话式表单系统提供了理想解决方案。本文将详细介绍如何基于LangChain实现一个完整的对话式表单系统。

2. 系统架构设计

2.1 核心组件

用户输入
意图识别
字段是否完整?
字段提问生成
LLM响应生成
答案解析
表单更新
表单提交

2.2 技术选型

组件技术方案备选方案
框架核心LangChainRasa, Dialogflow
大语言模型DeepSeek/QianfanGPT-4, Claude
表单定义Pydantic模型JSON Schema
持久化存储SQLite/内存MongoDB

3. 核心实现代码

3.1 表单模型定义

from pydantic import BaseModel, Field
from typing import Optional, Dict, Any, Type

from lang_chain_base.tools.search_tool import RobustJsonParser


class BaseDialogModel(BaseModel):
    """对话式表单基类"""

    def get_empty_fields(self) -> Dict[str, str]:
        """获取未填写的字段及其描述"""
        return {
            name: field.description
            for name, field in type(self).model_fields.items()
            if getattr(self, name) is None or getattr(self, name) == ""
        }

    def update_from_model(self, other: 'BaseDialogModel') -> None:
        """
        从另一个 BaseModel 实例更新当前实例的字段值
        :param other: 另一个 UserModel 实例
        """
        for field_name in type(self).model_fields.keys():
            value = getattr(other, field_name)
            if value is not None:
                setattr(self, field_name, value)

    def is_complete(self) -> bool:
        """检查表单是否填写完整(所有非可选字段均有值)"""
        for name, field in type(self).model_fields.items():
            # 检查字段值是否为 None
            value = getattr(self, name)
            if value is None or value == "":
                return False
        return True


# 示例:用户信息收集表单
class UserInfoForm(BaseDialogModel):
    name: Optional[str] = Field(None, description="您的姓名")
    age: Optional[int] = Field(None, description="年龄")
    gender: Optional[str] = Field(None, description="性别(男/女/其他)")
    email: Optional[str] = Field(None, description="电子邮箱")
    address: Optional[str] = Field(None, description="居住地址")

3.2 对话管理核心

from langchain_core.language_models import BaseLanguageModel
from langchain_core.prompts import PromptTemplate
from langchain.chains import LLMChain
import json


class DialogFormManager:
    def __init__(self, llm: BaseLanguageModel, typeForm: type[BaseDialogModel]):
        self.llm = llm
        self.typeForm = typeForm
        self.setup_chains()

    def setup_chains(self):
        """初始化对话链"""
        # 字段提问生成链
        self.ask_chain = LLMChain(
            llm=self.llm,
            prompt=PromptTemplate.from_template(
                "您需要收集以下信息,请用自然语言提问获取其中一个缺失字段的值:"
                "缺失字段: {empty_fields}\n"
                "请只输出问题,不要包含其他文字。"
            )
        )

        # 答案解析链
        self.parse_chain = LLMChain(
            llm=self.llm,
            prompt=self._generate_prompt_from_model(self.typeForm)
        )

    def _generate_prompt_from_model(self,model: Type[BaseDialogModel]) -> PromptTemplate:
        """从 Pydantic 模型自动生成 PromptTemplate(包含字段描述和示例 JSON)"""
        field_descriptions = []
        example_data: Dict[str, Any] = {}

        # 提取字段名、描述,并生成示例值
        for field_name, field_info in model.model_fields.items():
            description = field_info.description or "无描述"
            field_descriptions.append(field_name + ":" + description)

        # 构建 PromptTemplate
        fields_str = "\n".join(field_descriptions)
        template = f"""
        请从以下文本'{{user_input}}'中提取信息,并返回严格的 JSON 格式:

        字段说明:
        {fields_str}    

        注意:若输入文本不包含某字段,则JSON中不返回该字段

        """

        return PromptTemplate(input_variables=["input_text"], template=template)

    def generate_question(self, empty_fields: Dict[str, str]) -> str:
        """生成下一个提问"""
        prompt_input = {
            "empty_fields": json.dumps(list(empty_fields.values()), ensure_ascii=False)
        }
        print("📝 生成问题提示词:")
        print(self.ask_chain.prompt.format(**prompt_input))
        return self.ask_chain.invoke(prompt_input)['text']

    def parse_answer(self, user_input: str) -> Optional[BaseDialogModel]:
        """从对话中解析特定字段的值"""
        try:
            prompt_input = {
                "user_input": user_input
            }
            # print("📝 用户信息转换为LLM 的提示词:")
            # print(self.parse_chain.prompt.format(**prompt_input))
            result = self.parse_chain.invoke(prompt_input)
            # print("LLM 解析结果:", result)
            return RobustJsonParser.parseToModel(result['text'], self.typeForm)
        except:
            return None

3.3 完整对话系统

class ConversationalFormSystem:
    def __init__(self, form_model: type[BaseDialogModel], llm: BaseLanguageModel):
        self.form_model = form_model()
        self.manager = DialogFormManager(llm, form_model)
        self.dialog_history = []

    def run(self):
        """
        对话式表单运行
        :return:
        """
        print("对话式表单系统已启动(输入'退出'结束对话)")
        # 模拟对话流程
        while True:
            if self.form_model.is_complete():
                self._handle_complete()
                break
            question = self._generate_next_question()
            print(question)
            # 获取用户输入
            user_answer = input("您的回答: ").strip()
            if user_answer == "退出":
                print("当前填写进度:", self.form_model.model_dump())
                break
            user_input = f"{question} {user_answer}"
            print("输入的问题:", user_input)
            self._process_answer(user_input)

    def _generate_next_question(self) -> str:
        """生成下一个问题"""
        empty_fields = self.form_model.get_empty_fields()
        question = self.manager.generate_question(empty_fields)
        self.dialog_history.append(f"系统: {question}")
        return question

    def _process_answer(self, user_input: str) -> None:
        """处理用户回答"""
        # 记录对话历史
        self.dialog_history.append(f"用户: {user_input}")

        new_model = self.manager.parse_answer(
            user_input
        )
        if new_model:
            self.form_model.update_from_model(new_model)
        else:
            print("⚠️ 解析失败,请重新回答!")

    def _handle_complete(self) -> str:
        """处理表单完成"""
        result = json.dumps(self.form_model.model_dump(), ensure_ascii=False)
        self.dialog_history.append(f"系统: 表单收集完成: {result}")
        print("信息收集完成!",result)

4. 系统演示与效果

4.1 演示代码

if __name__ == "__main__":
    from lang_chain_base.chat_models.model_language import getLLM

    # 初始化系统(使用DeepSeek模型)
    llm = getLLM("deepseek")
    form_system = ConversationalFormSystem(UserInfoForm, llm)
    form_system.run()

4.2 实际对话示例

对话式表单系统已启动(输入'退出'结束对话)
 
系统: 您需要收集以下信息,请用自然语言提问获取其中一个缺失字段的值:["您的姓名", "年龄(数字)", "性别(男/女/其他)", "电子邮箱", "居住地址"]
 
您的回答: 请问您的姓名是?
用户: 张三
 
系统: 您需要收集以下信息,请用自然语言提问获取其中一个缺失字段的值:["年龄(数字)", "性别(男/女/其他)", "电子邮箱", "居住地址"]
 
您的回答: 您今年多大了?
用户: 30岁
 
系统: 您需要收集以下信息,请用自然语言提问获取其中一个缺失字段的值:["性别(男/女/其他)", "电子邮箱", "居住地址"]
 
您的回答: 您的性别是?
用户: 男
 
系统: 您需要收集以下信息,请用自然语言提问获取其中一个缺失字段的值:["电子邮箱", "居住地址"]
 
您的回答: 您的邮箱是?
用户: zhangsan@example.com
 
系统: 您需要收集以下信息,请用自然语言提问获取其中一个缺失字段的值:["居住地址"]
 
您的回答: 您住在哪里?
用户: 北京市海淀区
 
系统: 信息收集完成!
{"name":"张三","age":30,"gender":"男","email":"zhangsan@example.com","address":"北京市海淀区"}

5. 高级功能扩展

5.1 多轮对话历史管理

class EnhancedDialogManager(DialogFormManager):
    def __init__(self, llm: BaseLanguageModel, memory_size: int = 5):
        super().__init__(llm)
        self.memory_size = memory_size
        self.short_term_memory = []
    
    def get_relevant_history(self, current_field: str) -> str:
        """获取相关对话历史"""
        # 只保留最近的记忆片段
        relevant = [h for h in self.short_term_memory 
                  if current_field in h.lower()]
        return "\n".join(relevant[-self.memory_size:])
    
    def enhanced_parse(self, field_name: str, user_input: str) -> Optional[str]:
        """增强版答案解析"""
        context = self.get_relevant_history(field_name)
        prompt = PromptTemplate.from_template(
            "你正在从对话中提取特定信息。以下是相关对话历史和当前用户输入:\n"
            "历史对话:\n{context}\n"
            "当前输入: {user_input}\n"
            "请提取{field_name}的值,如果没有则返回'无'。"
        )
        chain = LLMChain(llm=self.llm, prompt=prompt)
        result = chain.invoke({
            "context": context,
            "user_input": user_input,
            "field_name": field_name
        })
        return result['text'].strip()

6. 性能优化与最佳实践

6.1 提示词工程优化

# 优化后的提问生成提示词
OPTIMIZED_ASK_PROMPT = """
你是一位专业的访谈者,需要收集用户信息。以下是待收集的字段信息:
{field_descriptions}
 
已收集的信息:
{collected_data}
 
请用友好自然的方式提出下一个问题,要求:
1. 每次只问一个字段
2. 问题要清晰明确
3. 避免重复提问
4. 使用口语化表达
 
当前最合适的字段是:{suggested_field}
请根据以上信息生成问题(不需要问候语):
"""
 
# 优化后的解析提示词
OPTIMIZED_PARSE_PROMPT = """
你是一位专业的信息提取专家,需要从对话中提取特定字段的值。
 
字段定义:
{field_description}
 
对话历史(相关部分):
{relevant_history}
 
用户最新输入:
{user_input}
 
请严格按照以下JSON格式返回提取结果:
{{
    "{field_name}": "提取的值",
    "confidence": "置信度(高/中/低)",
    "reason": "判断依据"
}}
 
如果没有找到有效值,confidence应为"低",value返回。
"""

6.2 缓存与会话管理

from functools import lru_cache
import pickle
import os
 
class CachedDialogSystem:
    def __init__(self, system: ConversationalFormSystem, cache_dir: str = ".dialog_cache"):
        self.system = system
        self.cache_dir = cache_dir
        os.makedirs(cache_dir, exist_ok=True)
    
    def _get_cache_key(self, session_id: str) -> str:
        return os.path.join(self.cache_dir, f"{session_id}.pkl")
    
    def save_session(self, session_id: str):
        """保存会话状态"""
        with open(self._get_cache_key(session_id), "wb") as f:
            state = {
                "form_model": self.system.form_model.model_dump(),
                "dialog_history": self.system.dialog_history
            }
            pickle.dump(state, f)
    
    def load_session(self, session_id: str) -> bool:
        """加载会话状态"""
        cache_file = self._get_cache_key(session_id)
        if not os.path.exists(cache_file):
            return False
            
        with open(cache_file, "rb") as f:
            state = pickle.load(f)
            self.system.form_model.update_from_dict(state["form_model"])
            self.system.dialog_history = state["dialog_history"]
            return True
    
    @lru_cache(maxsize=100)
    def cached_generate_question(self, empty_fields: tuple) -> str:
        """带缓存的问题生成"""
        return self.system.manager.generate_question(dict(empty_fields))

7. 总结与展望

本文详细介绍了基于LangChain框架构建对话式表单系统的完整方案,从基础实现到高级功能扩展,涵盖了:

  1. 核心架构设计:基于Pydantic的表单模型定义
  2. 对话管理:多轮对话状态维护
  3. 智能解析:利用LLM从自然语言中提取结构化信息
  4. 增强功能:对话历史管理、字段验证、性能优化

7.1 实际应用建议

  1. 模型选择:
    • 对准确性要求高的场景:使用GPT-4或Claude
    • 成本敏感场景:使用国产模型(DeepSeek、Qianfan等)
    • 私有部署场景:考虑Llama2或ChatGLM
  2. 领域适配:
    • 医疗领域:添加专业术语校验
    • 金融领域:强化数据隐私保护提示
    • 教育领域:简化问题表述
  3. 性能优化:
    • 对高频字段使用专用解析器
    • 实现冷热数据分离的缓存策略
    • 添加用户输入预处理(纠错、意图识别)

7.2 未来发展方向

  1. 多模态交互:集成语音识别和TTS实现全双工对话
  2. 主动学习:根据用户反馈自动优化提问策略
  3. 情感计算:识别用户情绪调整对话策略
  4. 多语言支持:添加国际化能力

通过本文介绍的方案,开发者可以快速构建出高效、灵活的对话式表单系统,显著提升用户体验和数据收集效率。完整代码已开源,欢迎读者根据实际需求进行修改和扩展。
链接: 基于langchain实现AI智能对话式表单

### 使用 LangChain 框架实现本地数据库 RAG LangChain 是一种强大的工具,用于构建复杂的自然语言处理应用程序。它支持多种模式,其中 RAG(检索增强生成)是一种结合了信息检索和生成模型的方法[^1]。以下是关于如何使用 LangChain 实现本地数据库 RAG 的详细介绍。 #### 1. 安装依赖项 为了运行基于 LangChain 的 RAG 应用程序,首先需要安装必要的库: ```bash pip install langchain openai faiss-cpu tiktoken unstructured ``` 上述命令会安装 `langchain`、`openai`(或其他 LLM 提供商)、`faiss-cpu`(向量存储引擎),以及一些辅助库。 --- #### 2. 数据准备与加载 在 RAG 中,数据通常被转换为嵌入形式并存储到向量数据库中。以下是一个简单的例子,展示如何将 PDF 文件中的内容加载到内存并向量化。 ```python from langchain.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter # 加载 PDF 文档 loader = PyPDFLoader("./example.pdf") # 替换为你自己的文件路径 pages = loader.load_and_split() # 将文档分割成较小的部分以便于索引 text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200) texts = text_splitter.split_documents(pages) print(f"Total chunks generated: {len(texts)}") ``` 此部分代码负责从指定的 PDF 文件中读取文本,并将其拆分为更小的片段以提高效率[^5]。 --- #### 3. 向量化与存储 接下来,我们需要将这些文本块转化为高维空间中的向量表示,并存入向量数据库中。 ```python from langchain.embeddings.openai import OpenAIEmbeddings from langchain.vectorstores import FAISS embeddings_model = OpenAIEmbeddings() # 或者替换为 HuggingFaceEmbeddings 等其他模型 db = FAISS.from_documents(texts, embeddings_model) # 存储到磁盘上 db.save_local("faiss_index") # 如果已有索引,则可以重新加载 existing_db = FAISS.load_local("faiss_index", embeddings_model) ``` 这里展示了如何利用 OpenAI Embedding API 创建向量表示并将它们保存至本地文件夹中。FAISS 是一个高效的开源库,专门设计用来执行相似度搜索操作[^4]。 --- #### 4. 查询接口设置 最后一步是定义查询逻辑,允许用户输入问题并通过检索机制找到最相关的上下文材料。 ```python from langchain.chains.question_answering import load_qa_chain from langchain.llms import OpenAI def query_database(query_text): docs = db.similarity_search(query_text, k=3) # 返回前三个匹配的结果 llm = OpenAI(temperature=0) # 初始化大语言模型实例 chain = load_qa_chain(llm, chain_type="stuff") response = chain.run(input_documents=docs, question=query_text) return response query_result = query_database("请解释一下这个主题的核心要点是什么?") print(query_result) ``` 以上脚本实现了基本的功能流程:先调用 `similarity_search()` 方法获取最近邻节点;再把这些作为加背景传递给预设好的对话链路完成最终的回答生成过程[^3]。 --- ### 总结 通过上述步骤可以看出,在 LangChain 上面建立一套完整的 RAG 流程相对简单明了。不仅能够充分利用现有的大型预训练模型资源,而且还能灵活定制满足实际业务需求的具体方案[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值