Coverage for agentos/agent/agent_builder.py: 0%
85 statements
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-06 21:19 +0800
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-06 21:19 +0800
1"""
2Agent Builder — 一键构建生产级 ToolAgent。
4自动发现所有 BaseTool 子类并通过 Bridge 注册到 ToolExecutor。
5支持多种 LLM Provider 的自动探测。
6"""
8from __future__ import annotations
10import importlib
11import inspect
12import os
13import pkgutil
15from agentos.agent.tool_agent import AgentConfig, ToolAgent, ToolExecutor
16from agentos.llm.base import LLMProvider
17from agentos.tools.base import BaseTool
18from agentos.tools.bridge import bridge_registry_to_executor
19from agentos.tools.registry import ToolRegistry
21# ── Tool Discovery ──
24def discover_tools(package_path: str = "agentos.tools") -> list[BaseTool]:
25 """自动发现 agentos.tools 包下所有 BaseTool 子类并实例化。
27 排除已知不能独立执行的基础类。
28 """
29 tools: list[BaseTool] = []
30 seen: set[str] = set()
32 package = importlib.import_module(package_path)
33 package_dir = os.path.dirname(package.__file__)
35 for _, module_name, is_pkg in pkgutil.iter_modules([package_dir]):
36 if module_name.startswith("_"):
37 continue
38 try:
39 mod = importlib.import_module(f"{package_path}.{module_name}")
40 except Exception:
41 continue
43 for name, obj in inspect.getmembers(mod, inspect.isclass):
44 if not issubclass(obj, BaseTool) or obj is BaseTool:
45 continue
46 if name in seen:
47 continue
48 # Skip abstract/helper base classes
49 if getattr(obj, "name", None) is None:
50 continue
51 try:
52 instance = obj()
53 tools.append(instance)
54 seen.add(name)
55 except Exception:
56 continue
58 return tools
61# ── Provider Auto-Detection ──
64def create_provider() -> LLMProvider:
65 """自动探测可用的 LLM Provider。
67 优先级: DEEPSEEK_API_KEY > OPENAI_API_KEY > Mock (dev fallback)
68 """
69 # DeepSeek
70 if os.getenv("DEEPSEEK_API_KEY"):
71 from agentos.llm.providers.deepseek import DeepSeekProvider
73 return DeepSeekProvider(model="deepseek-chat")
75 # OpenAI
76 if os.getenv("OPENAI_API_KEY"):
77 from agentos.llm.providers.openai import OpenAIProvider
79 return OpenAIProvider(model="gpt-4o-mini")
81 # Anthropic
82 if os.getenv("ANTHROPIC_API_KEY"):
83 from agentos.llm.providers.anthropic import AnthropicProvider
85 return AnthropicProvider(model="claude-3-5-sonnet-20241022")
87 # Mock (dev fallback)
88 from agentos.agent.agent_builder import _MockProvider
90 return _MockProvider()
93class _MockProvider(LLMProvider):
94 """仅用于开发环境的 Mock Provider。"""
96 provider_name = "mock-dev"
98 def __init__(self):
99 super().__init__(model="mock")
101 def chat(self, messages, **kwargs):
102 return self._make("Mock provider: no API key configured. Set DEEPSEEK_API_KEY.")
104 async def achat(self, messages, **kwargs):
105 return self.chat(messages, **kwargs)
107 def _make(self, content):
108 from agentos.llm.base import (
109 CompletionChoice,
110 CompletionResult,
111 CompletionUsage,
112 Message,
113 MessageRole,
114 )
116 return CompletionResult(
117 choices=[
118 CompletionChoice(
119 index=0,
120 message=Message(role=MessageRole.ASSISTANT, content=content),
121 finish_reason="stop",
122 )
123 ],
124 usage=CompletionUsage(prompt_tokens=0, completion_tokens=0, total_tokens=0),
125 model="mock",
126 )
129# ── Builder ──
132def build_agent(
133 *,
134 tools: list[BaseTool] | None = None,
135 provider: LLMProvider | None = None,
136 system_prompt: str | None = None,
137 max_steps: int = 10,
138 verbose: bool = False,
139 discover_all: bool = True,
140 include_skills: bool = True,
141) -> ToolAgent:
142 """一键构建生产级 ToolAgent。
144 Args:
145 tools: 手动指定的工具列表。为 None 且 discover_all=True 时自动发现全部。
146 provider: LLM Provider。为 None 时自动探测。
147 system_prompt: 系统提示词。为 None 时使用默认中文提示。
148 max_steps: 最大推理步数。
149 verbose: 是否打印详细日志。
150 discover_all: 是否自动发现所有 BaseTool。
152 Returns:
153 配置完成的 ToolAgent 实例。
155 Example:
156 agent = build_agent()
157 result = agent.run("列出 /tmp 目录下的所有 .txt 文件")
158 """
159 # Tools
160 if tools is None and discover_all:
161 tools = discover_tools()
163 # Skills — auto-discover and wrap as tools
164 if include_skills:
165 try:
166 from agentos.tools.skill_tool import discover_skills
168 skill_tools = discover_skills()
169 if tools is None:
170 tools = list(skill_tools)
171 else:
172 tools = list(tools) + list(skill_tools)
173 except Exception:
174 pass
176 if tools is None:
177 tools = []
179 reg = ToolRegistry()
180 for tool in tools:
181 reg.register(tool)
183 executor = ToolExecutor()
184 bridge_registry_to_executor(reg, executor)
186 # Provider
187 if provider is None:
188 provider = create_provider()
190 # System prompt
191 if system_prompt is None:
192 tool_names = ", ".join(t.name for t in tools) if tools else "无"
193 system_prompt = (
194 "你是一个智能助手,可以使用工具来完成任务。\n"
195 f"可用工具: {tool_names}\n"
196 "当你可以给出最终答案时直接回答,不要再调用工具。\n"
197 "用简洁的中文回答。"
198 )
200 agent = ToolAgent(
201 provider=provider,
202 tool_executor=executor,
203 config=AgentConfig(max_steps=max_steps, verbose=verbose),
204 system_prompt=system_prompt,
205 )
207 return agent