LangChain + Firecrawl

Создайте мощные RAG системы с актуальными веб-данными.
73% рост AI-related API трафика в 2024 году (Postman State of API Report)

Быстрый старт RAG

pip install langchain langchain-openai chromadb requests
from langchain.document_loaders.base import BaseLoader
from langchain.docstore.document import Document
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.llms import OpenAI
from langchain.chains import RetrievalQA
import requests

class FirecrawlLoader(BaseLoader):
    """Custom LangChain loader for Firecrawl API"""
    
    def __init__(self, api_key: str, urls: list = None, search_query: str = None):
        self.api_key = api_key
        self.urls = urls or []
        self.search_query = search_query
        self.base_url = "https://api.firecrawl.ru/v1"
        self.headers = {"X-API-Key": api_key}
    
    def load(self) -> list[Document]:
        """Load documents from Firecrawl API"""
        documents = []
        
        # Если есть URLs - парсим их
        if self.urls:
            for url in self.urls:
                doc = self._scrape_url(url)
                if doc:
                    documents.append(doc)
        
        # Если есть поисковый запрос - ищем контент
        if self.search_query:
            search_docs = self._search_content(self.search_query)
            documents.extend(search_docs)
        
        return documents
    
    def _scrape_url(self, url: str) -> Document:
        """Scrape single URL"""
        response = requests.post(f"{self.base_url}/scrape",
            headers=self.headers,
            json={
                "url": url,
                "formats": ["markdown"],
                "onlyMainContent": True
            }
        )
        
        data = response.json()
        if data.get('success'):
            metadata = {
                'source': url,
                'title': data['data'].get('metadata', {}).get('title', ''),
                'scraped_at': data.get('processingTime', 0)
            }
            
            return Document(
                page_content=data['data']['markdown'],
                metadata=metadata
            )
        return None
    
    def _search_content(self, query: str) -> list[Document]:
        """Search content and return documents"""
        response = requests.post(f"{self.base_url}/search",
            headers=self.headers,
            json={
                "query": query,
                "limit": 10,
                "parseResults": False
            }
        )
        
        data = response.json()
        documents = []
        
        if data.get('success') and data['data']['pages']:
            for page in data['data']['pages']:
                # Дополнительно парсим каждую найденную страницу
                doc = self._scrape_url(page['url'])
                if doc:
                    # Добавляем метаданные поиска
                    doc.metadata.update({
                        'search_query': query,
                        'search_title': page['title'],
                        'search_description': page['description']
                    })
                    documents.append(doc)
        
        return documents

# Создание RAG системы
def create_rag_system(firecrawl_api_key: str, openai_api_key: str):
    # 1. Загрузка документов через Firecrawl
    loader = FirecrawlLoader(
        api_key=firecrawl_api_key,
        search_query="машинное обучение тренды 2025"
    )
    documents = loader.load()
    
    # 2. Разбиение на чанки
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=1000,
        chunk_overlap=200
    )
    splits = text_splitter.split_documents(documents)
    
    # 3. Создание векторного хранилища
    embeddings = OpenAIEmbeddings(openai_api_key=openai_api_key)
    vectorstore = Chroma.from_documents(splits, embeddings)
    
    # 4. Создание QA цепочки
    llm = OpenAI(openai_api_key=openai_api_key, temperature=0)
    qa_chain = RetrievalQA.from_chain_type(
        llm=llm,
        chain_type="stuff",
        retriever=vectorstore.as_retriever(search_kwargs={"k": 3}),
        return_source_documents=True
    )
    
    return qa_chain

# Использование RAG системы
rag_system = create_rag_system(
    firecrawl_api_key="your_firecrawl_key",
    openai_api_key="your_openai_key"
)

# Задаем вопросы на основе актуальных данных
result = rag_system({
    "query": "Какие основные тренды в машинном обучении на 2025 год?"
})

print("Ответ:", result['result'])
print("\nИсточники:")
for doc in result['source_documents']:
    print(f"- {doc.metadata['source']}")

AI Агенты с веб-данными

from langchain.agents import Tool, AgentExecutor, create_react_agent
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI

class FirecrawlTools:
    """Набор инструментов для AI агентов"""
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.headers = {"X-API-Key": api_key}
        self.base_url = "https://api.firecrawl.ru/v1"
    
    def search_web(self, query: str) -> str:
        """Поиск информации в интернете"""
        response = requests.post(f"{self.base_url}/search",
            headers=self.headers,
            json={
                "query": query,
                "limit": 5,
                "parseResults": True,
                "aiPrompt": f"Кратко суммируй ключевую информацию по запросу: {query}"
            }
        )
        
        data = response.json()
        if data.get('success'):
            if 'markdown' in data['data']:
                return data['data']['markdown']
            else:
                # Если нет AI анализа, возвращаем список страниц
                pages = data['data']['pages'][:3]
                result = f"Найдено по запросу '{query}':\n\n"
                for i, page in enumerate(pages, 1):
                    result += f"{i}. {page['title']}\n{page['url']}\n{page['description']}\n\n"
                return result
        return f"Не удалось найти информацию по запросу: {query}"
    
    def scrape_url(self, url: str) -> str:
        """Парсинг конкретного URL"""
        response = requests.post(f"{self.base_url}/scrape",
            headers=self.headers,
            json={
                "url": url,
                "formats": ["markdown"],
                "onlyMainContent": True
            }
        )
        
        data = response.json()
        if data.get('success'):
            content = data['data']['markdown']
            # Ограничиваем длину для агента
            return content[:2000] + "..." if len(content) > 2000 else content
        return f"Не удалось получить контент с {url}"
    
    def analyze_competitor(self, company_name: str) -> str:
        """Анализ конкурента"""
        query = f"{company_name} компания услуги продукты"
        return self.search_web(query)

# Создание инструментов для агента
def create_firecrawl_agent(firecrawl_api_key: str, openai_api_key: str):
    tools_helper = FirecrawlTools(firecrawl_api_key)
    
    tools = [
        Tool(
            name="search_web",
            description="Поиск актуальной информации в интернете. Используй для поиска новостей, трендов, статистики.",
            func=tools_helper.search_web
        ),
        Tool(
            name="scrape_url", 
            description="Получение контента с конкретного URL. Используй когда нужен контент с определенной страницы.",
            func=tools_helper.scrape_url
        ),
        Tool(
            name="analyze_competitor",
            description="Анализ конкурента по названию компании. Возвращает информацию о продуктах и услугах.",
            func=tools_helper.analyze_competitor
        )
    ]
    
    # Промпт для агента
    template = """
    Ты AI-помощник с доступом к актуальным веб-данным через Firecrawl API.
    
    Доступные инструменты:
    {tools}
    
    Инструкции:
    1. Используй search_web для поиска актуальной информации
    2. Используй scrape_url для получения контента с конкретных URL
    3. Используй analyze_competitor для анализа компаний
    4. Всегда указывай источники информации
    5. Если информация устарела, ищи более свежие данные
    
    Вопрос: {input}
    
    Мысли: {agent_scratchpad}
    """
    
    prompt = PromptTemplate.from_template(template)
    llm = OpenAI(openai_api_key=openai_api_key, temperature=0)
    
    agent = create_react_agent(llm, tools, prompt)
    agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
    
    return agent_executor

# Использование агента
agent = create_firecrawl_agent(
    firecrawl_api_key="your_firecrawl_key",
    openai_api_key="your_openai_key"
)

# Примеры запросов
responses = agent.run("Какие новые тренды в веб-разработке появились в 2024 году?")
print(responses)

competitor_analysis = agent.run("Проанализируй компанию OpenAI - какие у них основные продукты?")
print(competitor_analysis)

Автоматическое обновление RAG

import schedule
import time
from datetime import datetime

class AutoUpdatingRAG:
    """RAG система с автоматическим обновлением"""
    
    def __init__(self, firecrawl_api_key: str, openai_api_key: str):
        self.firecrawl_key = firecrawl_api_key
        self.openai_key = openai_api_key
        self.topics = []
        self.vectorstore = None
        self.qa_chain = None
        self.last_update = None
    
    def add_topics(self, topics: list):
        """Добавить темы для отслеживания"""
        self.topics.extend(topics)
    
    def update_knowledge_base(self):
        """Обновление базы знаний"""
        print(f"Обновление знаний в {datetime.now()}")
        
        all_documents = []
        
        # Загружаем свежие данные по всем темам
        for topic in self.topics:
            loader = FirecrawlLoader(
                api_key=self.firecrawl_key,
                search_query=topic
            )
            documents = loader.load()
            
            # Добавляем тему в метаданные
            for doc in documents:
                doc.metadata['topic'] = topic
                doc.metadata['updated_at'] = datetime.now().isoformat()
            
            all_documents.extend(documents)
        
        if all_documents:
            # Пересоздаем векторное хранилище
            text_splitter = RecursiveCharacterTextSplitter(
                chunk_size=1000,
                chunk_overlap=200
            )
            splits = text_splitter.split_documents(all_documents)
            
            embeddings = OpenAIEmbeddings(openai_api_key=self.openai_key)
            self.vectorstore = Chroma.from_documents(splits, embeddings)
            
            # Пересоздаем QA цепочку
            llm = OpenAI(openai_api_key=self.openai_key, temperature=0)
            self.qa_chain = RetrievalQA.from_chain_type(
                llm=llm,
                chain_type="stuff", 
                retriever=self.vectorstore.as_retriever(search_kwargs={"k": 5}),
                return_source_documents=True
            )
            
            self.last_update = datetime.now()
            print(f"Обновлено {len(all_documents)} документов")
    
    def query(self, question: str) -> dict:
        """Запрос к RAG системе"""
        if not self.qa_chain:
            self.update_knowledge_base()
        
        result = self.qa_chain({"query": question})
        
        # Добавляем информацию о свежести данных
        result['knowledge_updated_at'] = self.last_update.isoformat() if self.last_update else None
        result['topics_tracked'] = self.topics
        
        return result
    
    def start_auto_update(self, hours: int = 24):
        """Запуск автоматического обновления"""
        schedule.every(hours).hours.do(self.update_knowledge_base)
        
        print(f"Автообновление настроено на каждые {hours} часов")
        
        # Первоначальное обновление
        self.update_knowledge_base()
        
        # Планировщик
        while True:
            schedule.run_pending()
            time.sleep(3600)  # Проверка каждый час

# Использование автообновляемой RAG
auto_rag = AutoUpdatingRAG(
    firecrawl_api_key="your_firecrawl_key",
    openai_api_key="your_openai_key"
)

# Добавляем темы для отслеживания
auto_rag.add_topics([
    "искусственный интеллект новости",
    "стартапы технологии", 
    "блокчейн разработка",
    "веб-разработка тренды"
])

# Запросы с актуальными данными
result = auto_rag.query("Какие новые AI модели появились недавно?")
print(result['result'])
print(f"Данные обновлены: {result['knowledge_updated_at']}")

# Запуск автообновления (блокирующий вызов)
# auto_rag.start_auto_update(hours=12)

Специализированные RAG системы

1. Конкурентная разведка

class CompetitorRAG:
    def __init__(self, firecrawl_api_key: str, openai_api_key: str):
        self.firecrawl_key = firecrawl_api_key
        self.openai_key = openai_api_key
        self.competitors = []
    
    def add_competitors(self, competitors: list):
        """Добавить конкурентов для отслеживания"""
        self.competitors = competitors
    
    def create_competitive_intelligence(self):
        """Создание системы конкурентной разведки"""
        all_docs = []
        
        for competitor in self.competitors:
            # Ищем информацию о конкуренте
            loader = FirecrawlLoader(
                api_key=self.firecrawl_key,
                search_query=f"{competitor} продукты услуги цены новости"
            )
            docs = loader.load()
            
            for doc in docs:
                doc.metadata['competitor'] = competitor
            
            all_docs.extend(docs)
        
        # Создаем специализированную RAG для конкурентов
        text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000)
        splits = text_splitter.split_documents(all_docs)
        
        embeddings = OpenAIEmbeddings(openai_api_key=self.openai_key)
        vectorstore = Chroma.from_documents(splits, embeddings)
        
        llm = OpenAI(openai_api_key=self.openai_key)
        
        # Специальный промпт для конкурентного анализа
        prompt_template = """
        Используй следующую информацию о конкурентах для ответа на вопрос.
        Фокусируйся на сравнении, ценах, продуктах и конкурентных преимуществах.
        
        Контекст: {context}
        
        Вопрос: {question}
        
        Подробный анализ:
        """
        
        qa_chain = RetrievalQA.from_chain_type(
            llm=llm,
            retriever=vectorstore.as_retriever(),
            return_source_documents=True,
            chain_type_kwargs={
                "prompt": PromptTemplate.from_template(prompt_template)
            }
        )
        
        return qa_chain

# Использование
competitor_rag = CompetitorRAG("firecrawl_key", "openai_key")
competitor_rag.add_competitors(["OpenAI", "Anthropic", "Google AI"])

intelligence_system = competitor_rag.create_competitive_intelligence()
analysis = intelligence_system({
    "query": "Сравни цены и возможности AI продуктов конкурентов"
})

2. Новостная аналитика

class NewsAnalyticsRAG:
    def __init__(self, firecrawl_api_key: str, openai_api_key: str):
        self.firecrawl_key = firecrawl_api_key
        self.openai_key = openai_api_key
    
    def create_news_analyzer(self, topics: list):
        """Создание аналитики новостей"""
        
        # Загрузка новостей по темам
        all_news = []
        for topic in topics:
            loader = FirecrawlLoader(
                api_key=self.firecrawl_key,
                search_query=f"{topic} новости"
            )
            news_docs = loader.load()
            
            for doc in news_docs:
                doc.metadata['news_topic'] = topic
                doc.metadata['analysis_date'] = datetime.now().isoformat()
            
            all_news.extend(news_docs)
        
        # Специализированная обработка для новостей
        text_splitter = RecursiveCharacterTextSplitter(
            chunk_size=800,
            chunk_overlap=100
        )
        
        news_splits = text_splitter.split_documents(all_news)
        
        embeddings = OpenAIEmbeddings(openai_api_key=self.openai_key)
        news_vectorstore = Chroma.from_documents(news_splits, embeddings)
        
        llm = OpenAI(openai_api_key=self.openai_key, temperature=0.3)
        
        news_prompt = """
        Анализируй новости как профессиональный аналитик.
        Выявляй тренды, делай прогнозы, указывай влияние на рынок.
        
        Новости: {context}
        
        Вопрос: {question}
        
        Аналитический ответ:
        """
        
        return RetrievalQA.from_chain_type(
            llm=llm,
            retriever=news_vectorstore.as_retriever(search_kwargs={"k": 8}),
            chain_type_kwargs={
                "prompt": PromptTemplate.from_template(news_prompt)
            },
            return_source_documents=True
        )

# Использование новостной аналитики
news_analyzer = NewsAnalyticsRAG("firecrawl_key", "openai_key")
news_rag = news_analyzer.create_news_analyzer([
    "искусственный интеллект",
    "блокчейн технологии", 
    "стартапы инвестиции"
])

trend_analysis = news_rag({
    "query": "Какие технологические тренды будут доминировать в 2025 году?"
})
print(trend_analysis['result'])

Метрики и мониторинг

class RAGMetrics:
    def __init__(self):
        self.query_history = []
        self.source_quality = {}
    
    def log_query(self, query: str, result: dict, response_time: float):
        """Логирование запросов"""
        self.query_history.append({
            'timestamp': datetime.now(),
            'query': query,
            'sources_count': len(result.get('source_documents', [])),
            'response_time': response_time,
            'confidence': self._calculate_confidence(result)
        })
    
    def _calculate_confidence(self, result: dict) -> float:
        """Расчет уверенности в ответе"""
        # Простая метрика на основе количества источников
        sources_count = len(result.get('source_documents', []))
        return min(sources_count * 0.2, 1.0)
    
    def get_analytics(self) -> dict:
        """Получение аналитики использования"""
        if not self.query_history:
            return {}
        
        df = pd.DataFrame(self.query_history)
        
        return {
            'total_queries': len(df),
            'avg_response_time': df['response_time'].mean(),
            'avg_sources_per_query': df['sources_count'].mean(),
            'avg_confidence': df['confidence'].mean(),
            'queries_per_day': len(df[df['timestamp'] >= datetime.now().date()])
        }

# Интеграция метрик в RAG
def enhanced_rag_query(rag_system, query: str, metrics: RAGMetrics):
    """Запрос с метриками"""
    start_time = time.time()
    
    result = rag_system({"query": query})
    
    response_time = time.time() - start_time
    metrics.log_query(query, result, response_time)
    
    return result

# Использование с метриками
metrics = RAGMetrics()
result = enhanced_rag_query(rag_system, "Вопрос", metrics)

# Аналитика
analytics = metrics.get_analytics()
print(f"Аналитика RAG: {analytics}")
LangChain + Firecrawl = Умные AI системы с актуальными данными! 🚀