ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
# coding: utf-8
|
||||
# Copyright (c) 2025 inclusionAI.
|
||||
|
||||
import json
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
from aworld.tools import FunctionTools
|
||||
|
||||
# Create another function tool server with a different name
|
||||
function = FunctionTools("another-server",
|
||||
description="Another function tools server example")
|
||||
|
||||
@function.tool(description="Get weather information for a city")
|
||||
def get_weather(
|
||||
city: str = Field(
|
||||
description="City name to get weather for"
|
||||
),
|
||||
days: int = Field(
|
||||
3,
|
||||
description="Number of days for forecast"
|
||||
)
|
||||
) -> Dict[str, Any]:
|
||||
"""Get weather information for a city (simulated data)"""
|
||||
# Simulated weather data
|
||||
weather_types = ["Sunny", "Cloudy", "Rainy", "Windy", "Snowy"]
|
||||
import random
|
||||
|
||||
forecast = []
|
||||
for i in range(days):
|
||||
forecast.append({
|
||||
"date": f"2023-06-{i+1:02d}",
|
||||
"weather": random.choice(weather_types),
|
||||
"temperature": {
|
||||
"min": random.randint(15, 25),
|
||||
"max": random.randint(26, 35)
|
||||
},
|
||||
"humidity": random.randint(30, 90)
|
||||
})
|
||||
|
||||
return {
|
||||
"city": city,
|
||||
"country": "Sample Country",
|
||||
"forecast": forecast
|
||||
}
|
||||
|
||||
@function.tool(description="Convert currency from one to another")
|
||||
def convert_currency(
|
||||
amount: float = Field(
|
||||
description="Amount to convert"
|
||||
),
|
||||
from_currency: str = Field(
|
||||
description="Source currency code (e.g. USD)"
|
||||
),
|
||||
to_currency: str = Field(
|
||||
description="Target currency code (e.g. EUR)"
|
||||
)
|
||||
) -> Dict[str, Any]:
|
||||
"""Currency conversion (simulated data)"""
|
||||
# Simulated exchange rate data
|
||||
rates = {
|
||||
"USD": 1.0,
|
||||
"EUR": 0.85,
|
||||
"GBP": 0.75,
|
||||
"JPY": 110.0,
|
||||
"CNY": 6.5
|
||||
}
|
||||
|
||||
# Check if currencies are supported
|
||||
if from_currency not in rates:
|
||||
return {"error": f"Currency {from_currency} not supported"}
|
||||
if to_currency not in rates:
|
||||
return {"error": f"Currency {to_currency} not supported"}
|
||||
|
||||
# Calculate conversion
|
||||
usd_amount = amount / rates[from_currency]
|
||||
converted_amount = usd_amount * rates[to_currency]
|
||||
|
||||
return {
|
||||
"from": {
|
||||
"currency": from_currency,
|
||||
"amount": amount
|
||||
},
|
||||
"to": {
|
||||
"currency": to_currency,
|
||||
"amount": round(converted_amount, 2)
|
||||
},
|
||||
"rate": round(rates[to_currency] / rates[from_currency], 4)
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Test tools
|
||||
print("=== Testing get_weather tool ===")
|
||||
weather = function.call_tool("get_weather", {"city": "Beijing"})
|
||||
|
||||
print("\n=== Testing convert_currency tool ===")
|
||||
conversion = function.call_tool("convert_currency", {
|
||||
"amount": 100,
|
||||
"from_currency": "USD",
|
||||
"to_currency": "EUR"
|
||||
})
|
||||
print(conversion)
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
# coding: utf-8
|
||||
# Copyright (c) 2025 inclusionAI.
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pprint
|
||||
from typing import List, Dict, Any, Optional, Union
|
||||
|
||||
import aiohttp
|
||||
from mcp.types import TextContent
|
||||
from pydantic import Field
|
||||
|
||||
from aworld.tools import FunctionTools
|
||||
|
||||
# Create function tools server
|
||||
function = FunctionTools("aworldsearch_server",
|
||||
description="Search service for AWorld")
|
||||
|
||||
async def search_single(query: str, num: int = 5) -> Optional[Dict[str, Any]]:
|
||||
"""Execute a single search query, returns None on error"""
|
||||
try:
|
||||
url = os.getenv('AWORLD_SEARCH_URL')
|
||||
searchMode = os.getenv('AWORLD_SEARCH_SEARCHMODE')
|
||||
source = os.getenv('AWORLD_SEARCH_SOURCE')
|
||||
domain = os.getenv('AWORLD_SEARCH_DOMAIN')
|
||||
uid = os.getenv('AWORLD_SEARCH_UID')
|
||||
if not url or not searchMode or not source or not domain:
|
||||
logging.warning(f"Query failed: url, searchMode, source, domain parameters incomplete")
|
||||
return None
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
data = {
|
||||
"domain": domain,
|
||||
"extParams": {},
|
||||
"page": 0,
|
||||
"pageSize": num,
|
||||
"query": query,
|
||||
"searchMode": searchMode,
|
||||
"source": source,
|
||||
"userId": uid
|
||||
}
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
try:
|
||||
async with session.post(url, headers=headers, json=data) as response:
|
||||
if response.status != 200:
|
||||
logging.warning(f"Query failed: {query}, status code: {response.status}")
|
||||
return None
|
||||
|
||||
result = await response.json()
|
||||
return result
|
||||
except aiohttp.ClientError:
|
||||
logging.warning(f"Request error: {query}")
|
||||
return None
|
||||
except Exception:
|
||||
logging.warning(f"Query exception: {query}")
|
||||
return None
|
||||
|
||||
|
||||
def filter_valid_docs(result: Optional[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
||||
"""Filter valid document results, returns empty list if input is None"""
|
||||
if result is None:
|
||||
return []
|
||||
|
||||
try:
|
||||
valid_docs = []
|
||||
|
||||
# Check success field
|
||||
if not result.get("success"):
|
||||
return valid_docs
|
||||
|
||||
# Check searchDocs field
|
||||
search_docs = result.get("searchDocs", [])
|
||||
if not search_docs:
|
||||
return valid_docs
|
||||
|
||||
# Extract required fields
|
||||
required_fields = ["title", "docAbstract", "url", "doc"]
|
||||
|
||||
for doc in search_docs:
|
||||
# Check if all required fields exist and are non-empty
|
||||
is_valid = True
|
||||
for field in required_fields:
|
||||
if field not in doc or not doc[field]:
|
||||
is_valid = False
|
||||
break
|
||||
|
||||
if is_valid:
|
||||
# Only keep required fields
|
||||
filtered_doc = {field: doc[field] for field in required_fields}
|
||||
valid_docs.append(filtered_doc)
|
||||
|
||||
return valid_docs
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
|
||||
@function.tool(description="Search based on the user's input query list")
|
||||
async def search(
|
||||
query_list: List[str] = Field(
|
||||
description="List format, queries to search for"
|
||||
),
|
||||
num: int = Field(
|
||||
5,
|
||||
description="Maximum number of results per query, default is 5, please keep the total results within 15"
|
||||
)
|
||||
) -> Union[str, TextContent]:
|
||||
"""Execute main search function, supports single query or query list"""
|
||||
try:
|
||||
# Get configuration from environment variables
|
||||
env_total_num = os.getenv('AWORLD_SEARCH_TOTAL_NUM')
|
||||
if env_total_num and env_total_num.isdigit():
|
||||
# Use environment variable to forcibly override the input num parameter
|
||||
num = int(env_total_num)
|
||||
|
||||
# If no query is provided, return empty list
|
||||
if not query_list:
|
||||
# Initialize TextContent with additional parameters
|
||||
return TextContent(
|
||||
type="text",
|
||||
text="", # Empty string instead of None
|
||||
**{"metadata": {}} # Pass as additional field
|
||||
)
|
||||
|
||||
# When query count >=3 or slice_num is set, use the corresponding value
|
||||
slice_num = os.getenv('AWORLD_SEARCH_SLICE_NUM')
|
||||
if slice_num and slice_num.isdigit():
|
||||
actual_num = int(slice_num)
|
||||
else:
|
||||
actual_num = 2 if len(query_list) >= 3 else num
|
||||
|
||||
# Execute all queries in parallel
|
||||
tasks = [search_single(q, actual_num) for q in query_list]
|
||||
raw_results = await asyncio.gather(*tasks)
|
||||
|
||||
# Filter and merge results
|
||||
all_valid_docs = []
|
||||
for result in raw_results:
|
||||
valid_docs = filter_valid_docs(result)
|
||||
all_valid_docs.extend(valid_docs)
|
||||
|
||||
# If no valid results found, return empty list
|
||||
if not all_valid_docs:
|
||||
# Initialize TextContent with additional parameters
|
||||
return TextContent(
|
||||
type="text",
|
||||
text="", # Empty string instead of None
|
||||
**{"metadata": {}} # Pass as additional field
|
||||
)
|
||||
|
||||
# Format results as JSON
|
||||
result_json = json.dumps(all_valid_docs, ensure_ascii=False)
|
||||
|
||||
# Create dictionary structure directly
|
||||
combined_query = ",".join(query_list)
|
||||
|
||||
search_items = []
|
||||
# Use dictionary for URL deduplication
|
||||
url_dict = {}
|
||||
for doc in all_valid_docs:
|
||||
url = doc.get("url", "")
|
||||
if url not in url_dict:
|
||||
url_dict[url] = {
|
||||
"title": doc.get("title", ""),
|
||||
"url": url,
|
||||
"snippet": doc.get("doc", "")[:100] + "..." if len(doc.get("doc", "")) > 100 else doc.get("doc", ""),
|
||||
"content": doc.get("doc", "") # Map doc field to content
|
||||
}
|
||||
|
||||
# Convert dictionary values to list
|
||||
search_items = list(url_dict.values())
|
||||
|
||||
search_output_dict = {
|
||||
"artifact_type": "WEB_PAGES",
|
||||
"artifact_data": {
|
||||
"query": combined_query,
|
||||
"results": search_items
|
||||
}
|
||||
}
|
||||
|
||||
# Log results
|
||||
logging.info(f"Completed {len(query_list)} queries, found {len(all_valid_docs)} valid documents")
|
||||
|
||||
# Initialize TextContent with additional parameters
|
||||
return TextContent(
|
||||
type="text",
|
||||
text=result_json,
|
||||
**{"metadata": search_output_dict} # Pass processed data as metadata
|
||||
)
|
||||
except Exception as e:
|
||||
# Handle errors
|
||||
logging.error(f"Search error: {e}")
|
||||
# Initialize TextContent with additional parameters
|
||||
return TextContent(
|
||||
type="text",
|
||||
text="", # Empty string instead of None
|
||||
**{"metadata": {}} # Pass as additional field
|
||||
)
|
||||
|
||||
# Test code
|
||||
if __name__ == "__main__":
|
||||
import pprint
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
|
||||
# List all tools
|
||||
print("Tool list:")
|
||||
tools = function.list_tools()
|
||||
print(tools)
|
||||
res = function.call_tool("search", {"query_list": ["Tencent financial report", "Baidu financial report", "Alibaba financial report"],})
|
||||
print(res)
|
||||
# for tool in tools:
|
||||
# print(f"Tool name: {tool.name}")
|
||||
# print(f"Tool description: {tool.description}")
|
||||
# print(f"Parameter schema: {tool.inputSchema}")
|
||||
# if tool.annotations:
|
||||
# print(f"Annotation information:")
|
||||
# print(f" - Title: {tool.annotations.title}")
|
||||
# print()
|
||||
@@ -0,0 +1,221 @@
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from typing import List, Dict, Any, Optional, Union
|
||||
|
||||
import aiohttp
|
||||
from mcp.server import FastMCP
|
||||
from mcp.types import TextContent
|
||||
from pydantic import Field
|
||||
|
||||
mcp = FastMCP("aworldsearch-server")
|
||||
|
||||
async def search_single(query: str, num: int = 5) -> Optional[Dict[str, Any]]:
|
||||
"""Execute a single search query, returns None on error"""
|
||||
try:
|
||||
url = os.getenv('AWORLD_SEARCH_URL')
|
||||
searchMode = os.getenv('AWORLD_SEARCH_SEARCHMODE')
|
||||
source = os.getenv('AWORLD_SEARCH_SOURCE')
|
||||
domain = os.getenv('AWORLD_SEARCH_DOMAIN')
|
||||
uid = os.getenv('AWORLD_SEARCH_UID')
|
||||
if not url or not searchMode or not source or not domain:
|
||||
logging.warning(f"Query failed: url, searchMode, source, domain parameters incomplete")
|
||||
return None
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
data = {
|
||||
"domain": domain,
|
||||
"extParams": {},
|
||||
"page": 0,
|
||||
"pageSize": num,
|
||||
"query": query,
|
||||
"searchMode": searchMode,
|
||||
"source": source,
|
||||
"userId": uid
|
||||
}
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
try:
|
||||
async with session.post(url, headers=headers, json=data) as response:
|
||||
if response.status != 200:
|
||||
logging.warning(f"Query failed: {query}, status code: {response.status}")
|
||||
return None
|
||||
|
||||
result = await response.json()
|
||||
return result
|
||||
except aiohttp.ClientError:
|
||||
logging.warning(f"Request error: {query}")
|
||||
return None
|
||||
except Exception:
|
||||
logging.warning(f"Query exception: {query}")
|
||||
return None
|
||||
|
||||
|
||||
def filter_valid_docs(result: Optional[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
||||
"""Filter valid document results, returns empty list if input is None"""
|
||||
if result is None:
|
||||
return []
|
||||
|
||||
try:
|
||||
valid_docs = []
|
||||
|
||||
# Check success field
|
||||
if not result.get("success"):
|
||||
return valid_docs
|
||||
|
||||
# Check searchDocs field
|
||||
search_docs = result.get("searchDocs", [])
|
||||
if not search_docs:
|
||||
return valid_docs
|
||||
|
||||
# Extract required fields
|
||||
required_fields = ["title", "docAbstract", "url", "doc"]
|
||||
|
||||
for doc in search_docs:
|
||||
# Check if all required fields exist and are not empty
|
||||
is_valid = True
|
||||
for field in required_fields:
|
||||
if field not in doc or not doc[field]:
|
||||
is_valid = False
|
||||
break
|
||||
|
||||
if is_valid:
|
||||
# Keep only required fields
|
||||
filtered_doc = {field: doc[field] for field in required_fields}
|
||||
valid_docs.append(filtered_doc)
|
||||
|
||||
return valid_docs
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
|
||||
@mcp.tool(description="Search based on the user's input query list")
|
||||
async def search(
|
||||
query_list: List[str] = Field(
|
||||
description="List format, queries to search for"
|
||||
),
|
||||
num: int = Field(
|
||||
5,
|
||||
description="Maximum number of results per query, default is 5, please keep the total results within 15"
|
||||
)
|
||||
) -> Union[str, TextContent]:
|
||||
"""Execute search main function, supports single query or query list"""
|
||||
try:
|
||||
# Get configuration from environment variables
|
||||
env_total_num = os.getenv('AWORLD_SEARCH_TOTAL_NUM')
|
||||
if env_total_num and env_total_num.isdigit():
|
||||
# Force override input num parameter with environment variable
|
||||
num = int(env_total_num)
|
||||
|
||||
# If no queries provided, return empty list
|
||||
if not query_list:
|
||||
# Initialize TextContent with additional parameters
|
||||
return TextContent(
|
||||
type="text",
|
||||
text="", # Empty string instead of None
|
||||
**{"metadata": {}} # Pass as additional fields
|
||||
)
|
||||
|
||||
# When query count is >= 3 or slice_num is set, use corresponding value
|
||||
slice_num = os.getenv('AWORLD_SEARCH_SLICE_NUM')
|
||||
if slice_num and slice_num.isdigit():
|
||||
actual_num = int(slice_num)
|
||||
else:
|
||||
actual_num = 2 if len(query_list) >= 3 else num
|
||||
|
||||
# Execute all queries in parallel
|
||||
tasks = [search_single(q, actual_num) for q in query_list]
|
||||
raw_results = await asyncio.gather(*tasks)
|
||||
|
||||
# Filter and merge results
|
||||
all_valid_docs = []
|
||||
for result in raw_results:
|
||||
valid_docs = filter_valid_docs(result)
|
||||
all_valid_docs.extend(valid_docs)
|
||||
|
||||
# If no valid results found, return empty list
|
||||
if not all_valid_docs:
|
||||
# Initialize TextContent with additional parameters
|
||||
return TextContent(
|
||||
type="text",
|
||||
text="", # Empty string instead of None
|
||||
**{"metadata": {}} # Pass as additional fields
|
||||
)
|
||||
|
||||
# Format results as JSON
|
||||
result_json = json.dumps(all_valid_docs, ensure_ascii=False)
|
||||
|
||||
# Create dictionary structure directly
|
||||
combined_query = ",".join(query_list)
|
||||
|
||||
search_items = []
|
||||
# Use a dictionary to deduplicate by URL
|
||||
url_dict = {}
|
||||
for doc in all_valid_docs:
|
||||
url = doc.get("url", "")
|
||||
if url not in url_dict:
|
||||
url_dict[url] = {
|
||||
"title": doc.get("title", ""),
|
||||
"url": url,
|
||||
"snippet": doc.get("doc", "")[:100] + "..." if len(doc.get("doc", "")) > 100 else doc.get("doc",
|
||||
""),
|
||||
"content": doc.get("doc", "") # Map doc field to content
|
||||
}
|
||||
|
||||
# Convert dictionary values to list
|
||||
search_items = list(url_dict.values())
|
||||
|
||||
search_output_dict = {
|
||||
"artifact_type": "WEB_PAGES",
|
||||
"artifact_data": {
|
||||
"query": combined_query,
|
||||
"results": search_items
|
||||
}
|
||||
}
|
||||
|
||||
# Log results
|
||||
logging.info(f"Completed {len(query_list)} queries, found {len(all_valid_docs)} valid documents")
|
||||
|
||||
# Initialize TextContent with additional parameters
|
||||
return TextContent(
|
||||
type="text",
|
||||
text=result_json,
|
||||
**{"metadata": search_output_dict} # Pass processed data as metadata
|
||||
)
|
||||
except Exception as e:
|
||||
# Handle errors
|
||||
logging.error(f"Search error: {e}")
|
||||
# Initialize TextContent with additional parameters
|
||||
return TextContent(
|
||||
type="text",
|
||||
text="", # Empty string instead of None
|
||||
**{"metadata": {}} # Pass as additional fields
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv(override=True)
|
||||
|
||||
print("Starting Audio MCP aworldsearch-server...", file=sys.stderr)
|
||||
mcp.run(transport="stdio")
|
||||
|
||||
|
||||
# Make the module callable
|
||||
def __call__():
|
||||
"""
|
||||
Make the module callable for uvx.
|
||||
This function is called when the module is executed directly.
|
||||
"""
|
||||
main()
|
||||
|
||||
|
||||
sys.modules[__name__].__call__ = __call__
|
||||
|
||||
# if __name__ == "__main__":
|
||||
# main()
|
||||
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"amap-amap-sse": {
|
||||
"type": "sse",
|
||||
"url": "https://mcp.amap.com/sse?key=${AMAP_AMAP_SSE_KEY}",
|
||||
"timeout": 5.0,
|
||||
"sse_read_timeout": 300.0
|
||||
},
|
||||
"tavily-mcp": {
|
||||
"type": "stdio",
|
||||
"command": "npx",
|
||||
"args": ["-y", "tavily-mcp@0.1.2"],
|
||||
"env": {
|
||||
"TAVILY_API_KEY": "tvly-dev-"
|
||||
}
|
||||
},
|
||||
"aworldsearch_server": {
|
||||
"type": "function_tool"
|
||||
},
|
||||
"aworldsearch_server1": {
|
||||
"command": "python",
|
||||
"args": [
|
||||
"-m",
|
||||
"mcp_servers.aworldsearch_server"
|
||||
],
|
||||
"env": {
|
||||
"AWORLD_SEARCH_URL": "${AWORLD_SEARCH_URL}",
|
||||
"AWORLD_SEARCH_TOTAL_NUM": "${AWORLD_SEARCH_TOTAL_NUM}",
|
||||
"AWORLD_SEARCH_SLICE_NUM": "${AWORLD_SEARCH_SLICE_NUM}",
|
||||
"AWORLD_SEARCH_DOMAIN": "${AWORLD_SEARCH_DOMAIN}",
|
||||
"AWORLD_SEARCH_SEARCHMODE": "${AWORLD_SEARCH_SEARCHMODE}",
|
||||
"AWORLD_SEARCH_SOURCE": "${AWORLD_SEARCH_SOURCE}",
|
||||
"AWORLD_SEARCH_UID": "${AWORLD_SEARCH_UID}"
|
||||
}
|
||||
},
|
||||
"picsearch_server": {
|
||||
"command": "python",
|
||||
"args": [
|
||||
"-m",
|
||||
"mcp_servers.picsearch_server"
|
||||
],
|
||||
"env": {
|
||||
"PIC_SEARCH_URL": "${PIC_SEARCH_URL}",
|
||||
"PIC_SEARCH_TOTAL_NUM": "${PIC_SEARCH_TOTAL_NUM}",
|
||||
"PIC_SEARCH_SLICE_NUM": "${PIC_SEARCH_SLICE_NUM}",
|
||||
"PIC_SEARCH_DOMAIN": "${PIC_SEARCH_DOMAIN}",
|
||||
"PIC_SEARCH_SEARCHMODE": "${PIC_SEARCH_SEARCHMODE}",
|
||||
"PIC_SEARCH_SOURCE": "${PIC_SEARCH_SOURCE}"
|
||||
}
|
||||
},
|
||||
"gen_audio_server": {
|
||||
"command": "python",
|
||||
"args": [
|
||||
"-m",
|
||||
"mcp_servers.gen_audio_server"
|
||||
],
|
||||
"env": {
|
||||
"AUDIO_TASK_URL": "${AUDIO_TASK_URL}",
|
||||
"AUDIO_QUERY_URL": "${AUDIO_QUERY_URL}",
|
||||
"AUDIO_APP_KEY": "${AUDIO_APP_KEY}",
|
||||
"AUDIO_SECRET": "${AUDIO_SECRET}",
|
||||
"AUDIO_SAMPLE_RATE": "${AUDIO_SAMPLE_RATE}",
|
||||
"AUDIO_AUDIO_FORMAT": "${AUDIO_AUDIO_FORMAT}",
|
||||
"AUDIO_TTS_VOICE": "${AUDIO_TTS_VOICE}",
|
||||
"AUDIO_TTS_SPEECH_RATE": "${AUDIO_TTS_SPEECH_RATE}",
|
||||
"AUDIO_TTS_VOLUME": "${AUDIO_TTS_VOLUME}",
|
||||
"AUDIO_TTS_PITCH": "${AUDIO_TTS_PITCH}",
|
||||
"AUDIO_VOICE_TYPE": "${AUDIO_VOICE_TYPE}"
|
||||
}
|
||||
},
|
||||
"gen_video_server": {
|
||||
"command": "python",
|
||||
"args": [
|
||||
"-m",
|
||||
"mcp_servers.gen_video_server"
|
||||
],
|
||||
"env": {
|
||||
"DASHSCOPE_API_KEY": "${DASHSCOPE_API_KEY}",
|
||||
"DASHSCOPE_VIDEO_SUBMIT_URL": "${DASHSCOPE_VIDEO_SUBMIT_URL}",
|
||||
"DASHSCOPE_QUERY_BASE_URL": "${DASHSCOPE_QUERY_BASE_URL}",
|
||||
"DASHSCOPE_VIDEO_MODEL": "${DASHSCOPE_VIDEO_MODEL}",
|
||||
"DASHSCOPE_VIDEO_SIZE": "${DASHSCOPE_VIDEO_SIZE}",
|
||||
"DASHSCOPE_VIDEO_SLEEP_TIME": "${DASHSCOPE_VIDEO_SLEEP_TIME}",
|
||||
"DASHSCOPE_VIDEO_RETRY_TIMES": "${DASHSCOPE_VIDEO_RETRY_TIMES}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
# coding: utf-8
|
||||
# Copyright (c) 2025 inclusionAI.
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from aworld.agents.llm_agent import Agent
|
||||
from aworld.config.conf import AgentConfig, TaskConfig
|
||||
from aworld.core.task import Task
|
||||
|
||||
from aworld.runner import Runners
|
||||
from aworld.runners.callback.decorator import reg_callback
|
||||
|
||||
|
||||
@reg_callback("print_content")
|
||||
def simple_callback(content):
|
||||
"""Simple callback function, prints content and returns it
|
||||
|
||||
Args:
|
||||
content: Content to print
|
||||
|
||||
Returns:
|
||||
The input content
|
||||
"""
|
||||
print(f"callback content: {content}")
|
||||
return content
|
||||
|
||||
async def run():
|
||||
load_dotenv()
|
||||
llm_provider = os.getenv("LLM_PROVIDER_WEATHER", "openai")
|
||||
llm_model_name = os.getenv("LLM_MODEL_NAME_WEATHER")
|
||||
llm_api_key = os.getenv("LLM_API_KEY_WEATHER")
|
||||
llm_base_url = os.getenv("LLM_BASE_URL_WEATHER")
|
||||
llm_temperature = os.getenv("LLM_TEMPERATURE_WEATHER", 0.0)
|
||||
|
||||
agent_config = AgentConfig(
|
||||
llm_provider=llm_provider,
|
||||
llm_model_name=llm_model_name,
|
||||
llm_api_key=llm_api_key,
|
||||
llm_base_url=llm_base_url,
|
||||
llm_temperature=llm_temperature,
|
||||
)
|
||||
#mcp_servers = ["filewrite_server", "fileread_server"]
|
||||
#mcp_servers = ["amap-amap-sse","filewrite_server", "fileread_server"]
|
||||
#mcp_servers = ["file_server"]
|
||||
#mcp_servers = ["amap-amap-sse"]
|
||||
mcp_servers = ["aworldsearch_server"]
|
||||
#mcp_servers = ["gen_video_server"]
|
||||
# mcp_servers = ["picsearch_server"]
|
||||
#mcp_servers = ["gen_audio_server"]
|
||||
#mcp_servers = ["playwright"]
|
||||
#mcp_servers = ["tavily-mcp"]
|
||||
|
||||
path_cwd = os.path.dirname(os.path.abspath(__file__))
|
||||
mcp_path = os.path.join(path_cwd, "mcp.json")
|
||||
with open(mcp_path, "r") as f:
|
||||
mcp_config = json.load(f)
|
||||
|
||||
print("-------------------mcp_config--------------",mcp_config)
|
||||
|
||||
#sand_box = Sandbox(mcp_servers=mcp_servers,mcp_config=mcp_config)
|
||||
# You can specify sandbox
|
||||
#sand_box = Sandbox(mcp_servers=mcp_servers, mcp_config=mcp_config,env_type=SandboxEnvType.K8S)
|
||||
#sand_box = Sandbox(mcp_servers=mcp_servers, mcp_config=mcp_config,env_type=SandboxEnvType.SUPERCOMPUTER)
|
||||
|
||||
search_sys_prompt = "You are a versatile assistant"
|
||||
search = Agent(
|
||||
conf=agent_config,
|
||||
name="search_agent",
|
||||
system_prompt=search_sys_prompt,
|
||||
mcp_config=mcp_config,
|
||||
mcp_servers=mcp_servers,
|
||||
#sandbox=sand_box,
|
||||
)
|
||||
|
||||
# Run agent
|
||||
# Runners.sync_run(input="Use tavily-mcp to check what tourist attractions are in Hangzhou", agent=search)
|
||||
task = Task(
|
||||
# input="Use tavily-mcp to check what tourist attractions are in Hangzhou",
|
||||
# input="Use the file_server tool to analyze this audio link: https://amap-aibox-data.oss-cn-zhangjiakou.aliyuncs.com/.mp3",
|
||||
# input="Use the amap-amap-sse tool to find hotels within one kilometer of West Lake in Hangzhou",
|
||||
input="Use the aworldsearch_server tool to search for the origin of the Dragon Boat Festival",
|
||||
# input="Use the picsearch_server tool to search for Captain America",
|
||||
# input="Make sure to use the human_confirm tool to let the user confirm this message: 'Do you want to make a payment to this customer'",
|
||||
# input="Use the gen_audio_server tool to convert this sentence to audio: 'Nice to meet you'",
|
||||
#input="Use the gen_video_server tool to generate a video of this description: 'A cat walking alone on a snowy day'",
|
||||
#input="How's the weather in New York, Shanghai, and Beijing right now? These are three cities, I hope the large model returns three tools when it identifies tool calls",
|
||||
# input="First call the filewrite_server tool, then call the fileread_server tool",
|
||||
# input="Use the playwright tool, with Google browser, search for the latest news about the Trump administration on www.baidu.com",
|
||||
# input="Use tavily-mcp",
|
||||
agent=search,
|
||||
conf=TaskConfig(),
|
||||
event_driven=True
|
||||
)
|
||||
|
||||
#result = Runners.sync_run_task(task)
|
||||
#result = Runners.sync_run_task(task)
|
||||
#result = await Runners.streamed_run_task(task)
|
||||
# result = await Runners.run_task(task)
|
||||
# print(
|
||||
# "----------------------------------------------------------------------------------------------"
|
||||
# )
|
||||
# print(result)
|
||||
# async for chunk in Runners.streamed_run_task(task).stream_events():
|
||||
# print(chunk, end="", flush=True)
|
||||
|
||||
async for output in Runners.streamed_run_task(task).stream_events():
|
||||
print(f"Agent Ouput: {output}")
|
||||
@@ -0,0 +1,55 @@
|
||||
# coding: utf-8
|
||||
# Copyright (c) 2025 inclusionAI.
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from aworld.config.conf import AgentConfig, TaskConfig
|
||||
from aworld.agents.llm_agent import Agent
|
||||
from aworld.core.task import Task
|
||||
from aworld.runner import Runners
|
||||
|
||||
|
||||
async def run():
|
||||
load_dotenv()
|
||||
llm_provider = os.getenv("LLM_PROVIDER_WEATHER", "openai")
|
||||
llm_model_name = os.getenv("LLM_MODEL_NAME_WEATHER")
|
||||
llm_api_key = os.getenv("LLM_API_KEY_WEATHER")
|
||||
llm_base_url = os.getenv("LLM_BASE_URL_WEATHER")
|
||||
llm_temperature = os.getenv("LLM_TEMPERATURE_WEATHER", 0.0)
|
||||
|
||||
agent_config = AgentConfig(
|
||||
llm_provider=llm_provider,
|
||||
llm_model_name=llm_model_name,
|
||||
llm_api_key=llm_api_key,
|
||||
llm_base_url=llm_base_url,
|
||||
llm_temperature=llm_temperature,
|
||||
)
|
||||
mcp_servers = ["tavily-mcp"]
|
||||
|
||||
path_cwd = os.path.dirname(os.path.abspath(__file__))
|
||||
mcp_path = os.path.join(path_cwd, "mcp.json")
|
||||
with open(mcp_path, "r") as f:
|
||||
mcp_config = json.load(f)
|
||||
|
||||
search_sys_prompt = "You are a versatile assistant"
|
||||
search = Agent(
|
||||
conf=agent_config,
|
||||
name="search_agent",
|
||||
system_prompt=search_sys_prompt,
|
||||
mcp_config=mcp_config,
|
||||
mcp_servers=mcp_servers,
|
||||
)
|
||||
|
||||
# Run agent
|
||||
task = Task(
|
||||
input="Use tavily-mcp to check what tourist attractions are in Hangzhou",
|
||||
agent=search,
|
||||
conf=TaskConfig(),
|
||||
)
|
||||
|
||||
result = Runners.sync_run_task(task)
|
||||
print( "----------------------------------------------------------------------------------------------")
|
||||
print(result)
|
||||
@@ -0,0 +1,78 @@
|
||||
# coding: utf-8
|
||||
# Copyright (c) 2025 inclusionAI.
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
def run():
|
||||
from aworld.tools import get_function_tools
|
||||
|
||||
aworldsearch_server = get_function_tools("aworldsearch_server")
|
||||
|
||||
print(aworldsearch_server.list_tools())
|
||||
res = aworldsearch_server.call_tool("search", {"query_list": ["Tencent financial report", "Baidu financial report", "Alibaba financial report"],})
|
||||
print(res)
|
||||
|
||||
another_server = get_function_tools("another-server")
|
||||
print(another_server.list_tools())
|
||||
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
|
||||
# Step 1: Import different modules, which will automatically register their respective FunctionTools instances
|
||||
print("=== Step 1: Import modules, automatically register FunctionTools instances ===")
|
||||
# Import aworldsearch_function_tools module, which registers "aworldsearch-server"
|
||||
print("Imported aworldsearch_function_tools module")
|
||||
|
||||
# Import another_function_tools module, which registers "another-server"
|
||||
|
||||
print("Imported another_function_tools module")
|
||||
|
||||
# Step 2: Get FunctionTools instances by name
|
||||
print("\n=== Step 2: Get FunctionTools instances by name ===")
|
||||
from aworld.tools import get_function_tools, list_function_tools
|
||||
|
||||
# List all registered FunctionTools servers
|
||||
print(f"All registered servers: {list_function_tools()}")
|
||||
|
||||
# Get server instance by specific name
|
||||
aworldsearch_server = get_function_tools("aworldsearch-server")
|
||||
print(f"Retrieved server: {aworldsearch_server.name}")
|
||||
print(f"Server description: {aworldsearch_server.description}")
|
||||
|
||||
another_server = get_function_tools("another-server")
|
||||
print(f"Retrieved server: {another_server.name}")
|
||||
print(f"Server description: {another_server.description}")
|
||||
|
||||
# Step 3: Use the retrieved instances to call methods
|
||||
print("\n=== Step 3: Use the retrieved instances to call methods ===")
|
||||
# List all tools of aworldsearch server
|
||||
print("aworldsearch-server tool list:")
|
||||
for tool in aworldsearch_server.list_tools():
|
||||
print(f" - {tool.name}: {tool.description}")
|
||||
|
||||
# List all tools of another server
|
||||
print("\nanother-server tool list:")
|
||||
for tool in another_server.list_tools():
|
||||
print(f" - {tool.name}: {tool.description}")
|
||||
|
||||
# Step 4: Call tools
|
||||
print("\n=== Step 4: Call tool examples ===")
|
||||
# Call aworldsearch server's tool
|
||||
if "demo_search" in [tool.name for tool in aworldsearch_server.list_tools()]:
|
||||
print("Calling demo_search tool:")
|
||||
result = aworldsearch_server.call_tool("demo_search", {"query_list": ["Test query"]})
|
||||
print(result)
|
||||
|
||||
# Call another server's tool
|
||||
if "get_weather" in [tool.name for tool in another_server.list_tools()]:
|
||||
print("\nCalling get_weather tool:")
|
||||
result = another_server.call_tool("get_weather", {"city": "Beijing"})
|
||||
print(result)
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass # Main logic has already been executed at the module level
|
||||
Reference in New Issue
Block a user