Claude Web Search API & Python

Anthropic just announced web search via the Claude API. Here's the docs.

Here's a video on how to build a research agent with this new functionality in Python.

Here's the code to go along with the video:

# web.py

import anthropic
from icecream import ic

question = "Who has the best pizza?"

client = anthropic.Anthropic()
response = client.messages.create(
    model="claude-3-7-sonnet-latest",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": question}],
    tools=[{
        "type": "web_search_20250305",
        "name": "web_search",
        "max_uses": 5,
    }]
)

ic(response.to_dict())

# report.py

import anthropic
from icecream import ic

PROMPT = """
Create a research report on the topic provided by the user.
Format the report in markdown. 
"""

def ask_claude(question):
    client = anthropic.Anthropic()
    response = client.messages.create(
        model="claude-3-7-sonnet-latest",
        max_tokens=1024,
        system=PROMPT,
        messages=[
            {"role": "user", "content": question}],
        tools=[{
            "type": "web_search_20250305",
            "name": "web_search",
            "max_uses": 5, 
        }]
    )
    
    return response


def get_citations(block):
    content = ""
    for citation in block.citations:
        content += "\n\n## Citation\n"
        content += f"url: {citation.url}\n"
        content += f"title: {citation.title}\n"
        content += f"cited_text: {citation.cited_text}\n\n"
    return content


def get_asst_msgs(response):
    content = ""
    for block in response.content:
        if block.type == "text":
            content += block.text
            if block.citations:
                content += get_citations(block)
    return content


def write_report(content):
    import datetime
    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = f"reports/report_{timestamp}.md"
    with open(filename, 'w') as file:
        file.write(content)


if __name__ == "__main__":
    question = "Who's the new pope?"
    response = ask_claude(question)
    
    content = question + "\n\n==========\n\n"
    content += get_asst_msgs(response) + "\n\n"
    content += f"\n\n========\n\n{response.to_json()}"
    write_report(content)
               
            
# web_streaming.py

import asyncio
from anthropic import AsyncAnthropic
from icecream import ic


client = AsyncAnthropic()

async def ask_claude(question) -> None:
    async with client.messages.stream(
        model="claude-3-7-sonnet-latest",
        max_tokens=1024,
        messages=[
            {"role": "user", "content": question}],
        tools=[{
            "type": "web_search_20250305",
            "name": "web_search",
            "max_uses": 5, 
        }]
    ) as stream:
        async for text in stream.text_stream:
            print(text, end="", flush=True)
        print()

    message = await stream.get_final_message()
    ic(message.to_dict())

question = "Who's the new pope?"

asyncio.run(ask_claude(question))