![[AI Agent 04]联网搜索](http://pic.xiahunao.cn/yaotu/[AI Agent 04]联网搜索)
代码是AI写的用的CC接入DS-v4-pro代码在前文基础上更新功能包括对话记忆、Agent 循环、Function Calling、Agent框架 、文件工具、联网搜索本篇文章仅作为个人学习笔记记录分享联网搜索完整代码如下 联网搜索 Agent —— 让 AI 能查网页 基于框架新增两个联网工具 1. web_search —— 搜索网页 2. fetch_url —— 抓取网页内容 import sys import os sys.stdout.reconfigure(encodingutf-8) from importlib.util import spec_from_file_location, module_from_spec spec spec_from_file_location(framework, os.path.join(os.path.dirname(__file__), 04-agent-framework.py)) framework module_from_spec(spec) spec.loader.exec_module(framework) Agent framework.Agent TOOL_REGISTRY framework.TOOL_REGISTRY.copy() # # 新工具1网页搜索 # def web_search(query: str, max_results: int 5) - str: 用 DuckDuckGo 搜索网页返回标题和链接 try: from ddgs import DDGS results [] with DDGS() as ddgs: for r in ddgs.text(query, max_resultsmax_results): results.append(f- {r[title]}\n {r[href]}\n {r[body][:100]}...) if not results: return 没有搜索到相关结果。 return \n\n.join(results) except Exception as e: return f搜索失败{e} # # 新工具2抓取网页 # def fetch_url(url: str) - str: 抓取一个网页的内容纯文本 try: import requests headers { User-Agent: Mozilla/5.0 (compatible; AI-Agent/1.0) } resp requests.get(url, headersheaders, timeout10) resp.raise_for_status() # 简单提取纯文本去掉 HTML 标签 import re text re.sub(r[^], , resp.text) text re.sub(r\s, , text) if len(text) 2000: text text[:2000] ...(内容已截断) return text.strip() except Exception as e: return f抓取失败{e} # # 注册 # TOOL_REGISTRY.update({ web_search: { func: web_search, description: 搜索网页。当需要查找最新信息、新闻、或你不知道的内容时使用。, parameters: { type: object, properties: { query: {type: string, description: 搜索关键词}, max_results: {type: integer, description: 最多返回几条结果默认5}, }, required: [query], }, }, fetch_url: { func: fetch_url, description: 抓取一个网页的详细内容。搜索到感兴趣的链接后用这个工具打开查看。, parameters: { type: object, properties: { url: {type: string, description: 要抓取的网页完整 URL}, }, required: [url], }, }, }) # # 启动 # if __name__ __main__: agent Agent(system_prompt你是一个能上网搜索的 AI 助手。当用户问需要最新信息的问题时用 web_search 搜索。找到感兴趣的结果后用 fetch_url 打开看详情。用中文回答。) for name, info in TOOL_REGISTRY.items(): agent.add_tool(name, info[func], info[description], info[parameters]) print( * 50) print(联网 Agent —— 我能搜索网页了) print(试试) print( 最近有什么科技新闻) print( 帮我查一下今天的天气) print( Python 3.13 有什么新特性) print(输入 quit 退出clear 清空记忆) print( * 50) while True: user_input input(\n你: ) if user_input.lower() quit: print(再见) break if user_input.lower() clear: agent.clear_memory() print((记忆已清空)) continue reply agent.chat(user_input) print(fAI: {reply})一、网页搜索工具1.ddgs是一个第三方python库封装了DuckDuckGo的搜索APIDDGS()是一个类DDGS()创建它的一个实例对象这个实例内部管理着与DuckDuckGo服务的网络连接query是函数的第一个参数代表用户要搜索的关键词或短语def web_search(query: str, max_results: int 5) - str: 用 DuckDuckGo 搜索网页返回标题和链接 try: from ddgs import DDGS results [] with DDGS() as ddgs: for r in ddgs.text(query, max_resultsmax_results): results.append(f- {r[title]}\n {r[href]}\n {r[body][:100]}...) if not results: return 没有搜索到相关结果。 return \n\n.join(results) except Exception as e: return f搜索失败{e}2.用三引号包裹的不是注释是函数的docstring文档字符串描述了函数的作用特性注释#开头Docstring三引号字符串归属独立行或代码行末尾不属于任何对象紧跟在函数、类、模块定义后的第一个语句属于该对象存储位置不存储仅用于阅读代码时提示会被存储在__doc__属性中运行时可以访问作用范围仅在源代码中可见可通过help()、IDE 提示、.__doc__获取用途解释代码细节、临时禁用代码等正式文档描述函数/类/模块的作用、参数、返回值等语法要求无任意位置必须是字符串字面量且紧跟在定义后用 DuckDuckGo 搜索网页返回标题和链接3.延迟导入作用是可以加快启动不需要搜索功能时不加载库同时减少依赖即使缺少库程序也能启动def web_search(query: str, max_results: int 5) - str: try: from ddgs import DDGS # 只在需要时导入二、网页抓取工具1.requests是一个第三方HTTP 库用于发送网络请求headers是一个字典用于模拟浏览器的请求头User-Agent用户代理是HTTP 协议中的一个请求头字段用于告诉服务器发起请求的客户端是什么类型resp requests.get(url, headersheaders, timeout10)向目标 URL发送GET 请求携带自定义请求头并设置超时时间为 10 秒resp.raise_for_status()在非200状态码时抛出异常import re导入正则表达式模块resp.text服务器返回的原始HTML的字符串内容正则表达式r[^]匹配任何以开头、结尾中间至少一个不是的字符的字符串也就是HTML 标签re.sub将所有匹配到的标签替换为空字符串得到没有标签的文本。def fetch_url(url: str) - str: 抓取一个网页的内容纯文本 try: import requests headers { User-Agent: Mozilla/5.0 (compatible; AI-Agent/1.0) } resp requests.get(url, headersheaders, timeout10) resp.raise_for_status() # 简单提取纯文本去掉 HTML 标签 import re text re.sub(r[^], , resp.text) text re.sub(r\s, , text) if len(text) 2000: text text[:2000] ...(内容已截断) return text.strip() except Exception as e: return f抓取失败{e}2.Python的requests库默认的User-Agent是python-requests/版本号这个字符串会被服务器识别为一个脚本很多网站会直接拒绝访问或者其他为了避免被当作“恶意爬虫”而屏蔽通常需要伪装成浏览器所以手动设置User-AgentMozilla/5.0代表兼容标记 几乎所有浏览器都保留Mozilla/5.0以通过某些旧网站的检测。(compatible; AI-Agent/1.0)是注释其中的compatible表示兼容AI-Agent/1.0是自定义名称和版本号表明这是一个 AI 代理工具。符合网络爬虫或 AI Agent 抓取网页时“礼貌且尽量不触发反爬”的常见实践自定义 UA声明身份同时模拟浏览器基础特征。import requests headers { User-Agent: Mozilla/5.0 (compatible; AI-Agent/1.0) }3.关于re正则表达式r...表示不对字符串内的反斜杠\进行转义处理而是按字面意思原样保留普通的字符串方法只能处理固定的、字面意义的文本。而正则表达式允许定义一种规则然后让Python找出字符串中符合该规则的所有部分。正则表达式定义规则\d代表一个数字\s代表一个空白字符空格、换行等[0-9]代表一个数字等价于\d[^]代表除了以外的任意字符表示前面的字符或组出现至少一次*表示出现零次或多次import re text re.sub(r[^], , resp.text)4.正则r\s匹配一个或多个空白字符将所有连续空白替换成单个空格使得原本多行、缩进的文本会被压缩成一行text re.sub(r\s, , text)5.删除字符串开头和结尾的空白字符空格、换行等空白字符return text.strip()三、工具注册1.max_results: {type: integer, description: 最多返回几条结果默认5}中的integer即为int类型一定为整数TOOL_REGISTRY.update({ web_search: { func: web_search, description: 搜索网页。当需要查找最新信息、新闻、或你不知道的内容时使用。, parameters: { type: object, properties: { query: {type: string, description: 搜索关键词}, max_results: {type: integer, description: 最多返回几条结果默认5}, }, required: [query], # max_results 可选 }, }, # ... fetch_url 类似 })