You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

google_search.py 5.2 kB

Enable LLM Call Observability in AGS (#5457) <!-- Thank you for your contribution! Please review https://microsoft.github.io/autogen/docs/Contribute before opening a pull request. --> <!-- Please add a reviewer to the assignee section when you create a PR. If you don't have the access to it, we will shortly find a reviewer and assign them to your PR. --> It is often helpful to inspect the raw request and response to/from an LLM as agents act. This PR, does the following: - Updates TeamManager to yield LLMCallEvents from core library - Run in an async background task to listen for LLMCallEvent JIT style when a team is run - Add events to an async queue and - yield those events in addition to whatever actual agentchat team.run_stream yields. - Update the AGS UI to show those LLMCallEvents in the messages section as a team runs - Add settings panel to show/hide llm call events in messages. - Minor updates to default team <img width="1539" alt="image" src="https://github.com/user-attachments/assets/bfbb19fe-3560-4faa-b600-7dd244e0e974" /> <img width="1554" alt="image" src="https://github.com/user-attachments/assets/775624f5-ba83-46e8-81ff-512bfeed6bab" /> <img width="1538" alt="image" src="https://github.com/user-attachments/assets/3becbf85-b75a-4506-adb7-e5575ebbaec4" /> ## Why are these changes needed? <!-- Please give a short summary of the change and the problem this solves. --> ## Related issue number <!-- For example: "Closes #1234" --> Closes #5440 ## Checks - [ ] I've included any doc changes needed for https://microsoft.github.io/autogen/. See https://microsoft.github.io/autogen/docs/Contribute#documentation to build and test documentation locally. - [ ] I've added tests (if relevant) corresponding to the changes introduced in this PR. - [ ] I've made sure all auto checks have passed.
1 year ago
Enable LLM Call Observability in AGS (#5457) <!-- Thank you for your contribution! Please review https://microsoft.github.io/autogen/docs/Contribute before opening a pull request. --> <!-- Please add a reviewer to the assignee section when you create a PR. If you don't have the access to it, we will shortly find a reviewer and assign them to your PR. --> It is often helpful to inspect the raw request and response to/from an LLM as agents act. This PR, does the following: - Updates TeamManager to yield LLMCallEvents from core library - Run in an async background task to listen for LLMCallEvent JIT style when a team is run - Add events to an async queue and - yield those events in addition to whatever actual agentchat team.run_stream yields. - Update the AGS UI to show those LLMCallEvents in the messages section as a team runs - Add settings panel to show/hide llm call events in messages. - Minor updates to default team <img width="1539" alt="image" src="https://github.com/user-attachments/assets/bfbb19fe-3560-4faa-b600-7dd244e0e974" /> <img width="1554" alt="image" src="https://github.com/user-attachments/assets/775624f5-ba83-46e8-81ff-512bfeed6bab" /> <img width="1538" alt="image" src="https://github.com/user-attachments/assets/3becbf85-b75a-4506-adb7-e5575ebbaec4" /> ## Why are these changes needed? <!-- Please give a short summary of the change and the problem this solves. --> ## Related issue number <!-- For example: "Closes #1234" --> Closes #5440 ## Checks - [ ] I've included any doc changes needed for https://microsoft.github.io/autogen/. See https://microsoft.github.io/autogen/docs/Contribute#documentation to build and test documentation locally. - [ ] I've added tests (if relevant) corresponding to the changes introduced in this PR. - [ ] I've made sure all auto checks have passed.
1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import os
  2. from typing import Dict, List, Optional
  3. from urllib.parse import urljoin
  4. import html2text
  5. import httpx
  6. from autogen_core.code_executor import ImportFromModule
  7. from autogen_core.tools import FunctionTool
  8. from bs4 import BeautifulSoup
  9. async def google_search(
  10. query: str,
  11. num_results: int = 3,
  12. include_snippets: bool = True,
  13. include_content: bool = True,
  14. content_max_length: Optional[int] = 10000,
  15. language: str = "en",
  16. country: Optional[str] = None,
  17. safe_search: bool = True,
  18. ) -> List[Dict[str, str]]:
  19. """
  20. Perform a Google search using the Custom Search API and optionally fetch webpage content.
  21. Args:
  22. query: Search query string
  23. num_results: Number of results to return (max 10)
  24. include_snippets: Include result snippets in output
  25. include_content: Include full webpage content in markdown format
  26. content_max_length: Maximum length of webpage content (if included)
  27. language: Language code for search results (e.g., en, es, fr)
  28. country: Optional country code for search results (e.g., us, uk)
  29. safe_search: Enable safe search filtering
  30. Returns:
  31. List[Dict[str, str]]: List of search results, each containing:
  32. - title: Result title
  33. - link: Result URL
  34. - snippet: Result description (if include_snippets=True)
  35. - content: Webpage content in markdown (if include_content=True)
  36. """
  37. api_key = os.getenv("GOOGLE_API_KEY")
  38. cse_id = os.getenv("GOOGLE_CSE_ID")
  39. if not api_key or not cse_id:
  40. raise ValueError("Missing required environment variables. Please set GOOGLE_API_KEY and GOOGLE_CSE_ID.")
  41. num_results = min(max(1, num_results), 10)
  42. async def fetch_page_content(url: str, max_length: Optional[int] = 50000) -> str:
  43. """Helper function to fetch and convert webpage content to markdown"""
  44. headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
  45. try:
  46. async with httpx.AsyncClient() as client:
  47. response = await client.get(url, headers=headers, timeout=10)
  48. response.raise_for_status()
  49. soup = BeautifulSoup(response.text, "html.parser")
  50. # Remove script and style elements
  51. for script in soup(["script", "style"]):
  52. script.decompose()
  53. # Convert relative URLs to absolute
  54. for tag in soup.find_all(["a", "img"]):
  55. if tag.get("href"):
  56. tag["href"] = urljoin(url, tag["href"])
  57. if tag.get("src"):
  58. tag["src"] = urljoin(url, tag["src"])
  59. h2t = html2text.HTML2Text()
  60. h2t.body_width = 0
  61. h2t.ignore_images = False
  62. h2t.ignore_emphasis = False
  63. h2t.ignore_links = False
  64. h2t.ignore_tables = False
  65. markdown = h2t.handle(str(soup))
  66. if max_length and len(markdown) > max_length:
  67. markdown = markdown[:max_length] + "\n...(truncated)"
  68. return markdown.strip()
  69. except Exception as e:
  70. return f"Error fetching content: {str(e)}"
  71. params = {
  72. "key": api_key,
  73. "cx": cse_id,
  74. "q": query,
  75. "num": num_results,
  76. "hl": language,
  77. "safe": "active" if safe_search else "off",
  78. }
  79. if country:
  80. params["gl"] = country
  81. try:
  82. async with httpx.AsyncClient() as client:
  83. response = await client.get("https://www.googleapis.com/customsearch/v1", params=params, timeout=10)
  84. response.raise_for_status()
  85. data = response.json()
  86. results = []
  87. if "items" in data:
  88. for item in data["items"]:
  89. result = {"title": item.get("title", ""), "link": item.get("link", "")}
  90. if include_snippets:
  91. result["snippet"] = item.get("snippet", "")
  92. if include_content:
  93. result["content"] = await fetch_page_content(result["link"], max_length=content_max_length)
  94. results.append(result)
  95. return results
  96. except httpx.RequestError as e:
  97. raise ValueError(f"Failed to perform search: {str(e)}") from e
  98. except KeyError as e:
  99. raise ValueError(f"Invalid API response format: {str(e)}") from e
  100. except Exception as e:
  101. raise ValueError(f"Error during search: {str(e)}") from e
  102. # Create the enhanced Google search tool
  103. google_search_tool = FunctionTool(
  104. func=google_search,
  105. description="""
  106. Perform Google searches using the Custom Search API with optional webpage content fetching.
  107. Requires GOOGLE_API_KEY and GOOGLE_CSE_ID environment variables to be set.
  108. """,
  109. global_imports=[
  110. ImportFromModule("typing", ("List", "Dict", "Optional")),
  111. "os",
  112. "httpx",
  113. "html2text",
  114. ImportFromModule("bs4", ("BeautifulSoup",)),
  115. ImportFromModule("urllib.parse", ("urljoin",)),
  116. ],
  117. )