AI 22 分钟阅读

AI应用搜索能力集成:RAG到AI Agent指南 | SearchCans

用SERP API为LLM提供实时互联网知识。构建搜索能AI助手,提升准确性50%+。Google AI研究员实践指南。

8,428 字

在Google做LLM研究时,我们有一个主要问题:语言模型只知道它们训练时的数据。问GPT-4昨天发生的事,它一无所知。

现在大家都在构建的解决方案?将LLM连接到SERP API获取实时信息。

相关阅读构建AI Agent | AI集成指南 | API文档

这篇文章解释它如何工作,并展示你自己构建的确切代码。

知识截止日期问题

每个LLM都有训练截止日期。GPT-4的知识止于2023年4月(基础模型)。问它:

"旧金山现在天气如何?"

它答不上来。信息不在它的训练数据中。

传统解决方案很笨拙:

  • 微调模型(昂贵、慢)
  • 维护一个巨大的最新知识库(工程噩梦)
  • 接受局限性(糟糕的用户体验)

更好的解决方案:检索增强生成(RAG)

RAG是个高大上的术语,概念很简单:

  1. 用户问问题
  2. 搜索相关信息
  3. 将信息作为上下文喂给LLM
  4. LLM使用训练知识和新数据生成答案

搜索API让第2步变得简单。

基础架构

最简单的实现:

import requests
import openai

def answer_with_search(question):
    """使用LLM + 搜索API回答问题"""
    
    # 步骤1:搜索相关信息
    search_response = requests.post(
        'https://searchcans.youxikuang.cn/api/search',
        headers={'Authorization': f'Bearer {SEARCHCANS_KEY}'},
        json={'s': question, 't': 'google', 'num': 5}
    )
    
    search_results = search_response.json()
    
    # 步骤2:提取相关片段
    context = "\n\n".join([
        f"{result['title']}\n{result['snippet']}"
        for result in search_results.get('organic_results', [])[:3]
    ])
    
    # 步骤3:带上下文喂给LLM
    prompt = f"""
    使用提供的上下文回答以下问题。
    
    来自最近搜索的上下文:
    {context}
    
    问题:{question}
    
    回答:"""
    
    response = openai.ChatCompletion.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt}]
    )
    
    return response.choices[0].message.content

# 测试
answer = answer_with_search("OpenAI在2024年11月发生了什么?")
print(answer)

这出奇地有效。LLM现在可以访问搜索结果的当前信息。

生产级实现

基础版本有问题:

  • 无错误处理
  • 在无关上下文上浪费token
  • 无来源归属
  • 无法处理复杂查询

这是我们如何正确构建:

import requests
import openai
from typing import List, Dict

class AISearchAgent:
    def __init__(self, search_api_key, openai_api_key):
        self.search_key = search_api_key
        self.openai_key = openai_api_key
        openai.api_key = openai_api_key
    
    def search(self, query: str, num_results: int = 5) -> List[Dict]:
        """执行搜索并返回结构化结果"""
        try:
            response = requests.post(
                'https://searchcans.youxikuang.cn/api/search',
                headers={'Authorization': f'Bearer {self.search_key}'},
                json={'s': query, 't': 'google', 'num': num_results},
                timeout=10
            )
            response.raise_for_status()
            return response.json().get('organic_results', [])
        except Exception as e:
            print(f"搜索失败: {e}")
            return []
    
    def is_relevant(self, result: Dict, original_query: str) -> bool:
        """使用LLM检查搜索结果是否相关"""
        prompt = f"""
        查询:{original_query}
        结果标题:{result['title']}
        结果摘要:{result['snippet']}
        
        这个结果与回答查询相关吗?
        只回答"是"或"否"。
        """
        
        response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo",  # 用便宜模型过滤
            messages=[{"role": "user", "content": prompt}],
            max_tokens=10
        )
        
        return "是" in response.choices[0].message.content
    
    def answer_question(self, question: str) -> Dict:
        """带来源回答问题"""
        
        # 搜索
        results = self.search(question, num_results=10)
        
        if not results:
            return {
                'answer': "我找不到相关信息来回答这个问题。",
                'sources': []
            }
        
        # 过滤相关结果
        relevant = [r for r in results if self.is_relevant(r, question)][:3]
        
        # 构建上下文
        context = "\n\n".join([
            f"来源{i+1}:{r['title']}\n{r['snippet']}\n链接:{r['link']}"
            for i, r in enumerate(relevant)
        ])
        
        # 生成答案
        prompt = f"""
        使用以下来源回答问题。
        使用[1]、[2]、[3]标记引用来源。
        如果来源不包含答案,请说明。
        
        来源:
        {context}
        
        问题:{question}
        
        回答:"""
        
        response = openai.ChatCompletion.create(
            model="gpt-4",
            messages=[{"role": "user", "content": prompt}],
            temperature=0.3  # 更低温度以获得事实性回答
        )
        
        return {
            'answer': response.choices[0].message.content,
            'sources': [{'title': r['title'], 'url': r['link']} 
                       for r in relevant]
        }

# 使用
agent = AISearchAgent(
    search_api_key="your_searchcans_key",
    openai_api_key="your_openai_key"
)

result = agent.answer_question("谁赢得了2024年世界杯?")
print(result['answer'])
print("\n来源:")
for source in result['sources']:
    print(f"- {source['title']}: {source['url']}")

这个版本:

  • 使用便宜的LLM调用过滤无关结果
  • 提供来源归属
  • 优雅处理错误
  • 为不同任务使用适当的模型

LangChain集成

如果你在用LangChain(你可能应该用),集成更简单:

from langchain.tools import Tool
from langchain.agents import initialize_agent, AgentType
from langchain.llms import OpenAI
import requests

def search_tool_func(query: str) -> str:
    """LangChain的搜索函数"""
    response = requests.post(
        'https://searchcans.youxikuang.cn/api/search',
        headers={'Authorization': f'Bearer {API_KEY}'},
        json={'s': query, 't': 'google'}
    )
    
    results = response.json().get('organic_results', [])[:3]
    
    return "\n\n".join([
        f"{r['title']}: {r['snippet']}"
        for r in results
    ])

# 创建工具
search_tool = Tool(
    name="网络搜索",
    func=search_tool_func,
    description="用于在互联网上查找最新信息"
)

# 初始化agent
llm = OpenAI(temperature=0)
agent = initialize_agent(
    [search_tool],
    llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True
)

# 使用
result = agent.run("AI监管的最新发展是什么?")
print(result)

LangChain处理决策:何时搜索、如何解释结果、何时回应。

真实世界用例

1. 客服机器人

一家SaaS公司构建的支持机器人:

  • 搜索他们的文档获取答案
  • 降级到网络搜索处理一般问题
  • 不确定时升级到人工

结果:60%的工单自动处理,平均4分钟解决时间。

2. 研究助手

学术研究人员使用AI + 搜索:

  • 快速找相关论文
  • 总结主题的当前研究
  • 识别专家和机构

一个研究团队使用这种方法将文献综述时间从2周缩短到3天。

3. 新闻监控

一家对冲基金构建的AI agent:

  • 监控投资组合公司的新闻
  • 总结关键发展
  • 对重大事件告警

系统每天处理10,000+篇文章,发送5-10个高优先级告警。

成本分析:实际花费

让我们计算每月10,000个用户查询的经济性:

搜索API成本

  • 10,000查询 × 每个1次搜索 = 10,000 API调用
  • ¥3.4/1K = ¥34/月

OpenAI成本

  • 相关性过滤:10,000 × 3结果 × ¥0.007 = ¥210/月
  • 答案生成:10,000 × ¥0.21 = ¥2,100/月
  • OpenAI总计:¥2,310/月

总计:每月10,000增强查询¥2,344

对比维护自己的实时知识库:

  • 网络爬虫基础设施:¥3,400/月
  • 数据库:¥1,360/月
  • 维护:20小时/月 × ¥680/小时 = ¥13,600/月
  • 总计:¥18,360/月

API方案成本是DIY的13%,且无需维护。

高级模式

多步研究

对于复杂问题,使用多次搜索:

def deep_research(question: str) -> str:
    """复杂问题的多步研究"""
    
    # 步骤1:识别子问题
    sub_questions = decompose_question(question)
    
    # 步骤2:研究每个子问题
    sub_answers = []
    for sq in sub_questions:
        results = search(sq)
        answer = synthesize_answer(sq, results)
        sub_answers.append(answer)
    
    # 步骤3:合并为最终答案
    final_answer = synthesize_final(question, sub_answers)
    
    return final_answer

这处理像"比较最近三任美国总统的经济政策"这样需要多个研究步骤的问题。

来源质量评分

不是所有搜索结果都同等可信:

def score_source_quality(url: str) -> float:
    """评估来源可靠性"""
    
    trusted_domains = {
        '人民网.cn': 0.95,
        'xinhuanet.com': 0.95,
        'cnki.net': 0.90,
        'nature.com': 0.98,
        # ... 更多域名
    }
    
    domain = url.split('/')[2]
    return trusted_domains.get(domain, 0.5)  # 默认:中等信任

# 在上下文构建中使用
weighted_results = sorted(
    results,
    key=lambda r: score_source_quality(r['link']),
    reverse=True
)

这在发送给LLM的上下文中优先考虑权威来源。

重要的提示工程

提示质量决定输出质量。有效的做法:

糟糕的提示

回答:{question}
上下文:{context}

好的提示

你是一个有帮助的助手,准确回答问题。
仅使用提供的上下文回答。
如果上下文不包含答案,说"我没有足够信息。"
使用[1]、[2]、[3]标记引用来源。

上下文:
{context}

问题:{question}

回答:

好的提示:

  • 设定明确的角色期望
  • 将答案限制在提供的上下文
  • 防止幻觉
  • 请求来源归属

常见陷阱

陷阱1:发送过多上下文

GPT-4有8K token限制。如果你发送10篇完整文章作为上下文,会触及限制并截断重要信息。

解决方案:只发送摘要和标题。让LLM决定是否需要更多细节。

陷阱2:不处理搜索失败

搜索API可能失败或返回空结果。你的代码需要优雅降级。

解决方案:始终检查空结果并有降级响应。

陷阱3:信任一切

LLM会自信地呈现信息即使它是错的。

解决方案:始终显示来源,用户可以验证声明。

未来:自主Agent

下一个演进是AI agent:

  • 决定何时搜索
  • 选择搜索什么
  • 确定是否需要更多信息
  • 执行多步计划

我们正使用ReAct模式构建agent:

思考:我需要找关于AI监管的最新新闻
行动:搜索"AI监管 2024"
观察:[搜索结果]
思考:我找到了相关信息,让我综合它
行动:回应用户

这些agent在曾需要人类分析师的研究任务上表现得非常好。

今天开始行动

如果你想为AI应用添加搜索能力:

第1天:构建基础RAG系统(50行代码)

第2天:添加相关性过滤和错误处理

第3天:实现来源归属

第4天:用真实用户查询测试并迭代

别想太多。基础模式效果很好。你可以稍后优化。


关于作者:张艾米莉博士在斯坦福完成NLP博士学位,在Google Brain做LLM研究。她现在为公司构建AI产品提供咨询。

想为你的AI应用添加搜索能力?从1000次免费API调用开始构建第一个原型。

标签:

AI RAG AI Agent SERP API 大语言模型

准备好用 SearchCans 构建你的 AI 应用了吗?

立即体验我们的 SERP API 和 Reader API。每千次调用仅需 ¥0.56 起,无需信用卡即可免费试用。