当前位置: 首页 > news >正文

实现自己的AI视频监控系统-第四章-基于langchain的AI大模型与智能体应用2

文章目录

  • 前言
  • 一、需求分析
  • 二、需求拆解
    • 具备友好的对话和问答能力
    • 具备一定记忆能力
    • 功能调用
  • 三、实现与代码展示
  • 总结
  • 下期预告


前言

在上一小节,我们简单介绍了langchain的使用方式,包括模型调用、工具调用、智能体功能以及上下文记忆。本小节我们将深入系统直接进行需求的分析的和智能体的搭载。


一、需求分析

对于AI技术的使用,明确需求是重中之重,以大语言模型为例,我们的提示词准确且完善,所得到的结果会更好。回归到我们AI视频监控系统,我希望大模型助手可以实现以下基本功能:

  • 具备友好的对话和问答能力
  • 具备一定记忆能力
  • 依据用户提示进行RTSP摄像头的拉流与管理。
  • 依据用户提示进行AI模型的加载和推理。
  • 依据用户提示进行分析视频流和原始视频流的切换

二、需求拆解

具备友好的对话和问答能力

  • 这一条本身就是伪命题,我们采用LLM进行对话的时候就已经具备了基本的功能,我们只需要采用langchain进行正确模型的调用,即可实现。

具备一定记忆能力

  • 我们依据实现了带有记忆的大模型和agent应用,我们需要聚焦于“记住哪些,忽略哪些,利用哪些”,实现更智能的助手应用。

功能调用

  • 对于学习了上一小节的朋友或者是对LLM了解的朋友应该很清楚,最直观的方式就是基于大模型的function calling功能,让大模型依据我们的需要进行正确工具的调用,最终实现相关的需求

三、实现与代码展示

  • 这里直接给出实现的代码
from langchain_core.messages import ChatMessage, HumanMessage, ToolMessage
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import START, MessagesState, StateGraph
from langchain_ollama import ChatOllama
from langchain_core.tools import tool
import yamlcur_info = {"open_camera": [],"yaml_path":r"path\to\config.yaml" }
import json@tool
def check_info() -> dict:"""check global information"""global cur_inforeturn cur_info@tool
def open_stream(cameraId: int, rtsp: str) -> bool:"""pulling streaminput:cameraId : channel index(lobally Unique Identifier)rtsp : pulling stream address"""global cur_infoimport requestsdata = {"cameraId": cameraId,"rtsp": rtsp,}print(f"Opening stream: cameraId={cameraId}, rtsp={rtsp}")cur_info["open_camera"].append({"cameraId": cameraId, "rtsp": rtsp})return True@tool
def operation(type: str, **kwargs) -> str:"""type: operation type [open , close]**kwargs: 参数通过关键字传递open: 需要 cameraId 和 rtspclose: 需要 cameraId"""# llm调用存在参数传递的格式问题global cur_infotry:kwargs = kwargs["kwargs"]if isinstance(kwargs, list):return "failed: just open one camera at the same time"if type == "open":# 检查必需参数if 'cameraId' not in kwargs or 'rtsp' not in kwargs:return "failed: open operation requires cameraId and rtsp"camera_id = kwargs['cameraId']rtsp = kwargs['rtsp']for info in cur_info["open_camera"]:if info["cameraId"] == str(camera_id):return f"failed: camera {camera_id} has opened! please dont open again."if info["rtsp"] == rtsp:return f"failed: rtsp {rtsp} has opened with camera_id {info['cameraId']}!"cur_info["open_camera"].append({"cameraId": str(camera_id), "rtsp": rtsp})# 执行打开操作return f"success: opened camera {camera_id} with rtsp {rtsp}"elif type == "close":if 'cameraId' not in kwargs:return "failed: close operation requires cameraId"camera_id = kwargs['cameraId']# 执行关闭操作index = -1for cur_index, info in enumerate(cur_info["open_camera"]):if info["cameraId"] == str(camera_id):index = cur_indexbreakif index != -1:cur_info["open_camera"].pop(index)return f"success: closed camera {camera_id}"else:return f"failed: camera {camera_id} not exists"else:return "failed: operation type must be 'open' or 'close'"except Exception as e:return e@tool
def load_yaml_config(config_path='config.yaml'):"""加载 YAML 配置文件Args:config_path: YAML 配置文件路径Returns:解析后的配置字典,如果出错返回 None"""try:with open(config_path, 'r', encoding='utf-8') as file:config = yaml.safe_load(file)return configexcept FileNotFoundError:return f"配置文件 {config_path} 不存在"except yaml.YAMLError as e:return f"配置文件 {config_path} 格式错误: {e}"except Exception as e:return f"读取文件时发生未知错误: {e}"tools = [operation, check_info,load_yaml_config]# Define a new graph
workflow = StateGraph(state_schema=MessagesState)
llm = ChatOllama(base_url="path/to/ollama",  # 添加了协议和端口model="model_name",validate_model_on_init=True,temperature=0.0,num_predict=1024,
).bind_tools(tools)# Define the function that calls the model
def call_model(state: MessagesState):response = llm.invoke(state["messages"])return {"messages": response}# Define the (single) node in the graph
workflow.add_edge(START, "model")
workflow.add_node("model", call_model)# Add memory
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)# 使用固定的thread_id来保持对话上下文
config = {"configurable": {"thread_id": "terminal_chat_session"}}print("欢迎使用聊天机器人! 输入 'quit' 或 'exit' 退出程序。")while True:# try:# 获取用户输入user_input = input("\n用户: ").strip()# 检查退出条件if user_input.lower() in ['quit', 'exit', 'bye']:print("再见!")breakif not user_input:continue# 创建输入消息input_messages = [HumanMessage(user_input)]# 调用模型output = app.invoke({"messages": input_messages}, config)# 检查是否有工具调用while len(output["messages"]) > 0 and hasattr(output["messages"][-1], 'tool_calls') and len(output["messages"][-1].tool_calls) > 0:# 处理工具调用for tool_call in output["messages"][-1].tool_calls:# try:# 选择并执行工具selected_tool = \{"operation": operation, "check_info": check_info,"load_yaml_config":load_yaml_config}[tool_call["name"].lower()]print(f"调用工具: {tool_call['name']} 参数: {tool_call['args']}")tool_output = selected_tool.invoke(tool_call["args"])print(f"工具返回: {tool_output}")# 添加工具响应消息input_messages.append(ToolMessage(str(tool_output), tool_call_id=tool_call["id"]))# except Exception as e:#     print(f"工具执行错误: {e}")#     input_messages.append(ToolMessage(f"Error: {str(e)}", tool_call_id=tool_call["id"]))# 再次调用模型处理工具结果output = app.invoke({"messages": input_messages}, config)# 显示最终回复if len(output["messages"]) > 0:last_message = output["messages"][-1]if hasattr(last_message, 'content'):print(f"\n助手: {last_message.content}")else:print("\n助手: (无文本回复)")else:print("\n助手: (无回复)")#-------------------------------------------------------------------------------------------------------# 结果展示
欢迎使用聊天机器人! 输入 'quit''exit' 退出程序。**用户**: 你好,我是AI视频监控系统,请问你是谁?**助手**: 您好!我是阿里云开发的助手Qwen。我在这里可以帮助您解答问题、编写代码或者完成各种任务。请问您需要什么帮助呢?如果您是AI视频监控系统的管理员或操作员,我可以协助您进行摄像头的操作和配置检查等任务。请告诉我具体的需求吧。**用户**: 你好,请问我是谁?**助手**: 您好!根据之前的对话内容,您似乎是AI视频监控系统的一部分或者是该系统的使用者。请问您需要了解更具体的哪方面的信息呢?如果有关于摄像头操作或配置的问题,我可以帮助解答和执行相关任务。请详细说明您的需求。**用户**: 好的,请你根据系统配置信息,打开对应的摄像头
调用工具: check_info 参数: {}
工具返回: {'open_camera': [], 'yaml_path': 'langchain_test\\config.yaml'}
调用工具: load_yaml_config 参数: {'config_path': '/path/to/config.yaml'}
工具返回: 配置文件 /path/to/config.yaml 不存在**助手**: 看起来提供的配置路径 `/path/to/config.yaml` 并不存在。请提供正确的 YAML 配置文件路径,以便我可以从中获取摄像头的 ID 和 RTSP 地址等信息来打开对应的摄像头。您可以再次尝试并提供一个有效的路径吗?如果不确定具体路径,请告知我您希望操作的具体摄像头名称或其他标识符,我会尽力帮助您找到正确的配置。**用户**: 好的,我的配置路径在./config.yaml,请你读取内容并显示
调用工具: load_yaml_config 参数: {'config_path': './config.yaml'}
工具返回: {'rtsp': ['rtsp://camera1', 'rtsp://camera2', 'rtsp://camera3', 'rtsp://camera4', 'rtsp://camera5', 'rtsp://camera6', 'rtsp://camera7', 'rtsp://camera8', 'rtsp://camera9', 'rtsp://camera10']}**助手**: 我已经读取了配置文件 `./config.yaml` 并获取到了摄像头的 RTSP 地址列表。现在请告诉我您希望打开哪个具体的摄像头,以便我可以继续进行操作。例如,如果您想打开第一个摄像头(RTSP地址为 `rtsp://192.168.10.207:554/camera1`),请告知我对应的摄像头 ID 或名称。如果配置文件中有定义,请提供相应的标识符。如果没有明确的标识符,您可以直接告诉我您想打开哪个位置或编号的摄像头。请问您希望操作哪一个摄像头呢?**用户**: 当前一共有多少摄像头信息?助手: 根据读取到的配置文件内容,总共有 10 个摄像头的信息,它们的 RTSP 地址如下:- `rtsp://camera1`
- `rtsp://camera2`
- `rtsp://camera3`
- `rtsp://camera4`
- `rtsp://camera5`
- `rtsp://camera6`
- `rtsp://camera7`
- `rtsp://camera8`
- `rtsp://camera9`
- `rtsp://camera10`请问您想操作其中的哪一个摄像头呢?请提供具体的摄像头 ID 或名称。**用户**: 请你帮我打开这10个摄像头的视频流
调用工具: operation 参数: {'kwargs': {'cameraId': 1, 'rtsp': 'rtsp://camera1'}, 'type': 'open'}
工具返回: success: opened camera 1 with rtsp rtsp://camera1
调用工具: operation 参数: {'kwargs': {'cameraId': 2, 'rtsp': 'rtsp://camera2'}, 'type': 'open'}
工具返回: success: opened camera 2 with rtsp rtsp://camera2
调用工具: operation 参数: {'kwargs': {'cameraId': 3, 'rtsp': 'rtsp://camera3'}, 'type': 'open'}
工具返回: success: opened camera 3 with rtsp rtsp://camera3
调用工具: operation 参数: {'kwargs': {'cameraId': 4, 'rtsp': 'rtsp://camera4'}, 'type': 'open'}
工具返回: success: opened camera 4 with rtsp rtsp://camera4
调用工具: operation 参数: {'kwargs': {'cameraId': 5, 'rtsp': 'rtsp://camera5'}, 'type': 'open'}
工具返回: success: opened camera 5 with rtsp rtsp://camera5
调用工具: operation 参数: {'kwargs': {'cameraId': 6, 'rtsp': 'rtsp://camera6'}, 'type': 'open'}
工具返回: success: opened camera 6 with rtsp rtsp://camera6
调用工具: operation 参数: {'kwargs': {'cameraId': 7, 'rtsp': 'rtsp://camera7'}, 'type': 'open'}
工具返回: success: opened camera 7 with rtsp rtsp://camera7
调用工具: operation 参数: {'kwargs': {'cameraId': 8, 'rtsp': 'rtsp://camera8'}, 'type': 'open'}
工具返回: success: opened camera 8 with rtsp rtsp://camera8
调用工具: operation 参数: {'kwargs': {'cameraId': 9, 'rtsp': 'rtsp://camera9'}, 'type': 'open'}
工具返回: success: opened camera 9 with rtsp rtsp://camera9
调用工具: operation 参数: {'kwargs': {'cameraId': 10, 'rtsp': 'rtsp://camera10'}, 'type': 'open'}
工具返回: success: opened camera 10 with rtsp rtsp://camera10**助手**: 所有 10 个摄像头的视频流都已经成功打开。每个摄像头都通过其对应的 RTSP 流地址连接到了指定的服务器。如果您需要进一步的帮助或有其他请求,请告诉我!
  • 执行流程图如下所示:
工具函数
operation
check_info
open_stream
load_yaml_config
开始
初始化全局变量和工具函数
构建LangGraph工作流
配置记忆存储和会话ID
等待用户输入
用户输入文本指令
检查退出条件?
退出程序
创建HumanMessage
调用工作流app.invoke
模型推理
是否有工具调用?
遍历每个工具调用
选择并执行对应工具
添加ToolMessage到消息历史
再次调用模型
生成最终文本响应
打印助手回复
  • 流程甘特图如下所示:
00:00:0000:00:0500:00:1000:00:1500:00:2000:00:2500:00:3000:00:3500:00:4000:00:4500:00:5000:00:55加载全局变量和工具 构建工作流图 配置记忆和会话 等待用户输入 处理用户输入 模型推理 检查工具调用 执行工具函数 添加工具结果 再次模型推理 生成最终响应 输出回复 下一次等待输入 初始化阶段用户交互循环工具调用循环响应生成下一次循环AI视频监控助手执行流程

总结

以上,我们已经实现了一个基本的AI大模型助手,具备上文理解、记忆以及工具的调用能力,下一节,我们将设计一个完备的客户端界面,并融入更加完善的AI助手系统,以实现最终的应用客户端。


下期预告

  1. AI视频监控系统客户端设计

文章转载自:

http://G82DUkqx.dpbdq.cn
http://4zUXJuO9.dpbdq.cn
http://08Nvl3pI.dpbdq.cn
http://rSKLNZwV.dpbdq.cn
http://XSSJwxTB.dpbdq.cn
http://Pqubls5a.dpbdq.cn
http://HlX6ghk4.dpbdq.cn
http://IxI0dkNo.dpbdq.cn
http://jJ2sFyMs.dpbdq.cn
http://0ukiHvBg.dpbdq.cn
http://eHcm4SKT.dpbdq.cn
http://MhEBAFwx.dpbdq.cn
http://sD8kbCfi.dpbdq.cn
http://vHbBlGXY.dpbdq.cn
http://RU3ExWAK.dpbdq.cn
http://6skHFHym.dpbdq.cn
http://K3aqeTyZ.dpbdq.cn
http://1ulOM88J.dpbdq.cn
http://5ojPoGOn.dpbdq.cn
http://T85yUVkM.dpbdq.cn
http://p3IBDBmv.dpbdq.cn
http://TX4JRxuk.dpbdq.cn
http://4EIOl68S.dpbdq.cn
http://OX3gqHn2.dpbdq.cn
http://PCG3BxLX.dpbdq.cn
http://JjKiGMmw.dpbdq.cn
http://UwH8cUta.dpbdq.cn
http://9chHEQYC.dpbdq.cn
http://BqwtQkCz.dpbdq.cn
http://2UChudDE.dpbdq.cn
http://www.dtcms.com/a/373253.html

相关文章:

  • 消息队列-初识kafka
  • linux 100个问答81~101 主要是k8s相关
  • 【C++设计模式】第三篇:观察者模式(别名:发布-订阅模式、模型-视图模式、源-监听器模式)
  • OpenCV C++ 二值图像处理:阈值化技术全解析
  • OpenCV C++ 形态学分析:从基础操作到高级应用
  • 区块链里的 “信标” 是啥?
  • ROS与SDF/URDF的关系及其设计差异(为什么ROS不能直接调用sdf模型进行控制)
  • 15 种 HTTP 请求方法详解:从 GET/POST 核心方法到 WebDAV 扩展及Python实现示例
  • 2025年Q3 GEO服务市场全景:技术路径、行业实践与合规框架解析——兼谈GEO公司有哪些核心能力
  • 【Day 50 】Linux-nginx反向代理与负载均衡
  • 【多线程案例】:单例模式
  • JavaSE 异常从入门到面试:全面解析与实战指南
  • 浮动交易策略
  • 在云手机当中有哪些靠谱的平台?
  • django跨域配置
  • 工控机创新驱动为工业升级注入科技强心剂
  • AI Agents with n8n: 10+ 自动化创意路线图
  • 【计算机视觉】图像中的高频信息,和低频信息指的是什么?
  • 光伏助力碳中和:智慧运营平台如何精准计算与追踪减排贡献?
  • 计算机视觉 (CV) 基础:图像处理、特征提取与识别
  • 网络身份安全防线:身份证实名认证接口-网络社交身份安全
  • 某互联网大厂的面试go语言从基础到实战的经验和总结
  • 软件设计师备考-(十六)数据结构及算法应用(重要)
  • flutter日期选择国际化支持
  • 最短路算法和最小生成树算法详解
  • 2005–2021年中国城市级终端能源消费(含可再生能源)综合数据集
  • Redis入门(部署、持久化、缓存问题)
  • 聊一聊 .NET 中的 CompositeChangeToken
  • 视觉语言模型应用开发——Qwen 2.5 VL模型视频理解与定位能力深度解析及实践指南
  • 深入理解 MDC(Mapped Diagnostic Context):日志记录的利器