news 2026/6/13 23:25:12

NewsAPI、Google Search

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
NewsAPI、Google Search

day39: 外部API封装(NewsAPI、Google Search)

外部API封装(NewsAPI、Google Search)

定义:

1. 概念

把外部 API 封装成你项目里的一个“标准能力模块”,通常要做到:

  1. 统一接口(Interface)
例如所有接口都实现:search(query, **kwargs) -> List[SearchItem]
  1. 配置外置(Config)
API_KEY / BASE_URL / 超时 / 重试 / 限流 / 代理 走环境变量或配置文件,不写死
  1. 错误处理(Resilience)
  • 超时、网络错误

  • 401/403(key/权限)

  • 429(限流)

    • 5xx(对端故障)
      • 做好:重试、退避、降级(fallback)
  1. 结果标准化(Normalization)
不同供应商字段不同:统一成你自己的 SearchResult(title, url, snippet, source, published_at) 结构
  1. 可观测(Observability)
打日志:请求耗时、命中数、失败原因、配额信息(若对端给 header)
  1. 成本控制(Cost & Rate limit)
1. 缓存(相同 query 一段时间内不重复请求) 2. 截断(限制返回条数) 3. 只在需要时调用(Router/Agent decision)

2. NewsAPI 与 Google Search 各适合做什么?

NewsAPI(新闻聚合/检索)

官方文档

典型用法是用 /v2/everything 做关键词检索,支持 q、language、sortBy、from/to、分页等。

注意:NewsAPI 的 Developer 计划通常仅允许开发/测试环境使用,生产要换付费计划(条款要注意)。

Google Search(网页搜索)

官方文档
官方路线一般是 Programmable Search Engine(原 CSE)+ Custom Search JSON API:你需要先创建 Search Engine,然后用 cx(search engine id)+ API key 调接口。

工程上很多人也会用第三方 SERP API(如 Serper/SerpApi)来省去一些麻烦,但是否合规、成本与稳定性要你自己评估。


3. Demo:封装两个外部 API → 变成 Agent 的 Tools

3.1 安装依赖
pip install -U httpx pydantic langgraph langchain-openai langchain-core
3.2 配置环境变量(.env)
# LLMOPENAI_API_KEY=sk-xxx OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 OPENAI_MODEL=qwen-plus-latest# NewsAPINEWSAPI_KEY=your_newsapi_key# Google Custom Search JSON APIGOOGLE_API_KEY=your_google_api_key GOOGLE_CSE_CX=your_cx
3.3 代码:external_api_tools_demo.py
importosimporttimefromtypingimportList,Optional,Dict,AnyfrompydanticimportBaseModelimporthttpxfromlangchain_core.toolsimportToolfromlangchain_openaiimportChatOpenAIfromlanggraph.prebuiltimportcreate_react_agent# --------- 1) 统一数据结构(标准化输出)---------classSearchItem(BaseModel):title:strurl:strsnippet:str=""source:str=""published_at:str=""# --------- 2) 通用 HTTP 客户端:超时 + 重试 + 退避 ---------classResilientHttp:def__init__(self,timeout_s:float=15.0,max_retries:int=3):self.timeout_s=timeout_s self.max_retries=max_retries self.client=httpx.Client(timeout=timeout_s)defget(self,url:str,params:Dict[str,Any],headers:Optional[Dict[str,str]]=None)->httpx.Response:last_exc=Noneforiinrange(self.max_retries):try:r=self.client.get(url,params=params,headers=headers)# 429/5xx 做退避重试ifr.status_codein(429,500,502,503,504)andi<self.max_retries-1:time.sleep(0.8*(2**i))continuer.raise_for_status()returnrexceptExceptionase:last_exc=eifi<self.max_retries-1:time.sleep(0.8*(2**i))else:raiselast_exc# --------- 3) NewsAPI 封装 ---------classNewsAPIClient:def__init__(self,api_key:str,base_url:str="https://newsapi.org"):self.api_key=api_key self.base_url=base_url.rstrip("/")self.http=ResilientHttp()defsearch_everything(self,q:str,language:str="zh",page_size:int=5,sort_by:str="publishedAt")->List[SearchItem]:url=f"{self.base_url}/v2/everything"params={"q":q,"language":language,"pageSize":page_size,"sortBy":sort_by,"apiKey":self.api_key,}data=self.http.get(url,params=params).json()items=[]foraindata.get("articles",[])[:page_size]:items.append(SearchItem(title=a.get("title",""),url=a.get("url",""),snippet=a.get("description","")or"",source=(a.get("source")or{}).get("name","")or"",published_at=a.get("publishedAt","")or"",))returnitems# --------- 4) Google Custom Search JSON API 封装 ---------classGoogleCSEClient:def__init__(self,api_key:str,cx:str,base_url:str="https://www.googleapis.com/customsearch/v1"):self.api_key=api_key self.cx=cx self.base_url=base_url self.http=ResilientHttp()defsearch(self,q:str,num:int=5,lr:Optional[str]=None)->List[SearchItem]:params={"key":self.api_key,"cx":self.cx,"q":q,"num":min(max(num,1),10),}iflr:params["lr"]=lr# 例如 lr="lang_zh-CN"(按需)data=self.http.get(self.base_url,params=params).json()items=[]foritindata.get("items",[])[:num]:items.append(SearchItem(title=it.get("title",""),url=it.get("link",""),snippet=it.get("snippet","")or"",source="GoogleCSE",published_at="",))returnitemsdefformat_items(items:List[SearchItem])->str:ifnotitems:return"未找到结果。"lines=[]fori,xinenumerate(items,1):lines.append(f"{i}.{x.title}\n -{x.url}\n -{x.snippet}\n - source={x.source}time={x.published_at}".strip())return"\n".join(lines)# --------- 5) 把外部 API 变成 Agent Tools ---------defmain():# LLM(DashScope OpenAI compatible)llm=ChatOpenAI(model=os.getenv("OPENAI_MODEL","qwen-plus-latest"),api_key=os.getenv("OPENAI_API_KEY"),base_url=os.getenv("OPENAI_BASE_URL"),temperature=0.2,)news_key=os.getenv("NEWSAPI_KEY","")google_key=os.getenv("GOOGLE_API_KEY","")google_cx=os.getenv("GOOGLE_CSE_CX","")news_client=NewsAPIClient(news_key)ifnews_keyelseNonegoogle_client=GoogleCSEClient(google_key,google_cx)if(google_keyandgoogle_cx)elseNonedefnews_search_tool(query:str)->str:ifnotnews_client:return"NEWSAPI_KEY 未配置。"items=news_client.search_everything(query,language="zh",page_size=5,sort_by="publishedAt")returnformat_items(items)defweb_search_tool(query:str)->str:ifnotgoogle_client:return"GOOGLE_API_KEY / GOOGLE_CSE_CX 未配置。"items=google_client.search(query,num=5)returnformat_items(items)tools=[Tool(name="NewsSearch",func=news_search_tool,description="搜索新闻(NewsAPI)并返回标题/链接/摘要"),Tool(name="WebSearch",func=web_search_tool,description="搜索网页(Google Custom Search JSON API)并返回标题/链接/摘要"),]agent=create_react_agent(llm,tools)question="帮我找一下最近关于“AI Agent LangGraph GraphRAG”的新闻和网页资料,各给5条,并用中文总结要点。"result=agent.invoke({"messages":[("user",question)]})print(result["messages"][-1].content)if__name__=="__main__":main()
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/12 17:52:31

【计算机毕业设计案例】基于springboot的汽车租赁管理系统“车辆管理 - 订单履约 - 数据分析(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/13 0:23:29

Java毕设项目推荐-基于Java+SpringBoot+Vue实现前后端分离的汽车租赁管理系统基于springboot的汽车租赁管理系统【附源码+文档,调试定制服务】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/10 19:07:49

EF Core实体映射到多个表

把一个实体类型映射到多个表&#xff0c;官方叫法是 Entity splitting&#xff0c;这个称呼有点难搞&#xff0c;要是翻译为“实体拆分”或“拆分实体”&#xff0c;你第一感觉会不会认为是把一个表拆分为多个实体的意思。可它的含义是正好相反。为了避免大伙伴们产生误解&…

作者头像 李华
网站建设 2026/6/11 23:41:13

在 Spring Boot 中实现 JSON 字段的蛇形命

在 Spring Boot 项目中&#xff0c;常常需要实现 Java 对象字段使用驼峰命名&#xff0c;而在序列化为 JSON 时使用蛇形命名。这种需求在与外部 API 交互或满足特定数据格式规范时尤为常见。本文将详细介绍几种实现方案&#xff0c;并提供代码示例。 方案一&#xff1a;全局配…

作者头像 李华
网站建设 2026/6/12 22:24:03

Win7程序崩溃问题解决全攻略

让老旧系统跑动前沿AI&#xff1a;Win7环境下部署Hunyuan-MT-7B-WEBUI的实战修复指南 在不少企业机房、工业控制终端甚至科研实验室里&#xff0c;Windows 7 依然顽强地“服役”着。尽管微软早已终止支持&#xff0c;但受限于硬件兼容性、软件依赖或组织迁移成本&#xff0c;许…

作者头像 李华
网站建设 2026/6/10 14:53:17

Redshift数据迁移至MaxCompute技术方案

Hunyuan-MT-7B-WEBUI&#xff1a;高性能机器翻译模型网页一键推理部署方案 在企业出海加速、跨国协作频繁的今天&#xff0c;高质量、低延迟的多语言翻译能力已成为许多产品的“标配”。然而&#xff0c;部署一个真正可用的大规模翻译模型&#xff0c;往往面临环境配置复杂、依…

作者头像 李华