base_agent/main.py

257 lines
10 KiB
Python
Raw Normal View History

2026-02-28 08:21:35 +00:00
"""
main.py
2026-03-09 05:37:29 +00:00
智能体 Demo 程序入口OpenAI Function Calling 驱动
运行模式:
python main.py 交互模式
python main.py demo 演示模式
python main.py config 打印当前配置
python main.py health 检测 OpenAI API 连通性
LLM_API_KEY=sk-xxx python main.py 指定 API Key
LLM_MODEL_NAME=gpt-4-turbo python main.py 指定模型
AGENT_CONFIG_PATH=my.yaml python main.py 指定配置文件
2026-02-28 08:21:35 +00:00
"""
import sys
2026-03-09 05:37:29 +00:00
from client.agent_client import AgentClient, AgentResponse
from config.settings import settings
2026-02-28 08:21:35 +00:00
from llm.llm_engine import LLMEngine
from mcp.mcp_server import MCPServer
from memory.memory_store import MemoryStore
from tools.calculator import CalculatorTool
from tools.code_executor import CodeExecutorTool
from tools.file_reader import FileReaderTool
from tools.web_search import WebSearchTool
2026-03-09 06:10:07 +00:00
from tools.static_analyzer import StaticAnalyzerTool
from tools.ssh_docker import SSHDockerTool
2026-02-28 08:21:35 +00:00
from utils.logger import get_logger
logger = get_logger("SYSTEM")
2026-03-09 05:37:29 +00:00
_ALL_TOOLS = {
"calculator": CalculatorTool,
"web_search": WebSearchTool,
"file_reader": FileReaderTool,
"code_executor": CodeExecutorTool,
2026-03-09 06:10:07 +00:00
"static_analyzer": StaticAnalyzerTool,
"ssh_docker": SSHDockerTool
2026-03-09 05:37:29 +00:00
}
2026-02-28 08:21:35 +00:00
# ── 系统组装 ───────────────────────────────────────────────────
2026-03-09 05:37:29 +00:00
def build_agent() -> AgentClient:
"""工厂函数:由 settings 驱动的 Agent 组装"""
logger.info("🔧 开始组装 Agent 系统OpenAI Function Calling 模式)...")
logger.info(settings.display())
mcp_server = MCPServer()
for tool_cls in _ALL_TOOLS.values():
mcp_server.register_tool(tool_cls)
llm = LLMEngine()
memory = MemoryStore(max_history=settings.memory.max_history)
client = AgentClient(llm=llm, mcp_server=mcp_server, memory=memory)
2026-02-28 08:21:35 +00:00
logger.info(f"✅ Agent 组装完成,已注册工具: {mcp_server.list_tools()}")
return client
2026-03-09 05:37:29 +00:00
# ── 结果打印 ───────────────────────────────────────────────────
def print_response(response: AgentResponse) -> None:
"""格式化打印 AgentResponse"""
print(f"\n{'' * 62}")
print(f"👤 用户: {response.user_input}")
print(f"{'' * 62}")
if response.chain_result:
cr = response.chain_result
tag = "🔗 多步串行" if response.is_multi_step else "🔧 单步调用"
status = "✅ 全部成功" if cr.success else f"⚠️ 步骤 {cr.failed_step} 失败"
print(f"{tag} | {cr.completed_steps}/{cr.total_steps} 步 | {status}")
print()
for r in cr.step_results:
icon = "" if r.success else ""
preview = r.output.replace("\n", " ")[:90]
print(f" {icon} Step {r.step_id} [{r.tool_name}]")
if r.success:
print(f" └─ {preview}...")
else:
print(f" └─ 错误: {r.error}")
print()
print(f"🤖 Agent 回复:\n{response.final_reply}")
print(f"{'' * 62}\n")
# ── API 健康检测 ───────────────────────────────────────────────
def run_health_check() -> None:
"""检测 OpenAI API 连通性"""
print(f"\n{'' * 50}")
print(f" 🏥 OpenAI API 健康检测")
print(f"{'' * 50}")
print(f" Provider : {settings.llm.provider}")
print(f" Model : {settings.llm.model_name}")
print(f" API Key : {'***' + settings.llm.api_key[-4:] if len(settings.llm.api_key) > 4 else '(未设置)'}")
print(f" Base URL : {settings.llm.api_base_url or 'https://api.openai.com/v1'}")
print(f"{'' * 50}")
if not settings.llm.api_key:
print(" ❌ API Key 未设置")
print(" 💡 请设置环境变量: export LLM_API_KEY=sk-...")
print(f"{'' * 50}\n")
return
print(" ⏳ 正在检测连通性...")
llm = LLMEngine()
ok = llm.provider.health_check()
if ok:
print(f" ✅ API 连通正常,模型 [{settings.llm.model_name}] 可用")
else:
print(f" ❌ API 连接失败,请检查网络或 API Key")
print(f" 💡 可尝试设置代理: export LLM_API_BASE_URL=https://your-proxy/v1")
print(f"{'' * 50}\n")
2026-02-28 08:21:35 +00:00
# ── 演示场景 ───────────────────────────────────────────────────
def run_demo(client: AgentClient) -> None:
2026-03-09 05:37:29 +00:00
"""运行预设演示场景"""
2026-02-28 08:21:35 +00:00
demo_cases = [
2026-03-09 05:37:29 +00:00
("🔢 单步: 数学计算",
"计算 (100 + 200) × 3 等于多少?"),
("🌐 单步: 网络搜索",
"搜索 Python 3.12 的主要新特性"),
("🔗 两步: 搜索 + 计算",
"搜索 Python 最新版本号,然后计算 3.12 × 100 的结果"),
("🔗 两步: 读取文件 + 执行代码",
"读取 script.py 文件然后执行里面的代码"),
("💬 无工具: 直接问答",
"你好,请介绍一下你自己"),
2026-02-28 08:21:35 +00:00
]
2026-03-09 05:37:29 +00:00
logger.info("\n" + "" * 62)
logger.info(f"🎬 演示模式 | 模型: {settings.llm.model_name} | "
f"Provider: {settings.llm.provider}")
logger.info("" * 62)
2026-02-28 08:21:35 +00:00
for title, question in demo_cases:
2026-03-09 05:37:29 +00:00
logger.info(f"\n📌 场景: {title}")
2026-02-28 08:21:35 +00:00
response = client.chat(question)
2026-03-09 05:37:29 +00:00
print_response(response)
2026-02-28 08:21:35 +00:00
stats = client.get_memory_stats()
2026-03-09 05:37:29 +00:00
print(f"📊 Memory 统计: {stats}\n")
2026-02-28 08:21:35 +00:00
2026-03-09 05:37:29 +00:00
# ── 交互模式 ───────────────────────────────────────────────────
2026-02-28 08:21:35 +00:00
def run_interactive(client: AgentClient) -> None:
"""启动交互式命令行对话"""
2026-03-09 05:37:29 +00:00
print("\n" + "" * 62)
print(f" 🤖 Agent | {settings.llm.model_name} | {settings.llm.provider}")
print(f" Function Calling: {'✅ 开启' if settings.llm.function_calling else '❌ 关闭(规则引擎)'}")
print(f" Fallback Rules : {'✅ 开启' if settings.agent.fallback_to_rules else '❌ 关闭'}")
print("" * 62)
print(" 💡 示例:")
print(" 计算 (100+200) × 3")
print(" 搜索 Python 新特性,然后计算 3.12 × 100")
print(" 读取 config.json 文件然后执行代码")
print("" * 62)
print(" 🛠 命令: config / health / tools / chains / stats / clear / quit")
print("" * 62 + "\n")
2026-02-28 08:21:35 +00:00
while True:
try:
user_input = input("👤 你: ").strip()
except (KeyboardInterrupt, EOFError):
print("\n👋 再见!")
break
if not user_input:
continue
match user_input.lower():
case "quit" | "exit":
print("👋 再见!")
break
2026-03-09 05:37:29 +00:00
case "config":
print(settings.display())
case "health":
run_health_check()
2026-02-28 08:21:35 +00:00
case "clear":
client.clear_session()
print("✅ 会话已清空\n")
case "stats":
2026-03-09 05:37:29 +00:00
print(f"📊 {client.get_memory_stats()}\n")
2026-02-28 08:21:35 +00:00
case "tools":
2026-03-09 05:37:29 +00:00
schemas = client.mcp_server.get_tool_schemas()
print(f"🔧 已注册工具 ({len(schemas)} 个):")
for s in schemas:
print(f" • [{s.name}] {s.description}")
print()
case "chains":
chains = client.memory.get_chain_history()
if not chains:
print("🔗 暂无调用链历史\n")
else:
print(f"🔗 调用链历史 ({len(chains)} 条):")
for i, c in enumerate(chains, 1):
steps = "".join(s["tool_name"] for s in c["steps"])
ok_cnt = sum(1 for s in c["steps"] if s["success"])
total = len(c["steps"])
print(f" {i}. [{c['timestamp'][11:19]}] {c['goal'][:38]}...")
print(f" 链路: {steps} ({ok_cnt}/{total} 步成功)")
print()
case _:
response = client.chat(user_input)
print_response(response)
# ── 配置打印 ───────────────────────────────────────────────────
def run_show_config() -> None:
print(settings.display())
print("\n📁 配置文件查找路径(按优先级):")
print(" 1. 环境变量 AGENT_CONFIG_PATH")
print(" 2. ./config/config.yaml")
print(" 3. ./config.yaml")
print("\n🌍 支持的环境变量覆盖:")
env_vars = [
("LLM_API_KEY", "OpenAI API 密钥sk-..."),
("LLM_MODEL_NAME", "模型名称,如 gpt-4o / gpt-4-turbo"),
("LLM_API_BASE_URL", "自定义 API 地址(兼容代理)"),
("LLM_MODEL_PATH", "本地模型路径"),
("SEARCH_API_KEY", "搜索 API 密钥"),
("LOG_LEVEL", "日志级别 DEBUG/INFO/WARNING/ERROR"),
("AGENT_CONFIG_PATH","配置文件路径"),
]
for var, desc in env_vars:
print(f" {var:<22}{desc}")
print()
2026-02-28 08:21:35 +00:00
# ── 主函数 ─────────────────────────────────────────────────────
def main() -> None:
2026-03-09 05:37:29 +00:00
mode = sys.argv[1] if len(sys.argv) > 1 else "interactive"
if mode == "config":
run_show_config()
return
if mode == "health":
run_health_check()
return
client = build_agent()
if mode == "demo":
2026-02-28 08:21:35 +00:00
run_demo(client)
else:
run_interactive(client)
if __name__ == "__main__":
main()