LangChain 智能体创建与配置详解
答辩回答(建议):
本系统使用 LangChain 框架构建字段匹配智能体,具体实现包含三个关键步骤:创建 ChatOpenAI 实例、配置 Agent、编写 Prompt。
一、创建 ChatOpenAI 实例
系统通过 ChatOpenAI 类连接阿里云百炼平台(兼容 OpenAI API 格式)的通义千问模型。创建时主要配置以下参数:
| 参数 | 设置值 | 作用 |
|---|---|---|
model | qwen-turbo | 指定使用的模型名称 |
api_key | 从环境变量读取 | 身份认证,调用 API 的凭证 |
base_url | https://dashscope.aliyuncs.com/compatible-mode/v1 | API 服务地址,指向阿里云百炼平台 |
temperature | 0.1 | 控制输出随机性,值越低越稳定 |
max_tokens | 2048 | 限制模型生成的最大 token 数,控制响应长度 |
二、create_agent 函数的主要参数
| 参数 | 在本系统中的设置 | 作用 |
|---|---|---|
model | ChatOpenAI 实例 | 指定智能体使用的大模型 |
tools | [analyze_source_columns, analyze_target_fields] | 注册工具列表,让模型能调用这些函数获取信息 |
system_prompt | 自定义的系统指令文本 | 定义智能体的角色、任务目标和行为规范 |
三、Prompt 的编写方式
系统提示词(system_prompt)采用结构化指令的方式编写,核心内容包括:
- 角色定义:明确模型扮演“专业的数据映射专家”。
- 任务说明:要求模型比较源数据列和目标表单字段,找出语义对应关系。
- 步骤要求:强制模型先调用工具(分析源列、分析目标字段),再推理。
- 输出格式约束:要求返回严格的 JSON 对象,包含
recommended_mapping、confidence_scores、unmapped_source、unmapped_target四个字段。 - 行为约束:只映射有明确对应关系的字段;置信度表示确信程度;结果必须是合法 JSON,不含额外解释文字。
用户消息(context)只提供概述(如“源数据表有 X 列,目标表单有 Y 个字段”),不包含具体数据,强制模型主动调用工具获取详细信息。
四、关键函数的参数说明
在 Agent 和工具函数中,以下参数最为关键:
| 函数 | 关键参数 | 作用 |
|---|---|---|
analyze_source_columns | source_columns, source_sample, source_types | 接收源列名、示例数据、类型信息,整理后返回给模型 |
analyze_target_fields | target_columns, target_labels, target_types, target_sample | 接收目标字段信息,整理后返回给模型 |
agent.invoke / invoke | messages(包含 system 和 user 消息)、config(如 recursion_limit) | 执行智能体,发送消息并接收模型响应 |
RunnableConfig | recursion_limit | 控制 Agent 执行的最大递归/调用次数,防止死循环 |
总结:通过合理设置 ChatOpenAI 的参数(尤其是低 temperature 保证稳定性),为 Agent 注册专用工具,编写明确的结构化提示词,本系统实现了稳定、可控的字段匹配智能体。模型会先调用工具获取源数据和目标表单的特征,再推理输出带置信度的 JSON 映射结果,失败时自动降级到规则匹配。
各模块关键函数/方法清单(答辩参考)
以下是本系统中每个核心模块使用的最关键函数/方法,按模块列出。答辩时如果老师问“你怎么实现某个功能的”,可以说“我调用了xxx函数,它做了xxx”。不需要背诵参数细节,能说清作用即可。
一、数据接入模块
| 函数/方法 | 所属技术 | 作用说明 |
|---|---|---|
pd.read_excel() | Pandas | 读取用户上传的 Excel 文件,返回 DataFrame |
pd.read_csv() | Pandas | 读取 CSV 文件(导出时使用) |
pd.DataFrame() | Pandas | 创建内存中的二维表格结构,统一存储源数据 |
pd.read_html() | Pandas | 尝试从静态网页中提取 <table> 表格 |
driver.get(url) | Selenium | 驱动浏览器访问指定 URL,用于动态网页表格抓取 |
WebDriverWait() | Selenium | 等待页面元素加载完成,防止因渲染延迟导致提取失败 |
实现了什么功能:将 Excel、SQL 文件、网页表格三种异构数据源统一转换为 Pandas DataFrame,便于后续处理。
二、数据清洗模块
| 函数/方法 | 所属技术 | 作用说明 |
|---|---|---|
df.columns.str.strip() | Pandas | 去除列名首尾空格 |
df.dropna(how='all') | Pandas | 删除全为空值的行 |
df.drop_duplicates() | Pandas | 删除完全重复的行 |
df.select_dtypes(include=['object']) | Pandas | 筛选出所有文本类型的列(字符串列) |
df[col].str.replace() | Pandas | 将字符串列中的特殊字符或多余空格替换掉 |
re.sub() | Python re | 用正则表达式清洗每个单元格内的文本(如移除控制字符) |
实现了什么功能:自动清理列名、删除备注行和空行、去除重复行、标准化字符串列(去特殊字符、合并空白),输出干净规整的 DataFrame。
三、目标表单解析模块
| 函数/方法 | 所属技术 | 作用说明 |
|---|---|---|
driver.find_elements(By.TAG_NAME, "form") | Selenium | 找出页面中所有 <form> 元素 |
element.find_elements(By.CSS_SELECTOR, "input, select, textarea") | Selenium | 遍历表单内的所有输入控件 |
element.get_attribute("name") / "id" / "placeholder" | Selenium | 获取控件的 name、id、placeholder 属性 |
element.tag_name | Selenium | 判断当前控件是 input、select 还是 textarea |
element.get_attribute("type") | Selenium | 获取 input 的具体类型(text、radio、checkbox 等) |
driver.find_element(By.XPATH, f"//label[@for='{id}']") | Selenium | 通过 for 属性找到与控件关联的 <label> 标签文本 |
实现了什么功能:提取目标网页表单中每个字段的字段名(name)、显示标签(label)、控件类型(type)、下拉框选项列表等信息,返回结构化数据供前端展示和后续匹配。
四、字段智能匹配模块
| 函数/方法 | 所属技术 | 作用说明 |
|---|---|---|
ChatOpenAI(model=..., temperature=...) | LangChain | 创建大模型客户端实例,连接通义千问 |
@tool 装饰器 | LangChain | 将普通函数(如 analyze_source_columns)标记为模型可调用的工具 |
create_agent(model, tools, system_prompt) | LangChain | 创建智能体,绑定模型和工具,设置系统指令 |
agent.invoke({"messages": [...]}) | LangChain | 执行智能体,发送对话消息,获取模型回复 |
json.loads() | Python json | 将模型返回的字符串解析成 JSON 对象,提取映射结果 |
实现了什么功能:让大模型“先调用工具获取源数据和目标字段信息,再推理输出带置信度的字段映射 JSON”。如果大模型调用失败或解析出错,自动降级为子串匹配。
五、选项匹配模块(自动填充中用到)
| 函数/方法 | 所属技术 | 作用说明 |
|---|---|---|
dashscope.Generation.call() | DashScope | 直接调用通义千问 API,不使用 LangChain,用于快速匹配下拉框选项 |
re.split(r'[、,;,;\s]+', value) | Python re | 将源数据值拆分成多个子项(如“男,女”拆成两个) |
difflib.SequenceMatcher() | Python difflib | 计算两个字符串的相似度(降级时使用) |
实现了什么功能:对于下拉框、单选/复选框,系统需要将源数据中的值(如“男”)匹配到选项的实际 value(如“1”)。先用大模型直接匹配,失败则用同义词扩展和编辑距离降级。
六、自动填充模块
| 函数/方法 | 所属技术 | 作用说明 |
|---|---|---|
webdriver.Firefox() | Selenium | 启动 Firefox 浏览器驱动 |
driver.get(url) | Selenium | 让浏览器打开目标网页 |
driver.find_element(By.NAME, name) | Selenium | 按 name 属性定位输入框(第一优先级) |
element.clear() | Selenium | 清空输入框原有内容 |
element.send_keys(value) | Selenium | 向输入框中填入文本值 |
Select(element).select_by_visible_text(text) | Selenium | 在下拉框中按可见文本选中选项 |
element.click() | Selenium | 点击单选按钮、复选框或提交按钮 |
time.sleep() | Python time | 适当等待,避免操作过快导致页面未响应 |
实现了什么功能:按用户确认的映射关系,驱动真实浏览器逐个字段填充数据,支持文本框、下拉框、单选/复选框。每条记录填充后保持浏览器打开供用户检查。
七、后端接口模块(FastAPI)
| 函数/方法 | 所属技术 | 作用说明 |
|---|---|---|
@app.post("/api/source/preview") | FastAPI | 定义 POST 接口,接收前端上传的源数据文件或 URL |
@app.get("/api/target/preview") | FastAPI | 定义 GET 接口,接收目标表单 URL 参数 |
@app.post("/api/mapping/recommend") | FastAPI | 定义 POST 接口,接收源列和目标字段信息,返回映射推荐 |
@app.post("/api/fill/execute") | FastAPI | 定义 POST 接口,接收最终映射和 URL,执行填充 |
@app.get("/api/export") | FastAPI | 定义 GET 接口,根据参数返回 Excel 或 CSV 文件 |
FileResponse() | FastAPI | 将临时文件返回给前端下载,并自动清理 |
实现了什么功能:提供 RESTful API 作为前后端桥梁,处理所有业务逻辑请求,返回 JSON 数据或文件。
八、前端界面模块(Vue.js)
| 函数/方法 | 所属技术 | 作用说明 |
|---|---|---|
createApp() | Vue | 创建 Vue 应用实例 |
ref() / reactive() | Vue | 定义响应式数据(如源数据预览、映射列表、填充结果) |
v-if / v-else | Vue 模板指令 | 根据条件显示/隐藏组件(实现步骤化引导) |
v-for | Vue 模板指令 | 循环渲染映射表格的每一行 |
v-model | Vue 模板指令 | 双向绑定下拉框的值,用户修改映射时自动更新数据 |
axios.post(url, data) | axios | 向后端发送 POST 请求,携带文件或 JSON |
axios.get(url, { params }) | axios | 向后端发送 GET 请求,携带查询参数 |
实现了什么功能:提供可视化操作界面,包括文件上传、数据预览、映射表格(含置信度颜色和手动修正)、填充执行和结果导出。通过 v-if 实现步骤化引导(只有前置条件满足才显示下一步按钮)。
总结:以上函数/方法覆盖了数据接入、清洗、匹配、填充、前后端通信和界面交互的完整流程。答辩时如果老师询问具体实现,可以从这张表中挑选对应函数说明其作用即可,无需展示代码细节。